概述
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觸發器全部編譯到內核中。這樣方便使用和選擇。
設備註冊及使用
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; // 默認狀態
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
};
另外還要填寫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 /* No blink GPIO state low */
#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
#define GPIO_LED_BLINK 2 /* Please, blink */
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,一個紅燈,一個綠燈,都是低電平燈亮。
驅動源碼分析
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做操作。
亮滅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
觸發器
直接查看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
設置值已經生效了。