linux驱动之LED

 

Linux驱动学习之设备树中编写的设备树LED驱动,都是配置LED灯的GPIO寄存器,驱动方式和裸机没有区别。Linux是一个庞大而完善的系统,尤其是驱动框架,像GPIO这种最基本的驱动不可能采用“原始”的裸机驱动方式,否则就相当你买了一辆车,结果每天推着车去上班。

基础知识

Linux内核提供了pinctrl和gpio子系统用于GPIO驱动,可以在leds-gpio.c中可以看到相关功能的使用。
(一)pinctrl子系统
pinctrl子系统用于对设备树中相关pin属性的实现,工作内容如下:
①    获取设备树中的pin信息。
②    根据获取到的pin信息来设置pin的复用功能。
③    根据获取到的pin信息来设置pin的电气特性,比如上/下拉、速度、驱动能力等。
(二)gpio子系统
gpio子系统用于初始化GPIO并且提供相应的API函数,比如设置输入输出、读取GPIO的值等。gpio_direction_output、gpio_free等等,在gpio.h中。

leds-gpio驱动解析

(一)leds的设备树
leds-gpio驱动会以设备树的形式加载到内核中,在设备树配置文件.dts中可以查看到leds设备树节点信息。如下:

 leds {
    compatible = "gpio-leds";
    d2 {
        label = "d2";
        gpios = <&pioE 25 GPIO_ACTIVE_LOW>;    /* PE25, conflicts with A25, RXD2 */
        linux,default-trigger = "heartbeat";
    };
}; 
leds {
    d4 {
        label = "d4";
        gpios = <&pioE 24 GPIO_ACTIVE_HIGH>;
    };
};
pioE: [email protected] {   
            compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
            reg = <0xfffffa00 0x100>;
            interrupts = <10 IRQ_TYPE_LEVEL_HIGH 1>;
            #gpio-cells = <2>;
            gpio-controller;//表示gpio1节点是一个gpio控制器
            interrupt-controller;
            #interrupt-cells = <2>;
            clocks = <&pioE_clk>;
        };

leds {
    compatible = "gpio-leds";
    d2 {
        label = "d2";
        gpios = <&pioE 25 GPIO_ACTIVE_LOW>;    /* PE25, conflicts with A25, RXD2 */
        linux,default-trigger = "heartbeat";
    };
}; 
leds {
    d4 {
        label = "d4";
        gpios = <&pioE 24 GPIO_ACTIVE_HIGH>;
    };
};
pioE: [email protected] {   
            compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
            reg = <0xfffffa00 0x100>;
            interrupts = <10 IRQ_TYPE_LEVEL_HIGH 1>;
            #gpio-cells = <2>;
            gpio-controller;//表示gpio1节点是一个gpio控制器
            interrupt-controller;
            #interrupt-cells = <2>;
            clocks = <&pioE_clk>;
        };
gpios:描述了leds的引脚。
GPIO_ACTIVE_HIGH:说明高电平点亮
&pioE:表示leds使用的IO属于GPIOE组,pioE的定义可以搜索到。
pioE: [email protected] :pioE的起始地址0xfffffa00,可以在datasheet中找到与之对应
#gpio-cells = <2>:表示gpio有两个cell,符合gpios = <&pioE 24 GPIO_ACTIVE_HIGH>的格式定义。
gpio-controller:表示gpioE节点是一个gpio控制器
(二)驱动代码
在驱动/driver目录中,搜索"gpio-leds"内容,找到对应的驱动leds-gpio.c中的compatible与设备树中的compatible一致。查看配置文件“.config”中“CONFIG_LEDS_GPIO=y”。满足以上两个条件leds-gpio会被编译进入内核。
在”leds-gpio.c”中可以看到对设备树信息的提取和使用,即如下图所示的of_函数。

linux驱动之LED

在”leds-gpio.c”中也可以看到对gpio子系统的使用

linux驱动之LED

在”leds-gpio.c”中采用平台总线实现。

linux驱动之LED
操作LEDS

linux驱动之LED

LED设备和驱动都正常的情况下,在系统运行过后,可以在系统中查看到有两个leds设备树节点,与设备树配置文件一致。

同时,会产生/sys/bus/platform/devices/leds/leds目录,其下分别有d2和d4两个子目录,可直接对leds进行控制操作。
将255或0写入brightness文件即可控制亮灭:

echo 0 > /sys/bus/platform/devices/leds/leds/d2/brightness
echo 255 > /sys/bus/platform/devices/leds/leds/d2/brightness

echo 0 > /sys/bus/platform/devices/leds/leds/d2/brightness
echo 255 > /sys/bus/platform/devices/leds/leds/d2/brightness
查看trigger文件,即可知道当前系统支持的触发器,示例:

cat /sys/bus/platform/devices/leds/leds/d2/trigger
none nand-disk mmc0 mmc1 timer [heartbeat] gpio
在设备树文件中,d2内容“linux,default-trigger = “heartbeat””,所以当前触发器为heartbeat,此时可以观察d2对应的LED灯,正常会每1秒间隔闪烁2次,也就是heartbeat效果。
想要重新设置触发器很简单,使用echo将需要的触发器名称写入trigger文件即可。

echo timer > /sys/bus/platform/devices/leds/leds/d2/trigger
再次查看,timer则设置成了触发器

none nand-disk mmc0 mmc1 [timer] heartbeat gpio
此时d2对应的LED灯,正常会每隔1秒闪烁1次。