Linux下led子系统 --- 实例篇

本例将根据上一篇分析的led子系统框架去讲述如何在子系统中注册一个led设备,前提是通过make menucong将device driver下面的LED Support和它下面的LED class support及相应的trigger打开.
具体步骤分三步:

1. 分配led_classdev结构体
     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;       
     }     
2. 初始化这个结构体
     //设置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将需要设置的内容写到对应的芯片中,
  */
}  
3. 注册这个结构体
//调用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);

你可能感兴趣的:(Linux驱动,led子系统,驱动框架)