基于sys文件系统的LED驱动的移植【原创】
基于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驱动的移植【原创】的更多相关文章
- 基于S3C2440的linux-3.6.6移植——LED驱动【转】
本文转载自:http://www.voidcn.com/blog/lqxandroid2012/article/p-625005.html 目前的linux版本的许多驱动都是基于设备模型,LED也不例 ...
- JZ2440 启动NFS网络文件系统_初试led驱动
http://blog.csdn.net/emdfans/article/details/12260969 u-boot ---> q 修改bootargs变量 默认: bootargs=noi ...
- Android系统移植与驱动开发——第七章——LED驱动
LED驱动的实现原理 编写LED驱动: 测试LED驱动之前需要用USB数据线连接开发板,然后打开电源,成功启动之后,执行build.sh脚本文件编译和安装LED驱动,顺利则会自动连接 如果有多个设备文 ...
- 使用 /sys 文件系统访问 Linux 内核
sysfs 与 /sys sysfs 文件系统总是被挂载在 /sys 挂载点上.虽然在较早期的2.6内核系统上并没有规定 sysfs 的标准挂载位置,可以把 sysfs 挂载在任何位置,但较近的2.6 ...
- (笔记)linux设备驱动--LED驱动
linux设备驱动--LED驱动 最近正在学习设备驱动开发,因此打算写一个系列博客,即是对自己学习的一个总结,也是对自己的一个督促,有不对,不足,需要改正的地方还望大家指出,而且希望结识志同道合的朋友 ...
- Linux驱动之LED驱动编写
从上到下,一个软件系统可以分为:应用程序.操作系统(内核).驱动程序.结构图如下:我们需要做的就是写出open.read.write等驱动层的函数.一个LED驱动的步骤如下: 1.查看原理图,确定需要 ...
- 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl 0. 导语 在嵌入式的道路上寻寻觅觅很久,进入嵌入式这个行业也有几年的时间了,从2011年后 ...
- linux驱动之LED驱动
通过之前的学习,了解到linux驱动编写的流程是:先通过注册函数注册我们编写的入口函数,然后在入口函数中获取设备号->注册字符设备->自动创建设备节点->获取设备树信息,最后通过销毁 ...
- FL2440驱动添加(4)LED 驱动添加
硬件信息:FL2440板子,s3c2440CPU带四个LED,分别在链接GPB5,GPB6,GPB8,GPB10 内核版本:linux-3.8.0 led驱动代码如下: 值得注意地方地方: 1,定时器 ...
随机推荐
- [Machine Learning with Python] How to get your data?
Using Pandas Library The simplest way is to read data from .csv files and store it as a data frame o ...
- Ural 1780 Gray Code 乱搞暴力
原题链接:http://acm.timus.ru/problem.aspx?space=1&num=1780 1780. Gray Code Time limit: 0.5 secondMem ...
- [Bzoj4943][Noi2017]蚯蚓(hash)
4943: [Noi2017]蚯蚓 Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 237 Solved: 110[Submit][Status][D ...
- datetimepicker使用总结
datetimepicker使用总结 2019-03-06 16:55:00 使用效果: 官方教程:http://www.bootcss.com/p/bootstrap-datetimepick ...
- BZOJ1006神奇的国度 弦圖染色 最大勢算法
@[弦圖染色, 最大勢算法] Description K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA 相互认识,是简洁高效的.为了巩固三角 ...
- Chrom查看Flash缓存文件及Flash下载方法
比如在优酷看视频时,或者熊猫直播,如果使用Flash进行播放的基本都会先缓存在本地,只不过这个缓存的名字后缀不叫flv,而是类似tmp这样:通常只要找到这个缓存文件,然后改为flv即可播放:如果出现文 ...
- Eclipse工程中Java Build Path中的JDK版本和Java Compiler Compiler compliance level的区别(转)
在这里记录一下在eclipse中比较容易搞混淆和设置错误的地方.如下图所示的功能: 最精准的解释如下: Build Path是运行时环境 Compiler是编译时环境 假设,你的代码用到泛型,Bu ...
- 使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务。
使用spring声明式事务,spring使用AOP来支持声明式事务,会根据事务属性,自动在方法调用之前决定是否开启一个事务,并在方法执行之后决定事务提交或回滚事务.
- vue-router 的URL路径中#的意义
传送门 https://router.vuejs.org/zh-c... Router 构造配置 routes 类型: Array<RouteConfig> RouteConfig 的类型 ...
- [反汇编练习] 160个CrackMe之037
[反汇编练习] 160个CrackMe之037. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...