imx6ull-驅動開發篇36——Linux 自帶的 LED 燈驅動實驗

在之前的文章里,我們掌握了無設備樹和有設備樹這兩種 platform 驅動的開發方式。

但實際上有現成的,Linux 內核的 LED 燈驅動采用 platform 框架,我們只需要按照要求在設備樹文件中添加相應的 LED 節點即可。

本講內容,我們就來學習如何使用 Linux 內核自帶的 LED 驅動,來驅動 I.MX6U-ALPHA 開發板上的 LED0。

LED 驅動使能

要使用 Linux 內核自帶的 LED 燈驅動首先得先配置 Linux 內核,使能自帶的 LED 燈驅動。

輸入如下命令打開 Linux 配置菜單:

make menuconfig

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

選擇“LED Support for GPIO connected LEDs”,按下“Y”鍵,將其編譯進 Linux 內核,也即是在此選項上,如圖:

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

把 Linux 內部自帶的LED 燈驅動編譯進內核以后 ,CONFIG_LEDS_GPIO 就會等于‘y’。

配置好 Linux 內核以后退出配置界面,打開.config 文件,搜索“CONFIG_LEDS_GPIO=y”:

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

LED 驅動分析

驅動框架

LED 燈驅動文件為/drivers/leds/leds-gpio.c,打開/drivers/leds/Makefile文件,可以發現:

 obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o

如果定義了 CONFIG_LEDS_GPIO 的話,就會編譯 leds-gpio.c 這個文件,通過圖形化界面我們已經使能LED,因此 leds-gpio.c 驅動文件就會被編譯。

打開 leds-gpio.c 這個驅動文件,采用了 platform 框架:

static const struct of_device_id of_gpio_leds_match[] = {{ .compatible = "gpio-leds", },{},
};
......static struct platform_driver gpio_led_driver = {.probe = gpio_led_probe,.remove = gpio_led_remove,.driver = {.name = "leds-gpio",.of_match_table = of_gpio_leds_match,},
};module_platform_driver(gpio_led_driver);

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

probe 函數為 gpio_led_probe,驅動名字為“leds-gpio”,當驅動和設備匹配成功以后 gpio_led_probe 函數就會執行。

/sys/bus/platform/drivers 目錄下,存在一個名為“leds-gpio”的文件,如圖:

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

module_platform_driver(gpio_led_driver);

module_platform_driver 函數

在 Linux 內核中,會大量采用 module_platform_driver 來完成向 Linux 內核注冊 platform 驅動的操作。

module_platform_driver 定義在 include/linux/platform_device.h 文件中,為一個宏,定義如下:

#define module_platform_driver(__platform_driver) \module_driver(__platform_driver, platform_driver_register, \platform_driver_unregister)

可以看出, module_platform_driver 依賴 module_driver, module_driver 也是一個宏。

module_driver? 定義在include/linux/device.h 文件中,內容如下:

#define module_driver(__driver, __register, __unregister, ...) \static int __init __driver##_init(void) \{ \return __register(&(__driver), ##__VA_ARGS__); \} \module_init(__driver##_init); \static void __exit __driver##_exit(void) \{ \__unregister(&(__driver), ##__VA_ARGS__); \} \module_exit(__driver##_exit)

module_platform_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);

因此 module_platform_driver 函數的功能,就是完成 platform 驅動的注冊和刪除。

gpio_led_probe 函數

當驅動和設備匹配以后 gpio_led_probe 函數就會執行,此函數主要是從設備樹中獲取 LED燈的 GPIO 信息。

gpio_led_probe 函數,縮減后的函數內容如下所示:

/*** gpio_led_probe - GPIO LED驅動的探測函數* @pdev: 匹配到的平臺設備** 此函數在驅動與設備匹配成功后調用,負責初始化LED設備。* 支持傳統platform_data和設備樹兩種配置方式。*/
static int gpio_led_probe(struct platform_device *pdev)
{struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);struct gpio_leds_priv *priv;int i, ret = 0;/* 檢查并使用平臺數據(傳統非設備樹方式) */if (pdata && pdata->num_leds) {/* 獲取platform_device信息 */......} else { /* 設備樹方式初始化 */priv = gpio_leds_create(pdev);if (IS_ERR(priv))return PTR_ERR(priv);}/* 將私有數據保存到設備結構 */platform_set_drvdata(pdev, priv);return 0;
}

如果使用設備樹的話,使用 gpio_leds_create 函數從設備樹中提取設備信息,獲取到的 LED 燈 GPIO 信息保存在返回值中。

gpio_leds_create 函數內容如下:

