基于RK3188平台LED驱动程序的移植的移植。如有不正确之处,欢迎大家指点。

本文的LED驱动程序不是通过打开设备节点来访问和控制LED的,是通过sys文件系统来控制LED。

板子上有四盏灯以及对应的GPIO的引脚如下:

基于sys文件系统的LED驱动内核已经提供了,我们需要做的事情没有那么多。内核通过的LED驱动程序走的是平台总线的方式,板级文件Board-rk3188-u4301.c (kernel\arch\arm\mach-rk3188) 里添加LED的GPIO的信息。

 static struct gpio_led rk29_leds[] = {
{
.name = "power", //在/sys/class/leds/ 目录下显示的文件名
.gpio = RK30_PIN0_PB4, //LED的GPIO口的引脚
.default_state = LEDS_GPIO_DEFSTATE_OFF, //设置默认的状态
},
{
.name = "paper",
.gpio = RK30_PIN0_PB5,
.default_state = LEDS_GPIO_DEFSTATE_OFF,
},
{
.name = "connect",
.gpio = RK30_PIN0_PB6,
.default_state = LEDS_GPIO_DEFSTATE_OFF,
},
{
.name = "status",
.gpio = RK30_PIN0_PB7,
.default_state = LEDS_GPIO_DEFSTATE_OFF,
},
}; static struct gpio_led_platform_data rk29_leds_pdata = {
.leds = rk29_leds,
.num_leds = ARRAY_SIZE(rk29_leds),
}; static struct platform_device rk29_device_gpio_leds = {
.name = "leds-gpio", //设备的名称,驱动就是根据这个文件匹配的啊。
.id = -,
.dev = {
.platform_data = &rk29_leds_pdata,
},
};

