天天看點

linux中leds-gpio的問題描述

linux核心的leds-gpio是使用GPIO控制LED的驅動,隻要将闆子上LED燈對接的GPIO引腳号進行适當的配置,就能使用這個驅動了,十分友善。

對leds-gpio驅動有一個整體概念。

一、概述

leds-gpio封裝得十分好,隻需要提供可正常使用的GPIO即可。另外還具備觸發器功能,其實就是控制LED的亮滅(及頻率)。比如default-on是點亮LED燈的觸發器,沒有取消前一直亮着。heartbeat是心跳觸發器,經筆者實踐,此觸發器是快速閃爍2次,然後滅掉,滅掉時間較亮的時間長。timer為定時觸發器,即1HZ内亮滅。其它還有如ide硬碟、mmc、CPU觸發器,就不一一介紹了。

leds驅動位于drivers/leds目錄。leds-gpio驅動名稱為“leds-gpio”,驅動檔案為drivers/leds/leds-gpio.c。

觸發器驅動位于drivers/leds/trigger目錄。

二、核心配置

本文基于linux 3.17.1版本核心進行分析。

Device Drivers->

    -*- LED Support  --->  

        {*}   LED Class Support # 與使用者空間互動的

        <M>   LED Support for GPIO connected LEDs   # 可為子產品,也可編譯到核心中

        -*-   LED Trigger support  ---> #觸發器,最好編譯到核心中(即選項“*”)

        <*>   LED Timer Trigger

        <*>   LED One-shot Trigger

        <*>   LED Heartbeat Trigger

        <*>   LED backlight Trigger

        [*]   LED CPU Trigger

        <*>   LED GPIO Trigger

        <*>   LED Default ON Trigger

從配置中看到,筆者将LED觸發器全部編譯到核心中。這樣友善使用和選擇。

三、裝置注冊及使用

3.1 LED相關結構體

驅動開發者使用gpio_led對LED進行指派,包括LED名稱、GPIO引腳号、燈亮是哪個電平,還有預設狀态。gpio_led結構體定義如下:

struct gpio_led {

    const char *name; // 名稱,會生成/sys/.../leds/name目錄

    const char *default_trigger; // 預設觸發器,可寫可不寫,在指令行可以重新指派

    unsigned     gpio; // GPIO引腳号

    unsigned    active_low : 1; // 為1表示低電平LED點亮

    unsigned    retain_state_suspended : 1;

    unsigned    default_state : 2; // 預設狀态

};

另外還要填寫gpio_led_platform_data結構體,其定義如下:

struct gpio_led_platform_data {

    int         num_leds; // 一共有多少個LED燈

    const struct gpio_led *leds; // 上面的結構體指針

#define GPIO_LED_NO_BLINK_LOW    0    

#define GPIO_LED_NO_BLINK_HIGH    1    

#define GPIO_LED_BLINK        2    

    int        (*gpio_blink_set)(unsigned gpio, int state,

                    unsigned long *delay_on,

                    unsigned long *delay_off); // LED閃爍回調函數,可置為NULL

};

一個執行個體如下:

static struct gpio_led gpio_leds[] = {

    {

        .name = "red",

        .gpio = 33, // GP2_1   GPIO_NO = Group * 32 + Id

        .default_state = LEDS_GPIO_DEFSTATE_ON, // 預設LED亮

        .active_low = 1, // 低電平亮

        //.default_trigger = "timer", // 觸發器

    },

    {

        .name = "green",

        .gpio = 34,

        .default_state = LEDS_GPIO_DEFSTATE_ON, 

        .active_low = 1,

        //.default_trigger = "heartbeat", 

    },

};

static struct gpio_led_platform_data gpio_led_info = {

     .leds          = gpio_leds,

     .num_leds     = ARRAY_SIZE(gpio_leds),

};

從結構體中知道,系統有2個LED,一個紅燈,一個綠燈,都是低電平燈亮。

3.2 LED平台裝置

leds-gpio驅動定義如下(drivers/leds/leds-gpio.c):

static struct platform_driver gpio_led_driver = {

    .probe        = gpio_led_probe,

    .remove        = gpio_led_remove,

    .driver        = {

        .name    = "leds-gpio",

        .owner    = THIS_MODULE,

        .of_match_table = of_match_ptr(of_gpio_leds_match),

    },

};

module_platform_driver(gpio_led_driver);

從gpio_led_driver結構體中可以看到驅動名稱為leds-gpio。是以要使用這個驅動,必須另外定義一個platform裝置,并調用函數platform_device_register注冊。本文執行個體如下:

static struct platform_device leds_gpio = {

    .name = "leds-gpio",

    .id = -1,

    .dev = {

        .platform_data = &gpio_led_info,

        .release = platformdev_release,

    },

};

其中name表示裝置名稱,必須為“leds-gpio”,這樣才能比對并加載成功。最後提一下release成員,在較新的核心中必須對此進行指派,否則會有錯誤資訊提示:

Device 'leds-gpio' does not have a release() function, it is broken and must be fixed.

