本例将根据上一篇分析的led子系统框架去讲述如何在子系统中注册一个led设备,前提是通过make menucong将device driver下面的LED Support和它下面的LED class support及相应的trigger打开.
具体步骤分三步:
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函数被调用,
cat trigger会发现打印出很多的触发器(如果你在make menuconfig去将相应的trigger添加的话),并且如果你没有设置default_trigger的话在none的这个触发器上加了[],表示我们当前没有添加触发器, 这时如何你echo timer > trigger然后在cat trigger会发现[]加在了timer上面,表示当前的触发器是timer,并且在当前目录下生成了delay_on和delay_off两个文件,分别cat会发现打印的值和我们设置的值一样,同时看log会发现我们的my_brightness_set函数被不断的调用,brightness的值是0和default_brightness的值(表示led处于闪烁状态).
最后附上我自己的实例代码,虚拟了4个led:
/*************************************************************************
> File Name: led-test.c
> Author:
> Mail:
> Created Time: 2018年01月02日 星期二 18时37分17秒
************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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);