我们在看看驱动文件Leds-gpio.c (\\192.168.1.144\zsf\rk3188_5.1\android\kernel\drivers\leds)

 /*
* LEDs driver for GPIOs
*
* Copyright (C) 2007 8D Technologies inc.
* Raphael Assenat <raph@8d.com>
* Copyright (C) 2008 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h> #include <asm/gpio.h> struct gpio_led_data {
struct led_classdev cdev;
unsigned gpio;
struct work_struct work;
u8 new_level;
u8 can_sleep;
u8 active_low;
u8 blinking;
int (*platform_gpio_blink_set)(unsigned gpio, int state,
unsigned long *delay_on, unsigned long *delay_off);
}; static void gpio_led_work(struct work_struct *work)
{
struct gpio_led_data *led_dat =
container_of(work, struct gpio_led_data, work); if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpio,
led_dat->new_level,
NULL, NULL);
led_dat->blinking = ;
} else
gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
} static void gpio_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct gpio_led_data *led_dat =
container_of(led_cdev, struct gpio_led_data, cdev);
int level; if (value == LED_OFF)
level = ;
else
level = ; if (led_dat->active_low)
level = !level; /* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
*/
if (led_dat->can_sleep) {
led_dat->new_level = level;
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpio, level,
NULL, NULL);
led_dat->blinking = ;
} else
gpio_set_value(led_dat->gpio, level);
}
} static int gpio_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
struct gpio_led_data *led_dat =
container_of(led_cdev, struct gpio_led_data, cdev); led_dat->blinking = ;
return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
delay_on, delay_off);
} static int __devinit create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
{
int ret, state; led_dat->gpio = -; /* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) {
printk(KERN_INFO "Skipping unavailable LED gpio %d (%s)\n",
template->gpio, template->name);
return ;
} ret = gpio_request(template->gpio, template->name);
if (ret < )
return ret; led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->gpio = template->gpio;
led_dat->can_sleep = gpio_cansleep(template->gpio);
led_dat->active_low = template->active_low;
led_dat->blinking = ;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
led_dat->cdev.blink_set = gpio_blink_set;
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
if (ret < )
goto err; INIT_WORK(&led_dat->work, gpio_led_work); ret = led_classdev_register(parent, &led_dat->cdev);
if (ret < )
goto err; return ;
err:
gpio_free(led_dat->gpio);
return ret;
} static void delete_gpio_led(struct gpio_led_data *led)
{
if (!gpio_is_valid(led->gpio))
return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
gpio_free(led->gpio);
} struct gpio_leds_priv {
int num_leds;
struct gpio_led_data leds[];
}; static inline int sizeof_gpio_leds_priv(int num_leds)
{
return sizeof(struct gpio_leds_priv) +
(sizeof(struct gpio_led_data) * num_leds);
} /* Code to create from OpenFirmware platform devices */
#ifdef CONFIG_LEDS_GPIO_OF
static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node, *child;
struct gpio_leds_priv *priv;
int count = , ret; /* count LEDs in this device, so we know how much to allocate */
for_each_child_of_node(np, child)
count++;
if (!count)
return NULL; priv = kzalloc(sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return NULL; for_each_child_of_node(np, child) {
struct gpio_led led = {};
enum of_gpio_flags flags;
const char *state; led.gpio = of_get_gpio_flags(child, , &flags);
led.active_low = flags & OF_GPIO_ACTIVE_LOW;
led.name = of_get_property(child, "label", NULL) ? : child->name;
led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
state = of_get_property(child, "default-state", NULL);
if (state) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
led.default_state = LEDS_GPIO_DEFSTATE_ON;
else
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
} ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
&pdev->dev, NULL);
if (ret < ) {
of_node_put(child);
goto err;
}
} return priv; err:
for (count = priv->num_leds - ; count >= ; count--)
delete_gpio_led(&priv->leds[count]);
kfree(priv);
return NULL;
} static const struct of_device_id of_gpio_leds_match[] = {
{ .compatible = "gpio-leds", },
{},
};
#else
static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev)
{
return NULL;
}
#define of_gpio_leds_match NULL
#endif static int __devinit gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
int i, ret = ; if (pdata && pdata->num_leds) {
priv = kzalloc(sizeof_gpio_leds_priv(pdata->num_leds),
GFP_KERNEL);
if (!priv)
return -ENOMEM; priv->num_leds = pdata->num_leds;
for (i = ; i < priv->num_leds; i++) {
ret = create_gpio_led(&pdata->leds[i],
&priv->leds[i],
&pdev->dev, pdata->gpio_blink_set);
if (ret < ) {
/* On failure: unwind the led creations */
for (i = i - ; i >= ; i--)
delete_gpio_led(&priv->leds[i]);
kfree(priv);
return ret;
}
}
} else {
priv = gpio_leds_create_of(pdev);
if (!priv)
return -ENODEV;
} platform_set_drvdata(pdev, priv); return ;
} static int __devexit gpio_led_remove(struct platform_device *pdev)
{
struct gpio_leds_priv *priv = dev_get_drvdata(&pdev->dev);
int i; for (i = ; i < priv->num_leds; i++)
delete_gpio_led(&priv->leds[i]); dev_set_drvdata(&pdev->dev, NULL);
kfree(priv); return ;
} static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
.remove = __devexit_p(gpio_led_remove),
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
.of_match_table = of_gpio_leds_match,
},
}; MODULE_ALIAS("platform:leds-gpio"); static int __init gpio_led_init(void)
{
printk(KERN_ERR"zbzhuang leds"); return platform_driver_register(&gpio_led_driver);
} static void __exit gpio_led_exit(void)
{
platform_driver_unregister(&gpio_led_driver);
} module_init(gpio_led_init);
module_exit(gpio_led_exit); MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
MODULE_DESCRIPTION("GPIO LED driver");
MODULE_LICENSE("GPL");

驱动文件就是根据名字跟 设备进行匹配。匹配成功之后就会在创建sys文件系统提供接口给应用程序控制设备。

在内核执行make menuconfig,要配置LED驱动的一些功能如闪烁和呼吸灯等功能,编译进内核。

重新烧录开发板的内核。之后通过串口进入开发板。在/sys/class/leds目录下创建出了,我们板级文件下添加的4个LED驱动。

下面我们演示如何通过sys文件系统控制LED的亮灭。进入connect目录。执行下面三条命令就可控制LED灯的亮灭和进入呼吸灯的模式。