/*** gpio_leds_create - 從設備樹創建GPIO LED設備* @pdev: 平臺設備指針** 該函數解析設備樹節點,為每個子節點創建對應的LED設備* 返回包含所有LED的私有數據結構,錯誤時返回ERR_PTR*/
static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{struct device *dev = &pdev->dev;struct fwnode_handle *child;  // 設備樹子節點句柄struct gpio_leds_priv *priv;int count, ret;struct device_node *np;/* 1. 獲取子節點數量 */count = device_get_child_node_count(dev);if (!count)return ERR_PTR(-ENODEV);  // 無有效子節點/* 2. 分配私有數據結構內存 */priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);if (!priv)return ERR_PTR(-ENOMEM);  // 內存分配失敗/* 3. 遍歷所有子節點 */device_for_each_child_node(dev, child) {struct gpio_led led = {};const char *state = NULL;/* 3.1 獲取GPIO描述符 */led.gpiod = devm_get_gpiod_from_child(dev, NULL, child);if (IS_ERR(led.gpiod)) {fwnode_handle_put(child);ret = PTR_ERR(led.gpiod);goto err;  // GPIO獲取失敗跳轉錯誤處理}np = of_node(child);  // 獲取設備樹節點/* 3.2 解析LED名稱(label屬性優先) */if (fwnode_property_present(child, "label")) {fwnode_property_read_string(child, "label", &led.name);} else {if (IS_ENABLED(CONFIG_OF) && !led.name && np)led.name = np->name;  // 使用節點名作為備選if (!led.name)return ERR_PTR(-EINVAL);  // 名稱無效}/* 3.3 解析默認觸發器 */fwnode_property_read_string(child, "linux,default-trigger",&led.default_trigger);/* 3.4 解析默認狀態(on/off/keep) */if (!fwnode_property_read_string(child, "default-state", &state)) {if (!strcmp(state, "keep"))led.default_state = LEDS_GPIO_DEFSTATE_KEEP;else if (!strcmp(state, "on"))led.default_state = LEDS_GPIO_DEFSTATE_ON;elseled.default_state = LEDS_GPIO_DEFSTATE_OFF;}/* 3.5 解析電源管理屬性 */if (fwnode_property_present(child, "retain-state-suspended"))led.retain_state_suspended = 1;/* 3.6 創建單個LED設備 */ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],dev, NULL);if (ret < 0) {fwnode_handle_put(child);goto err;  // LED創建失敗跳轉錯誤處理}}return priv;  // 成功返回私有數據err:/* 錯誤處理:逆向清理已創建的LED設備 */for (count = priv->num_leds - 2; count >= 0; count--)delete_gpio_led(&priv->leds[count]);return ERR_PTR(ret);  // 返回錯誤指針
}
  • 調用 device_get_child_node_count 函數,統計子節點數量,一般在在設備樹中創建一個節點表示 LED 燈,然后在這個節點下面為每個 LED 燈創建一個子節點。因此子節點數量也是 LED 燈的數量。
  • 遍歷每個子節點,獲取每個子節點的信息
  • 獲取 LED 燈所使用的 GPIO 信息
  • 讀取子節點 label 屬性值,因為使用 label 屬性作為 LED 的名字。
  • 獲取“linux,default-trigger”屬性值,可以通過此屬性設置某個 LED 燈在Linux 系統中的默認功能,比如作為系統心跳指示燈等等。
  • 獲取“default-state”屬性值,也就是 LED 燈的默認狀態屬性。
  • 調用 create_gpio_led 函數,創建 LED 相關的 io,其實就是設置 LED 所使用的 io為輸出之類的。 create_gpio_led 函數主要是初始化 led_dat 這個 gpio_led_data 結構體類型變量, led_dat 保存了 LED 的操作函數等內容。

總結,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 燈的默認功能。
  • 可以設置“default-state”屬性值,可以設置為 on、 off 或 keep,為 on 的時候 LED 燈默認打開,為 off 的話 LED 燈默認關閉,為 keep 的話 LED 燈保持當前模式。

其中,LED 燈的默認功能,可以查閱Documentation/devicetree/bindings/leds/common.txt 這個文檔來查看可選功能,比如:

  • backlight: LED 燈作為背光。
  • default-on: LED 燈打開。
  • heartbeat: LED 燈作為心跳指示燈,可以作為系統運行提示燈。
  • ide-disk: LED 燈作為硬盤活動指示燈。
  • timer: LED 燈周期性閃爍,由定時器驅動,閃爍頻率可以修改。

按照上面描述,打開 imx6ull-alientek-emmc.dts文件, 添加如下所示 LED 燈設備節點:

dtsleds {compatible = "gpio-leds";led0 {label = "red";gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;default-state = "off";};
};

在 dtsleds 這個節點下只,有一個子節點led0, LED0 名字為 red,默認關閉。

修改完成以后保存,并重新編譯設備樹:make dtbs,然后用新的設備樹啟動開發板。

運行測試

用新的zImage 和 imx6ull-alientek-emmc.dtb 啟動開發板 , 啟動以后查 看/sys/bus/platform/devices/dtsleds 這個目錄是否存在。

