zoukankan      html  css  js  c++  java
  • 在Linux驱动中使用LED子系统

    在Linux驱动中使用LED子系统

    原文: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>;
            };
        };
    

    分配led_classdev实例以及初始化

    一般在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
    ", __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
    ", __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
    ", __func__, __LINE__, brightness, dev->gpio);
    }
    
    static int myled_init(void)
    {
        int i;
        int ret;
        printk("alex.han %s %d
    ", __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
    ", __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
    ", __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);
    
    如果说我的文章对你有用,只不过是我站在巨人的肩膀上再继续努力罢了。
    若在页首无特别声明,本篇文章由 Schips 经过整理后发布。
    博客地址:https://www.cnblogs.com/schips/
  • 相关阅读:
    hdu 5387 Clock (模拟)
    CodeForces 300B Coach (并查集)
    hdu 3342 Legal or Not(拓扑排序)
    hdu 3853 LOOPS(概率DP)
    hdu 3076 ssworld VS DDD(概率dp)
    csu 1120 病毒(LICS 最长公共上升子序列)
    csu 1110 RMQ with Shifts (线段树单点更新)
    poj 1458 Common Subsequence(最大公共子序列)
    poj 2456 Aggressive cows (二分)
    HDU 1869 六度分离(floyd)
  • 原文地址:https://www.cnblogs.com/schips/p/using_linux_kernel_led_sub_system.html
Copyright © 2011-2022 走看看