基于sys文件系统的LED驱动的移植【原创】的更多相关文章

  1. 基于S3C2440的linux-3.6.6移植——LED驱动【转】

    本文转载自:http://www.voidcn.com/blog/lqxandroid2012/article/p-625005.html 目前的linux版本的许多驱动都是基于设备模型,LED也不例 ...

  2. JZ2440 启动NFS网络文件系统_初试led驱动

    http://blog.csdn.net/emdfans/article/details/12260969 u-boot ---> q 修改bootargs变量 默认: bootargs=noi ...

  3. Android系统移植与驱动开发——第七章——LED驱动

    LED驱动的实现原理 编写LED驱动: 测试LED驱动之前需要用USB数据线连接开发板,然后打开电源,成功启动之后,执行build.sh脚本文件编译和安装LED驱动,顺利则会自动连接 如果有多个设备文 ...

  4. 使用 /sys 文件系统访问 Linux 内核

    sysfs 与 /sys sysfs 文件系统总是被挂载在 /sys 挂载点上.虽然在较早期的2.6内核系统上并没有规定 sysfs 的标准挂载位置,可以把 sysfs 挂载在任何位置,但较近的2.6 ...

  5. (笔记)linux设备驱动--LED驱动

    linux设备驱动--LED驱动 最近正在学习设备驱动开发,因此打算写一个系列博客,即是对自己学习的一个总结,也是对自己的一个督促,有不对,不足,需要改正的地方还望大家指出,而且希望结识志同道合的朋友 ...

  6. Linux驱动之LED驱动编写

    从上到下,一个软件系统可以分为:应用程序.操作系统(内核).驱动程序.结构图如下:我们需要做的就是写出open.read.write等驱动层的函数.一个LED驱动的步骤如下: 1.查看原理图,确定需要 ...

  7. 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl

    基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl 0. 导语 在嵌入式的道路上寻寻觅觅很久,进入嵌入式这个行业也有几年的时间了,从2011年后 ...

  8. linux驱动之LED驱动

    通过之前的学习,了解到linux驱动编写的流程是:先通过注册函数注册我们编写的入口函数,然后在入口函数中获取设备号->注册字符设备->自动创建设备节点->获取设备树信息,最后通过销毁 ...

  9. FL2440驱动添加(4)LED 驱动添加

    硬件信息:FL2440板子,s3c2440CPU带四个LED,分别在链接GPB5,GPB6,GPB8,GPB10 内核版本:linux-3.8.0 led驱动代码如下: 值得注意地方地方: 1,定时器 ...

随机推荐

  1. Ubuntu 16.04安装MongoDB的GUI工具RoboMongo

    一.下载: https://robomongo.org/download 离线版本:(链接: https://pan.baidu.com/s/1mirFi56 密码: y3t2) 二.安装: -lin ...

  2. SQL SERVER 内存

    http://www.cnblogs.com/CareySon/archive/2012/08/16/HowSQLServerManageMemory.html

  3. maven打包自动配置数据库链接信息

    pom.xml加入下面代码 <profiles> <profile> <id>dev</id> <activation> <activ ...

  4. 在asp.net 项目的bin目录中使用子目录

    如果要动态发布第三方扩展或者对asp.net项目进行二次开发时,希望不影响原有的程序并保持原有bin完整性,可以将扩展放到bin下的子目录中,并修改web.config的相应配置. 原配置: < ...

  5. 【hibernate postgresql】注解@TypeDef/@Enumerated/数据库字段gender为枚举类型,从前台接受到实体后进行保存报错:org.postgresql.util.PSQLException: ERROR: column "gender" is of type gender but expression is of type character varying

    数据库字段gender为枚举类型,从前台接受到实体后进行保存报错:org.postgresql.util.PSQLException: ERROR: column "gender" ...

  6. MY JAVA-NOTE FIRST DAY

    今天是第一天开通博客,我很开心,总算拥有了自己的博客了,以后我会经常在博客里分享一些JAVA的心得.

  7. 椭圆人头跟踪bmp图像序列 BMP Image Sequences for Elliptical Head Tracking

    BMP Image Sequences for Elliptical Head Tracking The BMP image sequences used in the head tracking d ...

  8. [反汇编练习] 160个CrackMe之037

    [反汇编练习] 160个CrackMe之037. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  9. 每天进步一点点——Linux中的线程局部存储(二)

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/26876231     在Linux中另一种更为高效的线程局部存储方法,就是使用keyword ...

  10. java开始到熟悉103-104

    本次内容:linkedlist() 此次是承接上次arraylist(),自己实现linkedlist()(内容较少) package list; /** * 自定义linkedlist类 * @au ...