如果存在的話,進入該目錄,如圖:

繼續進入到 leds 目錄中,如圖:

可以看出,在 leds 目錄下有一個名為“red”子目錄,這個子目錄的名字就是我們在設備樹中設置的 label 屬性值。

查看一下系統中有沒有“sys/class/leds/red/brightness”這個文件,存在就說明運行正常,輸入如下命令測試LED燈:

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

我們也可以設置 LED0 作為系統指示燈,修改設備樹文件:在 dtsleds 這個設備節點中加入“linux,default-trigger”屬性信息即可,屬性值為“heartbeat”,

dtsleds {compatible = "gpio-leds";led0 {label = "red";gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;linux,default-trigger = "heartbeat";default-state = "on";};
};

重新編譯設備樹,使用新的設備樹啟動 Linux 系統。

啟動以后 LED0 就會閃爍,作為系統心跳指示燈,表示系統正在運行。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94046.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94046.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94046.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度學習中主流激活函數的數學原理與PyTorch實現綜述

1. 定義與作用什么是激活函數&#xff1f;激活函數有什么用&#xff1f;答&#xff1a;激活函數&#xff08;Activation Function&#xff09;是一種添加到人工神經網絡中的函數&#xff0c;旨在幫助網絡學習數據中的復雜模式。類似于人類大腦中基于神經元的模型&#xff0c;激…

Linux高效備份:rsync + inotify實時同步

一、rsync 簡介 rsync&#xff08;Remote Sync&#xff09;是 Linux 系統下的數據鏡像備份工具&#xff0c;支持本地復制、遠程同步&#xff08;通過 SSH 或 rsync 協議&#xff09;&#xff0c;是一個快速、安全、高效的增量備份工具。二、rsync 特性 支持鏡像保存整個目錄樹和…

一種通過模板輸出Docx的方法

起因在2個群里都有網友討論這個問題&#xff0c;俺就寫了一個最簡單的例子。其實&#xff0c;我們經常遇到一些Docx的輸出的需求&#xff0c;“用模板文件進行處理”是最簡單的一個方法&#xff0c;如果想預覽也簡單 DevExpress 、Teleric 都可以&#xff0c;而且也支持 Web 、…

探索 List 的奧秘:自己動手寫一個 STL List?

&#x1f4d6;引言大家好&#xff01;今天我們要一起來揭開 C 中 list 容器的神秘面紗——不是直接用 STL&#xff0c;而是親手實現一個簡化版的 list&#xff01;&#x1f389;你是不是曾經好奇過&#xff1a;list 是怎么做到高效插入和刪除的&#xff1f;&#x1f50d;迭代器…

mysql占用高內存排查與解決

mysql占用高內存排查-- 查看當前全局內存使用情況&#xff08;需要啟用 performance_schema&#xff09; SELECT * FROM sys.memory_global_total; -- 查看總內存使用 SELECT * FROM sys.memory_global_by_current_bytes LIMIT 10; -- 按模塊分類查看內存使用排行memory/perfor…

構建真正自動化知識工作的AI代理

引言&#xff1a;新一代生產力范式的黎明 自動化知識工作的人工智能代理&#xff08;AI Agent&#xff09;&#xff0c;或稱“智能體”&#xff0c;正迅速從理論構想演變為重塑各行各業生產力的核心引擎。這些AI代理被定義為能夠感知環境、進行自主決策、動態規劃、調用工具并持…

青少年機器人技術(四級)等級考試試卷-實操題(2021年12月)

更多內容和歷年真題請查看網站&#xff1a;【試卷中心 -----> 電子學會 ----> 機器人技術 ----> 四級】 網站鏈接 青少年軟件編程歷年真題模擬題實時更新 青少年機器人技術&#xff08;四級&#xff09;等級考試試卷-實操題&#xff08;2021年12月&#xff09; …

最新短網址源碼,防封。支持直連、跳轉。 會員無廣

最新短網址源碼&#xff0c;防封。支持直連、跳轉。 會員無廣告1.可將長網址自動縮短為短網址&#xff0c;方便記憶和使用。2.短網址默認為臨時有效&#xff0c;可付費升級為永久有效&#xff0c;接入支付后可自動完成&#xff0c;無需人工操作。3.系統支持設置圖片/文字/跳轉頁…

緩存-變更事件捕捉、更新策略、本地緩存和熱key問題

緩存-基礎知識 熟悉計算機基礎的同學們都知道&#xff0c;服務的存儲大多是多層級的&#xff0c;呈現金字塔類型。通常來說本機存儲比通過網絡通信的外部存儲更快&#xff08;現在也不一定了&#xff0c;因為網絡傳輸速度很快&#xff0c;至少可以比一些過時的本地存儲設備速度…

