Linux內(nèi)核LED子系統(tǒng)、請務(wù)必看

LED子系統(tǒng)你要是說很難嘛,但是它就是控制一些簡單的GPIO口,但是你要是說它很簡單嘛,但是我也不見得一個初學(xué)者很快就能掌握,你如果是剛?cè)腴T這部分的話,我覺得你還是要去仔細(xì)研究下這些驅(qū)動。前兩天在網(wǎng)上看到一句話,初學(xué)者喜歡研究語法,大牛喜歡研究數(shù)據(jù)結(jié)構(gòu),Linux下的數(shù)據(jù)結(jié)構(gòu)非常多,把這些東西搞明白對你非常有幫助。
簡單說下LED子系統(tǒng)
- 應(yīng)用的話不是很想解釋,應(yīng)用就是調(diào)用驅(qū)動的接口,打開、關(guān)閉、設(shè)置等等操作。
- 核心是為驅(qū)動和效果和應(yīng)用服務(wù)的,所以我們很多東西都依賴于核心,所以會有一些基本的數(shù)據(jù)結(jié)構(gòu),注冊、卸載等函數(shù)。
- 驅(qū)動的用法很簡單,但是在簡單的用法后面蘊(yùn)藏著巨大的秘密,Linux下的很多驅(qū)動都是如此,填充好一些數(shù)據(jù)結(jié)構(gòu),然后調(diào)用register函數(shù)注冊,這樣之后,就能把驅(qū)動注冊起來。
- trigger指的是一種效果,比如亮、滅、是一個效果,驅(qū)動里面就做成了default-on的效果,還有閃爍、呼吸等,都是不同的效果。
AW9110 LED驅(qū)動芯片
我們分析下這個芯片的硬件連接吧,先分析下硬件有啥特點(diǎn)。
這是一款I(lǐng)2C接口的LED驅(qū)動IC,默認(rèn)的驅(qū)動電流大小是37mA,有256個驅(qū)動等級,讀到這里我們應(yīng)該可以知道,我們可以用這個IC做呼吸的功能。
看一個驅(qū)動的流程理解
我吹幾句
我們寫程序的時候,需要注意的是在dts里面可以設(shè)置什么,這個應(yīng)該是關(guān)鍵,如果這個是一個LED燈驅(qū)動,那么,在dts里面就需要設(shè)置LED的屬性,比如這個LED燈有什么效果,默認(rèn)效果是什么。
還有就是要注意led_classdev,因?yàn)閞egister注冊的時候就是把這個結(jié)構(gòu)體填充的東西給注冊起來的。
dts
+???????aw9110b:?aw9110b@5b?{
+???????????????compatible?=?"aw9110b-leds";
+???????????????gpio_out_drv?=?;
+???????????????shdn-gpio?=?<&pio?19?GPIO_ACTIVE_HIGH>;
+???????????????reg?=?<0x5b>;
+???????????????#address-cells?=?<1>;
+???????????????#size-cells?=?<0>;
+???????????????status?=?"okay";
+
+???????????????led1:?led@1?{
+???????????????????????????????label?=?"led_cam1";
+???????????????????????????????reg?=?<1>;
+???????????????????????????????flags?=?;
+???????????????????????????????led-max-microamp?=?<10000>;
+???????????????????????????????linux,default-trigger?=?"default-on";
+???????????????};
}
led_classdev 結(jié)構(gòu)體
struct?led_classdev?{
?const?char??*name;
?enum?led_brightness??brightness;
?enum?led_brightness??max_brightness;
?int????flags;
?/*?Lower?16?bits?reflect?status?*/
#define?LED_SUSPENDED??(1?<0)
?/*?Upper?16?bits?reflect?control?information?*/
#define?LED_CORE_SUSPENDRESUME?(1?<16)
#define?LED_BLINK_ONESHOT?(1?<17)
#define?LED_BLINK_ONESHOT_STOP?(1?<18)
#define?LED_BLINK_INVERT?(1?<19)
#define?LED_SYSFS_DISABLE?(1?<20)
#define?SET_BRIGHTNESS_ASYNC?(1?<21)
#define?SET_BRIGHTNESS_SYNC?(1?<22)
#define?LED_DEV_CAP_FLASH?(1?<23)
?/*?Set?LED?brightness?level?*/
?/*?Must?not?sleep,?use?a?workqueue?if?needed?*/
?void??(*brightness_set)(struct?led_classdev?*led_cdev,
???????enum?led_brightness?brightness);
?/*
??*?Set?LED?brightness?level?immediately?-?it?can?block?the?caller?for
??*?the?time?required?for?accessing?a?LED?device?register.
??*/
?int??(*brightness_set_sync)(struct?led_classdev?*led_cdev,
?????enum?led_brightness?brightness);
?/*?Get?LED?brightness?level?*/
?enum?led_brightness?(*brightness_get)(struct?led_classdev?*led_cdev);
?/*
??*?Activate?hardware?accelerated?blink,?delays?are?in?milliseconds
??*?and?if?both?are?zero?then?a?sensible?default?should?be?chosen.
??*?The?call?should?adjust?the?timings?in?that?case?and?if?it?can't
??*?match?the?values?specified?exactly.
??*?Deactivate?blinking?again?when?the?brightness?is?set?to?a?fixed
??*?value?via?the?brightness_set()?callback.
??*/
?int??(*blink_set)(struct?led_classdev?*led_cdev,
?????????unsigned?long?*delay_on,
?????????unsigned?long?*delay_off);
?struct?device??*dev;
?const?struct?attribute_group?**groups;
?struct?list_head??node;???/*?LED?Device?list?*/
?const?char??*default_trigger;?/*?Trigger?to?use?*/
?unsigned?long???blink_delay_on,?blink_delay_off;
?struct?timer_list??blink_timer;
?int????blink_brightness;
?void???(*flash_resume)(struct?led_classdev?*led_cdev);
?struct?work_struct?set_brightness_work;
?int???delayed_set_value;
#ifdef?CONFIG_LEDS_TRIGGERS
?/*?Protects?the?trigger?data?below?*/
?struct?rw_semaphore??trigger_lock;
?struct?led_trigger?*trigger;
?struct?list_head??trig_list;
?void???*trigger_data;
?/*?true?if?activated?-?deactivate?routine?uses?it?to?do?cleanup?*/
?bool???activated;
#endif
?/*?Ensures?consistent?access?to?the?LED?Flash?Class?device?*/
?struct?mutex??led_access;
};
LED trigger 的理解

