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