報表工具DevExpress .NET Reports v25.1新版本亮點:AI驅動的擴展

DevExpress Reporting是.NET Framework下功能完善的報表平臺&#xff0c;它附帶了易于使用的Visual Studio報表設計器和豐富的報表控件集&#xff0c;包括數據透視表、圖表&#xff0c;因此您可以構建無與倫比、信息清晰的報表。 DevExpress Reporting控件日前正式發布了v25.1…

kubernetes中pod的管理及優化

目錄 2 資源管理方式 2.1 命令式對象管理 2.2 資源類型 2.2.1 常用的資源類型 2.2.2 kubectl常見命令操作 2.3 基本命令示例 2.4 運行和調試命令示例 2.5 高級命令示例 3 pod簡介 3.1 創建自主式pod&#xff08;生產環境不推薦&#xff09; 3.1.1 優缺點 3.1.2 創建…

解釋一下,Linux,shell,Vmware,Ubuntu,以及Linux命令和shell命令的區別

Linux 操作系統概述Linux 是一種開源的類 Unix 操作系統內核&#xff0c;由 Linus Torvalds 于 1991 年首次發布。作為現代計算的基礎設施之一&#xff0c;它具有以下核心特征&#xff1a;多用戶多任務特性允許多個用戶同時操作系統資源&#xff0c;而模塊化設計使其能夠適應從…

Windows 系統中,添加打印機主要有以下幾種方式

在 Windows 系統中,添加打印機主要有以下幾種方式,我將從最簡單到最復雜為您詳細介紹。 方法一:自動安裝(推薦首選) 這是 Windows 10 和 Windows 11 中最簡單、最現代的方法。系統會自動搜索網絡(包括無線和有線網絡)上可用的打印機并安裝驅動程序。 操作步驟: 進入…

Mixture of Experts Guided by Gaussian Splatters Matters

Mixture of Experts Guided by Gaussian Splatters Matters: A new Approach to Weakly-Supervised Video Anomaly Detection ICCV2025 https://arxiv.org/pdf/2508.06318 https://github.com/snehashismajhi/GS-MoEAbstract 視頻異常檢測&#xff08;VAD&#xff09;是一項具有…

SeaTunnel Databend Sink Connector CDC 功能實現詳解

Databend 是一個面向分析型工作負載優化的 OLAP 數據庫&#xff0c;采用列式存儲架構。在處理 CDC&#xff08;Change Data Capture&#xff0c;變更數據捕獲&#xff09;場景時&#xff0c;如果直接執行單條的 UPDATE 和 DELETE 操作&#xff0c;會嚴重影響性能&#xff0c;無…

算法230. 二叉搜索樹中第 K 小的元素

題目&#xff1a;給定一個二叉搜索樹的根節點 root &#xff0c;和一個整數 k &#xff0c;請你設計一個算法查找其中第 k 小的元素&#xff08;從 1 開始計數&#xff09;。示例 1&#xff1a;輸入&#xff1a;root [3,1,4,null,2], k 1 輸出&#xff1a;1 示例 2&#xff1…

Seaborn數據可視化實戰:Seaborn多變量圖表繪制高級教程

Seaborn多變量圖表實戰&#xff1a;從數據到洞察 學習目標 本課程將帶領學員深入了解Seaborn庫中用于繪制多變量圖表的高級功能&#xff0c;包括聯合圖&#xff08;Joint Plot&#xff09;、對角線圖&#xff08;Pair Plot&#xff09;等。通過本課程的學習&#xff0c;學員將能…

【數智化人物展】首衡科技CTO李蒙:算法會過時,數據會貶值,只有系統智能才具未來性

李蒙本文由首衡科技CTO李蒙投遞并參與由數智猿數據猿上海大數據聯盟共同推出的《2025中國數智化轉型升級先鋒人物》榜單/獎項評選。大數據產業創新服務媒體——聚焦數據 改變商業“算法會過時&#xff0c;數據會貶值。”當我第一次在內部戰略會上拋出這句話時&#xff0c;現場…

word——將其中一頁變成橫向

在word中如何將其中一頁變成橫向&#xff1f; 在需要橫向的這一頁和上一頁插入分節符&#xff08;連續&#xff09; 1.點擊布局→分隔符→分節符&#xff08;連續&#xff09; 2.在所需要橫向頁將紙張方向改為橫向即可。

使用WORD實現論文格式的樣式化制作【標題樣式、自動序列、頁號(分節)、自動目錄(修改字體類型)】

背景 每家院校對論文的格式都有一系列的特定要求&#xff0c;相應的會有一份格式標準的說明文檔&#xff0c;該說明文檔中會羅列對文檔各個項的格式標準要求&#xff08;例如&#xff1a;題目、1級標題、2級標題、頁號、每個級別的字體字號&#xff0c;行距&#xff0c;段前段…