我這里打開的是呼吸的trigger,這個trigger是用來實(shí)現(xiàn)呼吸效果的,但是我們這個IC沒有自主呼吸的功能,所以我們需要實(shí)現(xiàn)呼吸的話,肯定是離不開定時器的,我們使用一個定時器在一個時間段內(nèi)不斷的改變輸出的電流,以此來改變輸出的亮度。這樣讓用戶就看到呼吸的效果了。
我簡單的說下這個呼吸曲線,因?yàn)槿搜蹖α炼鹊挠^察并不是線性的,舉個例子,理想的做法是,我們的曲線在一個時間內(nèi)遞增一樣大小的電流,這樣輸出看到的亮度也是曲線增加的,但是因?yàn)槲覀內(nèi)搜蹖α炼扔^察并不是理想的,所以我們可能看到的是突然變亮,變滅的過程也會極其尷尬。
贈送一段不健全的呼吸曲線
static?const?uint8_t?s_breath_effect[]?=?{
????0,?0,?0,?0,?1,?2,?3,?4,?6,?8,
????10,?12,?14,?16,?19,?22,?25,?28,?32,?36,
????40,?44,?48,?52,?57,?62,?67,?72,?78,?84,
????90,?96,?102,?108,?115,?122,?129,?136,?144,?152,
????160,?168,?176,?184,?193,?202,?211,?220,?230,?240,
????250,?240,?230,?220,?211,?202,?193,?184,?176,?168,
????160,?152,?144,?136,?129,?122,?115,?108,?102,?96,
????90,?84,?78,?72,?67,?62,?57,?52,?48,?44,
????40,?36,?32,?28,?25,?22,?19,?16,?14,?12,
????10,?8,?6,?4,?3,?2,?1,?0,?0,?0,
};

節(jié)點(diǎn)
android:/sys/class/leds?#?ls
blue??????????led_cam_b?led_key1?
屬性
android:/sys/class/leds/led_key1?#?ls
brightness?device?max_brightness?power?subsystem?trigger?uevent
trigger
android:/sys/class/leds/led_key1?#?cat?trigger
[none]?rc-feedback?nand-disk?mmc0?timer?oneshot?heartbeat?breath

微信掃描二維碼,關(guān)注我的公眾號
