原文:https://blog.csdn.net/hanp_linux/article/details/79037684
前提配置device driver
下面的LED Support
和它下面的LED class support
及相应的trigger打开。
类似高通平台的方案。
qcom,gpio-leds { compatible = "gpio-leds"; led-blue{ label = "red"; default-state = "off"; linux,default-trigger = "none";//没有默认的触发源,也可以写为timer gpios = <&msm_gpio 17 0x00>; }; led-green{ label = "green"; default-state = "on"; gpios = <&msm_gpio 34 0x00>; }; };
一般在init
或者probe
中实现这个。
static struct led_classdev *led_devs; led_devs = kzalloc(sizeof(struct led_classdev), GFP_KERNEL); if (led_devs == NULL) { printk("alex.han %s:%d led_devs alloc error\n", __func__, __LINE__); return -1; } //设置led的最大亮度 LED_FULL在leds.h中定义,为255(有些led是可以通过控制电流来控制亮度的,) led_devs->max_brightness = LED_FULL; //设置led的默认亮度,LED_HALF在leds.h中定义,为127,如果不设置默认为0 led_devs->brightness = LED_HALF; led_devs->flags = LED_CORE_SUSPENDRESUME; //这个led设备的名字,注册后将会在/sys/class/leds/目录下创建xxx设备目录 led_devs->name = "xxx"; //设置默认的trigger,如果不设置则默认trigger为0, 如果不需要trigger,这个地方可以不设置 led_devs->default_trigger = "timer"; //默认trigger为timer //设置亮度的函数,当我们通过sys文件系统来调节led亮度的时候,会调用这个函数,当我们设置了trigger,对应的trigger也会调用这个函数 led_devs->brightness_set = my_brightness_set; //delay_on和delay_off表示默认led闪烁的频率,只有在使用timer这个trigger的时候才有效,表示led亮的时间和灭的时间,从而来控制闪烁频率,单位是ms led_devs->blink_delay_on = 1000; led_devs->blink_delay_off = 2000; //设置闪烁时led的亮度 led_devs->blink_brightness = 100;
static void my_brightness_set(struct led_classdev * led_cdev, enum led_brightness brightness) { struct led_device * dev = (struct led_device *)led_cdev; led_cdev->brightness = brightness; printk("alex.han %s %d brightness = %d gpio = %d\n", __func__, __LINE__, brightness, dev->gpio); /* 这个地方要实现你自己的的led设备的亮和灭或者是设置亮度操作 比如: 如果你的led设备是用一个gpio进行简单控制,那么这个地方对你来说brightness就是亮和灭的开个,brightness=0就设置灯亮,否则就设置led灭 如果你的led设备使用一个中间芯片来控制的(比如lp5523,可以通过iic控制lp5523芯片从而来控制led的亮度),同时又是通过控制电流来控制亮度,那么就需要调用i2c_write将需要设置的内容写到对应的芯片中, */ }
//调用led_class.c中的注册函数,将初始化的led_classdev结构体注册到led子系统中,创建对应的设备节点 led_classdev_register(NULL, led_devs);
将上述框架添加到一个模块中,编译到kernel中,并make menuconfig打开相应的宏,重新烧写image。
进入/sys/class/目录会发现有leds目录,进入leds目录会发现我们注册的xxx设备,进入xxx目录会发现有brightness max_brightness trigger等属性
cat brightness #会打印出我们设置的默认的brightness值, echo 100 > brightness #根据log会发现我们驱动的my_brightness_set函数被调用,
关于 trigger,如果你在make menuconfig
去将相应的trigger添加的话,cat trigger
会发现打印出很多的触发器。此时,对应触发器前面如果有[]
代表当前使用的trigger。
如果在
none
的这个触发器上加了[]
,表示我们当前没有添加触发器,
这时如果你echo timer > trigger
然后cat trigger
会发现[]加在了timer上面,表示当前的触发器是timer,并且在当前目录下生成了delay_on和delay_off两个文件。
分别cat会发现打印的值和我们设置的值一样,同时看log会发现我们的my_brightness_set函数被不断的调用。
最后附上我自己的实例代码,虚拟了4个led:
/************************************************************************* > File Name: led-test.c > Author: > Mail: > Created Time: 2018年01月02日 星期二 18时37分17秒 ************************************************************************/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/leds.h> struct led_desc { int gpio; char * name; }; /* 虚拟了4个led */ static struct led_desc led_gpios[] = { {1, "led1"}, {2, "led2"}, {3, "led3"}, }; struct led_device { struct led_classdev cdev; int gpio; }; static struct led_device * led_devs = NULL; static void my_brightness_set(struct led_classdev * led_cdev, enum led_brightness brightness) { struct led_device * dev = (struct led_device *)led_cdev; led_cdev->brightness = brightness; printk("alex.han %s %d brightness = %d gpio = %d\n", __func__, __LINE__, brightness, dev->gpio); } static int myled_init(void) { int i; int ret; printk("alex.han %s %d\n", __func__, __LINE__); led_devs = kzalloc(sizeof(struct led_device) * sizeof(led_gpios) / sizeof(led_gpios[0]), GFP_KERNEL); if (led_devs == NULL) { printk("alex.han %s:%d led_devs alloc error\n", __func__, __LINE__); return -1; } for (i = 0; i < (sizeof(led_gpios) / sizeof(led_gpios[0])); i++) { led_devs[i].cdev.max_brightness = LED_FULL; led_devs[i].cdev.brightness = LED_HALF; led_devs[i].cdev.flags = LED_CORE_SUSPENDRESUME; led_devs[i].cdev.name = led_gpios[i].name; led_devs[i].cdev.default_trigger = "timer"; //默认trigger为timer led_devs[i].gpio = led_gpios[i].gpio; // gpio端口号 led_devs[i].cdev.brightness_set = my_brightness_set; led_devs[i].cdev.blink_delay_on = 1000; led_devs[i].cdev.blink_delay_off = 2000; led_devs[i].cdev.blink_brightness = 100; ret = led_classdev_register(NULL, &led_devs[i].cdev); if (ret < 0) { i--; while (i >= 0) { i--; printk("alex.han %s %d register err\n", __func__, __LINE__); led_classdev_unregister(&led_devs[i].cdev); } kfree(led_devs); return -1; } } return 0; } static void myled_exit(void) { int i; for (i = 0; i < (sizeof(led_gpios) / sizeof(led_gpios[0])); i++) { led_classdev_unregister(&led_devs[i].cdev); } kfree(led_devs); } module_init(myled_init); module_exit(myled_exit);