日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 自带的LED 灯驱动实验

發布時間:2023/12/10 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 自带的LED 灯驱动实验 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • Linux 內核自帶LED 驅動使能
  • Linux 內核自帶LED 驅動簡介
    • LED 燈驅動框架分析
    • module_platform_driver 函數簡析
    • gpio_led_probe 函數簡析
  • 設備樹節點編寫
  • 運行測試

前面我們都是自己編寫LED 燈驅動,其實像LED 燈這樣非常基礎的設備驅動,Linux 內核已經集成了。Linux 內核的LED 燈驅動采用platform 框架,因此我們只需要按照要求在設備樹文件中添加相應的LED 節點即可,本章我們就來學習如何使用Linux 內核自帶的LED 驅動來驅動I.MX6U-ALPHA 開發板上的LED0。

Linux 內核自帶LED 驅動使能

上一章節我們編寫基于設備樹的platform LED 燈驅動,其實Linux 內核已經自帶了LED 燈
驅動,要使用Linux 內核自帶的LED 燈驅動首先得先配置Linux 內核,使能自帶的LED 燈驅
動,輸入如下命令打開Linux 配置菜單:

make menuconfig

按照如下路徑打開LED 驅動配置項:

-> Device Drivers-> LED Support (NEW_LEDS [=y])->LED Support for GPIO connected LEDs

按照上述路徑,選擇“LED Support for GPIO connected LEDs”,將其編譯進Linux 內核,也即是在此選項上按下“Y”鍵,使此選項前面變為“<*>”,如圖56.1.1 所示:

在“LED Support for GPIO connected LEDs”上按下‘?’可以打開此選項的幫助信息,如圖56.1.2 所示:

從圖56.1.2 可以看出,把Linux 內部自帶的LED 燈驅動編譯進內核以后,
CONFIG_LEDS_GPIO 就會等于‘y’,Linux 會根據CONFIG_LEDS_GPIO 的值來選擇如何編譯LED 燈驅動,如果為‘y’就將其編譯進Linux 內核。

配置好Linux 內核以后退出配置界面,打開.config 文件,會找到“CONFIG_LEDS_GPIO=y”這一行,如圖56.1.3 所示:

重新編譯Linux 內核,然后使用新編譯出來的zImage 鏡像啟動開發板。

Linux 內核自帶LED 驅動簡介

LED 燈驅動框架分析

LED 燈驅動文件為/drivers/leds/leds-gpio.c,大家可以打開/drivers/leds/Makefile 這個文件,找到如下所示內容:

2 # LED Core 3 obj-$(CONFIG_NEW_LEDS) += led-core.o ..... 23 obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o 24 obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o 25 obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o ......

第24 行,如果定義了CONFIG_LEDS_GPIO 的話就會編譯leds-gpio.c 這個文件,在上一小節我們選擇將LED 驅動編譯進Linux 內核,在.config 文件中就會有“CONFIG_LEDS_GPIO=y”
這一行,因此leds-gpio.c 驅動文件就會被編譯。
接下來我們看一下leds-gpio.c 這個驅動文件,找到如下所示內容:

236 static const struct of_device_id of_gpio_leds_match[] = { 237 { .compatible = "gpio-leds", }, 238 {}, 239 }; ...... 290 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 }, 297 }; 298 299 module_platform_driver(gpio_led_driver);

第236~239 行,LED 驅動的匹配表,此表只有一個匹配項,compatible 內容為“gpio-leds”,因此設備樹中的LED 燈設備節點的compatible 屬性值也要為“gpio-leds”,否則設備和驅動匹配不成功,驅動就沒法工作。

第290~296 行,platform_driver 驅動結構體變量,可以看出,Linux 內核自帶的LED 驅動采用了platform 框架。第291 行可以看出probe 函數為gpio_led_probe,因此當驅動和設備匹配成功以后gpio_led_probe 函數就會執行。從294 行可以看出,驅動名字為“leds-gpio”,因此會在/sys/bus/platform/drivers 目錄下存在一個名為“leds-gpio”的文件,如圖56.2.1.1 所示:

第299 行通過module_platform_driver 函數向Linux 內核注冊gpio_led_driver 這個platform驅動。

module_platform_driver 函數簡析