最後,注冊leds裝置——建議在闆子的GPIO正常工作之後再進行注冊。

platform_device_register(&leds_gpio); // 注冊leds裝置

注意,如果是以modules形式動态加載的話,必須要适合的地方如remove函數在解除安裝leds裝置:

platform_device_unregister(&leds_gpio); // 解除安裝leds裝置

四、應用執行個體

LED裝置和驅動都正常情況下,系統啟動後,會産生/sys/bus/platform/devices/leds-gpio/leds目錄,其下分别有red和green兩個子目錄。可以分别對不同的紅色LED和綠色LED做操作。

4.1 亮滅LED

将1或0寫入brightness檔案即可控制亮滅。

示例如下:

echo 0 > /sys/bus/platform/devices/leds-gpio/leds/green/brightness

echo 0 > /sys/bus/platform/devices/leds-gpio/leds/red/brightness 

echo 1 > /sys/bus/platform/devices/leds-gpio/leds/green/brightness

echo 1 > /sys/bus/platform/devices/leds-gpio/leds/red/brightness 

4.1 觸發器

直接檢視trigger檔案,即可知道目前系統支援的觸發器,示例:

cat /sys/bus/platform/devices/leds-gpio/leds/red/trigger 

[none] timer oneshot heartbeat backlight gpio cpu0 default-on mmc0 mmc1 mmc2

在前面的驅動中注釋掉了trigger,是以現在是none。

設定觸發器很簡單,使用ecoh将需要的觸發器名稱寫入trigger檔案即可。注意,寫入的字元串一定是trigger檔案已經存在的,否則會提示參數非法。寫入心跳觸發器示例:

echo heartbeat > /sys/bus/platform/devices/leds-gpio/leds/red/trigger

此時闆子上紅燈應會閃爍。

再次檢視:

cat /sys/bus/platform/devices/leds-gpio/leds/red/trigger 

none timer oneshot [heartbeat] backlight gpio cpu0 default-on mmc0 mmc1 mmc2

設定值已經生效了。

參考資源:

1、核心源碼官網:https://www.kernel.org

2、核心源碼查詢:http://lxr.free-electrons.com/source/?v=3.17

LED的配置

一、前言

用于非PMIC的LED,Linux内部有對應的庫可以直接調用。

二、CONFIG檔案

CONFIG_LEDS_TRIGGER_TIMER=y 

CONFIG_LEDS_GPIO=y

使能核心的LED GPIO子產品

三、DTS描述

添加GPIO-LED的具體描述

gpio-leds { 

    compatible = "gpio-leds"; 

    status = "okay"; 

    led-blink { 

        gpios = <&tlmm 76 0x00>; 

        label = "led-blink";//建立子節點 

        linux,default-trigger = "none";//沒有預設的觸發源,也可以寫為timer 

        retain-state-suspended; //休眠保持運作

    }; 

};

四、權限添加

GPIO-LED中亮滅時間的節點預設為644,是以需要補充加上讀寫權限

//drivers/leds/trigger/ledtrig-timer.c

static DEVICE_ATTR(delay_on, 0666, led_delay_on_show, led_delay_on_store); 

static DEVICE_ATTR(delay_off, 0666, led_delay_off_show, led_delay_off_store);

但是直接這樣修改,會發現核心編譯會報錯誤,這是因為修改/sys檔案系統下的檔案權限,會受到VERIFY_OCTAL_PERMISSIONS的權限檢查。詳細内容檢視include/linux/kernel.h檔案中的定義

//include/linux/kernel.h

#define VERIFY_OCTAL_PERMISSIONS(perms)     \ 

(BUILD_BUG_ON_ZERO((perms) < 0) +         \ 

BUILD_BUG_ON_ZERO((perms) > 0777) +     \ 

BUILD_BUG_ON_ZERO((((perms) >> 6) & 4) < (((perms) >> 3) & 4)) + \ BUILD_BUG_ON_ZERO((((perms) >> 3) & 4) < ((perms) & 4)) + \ 

BUILD_BUG_ON_ZERO((((perms) >> 6) & 2) < (((perms) >> 3) & 2)) + \ 

BUILD_BUG_ON_ZERO((perms) & 2) + \ 

(perms))

這裡從注釋上也看的比較清晰權限的要求: 

1.User perms >= group perms >= other perms 

即所有者權限>=組使用者權限>=其他人權限 

也就是說 類似0466的這種權限是不允許的 

2. Other writable? Generally considered a bad idea.

不允許其他使用者寫的權限

BUILD_BUG_ON_ZERO(e) 表示的就是若表達式e結果為0,則編譯通過,該宏的值也為0;若表達式e的結果不為0,則編譯不通過。

是以隻需要将最後一個檢查:其他使用者可寫,這一項删除即可

BUILD_BUG_ON_ZERO((perms) & 2) +     /

五、測試功能

//10Hz 閃爍

echo timer > /sys/class/leds/led-blink/trigger 

echo 50> /sys/class/leds/led-blink/delay_on 

echo 50> /sys/class/leds/led-blink/delay_off

bmc