Linux版本號(hào)4.1.15? ?芯片I.MX6ULL? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? ??大叔學(xué)Linux? ? 品人間百味? 思文短情長(zhǎng)?
? ? ? ? ?學(xué)習(xí)嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)整整30天了。今天簡(jiǎn)單做一個(gè)小結(jié)。因?yàn)橹暗闹饕ぷ魇亲鯝RM的裸機(jī)開(kāi)發(fā),所以接觸Linux以后感覺(jué)很多東西都變了。不僅僅包括相關(guān)知識(shí)點(diǎn)的歸納,更重要的是思維方式的轉(zhuǎn)變。做裸機(jī)開(kāi)發(fā)的時(shí)候,在很多時(shí)候是要弄清楚最底層的邏輯才能進(jìn)行代碼的開(kāi)發(fā)。而Linux則更像是站在一個(gè)更高的維度去思考,很細(xì)枝末葉的東西是不需要考慮的。相對(duì)裸機(jī)開(kāi)發(fā)的維度來(lái)說(shuō),裸機(jī)開(kāi)發(fā)后做Linux驅(qū)動(dòng)開(kāi)發(fā)更有點(diǎn)降維打擊的感覺(jué)。但并不是說(shuō)Linux驅(qū)動(dòng)開(kāi)發(fā)簡(jiǎn)單,而是說(shuō)裸機(jī)開(kāi)發(fā)對(duì)底層的要求可能會(huì)更高一些。以上僅僅是個(gè)人的一點(diǎn)自我感受。
????????本節(jié)筆記主要學(xué)習(xí)Linux自帶的LED驅(qū)動(dòng)試驗(yàn)。主要內(nèi)容包括驅(qū)動(dòng)使能、簡(jiǎn)介、設(shè)備樹(shù)節(jié)點(diǎn)編寫(xiě)及運(yùn)行測(cè)試。其中驅(qū)動(dòng)簡(jiǎn)介又包括LED燈驅(qū)動(dòng)框架分析、module_platform_driver函數(shù)簡(jiǎn)介和gpio_led_probe函數(shù)簡(jiǎn)析。
一、Linux內(nèi)核自帶的LED燈驅(qū)動(dòng)使能
? ? ? ? 需要配置Linux內(nèi)核,使能自帶的LED驅(qū)動(dòng)。使用make menuconfig打開(kāi)Linux配置菜單。
? ? ? ? 按照如下路徑打開(kāi)LED驅(qū)動(dòng)配置項(xiàng):
? ? ? ? Device Drivers
? ? ? ? ? ? ? ? LED Support(NEW_LEDS=[y])
? ? ? ? ? ? ? ? ? ? ? ? LED Support for GPIO connected LEDs.?在此選項(xiàng)上按下“ Y”鍵,使此選項(xiàng)前面變?yōu)椤?<*>”,
????????重新編譯 Linux 內(nèi)核,然后使用新編譯出來(lái)的 zImage 鏡像啟動(dòng)開(kāi)發(fā)板。
二、Linux內(nèi)核自帶LED驅(qū)動(dòng)簡(jiǎn)介
1、LED燈驅(qū)動(dòng)框架分析
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
236 static const struct of_device_id of_gpio_leds_match[] = {
237 { .compatible = "gpio-leds", },
238 {},
239 };
????????LED 驅(qū)動(dòng)的匹配表,此表只有一個(gè)匹配項(xiàng), compatible 內(nèi)容為“ gpio-leds”,因此設(shè)備樹(shù)中的 LED 燈設(shè)備節(jié)點(diǎn)的 compatible 屬性值也要為“ gpio-leds”,否則設(shè)備和驅(qū)動(dòng)匹配不成功,驅(qū)動(dòng)就沒(méi)法工作。
static struct platform_driver gpio_led_driver = {
291 .probe = gpio_led_probe,
292 .remove = gpio_led_remove,
293 .driver = {
294 .name = "leds-gpio",
295 .of_match_table = of_gpio_leds_match,
296 },
????????platform_driver 驅(qū)動(dòng)結(jié)構(gòu)體變量,可以看出, Linux 內(nèi)核自帶的 LED 驅(qū)動(dòng)采用了 platform 框架。
module_platform_driver(gpio_led_driver);
????????通過(guò) module_platform_driver 函數(shù)向 Linux 內(nèi)核注冊(cè) gpio_led_driver 這個(gè) platform
驅(qū)動(dòng)。
2、module_platform_driver函數(shù)簡(jiǎn)介
????????module_platform_driver 定義在 include/linux/platform_device.h 文件中為一個(gè)宏,
????????module_platform_driver 依賴(lài) module_driver, module_driver 也是一個(gè)宏。
????????module_platform_driver 函數(shù)的功能就是完成 platform 驅(qū)動(dòng)的注冊(cè)和刪除。
3、gpio_led_probe函數(shù)簡(jiǎn)析
269 priv = gpio_leds_create(pdev);
270 if (IS_ERR(priv))
271 return PTR_ERR(priv);
????????如果使用設(shè)備樹(shù)的話,使用 gpio_leds_create 函數(shù)從設(shè)備樹(shù)中提取設(shè)備信息,獲取到的 LED 燈 GPIO 信息保存在返回值中。
? ? ? ? 在gpio_leds_create 函數(shù)中,調(diào)用 device_get_child_node_count 函數(shù)統(tǒng)計(jì)子節(jié)點(diǎn)數(shù)量,一般在在設(shè)備樹(shù)中創(chuàng)建一個(gè)節(jié)點(diǎn)表示 LED 燈,然后在這個(gè)節(jié)點(diǎn)下面為每個(gè) LED 燈創(chuàng)建一個(gè)子節(jié)點(diǎn)。因此子節(jié)點(diǎn)數(shù)量也是 LED 燈的數(shù)量。
?
device_for_each_child_node(dev, child) {
????????遍歷每個(gè)子節(jié)點(diǎn),獲取每個(gè)子節(jié)點(diǎn)的信息。
led.gpiod = devm_get_gpiod_from_child(dev, NULL, child);
????????獲取 LED 燈所使用的 GPIO 信息。
196 if (fwnode_property_present(child, "label")) {
197 fwnode_property_read_string(child, "label", &led.name);
????????讀取子節(jié)點(diǎn) label 屬性值,因?yàn)槭褂?label 屬性作為 LED 的名字。
204 fwnode_property_read_string(child, "linux,default-trigger",
205 &led.default_trigger);
????????獲取“ linux,default-trigger”屬性值,可以通過(guò)此屬性設(shè)置某個(gè) LED 燈在Linux 系統(tǒng)中的默認(rèn)功能,比如作為系統(tǒng)心跳指示燈等等。
207 if (!fwnode_property_read_string(child, "default-state",
208 &state)) {
209 if (!strcmp(state, "keep"))
210 led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
211 else if (!strcmp(state, "on"))
212 led.default_state = LEDS_GPIO_DEFSTATE_ON;
213 else
214 led.default_state = LEDS_GPIO_DEFSTATE_OFF;
215 }
????????獲取“ default-state”屬性值,也就是 LED 燈的默認(rèn)狀態(tài)屬性。
220 ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
221 dev, NULL);
????????調(diào)用 create_gpio_led 函數(shù)創(chuàng)建 LED 相關(guān)的 io,其實(shí)就是設(shè)置 LED 所使用的 io為輸出之類(lèi)的。 create_gpio_led 函數(shù)主要是初始化 led_dat 這個(gè) gpio_led_data 結(jié)構(gòu)體類(lèi)型變量,led_dat 保存了 LED 的操作函數(shù)等內(nèi)容。
????????gpio_led_probe 函數(shù)主要功能就是獲取 LED 燈的設(shè)備信息,然后根據(jù)這些信息來(lái)初始化對(duì)應(yīng)的 IO,設(shè)置為輸出等。? ? ?
三、設(shè)備樹(shù)節(jié)點(diǎn)編寫(xiě)
????????在編寫(xiě)設(shè)備節(jié)點(diǎn)的時(shí)候要注意以下幾點(diǎn):
①、創(chuàng)建一個(gè)節(jié)點(diǎn)表示 LED 燈設(shè)備,比如 dtsleds,如果板子上有多個(gè) LED 燈的話每個(gè) LED
燈都作為 dtsleds 的子節(jié)點(diǎn)。
②、 dtsleds 節(jié)點(diǎn)的 compatible 屬性值一定要為“ gpio-leds”。
③、設(shè)置 label 屬性,此屬性為可選,每個(gè)子節(jié)點(diǎn)都有一個(gè) label 屬性, label 屬性一般表示
LED 燈的名字,比如以顏色區(qū)分的話就是 red、 green 等等。
④、每個(gè)子節(jié)點(diǎn)必須要設(shè)置 gpios 屬性值,表示此 LED 所使用的 GPIO 引腳!
⑤、可以設(shè)置“ linux,default-trigger”屬性值,也就是設(shè)置 LED 燈的默認(rèn)功能,比如:
backlight: LED 燈作為背光。
default-on: LED 燈打開(kāi)
heartbeat: LED 燈作為心跳指示燈,可以作為系統(tǒng)運(yùn)行提示燈。
ide-disk: LED 燈作為硬盤(pán)活動(dòng)指示燈。
timer: LED 燈周期性閃爍,由定時(shí)器驅(qū)動(dòng),閃爍頻率可以修改
⑥、可以設(shè)置“ default-state”屬性值,可以設(shè)置為 on、 off 或 keep,為 on 的時(shí)候 LED 燈默
認(rèn)打開(kāi),為 off 的話 LED 燈默認(rèn)關(guān)閉,為 keep 的話 LED 燈保持當(dāng)前模式。
1 dtsleds {
2 compatible = "gpio-leds";
3 4
led0 {
5 label = "red";
6 gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
7 default-state = "off";
8 };
9 };
四、運(yùn)行測(cè)試
????????啟 動(dòng) 開(kāi) 發(fā) 板 , 啟 動(dòng) 以 后 查 看/sys/bus/platform/devices/dtsleds 這個(gè)目錄是否存在。
進(jìn)入到 leds 目錄中,此目錄中的內(nèi)容如圖所示:
????????在 leds 目錄下有一個(gè)名為“ red”子目錄,這個(gè)子目錄的名字就是我們?cè)谠O(shè)備樹(shù)中第 5 行設(shè)置的 label 屬性值。
????????輸入如下命令打開(kāi) RED 這個(gè) LED 燈:
echo 1 > /sys/class/leds/red/brightness //打開(kāi) LED0
????????關(guān)閉 RED 這個(gè) LED 燈的命令如下:
echo 0 > /sys/class/leds/red/brightness //關(guān)閉 LED0
????????系統(tǒng)運(yùn)行指示燈:
1 dtsleds {
2 compatible = "gpio-leds";
3 4
led0 {
5 label = "red";
6 gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
7 linux,default-trigger = "heartbeat";
8 default-state = "on";
9 };
10 };
????????設(shè)置 LED0 作為系統(tǒng)指示燈,在 dtsleds 這個(gè)設(shè)備節(jié)點(diǎn)中加入“ linux,default-trigger”屬性信息即可,屬性值為“ heartbeat”。
五、總結(jié)
????????本節(jié)筆記主要內(nèi)容包括驅(qū)動(dòng)使能、簡(jiǎn)介、設(shè)備樹(shù)節(jié)點(diǎn)編寫(xiě)及運(yùn)行測(cè)試。其中驅(qū)動(dòng)簡(jiǎn)介又包括LED燈驅(qū)動(dòng)框架分析、module_platform_driver函數(shù)簡(jiǎn)介和gpio_led_probe函數(shù)簡(jiǎn)析。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-743720.html
本文為參考正點(diǎn)原子開(kāi)發(fā)板配套教程整理而得,僅用于學(xué)習(xí)交流使用,不得用于商業(yè)用途。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-743720.html
到了這里,關(guān)于Linux學(xué)習(xí)第30天:Linux 自帶的 LED 燈驅(qū)動(dòng)實(shí)驗(yàn):驅(qū)動(dòng)開(kāi)發(fā)思維方式的轉(zhuǎn)變勢(shì)在必行的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!