在上一小節中我們知道LED 驅動會采用module_platform_driver 函數向Linux 內核注冊platform 驅動,其實在Linux 內核中會大量采用module_platform_driver 來完成向Linux 內核注冊platform 驅動的操作。module_platform_driver 定義在include/linux/platform_device.h 文件中,
為一個宏,定義如下:

221 #define module_platform_driver(__platform_driver) \ 222 module_driver(__platform_driver, platform_driver_register, \ 223 platform_driver_unregister)

可以看出,module_platform_driver 依賴module_driver,module_driver 也是一個宏,定義在include/linux/device.h 文件中,內容如下:

1260 #define module_driver(__driver, __register, __unregister, ...) \ 1261 static int __init __driver##_init(void) \ 1262 { \ 1263 return __register(&(__driver) , ##__VA_ARGS__); \ 1264 } \ 1265 module_init(__driver##_init); \ 1266 static void __exit __driver##_exit(void) \ 1267 { \ 1268 __unregister(&(__driver) , ##__VA_ARGS__); \ 1269 } \ 1270 module_exit(__driver##_exit);

借助示例代碼56.2.2.1 和示例代碼56.2.2.2,將:

module_platform_driver(gpio_led_driver)

展開以后就是:

static int __init gpio_led_driver_init(void) { return platform_driver_register (&(gpio_led_driver)); } module_init(gpio_led_driver_init); static void __exit gpio_led_driver_exit(void) { platform_driver_unregister (&(gpio_led_driver) ); } module_exit(gpio_led_driver_exit);

上面的代碼不就是標準的注冊和刪除platform 驅動嗎?因此module_platform_driver 函數的功能就是完成platform 驅動的注冊和刪除。

gpio_led_probe 函數簡析

當驅動和設備匹配以后gpio_led_probe 函數就會執行,此函數主要是從設備樹中獲取LED燈的GPIO 信息,縮減后的函數內容如下所示:

243 static int gpio_led_probe(struct platform_device *pdev) 244 { 245 struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev); 246 struct gpio_leds_priv *priv; 247 int i, ret = 0; 248 249 if (pdata && pdata->num_leds) { /* 非設備樹方式*/ /* 獲取platform_device信息*/ ...... 268 } else { /* 采用設備樹*/ 269 priv = gpio_leds_create(pdev); 270 if (IS_ERR(priv)) 271 return PTR_ERR(priv); 272 } 273 274 platform_set_drvdata(pdev, priv); 275 276 return 0; 277 }

第269~271 行,如果使用設備樹的話,使用gpio_leds_create 函數從設備樹中提取設備信息,獲取到的LED 燈GPIO 信息保存在返回值中,gpio_leds_create 函數內容如下:

