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/
  • 相关阅读:
    Pandas加载含有嵌套(nested)文档的mongodb数据
    [Spark笔记]Spark Streaming连接Kafka的入门代码
    [Spark笔记]Apache Spark — Overview
    [Hive笔记]Hive常用命令整理
    Mac上安装MongoDB后没有默认用户或密码,需要创建用户
    游戏服务器架构系列
    游戏服务器架构系列
    giantbranch的专栏——只更新一些简单的东西,工具什么的,更多更新只在新博客:www.giantbranch.cn
    SpringBoot Admin 2.1.5监控微服务的基本配置
    一张图看清国内程序员的分布数量
  • 原文地址:https://www.cnblogs.com/schips/p/using_linux_kernel_led_sub_system.html
Copyright © 2011-2022 走看看