167 static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) 168 { 169 struct device *dev = &pdev->dev; 170 struct fwnode_handle *child; 171 struct gpio_leds_priv *priv; 172 int count, ret; 173 struct device_node *np; 174 175 count = device_get_child_node_count(dev); 176 if (!count) 177 return ERR_PTR(-ENODEV); 178 179 priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL); 180 if (!priv) 181 return ERR_PTR(-ENOMEM); 182 183 device_for_each_child_node(dev, child) { 184 struct gpio_led led = {}; 185 const char *state = NULL; 186 187 led.gpiod = devm_get_gpiod_from_child(dev, NULL, child); 188 if (IS_ERR(led.gpiod)) { 189 fwnode_handle_put(child); 190 ret = PTR_ERR(led.gpiod); 191 goto err; 192 } 193 194 np = of_node(child); 195 196 if (fwnode_property_present(child, "label")) { 197 fwnode_property_read_string(child, "label", &led.name); 198 } else { 199 if (IS_ENABLED(CONFIG_OF) && !led.name && np) 200 led.name = np->name; 201 if (!led.name) 202 return ERR_PTR(-EINVAL); 203 }

第175 行,調用device_get_child_node_count 函數統計子節點數量,一般在在設備樹中創建一個節點表示LED 燈,然后在這個節點下面為每個LED 燈創建一個子節點。因此子節點數量也是LED 燈的數量。
第183 行,遍歷每個子節點,獲取每個子節點的信息。
第187 行,獲取LED 燈所使用的GPIO 信息。
第196~197 行,讀取子節點label 屬性值,因為使用label 屬性作為LED 的名字。
第204~205 行,獲取“linux,default-trigger”屬性值,可以通過此屬性設置某個LED 燈在Linux 系統中的默認功能,比如作為系統心跳指示燈等等。
第207~215 行,獲取“default-state”屬性值,也就是LED 燈的默認狀態屬性。
第220 行,調用create_gpio_led 函數創建LED 相關的io,其實就是設置LED 所使用的io為輸出之類的。create_gpio_led 函數主要是初始化led_dat 這個gpio_led_data 結構體類型變量,led_dat 保存了LED 的操作函數等內容。

關于gpio_led_probe 函數就分析到這里,gpio_led_probe 函數主要功能就是獲取LED 燈的設備信息,然后根據這些信息來初始化對應的IO,設置為輸出等。

設備樹節點編寫

打開文檔Documentation/devicetree/bindings/leds/leds-gpio.txt,此文檔詳細的講解了Linux 自帶驅動對應的設備樹節點該如何編寫,我們在編寫設備節點的時候要注意以下幾點:
①、創建一個節點表示LED 燈設備,比如dtsleds,如果板子上有多個LED 燈的話每個LED燈都作為dtsleds 的子節點。
②、dtsleds 節點的compatible 屬性值一定要為“gpio-leds”。
③、設置label 屬性,此屬性為可選,每個子節點都有一個label 屬性,label 屬性一般表示LED 燈的名字,比如以顏色區分的話就是red、green 等等。
④、每個子節點必須要設置gpios 屬性值,表示此LED 所使用的GPIO 引腳!
⑤、可以設置“linux,default-trigger”屬性值,也就是設置LED 燈的默認功能,可以查閱Documentation/devicetree/bindings/leds/common.txt 這個文檔來查看可選功能,比如:
backlight:LED 燈作為背光。
default-on:LED 燈打開
heartbeat:LED 燈作為心跳指示燈,可以作為系統運行提示燈。
ide-disk:LED 燈作為硬盤活動指示燈。
timer:LED 燈周期性閃爍,由定時器驅動,閃爍頻率可以修改
⑥、可以設置“default-state”屬性值,可以設置為on、off 或keep,為on 的時候LED 燈默認打開,為off 的話LED 燈默認關閉,為keep 的話LED 燈保持當前模式。
根據上述幾條要求在imx6ull-alientek-emmc.dts 中添加如下所示LED 燈設備節點:

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 };

因為I.MX6U-ALPHA 開發板只有一個LED0,因此在dtsleds 這個節點下只有一個子節點led0,LED0 名字為red,默認關閉。修改完成以后保存并重新編譯設備樹,然后用新的設備樹啟動開發板。

運行測試

用新的zImage 和imx6ull-alientek-emmc.dtb 啟動開發板,啟動以后查看
/sys/bus/platform/devices/dtsleds 這個目錄是否存在,如果存在的話就如到此目錄中,如圖56.4.1所示:

進入到leds 目錄中,此目錄中的內容如圖56.4.2 所示:

從圖56.4.2 可以看出,在leds 目錄下有一個名為“red”子目錄,這個子目錄的名字就是我們在設備樹中第5 行設置的label 屬性值。
我們的設置究竟有沒有用,最終是要通過測試才能知道的,首先查看一下系統中有沒有“sys/class/leds/red/brightness”這個文件,如果有的話就輸入如下命令打開RED 這個LED 燈:

echo 1 > /sys/class/leds/red/brightness //打開LED0

關閉RED 這個LED 燈的命令如下:

echo 0 > /sys/class/leds/red/brightness //關閉LED0

如果能正常的打開和關閉LED 燈話就說明我們Linux 內核自帶的LED 燈驅動工作正常。
我們一般會使用一個LED 燈作為系統指示燈,系統運行正常的話這個LED 指示燈就會一閃一閃的。里我們設置LED0 作為系統指示燈,在dtsleds 這個設備節點中加入“linux,default-trigger”屬性信息即可,屬性值為“heartbeat”,修改完以后的dtsleds 節點內容如下:

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 };

第7 行,設置LED0 為heartbeat。
第8 行,默認打開LED0。
重新編譯設備樹并且使用新的設備樹啟動Linux 系統,啟動以后LED0 就會閃爍,作為系統心跳指示燈,表示系統正在運行。

總結

以上是生活随笔為你收集整理的Linux 自带的LED 灯驱动实验的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。