pinctrl和gpio子系统
目錄
1.pinctrl子系統(tǒng)
? ? 1)pinctrl子系統(tǒng)簡介
? ? 2)I.MX6ULL的的pinctrl子系統(tǒng)驅(qū)動
? ? 3)設(shè)備樹中添加pinctrl節(jié)點模板
2.gpio子系統(tǒng)
? ? 1)gpio子系統(tǒng)簡介
? ? 2)I.MX6ULL的的gpio子系統(tǒng)驅(qū)動
? ? 3)gpio子系統(tǒng)API函數(shù)
? ? 4)設(shè)備樹中添加gpio節(jié)點模板
? ? ? ? ? ?1、創(chuàng)建test設(shè)備節(jié)點
? ? ? ? ? ?2、添加pinctrl信息
? ? ? ? ? ?3、添加GPIO屬性信息
? ? 5)與gpio相關(guān)的OF函數(shù)
4.實驗程序編寫
? ? 1)修改設(shè)備樹文件
? ? ? ? ? ?1、添加pinctrl節(jié)點
? ? ? ? ? ?2、添加LED設(shè)備節(jié)點
? ? ? ? ? ?3、檢查PIN是否被其他外設(shè)使用
5.運行測試
? ? 1)編譯驅(qū)動程序和測試APP
? ? ? ? ? ?1、編譯驅(qū)動程序
? ? ? ? ? ? 2、編譯測試APP
? ? 2)運行測試
? ? ? Linux內(nèi)核提供了pinctrl和gpio子系統(tǒng)用于GPIO驅(qū)動,本章我們就來學(xué)習(xí)一下如何借助pinctrl和
? ? ? gpio子系統(tǒng)來簡化GPIO驅(qū)動開發(fā)。
1.pinctrl子系統(tǒng)
? ? 1)pinctrl子系統(tǒng)簡介
? ? ? ? ? ? ? Linux驅(qū)動講究驅(qū)動分離與分層,pinctrl和gpio子系統(tǒng)就是驅(qū)動分離與分層思想下的產(chǎn)物,
? ? ? ? ? ? ? 驅(qū)動分離與分層其實就是按照面向?qū)ο缶幊痰脑O(shè)計思想而設(shè)計的設(shè)備驅(qū)動框架,關(guān)于驅(qū)動
? ? ? ? ? ? ? 的分離與分層我們后面會講。
? ? ? ? ? ? ? 本來pinctrl和gpio子系統(tǒng)應(yīng)該放到驅(qū)動分離與分層章節(jié)后面講解,但是不管什么外設(shè)驅(qū)
? ? ? ? ? ? ? 動,GPIO驅(qū)動基本都是必須的,而pinctrl和gpio子系統(tǒng)又是GPIO驅(qū)動必須使用的,所以
? ? ? ? ? ? ? 就將pintrcl和gpio子系統(tǒng)這一章節(jié)提前了。
? ? ? ? ? ? ? 我們先來回顧一下上一章是怎么初始化LED燈所使用的GPIO,步驟如下:
? ? ? ? ? ? ? 1、修改設(shè)備樹,添加相應(yīng)的節(jié)點,節(jié)點里面重點是設(shè)置reg屬性,reg屬性包括了GPIO相
? ? ? ? ? ? ? ? ? ? 關(guān)寄存器。
? ? ? ? ? ? ? 2、獲取reg屬性中IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03和
? ? ? ? ? ? ? ? ? ? IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03這兩個寄存器地址,并且初始化這兩個
? ? ? ? ? ? ? ? ? ?寄存器,這兩個寄存器用于設(shè)置GPIO1_IO03這個PIN的復(fù)用功能、上下拉、速度等。
? ? ? ? ? ? ? 3、在步驟2里面將GPIO1_IO03這個PIN復(fù)用為了GPIO功能,因此需要設(shè)置GPIO1_IO03
? ? ? ? ? ? ? ? ? ? 這個GPIO相關(guān)的寄存器,也就是GPIO1_DR和GPIO1_GDIR這兩個寄存器。
? ? ? ? ? ? ? 總結(jié)一下,步驟2中完成對GPIO1_IO03這個PIN的初始化,設(shè)置這個PIN的復(fù)用功能、上
? ? ? ? ? ? ? 下拉等,比如將GPIO_IO03這個PIN設(shè)置為GPIO功能。步驟3中完成對GPIO的初始化,
? ? ? ? ? ? ? 設(shè)置GPIO為輸入/輸出等。
? ? ? ? ? ? ? 如果使用過STM32的話應(yīng)該都記得,STM32也是要先設(shè)置某個PIN的復(fù)用功能、速度、上
? ? ? ? ? ? ? 下拉等,然后再設(shè)置PIN所對應(yīng)的GPIO。其實對于大多數(shù)的32位SOC而言,引腳的設(shè)置
? ? ? ? ? ? ? 基本都是這兩方面,因此Linux內(nèi)核針對PIN的配置推出了pinctrl子系統(tǒng),對于GPIO的配
? ? ? ? ? ? ? 置推出了gpio子系統(tǒng)。本節(jié)我們來學(xué)習(xí)pinctrl子系統(tǒng),下一節(jié)再學(xué)習(xí)gpio子系統(tǒng)。
? ? ? ? ? ? ? 大多數(shù)SOC的pin都是支持復(fù)用的,比如I.MX6ULL的GPIO1_IO03既可以作為普通的
? ? ? ? ? ? ? GPIO使用,也可以作為I2C1的SDA等等。此外我們還需要配置pin的電氣特性,比如上/
? ? ? ? ? ? ? 下拉、速度、驅(qū)動能力等等。
? ? ? ? ? ? ? 傳統(tǒng)的配置pin的方式就是直接操作相應(yīng)的寄存器,但是這種配置方式比較繁瑣、而且容
? ? ? ? ? ? ? 易出問題(比如pin功能沖突)。pinctrl子系統(tǒng)就是為了解決這個問題而引入的,pinctrl子系
? ? ? ? ? ? ? 統(tǒng)主要工作內(nèi)容如下:
? ? ? ? ? ? ? 1、獲取設(shè)備樹中pin信息。
? ? ? ? ? ? ? 2、根據(jù)獲取到的pin信息來設(shè)置pin的復(fù)用功能。
? ? ? ? ? ? ? 3、根據(jù)獲取到的pin信息來設(shè)置pin的電氣特性,比如上/下拉、速度、驅(qū)動能力等。
? ? ? ? ? ? ? 對于我們使用者來講,只需要在設(shè)備樹里面設(shè)置好某個pin的相關(guān)屬性即可,其他的初始
? ? ? ? ? ? ? 化工作均由pinctrl子系統(tǒng)來完成,pinctrl子系統(tǒng)源碼目錄為drivers/pinctrl。
? ? 2)I.MX6ULL的的pinctrl子系統(tǒng)驅(qū)動
? ? ? ? ? ? ? 1、PIN配置信息詳解
? ? ? ? ? ? ? ? ? ?要使用pinctrl子系統(tǒng),我們需要在設(shè)備樹里面設(shè)置PIN的配置信息,畢竟pinctrl子系統(tǒng)
? ? ? ? ? ? ? ? ? ?要根據(jù)你提供的信息來配置PIN功能,一般會在設(shè)備樹里面創(chuàng)建一個節(jié)點來描述PIN的
? ? ? ? ? ? ? ? ? ?配置信息。打開imx6ull.dtsi文件,找到一個叫做iomuxc的節(jié)點,如下所示:
756 iomuxc: iomuxc@020e0000 {
757 compatible = "fsl,imx6ul-iomuxc";
758 reg = <0x020e0000 0x4000>;
759 };
? ? ? ? ? ? ? ? ? ? iomuxc節(jié)點就是I.MX6ULL的IOMUXC外設(shè)對應(yīng)的節(jié)點,看起來內(nèi)容很少,沒看出什
? ? ? ? ? ? ? ? ? ?么跟PIN的配置有關(guān)的內(nèi)容啊,別急!打開imx6ull-alientek-emmc.dts,找到如下所示
? ? ? ? ? ? ? ? ? ? 內(nèi)容:
311 &iomuxc {
312 pinctrl-names = "default";
313 pinctrl-0 = <&pinctrl_hog_1>;
314 imx6ul-evk {
315 pinctrl_hog_1: hoggrp-1 {
316 fsl,pins = <
317 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
318 MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059
319 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059
320 MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058
321 >;
322 };
......
371 pinctrl_flexcan1: flexcan1grp{
372 fsl,pins = <
373 MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
374 MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
375 >;
376 };
......
587 pinctrl_wdog: wdoggrp {
588 fsl,pins = <
589 MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY 0x30b0
590 >;
591 };
592 };
593 };
? ? ? ? ? ? ? ? ? ?以上代碼就是向iomuxc節(jié)點追加數(shù)據(jù),不同的外設(shè)使用的PIN不同、其配置也不同,因
? ? ? ? ? ? ? ? ? ?此一個蘿卜一個坑,將某個外設(shè)所使用的所有PIN都組織在一個子節(jié)點里面。以上代碼
? ? ? ? ? ? ? ? ? ?中pinctrl_hog_1子節(jié)點就是和熱插拔有關(guān)的PIN集合,比如USBOTG的ID引腳。
? ? ? ? ? ? ? ? ? ? pinctrl_flexcan1子節(jié)點是flexcan1這個外設(shè)所使用的PIN,pinctrl_wdog子節(jié)點是wdog
? ? ? ? ? ? ? ? ? ?外設(shè)所使用的PIN。如果需要在iomuxc中添加我們自定義外設(shè)的PIN,那么需要新建一
? ? ? ? ? ? ? ? ? ?個子節(jié)點,然后將這個自定義外設(shè)的所有PIN配置信息都放到這個子節(jié)點中。將其與以
? ? ? ? ? ? ? ? ? ?上代碼結(jié)合起來就可以得到完成的iomuxc節(jié)點,如下所示:
1 iomuxc: iomuxc@020e0000 {
2 compatible = "fsl,imx6ul-iomuxc";
3 reg = <0x020e0000 0x4000>;
4 pinctrl-names = "default";
5 pinctrl-0 = <&pinctrl_hog_1>;
6 imx6ul-evk {
7 pinctrl_hog_1: hoggrp-1 {
8 fsl,pins = <
9 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
10 MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059
11 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059
12 MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID 0x13058
13 >;
......
16 };
17 };
18 };
? ? ? ? ? ? ? ? ? ?第2行,compatible屬性值為“fsl,imx6ul-iomuxc”,前面講解設(shè)備樹的時候說過,Linux
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 內(nèi)核會根據(jù)compatbile屬性值來查找對應(yīng)的驅(qū)動文件,所以我們在Linux內(nèi)核源
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 碼中全局搜索字符串“fsl,imx6ul-iomuxc”就會找到I.MX6ULL這顆SOC的pinctrl
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 驅(qū)動文件。稍后我們會講解這個pinctrl驅(qū)動文件。
? ? ? ? ? ? ? ? ? ?第9~12行,pinctrl_hog_1子節(jié)點所使用的PIN配置信息,我們就以第9行的
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? UART1_RTS_B這個PIN為例,講解一下如何添加PIN的配置信息,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?UART1_RTS_B的配置信息如下:
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
? ? ? ? ? ? ? ? ? ?首先說明一下,UART1_RTS_B這個PIN是作為SD卡的檢測引腳,也就是通過此PIN就
? ? ? ? ? ? ? ? ? ?可以檢測到SD卡是否有插入。UART1_RTS_B的配置信息分為兩部分:
? ? ? ? ? ? ? ? ? ?MX6UL_PAD_UART1_RTS_B__GPIO1_IO19和0x17059,我們重點來看一下這兩部
? ? ? ? ? ? ? ? ? ?分是什么含義,前面說了,對于一個PIN的配置主要包括兩方面,一個是設(shè)置這個PIN
? ? ? ? ? ? ? ? ? ?的復(fù)用功能,另一個就是設(shè)置這個PIN的電氣特性。所以我們可以大膽的猜測
? ? ? ? ? ? ? ? ? ?UART1_RTS_B的這兩部分配置信息一個是設(shè)置UART1_RTS_B的復(fù)用功能,一個是
? ? ? ? ? ? ? ? ? ?用來設(shè)置UART1_RTS_B的電氣特性。
? ? ? ? ? ? ? ? ? ?首先來看一下MX6UL_PAD_UART1_RTS_B__GPIO1_IO19,這是一個宏定義,定義
? ? ? ? ? ? ? ? ? ?在文件arch/arm/boot/dts/imx6ul-pinfunc.h中,imx6ull.dtsi會引用imx6ull-pinfunc.h這個
? ? ? ? ? ? ? ? ? ?頭文件,而imx6ull-pinfunc.h又會引用imx6ul-pinfunc.h這個頭文件(繞啊繞!)。從這
? ? ? ? ? ? ? ? ? ?里可以看出,可以在設(shè)備樹中引用C語言中.h文件中的內(nèi)容。
? ? ? ? ? ? ? ? ? ?MX6UL_PAD_UART1_RTS_B__GPIO1_IO19的宏定義內(nèi)容如下:
190 #define MX6UL_PAD_UART1_RTS_B__UART1_DCE_RTS 0x0090 0x031C 0x0620 0x0 0x3
191 #define MX6UL_PAD_UART1_RTS_B__UART1_DTE_CTS 0x0090 0x031C 0x0000 0x0 0x0
192 #define MX6UL_PAD_UART1_RTS_B__ENET1_TX_ER 0x0090 0x031C 0x0000 0x1 0x0
193 #define MX6UL_PAD_UART1_RTS_B__USDHC1_CD_B 0x0090 0x031C 0x0668 0x2 0x1
194 #define MX6UL_PAD_UART1_RTS_B__CSI_DATA05 0x0090 0x031C 0x04CC 0x3 0x1
195 #define MX6UL_PAD_UART1_RTS_B__ENET2_1588_EVENT1_OUT 0x0090 0x031C 0x0000 0x4 0x0
196 #define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0
197 #define MX6UL_PAD_UART1_RTS_B__USDHC2_CD_B 0x0090 0x031C 0x0674 0x8 0x2
? ? ? ? ? ? ? ? ? ?以上代碼中一共有8個以“MX6UL_PAD_UART1_RTS_B”開頭的宏定義,大家仔細觀察
? ? ? ? ? ? ? ? ? ?應(yīng)該就能發(fā)現(xiàn),這8個宏定義分別對應(yīng)UART1_RTS_B這個PIN的8個復(fù)用IO。查閱
? ? ? ? ? ? ? ? ?《I.MX6ULL參考手冊》可以知UART1_RTS_B的可選復(fù)用IO如圖1所示:
?圖1?UART1_RTS_B引腳復(fù)用
? ? ? ? ? ? ? ? ? ?以上代碼196行的宏定義MX6UL_PAD_UART1_RTS_B__GPIO1_IO19表示將
? ? ? ? ? ? ? ? ? ?UART1_RTS_B這個IO復(fù)用為GPIO1_IO19。此宏定義后面跟著5個數(shù)字,也就是這個
? ? ? ? ? ? ? ? ? ?宏定義的具體值,如下所示:
0x0090 0x031C 0x0000 0x5 0x0
? ? ? ? ? ? ? ? ? ?這5個值的含義如下所示:
<mux_reg conf_reg input_reg mux_mode input_val>
? ? ? ? ? ? ? ? ? ?綜上所述可知:
? ? ? ? ? ? ? ? ? ?0x0090:mux_reg寄存器偏移地址,設(shè)備樹中的iomuxc節(jié)點就是IOMUXC外設(shè)對應(yīng)的
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?節(jié)點,根據(jù)其reg屬性可知IOMUXC外設(shè)寄存器起始地址為0x020e0000。因
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?此0x020e0000+0x0090=0x020e0090,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B寄存器地址正好是
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x020e0090,大家可以在《IMX6ULL參考手冊》中找到
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B這個寄存器的位域圖,如
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖2所示:?
?圖2?寄存器位域圖
? ? ? ? ? ? ? ? ? ?因此可知,0x020e0000+mux_reg就是PIN的復(fù)用寄存器地址。
? ? ? ? ? ? ? ? ? ?0x031C:conf_reg寄存器偏移地址,和mux_reg一樣,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0x020e0000+0x031c=0x020e031c,這個就是寄存器
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B的地址。
? ? ? ? ? ? ? ? ? ?0x0000:input_reg寄存器偏移地址,有些外設(shè)有input_reg寄存器,有input_reg寄存
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?器的外設(shè)需要配置input_reg寄存器。沒有的話就不需要設(shè)置,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?UART1_RTS_B這個PIN在做GPIO1_IO19的時候是沒有input_reg寄存器,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?因此這里intput_reg是無效的。
? ? ? ? ? ? ? ? ? ?0x5:mux_reg寄存器值,在這里就相當(dāng)于設(shè)置
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B寄存器為0x5,也即是設(shè)置
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?UART1_RTS_B這個PIN復(fù)用為GPIO1_IO19。
? ? ? ? ? ? ? ? ? ?0x0:input_reg寄存器值,在這里無效。
? ? ? ? ? ? ? ? ? ?這就是宏MX6UL_PAD_UART1_RTS_B__GPIO1_IO19的含義,看的比較仔細的同學(xué)
? ? ? ? ? ? ? ? ? ?應(yīng)該會發(fā)現(xiàn)并沒有conf_reg寄存器的值,config_reg寄存器是設(shè)置一個PIN的電氣特性
? ? ? ? ? ? ? ? ? ?的,這么重要的寄存器怎么沒有值呢?回到以上代碼中,第9行的內(nèi)容如下所示:
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059
? ? ? ? ? ? ? ? ? ?MX6UL_PAD_UART1_RTS_B__GPIO1_IO19我們上面已經(jīng)分析了,就剩下了一個
? ? ? ? ? ? ? ? ? ?0x17059,反應(yīng)快的同學(xué)應(yīng)該已經(jīng)猜出來了,0x17059就是conf_reg寄存器值!此值
? ? ? ? ? ? ? ? ? 由用戶自行設(shè)置,通過此值來設(shè)置一個IO的上/下拉、驅(qū)動能力和速度等。在這里就相
? ? ? ? ? ? ? ? ? 當(dāng)于設(shè)置寄存器IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B的值為0x17059。
? ? 3)設(shè)備樹中添加pinctrl節(jié)點模板
? ? ? ? ? ? ? 我們已經(jīng)對pinctrl有了比較深入的了解,接下來我們學(xué)習(xí)一下如何在設(shè)備樹中添加某個外
? ? ? ? ? ? ? 設(shè)的PIN信息。關(guān)于I.MX系列SOC的pinctrl設(shè)備樹綁定信息可以參考文檔
? ? ? ? ? ? ? Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt。這里我們虛擬一個名為
? ? ? ? ? ? ? “test”的設(shè)備,test使用了GPIO1_IO00這個PIN的GPIO功能,pinctrl節(jié)點添加過程如下:
? ? ? ? ? ? ? 1、創(chuàng)建對應(yīng)的節(jié)點
? ? ? ? ? ? ? ? ? ? 同一個外設(shè)的PIN都放到一個節(jié)點里面,打開imx6ull-alientek-emmc.dts,在iomuxc節(jié)
? ? ? ? ? ? ? ? ? ? 點中的“imx6ul-evk”子節(jié)點下添加“pinctrl_test”節(jié)點,注意!節(jié)點前綴一定要為
? ? ? ? ? ? ? ? ? ? “pinctrl_”。添加完成以后如下所示:
1 pinctrl_test: testgrp {
2 /* 具體的 PIN 信息 */
3 };
? ? ? ? ? ? ? 2、添加“fsl,pins”屬性
? ? ? ? ? ? ? ? ? ? 設(shè)備樹是通過屬性來保存信息的,因此我們需要添加一個屬性,屬性名字一定要為
? ? ? ? ? ? ? ? ? ? “fsl,pins”,因為對于I.MX系列SOC而言,pinctrl驅(qū)動程序是通過讀取“fsl,pins”屬性值
? ? ? ? ? ? ? ? ? ? 來獲取PIN的配置信息,完成以后如下所示:
1 pinctrl_test: testgrp {
2 fsl,pins = <
3 /* 設(shè)備所使用的 PIN 配置信息 */
4 >;
5 };
? ? ? ? ? ? ? 3、在“fsl,pins”屬性中添加PIN配置信息
? ? ? ? ? ? ? ? ? ?最后在“fsl,pins”屬性中添加具體的PIN配置信息,完成以后如下所示:
1 pinctrl_test: testgrp {
2 fsl,pins = <
3 MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config 是具體設(shè)置值*/
4 >;
5 };
2.gpio子系統(tǒng)
? ? 1)gpio子系統(tǒng)簡介
? ? ? ? ? ? ? 上一小節(jié)講解了pinctrl子系統(tǒng),pinctrl子系統(tǒng)重點是設(shè)置PIN(有的SOC叫做PAD)的復(fù)用和
? ? ? ? ? ? ? 電氣屬性,如果pinctrl子系統(tǒng)將一個PIN復(fù)用為GPIO的話,那么接下來就要用到gpio子系
? ? ? ? ? ? ? 統(tǒng)了。gpio子系統(tǒng)顧名思義,就是用于初始化GPIO并且提供相應(yīng)的API函數(shù),比如設(shè)置
? ? ? ? ? ? ? GPIO為輸入輸出,讀取GPIO的值等。gpio子系統(tǒng)的主要目的就是方便驅(qū)動開發(fā)者使用
? ? ? ? ? ? ? gpio,驅(qū)動開發(fā)者在設(shè)備樹中添加gpio相關(guān)信息,然后就可以在驅(qū)動程序中使用gpio子
? ? ? ? ? ? ?系統(tǒng)提供的API函數(shù)來操作GPIO,Linux內(nèi)核向驅(qū)動開發(fā)者屏蔽掉了GPIO的設(shè)置過程,極
? ? ? ? ? ? ?大的方便了驅(qū)動開發(fā)者使用GPIO。
? ? 2)I.MX6ULL的的gpio子系統(tǒng)驅(qū)動
? ? ? ? ? ? ? 1、設(shè)備樹中的gpio信息
? ? ? ? ? ? ? ? ? ? I.MX6ULL-ALPHA開發(fā)板上的UART1_RTS_B做為SD卡的檢測引腳,UART1_RTS_B
? ? ? ? ? ? ? ? ? ? 復(fù)用為GPIO1_IO19,通過讀取這個GPIO的高低電平就可以知道SD卡有沒有插
? ? ? ? ? ? ? ? ? ? 入。首先肯定是將UART1_RTS_B這個PIN復(fù)用為GPIO1_IO19,并且設(shè)置電氣屬性,
? ? ? ? ? ? ? ? ? ? 也就是上一小節(jié)講的pinctrl節(jié)點。打開imx6ull-alientek-emmc.dts,UART1_RTS_B這
? ? ? ? ? ? ? ? ? ? 個PIN的pincrtl設(shè)置如下:
316 pinctrl_hog_1: hoggrp-1 {
317 fsl,pins = <
318 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
......
322 >;
323 };
? ? ? ? ? ? ? ? ? ? 第318行,設(shè)置UART1_RTS_B這個PIN為GPIO1_IO19。
? ? ? ? ? ? ? ? ? ? pinctrl配置好以后就是設(shè)置gpio了,SD卡驅(qū)動程序通過讀取GPIO1_IO19的值來判斷
? ? ? ? ? ? ? ? ? ? SD卡有沒有插入,但是SD卡驅(qū)動程序怎么知道CD引腳連接的GPIO1_IO19呢?肯定
? ? ? ? ? ? ? ? ? ? 是需要設(shè)備樹告訴驅(qū)動啊!在設(shè)備樹中SD卡節(jié)點下添加一個屬性來描述SD卡的CD引
? ? ? ? ? ? ? ? ? ? 腳就行了,SD卡驅(qū)動直接讀取這個屬性值就知道SD卡的CD引腳使用的是哪個GPIO
? ? ? ? ? ? ? ? ? ? 了。SD卡連接在I.MX6ULL的usdhc1接口上,在imx6ull-alientek-emmc.dts中找到名
? ? ? ? ? ? ? ? ? ? 為“usdhc1”的節(jié)點,這個節(jié)點就是SD卡設(shè)備節(jié)點,如下所示:
760 &usdhc1 {
761 pinctrl-names = "default", "state_100mhz", "state_200mhz";
762 pinctrl-0 = <&pinctrl_usdhc1>;
763 pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
764 pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
765 /* pinctrl-3 = <&pinctrl_hog_1>; */
766 cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
767 keep-power-in-suspend;
768 enable-sdio-wakeup;
769 vmmc-supply = <®_sd1_vmmc>;
770 status = "okay";
771 };
? ? ? ? ? ? ? ? ? ?第765行,此行本來沒有,是作者添加的,usdhc1節(jié)點作為SD卡設(shè)備總節(jié)點,usdhc1
? ? ? ? ? ? ? ? ? ?節(jié)點需要描述SD卡所有的信息,因為驅(qū)動要使用。本行就是描述SD卡的CD引腳
? ? ? ? ? ? ? ? ? ?pinctrl信息所在的子節(jié)點,因為SD卡驅(qū)動需要根據(jù)pincrtl節(jié)點信息來設(shè)置CD引腳的復(fù)
? ? ? ? ? ? ? ? ? ?用功能等。762~764行的pinctrl-0~2都是SD卡其他PIN的pincrtl節(jié)點信息。但是大家
? ? ? ? ? ? ? ? ? ?會發(fā)現(xiàn),其實在usdhc1節(jié)點中并沒有“pinctrl-3=<&pinctrl_hog_1>”這一行,也就是說
? ? ? ? ? ? ? ? ? ?并沒有指定CD引腳的pinctrl信息,那么SD卡驅(qū)動就沒法設(shè)置CD引腳的復(fù)用功能啊?
? ? ? ? ? ? ? ? ? ?這個不用擔(dān)心,因為在“iomuxc”節(jié)點下引用了pinctrl_hog_1這個節(jié)點,所以Linux內(nèi)
? ? ? ? ? ? ? ? ? ?核中的iomuxc驅(qū)動就會自動初始化pinctrl_hog_1節(jié)點下的所有PIN。
? ? ? ? ? ? ? ? ? ?第766行,屬性“cd-gpios”描述了SD卡的CD引腳使用的哪個IO。屬性值一共有三個,
? ? ? ? ? ? ? ? ? ?我們來看一下這三個屬性值的含義,“&gpio1”表示CD引腳所使用的IO屬于GPIO1組,
? ? ? ? ? ? ? ? ? ? “19”表示GPIO1組的第19號IO,通過這兩個值SD卡驅(qū)動程序就知道CD引腳使用了
? ? ? ? ? ? ? ? ? ?GPIO1_IO19這GPIO。“GPIO_ACTIVE_LOW”表示低電平有效,如果改為
? ? ? ? ? ? ? ? ? ?“GPIO_ACTIVE_HIGH”就表示高電平有效。
? ? ? ? ? ? ? ? ? ?根據(jù)上面這些信息,SD卡驅(qū)動程序就可以使用GPIO1_IO19來檢測SD卡的CD信號
? ? ? ? ? ? ? ? ? ?了,打開imx6ull.dtsi,在里面找到如下所示內(nèi)容:
504 gpio1: gpio@0209c000 {
505 compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
506 reg = <0x0209c000 0x4000>;
507 interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
508 <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
509 gpio-controller;
510 #gpio-cells = <2>;
511 interrupt-controller;
512 #interrupt-cells = <2>;
513 };
? ? ? ? ? ? ? ? ? ? gpio1節(jié)點信息描述了GPIO1控制器的所有信息,重點就是GPIO1外設(shè)寄存器基地址以
? ? ? ? ? ? ? ? ? ? 及兼容屬性。
? ? ? ? ? ? ? ? ? ? 第505行,設(shè)置gpio1節(jié)點的compatible屬性有兩個,分別為“fsl,imx6ul-gpio”和
? ? ? ? ? ? ? ? ? ? “fsl,imx35-gpio”,在Linux內(nèi)核中搜索這兩個字符串就可以找到I.MX6UL的GPIO驅(qū)動
? ? ? ? ? ? ? ? ? ? 程序。
? ? ? ? ? ? ? ? ? ? 第506行,reg屬性設(shè)置了GPIO1控制器的寄存器基地址為0X0209C000,大家可以打
? ? ? ? ? ? ? ? ? ? 開《I.MX6ULL參考手冊》找到“Chapter28:General Purpose Input/Output(GPIO)”章節(jié)
? ? ? ? ? ? ? ? ? ? 第28.5小節(jié),有如圖3所示的寄存器地址表:
圖3?GPIO1寄存器表
? ? ? ? ? ? ? ? ? ? 從圖3可以看出,GPIO1控制器的基地址就是0X0209C000。
? ? ? ? ? ? ? ? ? ? 第509行,“gpio-controller”表示gpio1節(jié)點是個GPIO控制器。
? ? ? ? ? ? ? ? ? ? 第510行,“#gpio-cells”屬性和“#address-cells”類似,#gpio-cells應(yīng)該為2,表示一共有
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 兩個cell,第一個cell為GPIO編號,比如“&gpio1 3”就表示GPIO1_IO03。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 第二個cell表示GPIO極性,如果為0(GPIO_ACTIVE_HIGH)的話表示高電
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?平有效,如果為1(GPIO_ACTIVE_LOW)的話表示低電平有效。
? ? 3)gpio子系統(tǒng)API函數(shù)
? ? ? ? ? ? ? ?對于驅(qū)動開發(fā)人員,設(shè)置好設(shè)備樹以后就可以使用gpio子系統(tǒng)提供的API函數(shù)來操作指定
? ? ? ? ? ? ? ?的GPIO,gpio子系統(tǒng)向驅(qū)動開發(fā)人員屏蔽了具體的讀寫寄存器過程。這就是驅(qū)動分層與
? ? ? ? ? ? ? ?分離的好處,大家各司其職,做好自己的本職工作即可。gpio子系統(tǒng)提供的常用的API函
? ? ? ? ? ? ? ?數(shù)有下面幾個:
? ? ? ? ? ? ? ?1、gpio_request函數(shù)
? ? ? ? ? ? ? ? ? ? ? ? gpio_request函數(shù)用于申請一個GPIO管腳,在使用一個GPIO之前一定要使用
? ? ? ? ? ? ? ? ? ? ? ? gpio_request進行申請,函數(shù)原型如下:
int gpio_request(unsigned gpio, const char *label)
? ? ? ? ? ? ? ? ? ? ? ?函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? ?gpio:要申請的gpio標(biāo)號,使用of_get_named_gpio()函數(shù)從設(shè)備樹獲取指定GPIO
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 屬性信息,此函數(shù)會返回這個GPIO的標(biāo)號。
? ? ? ? ? ? ? ? ? ? ? ?label:給gpio設(shè)置個名字。
? ? ? ? ? ? ? ? ? ? ? ?返回值:0,申請成功;其他值,申請失敗。
? ? ? ? ? ? ? ?2、gpio_free函數(shù)
? ? ? ? ? ? ? ? ? ? ? ?如果不使用某個GPIO了,那么就可以調(diào)用gpio_free函數(shù)進行釋放。函數(shù)原型如下:
void gpio_free(unsigned gpio)
? ? ? ? ? ? ? ? ? ? ? ?函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? ?gpio:要釋放的gpio標(biāo)號。
? ? ? ? ? ? ? ? ? ? ? ?返回值:無
? ? ? ? ? ? ? ?3、gpio_direction_input函數(shù)
? ? ? ? ? ? ? ? ? ? ? 此函數(shù)用于設(shè)置某個GPIO為輸入,函數(shù)原型如下所示:
int gpio_direction_input(unsigned gpio)
? ? ? ? ? ? ? ? ? ? ? 函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? gpio:要設(shè)置為輸入的GPIO標(biāo)號。
? ? ? ? ? ? ? ? ? ? ? 返回值:0,設(shè)置成功;負值,設(shè)置失敗。
? ? ? ? ?? ? ?4、gpio_direction_output函數(shù)
? ? ? ? ? ? ? ? ? ? ? 此函數(shù)用于設(shè)置某個GPIO為輸出,并且設(shè)置默認輸出值,函數(shù)原型如下:
int gpio_direction_output(unsigned gpio, int value)
? ? ? ? ? ? ? ? ? ? ? ?函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? ?gpio:要設(shè)置為輸出的GPIO標(biāo)號。
? ? ? ? ? ? ? ? ? ? ? ?value:GPIO默認輸出值。
? ? ? ? ? ? ? ? ? ? ? ?返回值:0,設(shè)置成功;負值,設(shè)置失敗。
? ? ? ? ? ? ? ?5、gpio_get_value函數(shù)
? ? ? ? ? ? ? ? ? ? ? 此函數(shù)用于獲取某個GPIO的值(0或1),此函數(shù)是個宏,定義所示:
#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned gpio)
? ? ? ? ? ? ? ? ? ? ? 函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? gpio:要獲取的GPIO標(biāo)號。
? ? ? ? ? ? ? ? ? ? ? 返回值:非負值,得到的GPIO值;負值,獲取失敗。
? ? ? ? ? ? ? ?6、gpio_set_value函數(shù)
? ? ? ? ? ? ? ? ? ? ? 此函數(shù)用于設(shè)置某個GPIO的值,此函數(shù)是個宏,定義如下
#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned gpio, int value)
? ? ? ? ? ? ? ? ? ? ? 函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? gpio:要設(shè)置的GPIO標(biāo)號。
? ? ? ? ? ? ? ? ? ? ? value:要設(shè)置的值。
? ? ? ? ? ? ? ? ? ? ? 返回值:無
關(guān)于gpio子系統(tǒng)常用的API函數(shù)就講這些,這些是我們用的最多的。
? ? 4)設(shè)備樹中添加gpio節(jié)點模板
? ? ? ? ? ? ? ?繼續(xù)完成之前的test設(shè)備,在之前中我們已經(jīng)講解了如何創(chuàng)建test設(shè)備的pinctrl節(jié)點。本
? ? ? ? ? ? ? ?節(jié)我們來學(xué)習(xí)一下如何創(chuàng)建test設(shè)備的GPIO節(jié)點。
? ? ? ? ? ?1、創(chuàng)建test設(shè)備節(jié)點
? ? ? ? ? ? ? ? ? ? ? ? 在根節(jié)點“/”下創(chuàng)建test設(shè)備子節(jié)點,如下所示:
1 test {
2 /* 節(jié)點內(nèi)容 */
3 };
? ? ? ? ? ?2、添加pinctrl信息
? ? ? ? ? ? ? ? ? ? ? ?在之前我們創(chuàng)建了pinctrl_test節(jié)點,此節(jié)點描述了test設(shè)備所使用的GPIO1_IO00這
? ? ? ? ? ? ? ? ? ? ? ?個PIN的信息,我們要將這節(jié)點添加到test設(shè)備節(jié)點中,如下所示:
1 test {
2 pinctrl-names = "default";
3 pinctrl-0 = <&pinctrl_test>;
4 /* 其他節(jié)點內(nèi)容 */
5 };
? ? ? ? ? ? ? ? ? ? ? ?第2行,添加pinctrl-names屬性,此屬性描述pinctrl名字為“default”。
? ? ? ? ? ? ? ? ? ? ? ?第3行,添加pinctrl-0節(jié)點,此節(jié)點引用之前創(chuàng)建的pinctrl_test節(jié)點,表示tset設(shè)備的
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?所使用的PIN信息保存在pinctrl_test節(jié)點中。
? ? ? ? ? ?3、添加GPIO屬性信息
? ? ? ? ? ? ? ? ? ? ? ?我們最后需要在test節(jié)點中添加GPIO屬性信息,表明test所使用的GPIO是哪個引
? ? ? ? ? ? ? ? ? ? ? ?腳,添加完成以后如下所示:
1 test {
2 pinctrl-names = "default";
3 pinctrl-0 = <&pinctrl_test>;
4 gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
5 };
? ? ? ? ? ? ? ? ? ? ? ? 第4行,test設(shè)備所使用的gpio。
? ? ? ? ? ? ? ? ? ? ? ?關(guān)于pinctrl子系統(tǒng)和gpio子系統(tǒng)就講解到這里,接下來就使用pinctrl和gpio子系統(tǒng)來
? ? ? ? ? ? ? ? ? ? ? ?驅(qū)動I.MX6ULL-ALPHA開發(fā)板上的LED燈。
? ? 5)與gpio相關(guān)的OF函數(shù)
? ? ? ? ? ? ? ?在之前的代碼中,我們定義了一個名為“gpio”的屬性,gpio屬性描述了test這個設(shè)備所使
? ? ? ? ? ? ? ?用的GPIO。在驅(qū)動程序中需要讀取gpio屬性內(nèi)容,Linux內(nèi)核提供了幾個與GPIO有關(guān)的
? ? ? ? ? ? ? ?OF函數(shù),常用的幾個OF函數(shù)如下所示:
? ? ? ? ? ? ? ?1、of_gpio_named_count函數(shù)
? ? ? ? ? ? ? ? ? ? ?of_gpio_named_count函數(shù)用于獲取設(shè)備樹某個屬性里面定義了幾個GPIO信息,要
? ? ? ? ? ? ? ? ? ? ? 注意的是空的GPIO信息也會被統(tǒng)計到,比如:
gpios = <0&gpio1 1 20&gpio2 3 4>;
? ? ? ? ? ? ? ? ? ? ?上述代碼的“gpios”節(jié)點一共定義了4個GPIO,但是有2個是空的,沒有實際的含義。
? ? ? ? ? ? ? ? ? ? ? 通過of_gpio_named_count函數(shù)統(tǒng)計出來的GPIO數(shù)量就是4個,此函數(shù)原型如下:
int of_gpio_named_count(struct device_node *np, const char *propname)
? ? ? ? ? ? ? ? ? ? ? 函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? np:設(shè)備節(jié)點。
? ? ? ? ? ? ? ? ? ? ? propname:要統(tǒng)計的GPIO屬性。
? ? ? ? ? ? ? ? ? ? ? 返回值:正值,統(tǒng)計到的GPIO數(shù)量;負值,失敗。
? ? ? ? ? ? ? ? 2、of_gpio_count函數(shù)
? ? ? ? ? ? ? ? ? ? ? 和of_gpio_named_count函數(shù)一樣,但是不同的地方在于,此函數(shù)統(tǒng)計的是“gpios”
? ? ? ? ? ? ? ? ? 這個屬性的GPIO數(shù)量,而of_gpio_named_count函數(shù)可以統(tǒng)計任意屬性的GPIO信息,
? ? ? ? ? ? ? ? ? ? ? ?函數(shù)原型如下所示:
int of_gpio_count(struct device_node *np)
? ? ? ? ? ? ? ? ? ? ? ?函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? ?np:設(shè)備節(jié)點。
? ? ? ? ? ? ? ? ? ? ? ?返回值:正值,統(tǒng)計到的GPIO數(shù)量;負值,失敗。
? ? ? ? ? ? ? ? 3、of_get_named_gpio函數(shù)
? ? ? ? ? ? ? ? ? ? ? 此函數(shù)獲取GPIO編號,因為Linux內(nèi)核中關(guān)于GPIO的API函數(shù)都要使用GPIO編號,
? ? ? ? ? ? ? ? ? ? ? 此函數(shù)會將設(shè)備樹中類似<&gpio5 7 GPIO_ACTIVE_LOW>的屬性信息轉(zhuǎn)換為對應(yīng)的
? ? ? ? ? ? ? ? ? ? ? GPIO編號,此函數(shù)在驅(qū)動中使用很頻繁!函數(shù)原型如下:
int of_get_named_gpio(struct device_node *np, const char *propname, int index)
? ? ? ? ? ? ? ? ? ? ? 函數(shù)參數(shù)和返回值含義如下:
? ? ? ? ? ? ? ? ? ? ? np:設(shè)備節(jié)點。
? ? ? ? ? ? ? ? ? ? ? propname:包含要獲取GPIO信息的屬性名。
? ? ? ? ? ? ? ? ? ? ? index:GPIO索引,因為一個屬性里面可能包含多個GPIO,此參數(shù)指定要獲取哪個
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? GPIO的編號,如果只有一個GPIO信息的話此參數(shù)為0。
? ? ? ? ? ? ? ? ? ? ? 返回值:正值,獲取到的GPIO編號。負值,失敗。
4.實驗程序編寫
? ? 1)修改設(shè)備樹文件
? ? ? ? ? ?1、添加pinctrl節(jié)點
? ? ? ? ? ? ? ? ? ? ? ?I.MX6U-ALPHA開發(fā)板上的LED燈使用了GPIO1_IO03這個PIN,打開imx6ull-
? ? ? ? ? ? ? ? ? ? ? ?alientek-emmc.dts,在iomuxc節(jié)點的imx6ul-evk子節(jié)點下創(chuàng)建一個名為
? ? ? ? ? ? ? ? ? ? ? ?“pinctrl_led”的子節(jié)點,節(jié)點內(nèi)容如下所示:
1 pinctrl_led: ledgrp {
2 fsl,pins = <
3 MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0 /* LED0 */
4 >;
5 };
? ? ? ? ? ? ? ? ? ? ? 第3行,將GPIO1_IO03這個PIN復(fù)用為GPIO1_IO03,電氣屬性值為0X10B0。
? ? ? ? ? ?2、添加LED設(shè)備節(jié)點
? ? ? ? ? ? ? ? ? ? ? ?在根節(jié)點“/”下創(chuàng)建LED燈節(jié)點,節(jié)點名為“gpioled”,節(jié)點內(nèi)容如下:
1 gpioled {
2 #address-cells = <1>;
3 #size-cells = <1>;
4 compatible = "atkalpha-gpioled";
5 pinctrl-names = "default";
6 pinctrl-0 = <&pinctrl_led>;
7 led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
8 status = "okay";
9 }
? ? ? ? ? ? ? ? ? ? ? ?第6行,pinctrl-0屬性設(shè)置LED燈所使用的PIN對應(yīng)的pinctrl節(jié)點。
? ? ? ? ? ? ? ? ? ? ? ?第7行,led-gpio屬性指定了LED燈所使用的GPIO,在這里就是GPIO1的IO03,低
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 電平有效。
? ? ? ? ? ? ? ? ? ? ? ?稍后編寫驅(qū)動程序的時候會獲取led-gpio屬性的內(nèi)容來得到GPIO編號,因為gpio子
? ? ? ? ? ? ? ? ? ? ? ?系統(tǒng)的API操作函數(shù)需要GPIO編號。
? ? ? ? ? ?3、檢查PIN是否被其他外設(shè)使用
? ? ? ? ? ? ? ? ? ? ? ?這一點非常重要!!!
? ? ? ? ? ? ? ? ? ? ? 很多初次接觸設(shè)備樹的驅(qū)動開發(fā)人員很容易因為這個小問題栽了大跟頭!因為我們所
? ? ? ? ? ? ? ? ? ? ? 使用的設(shè)備樹基本都是在半導(dǎo)體廠商提供的設(shè)備樹文件基礎(chǔ)上修改而來的,而半導(dǎo)體
? ? ? ? ? ? ? ? ? ? ? 廠商提供的設(shè)備樹是根據(jù)自己官方開發(fā)板編寫的,很多PIN的配置和我們所使用的開
? ? ? ? ? ? ? ? ? ? ? 發(fā)板不一樣。比如A這個引腳在官方開發(fā)板接的是I2C的SDA,而我們所使用的硬件
? ? ? ? ? ? ? ? ? ? ? 可能將A這個引腳接到了其他的外設(shè),比如LED燈上,接不同的外設(shè),A這個引腳的
? ? ? ? ? ? ? ? ? ? ? 配置就不同。一個引腳一次只能實現(xiàn)一個功能,如果A引腳在設(shè)備樹中配置為了I2C
? ? ? ? ? ? ? ? ? ? ? 的SDA信號,那么A引腳就不能再配置為GPIO,否則的話驅(qū)動程序在申請GPIO的時
? ? ? ? ? ? ? ? ? ? ? 候就會失敗。檢查PIN有沒有被其他外設(shè)使用包括兩個方面:
? ? ? ? ? ? ? ? ? ? ? 1.檢查pinctrl設(shè)置。
? ? ? ? ? ? ? ? ? ? ? 2.如果這個PIN配置為GPIO的話,檢查這個GPIO有沒有被別的外設(shè)使用。
? ? ? ? ? ? ? ? ? ? ? 在本章實驗中LED燈使用的PIN為GPIO1_IO03,因此先檢查GPIO_IO03這個PIN有
? ? ? ? ? ? ? ? ? ? ? 沒有被其他的pinctrl節(jié)點使用,在imx6ull-alientek-emmc.dts中找到如下內(nèi)容:
480 pinctrl_tsc: tscgrp {
481 fsl,pins = <
482 MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
483 MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0
484 MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0
485 MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0
486 >;
487 };
? ? ? ? ? ? ? ? ? ? ? pinctrl_tsc節(jié)點是TSC(電阻觸摸屏接口)的pinctrl節(jié)點,從第484行可以看出,默認情
? ? ? ? ? ? ? ? ? ? ? 況下GPIO1_IO03作為了TSC外設(shè)的PIN。所以我們需要將第484行屏蔽掉!和C語言
? ? ? ? ? ? ? ? ? ? ? 一樣,在要屏蔽的內(nèi)容前后加上“/*”和“*/”符號即可。其實在I.MX6U-ALPHA開發(fā)板上
? ? ? ? ? ? ? ? ? ? ? 并沒有用到TSC接口,所以第482~485行的內(nèi)容可以全部屏蔽掉。
? ? ? ? ? ? ? ? ? ? ? 因為本章實驗我們將GPIO1_IO03這個PIN配置為了GPIO,所以還需要查找一下有沒
? ? ? ? ? ? ? ? ? ? ? 有其他的外設(shè)使用了GPIO1_IO03,在imx6ull-alientek-emmc.dts中搜索“gpio1 3”,
? ? ? ? ? ? ? ? ? ? ? ?找到如下內(nèi)容:
723 &tsc {
724 pinctrl-names = "default";
725 pinctrl-0 = <&pinctrl_tsc>;
726 xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
727 measure-delay-time = <0xffff>;
728 pre-charge-time = <0xfff>;
729 status = "okay";
730 };
? ? ? ? ? ? ? ? ? ? ? ?tsc是TSC的外設(shè)節(jié)點,從726行可以看出,tsc外設(shè)也使用了GPIO1_IO03,同樣我
? ? ? ? ? ? ? ? ? ? ? ?們需要將這一行屏蔽掉。然后在繼續(xù)搜索“gpio1 3”,看看除了本章的LED燈以外還
? ? ? ? ? ? ? ? ? ? ? ?有沒有其他的地方也使用了GPIO1_IO03,找到一個屏蔽一個。
? ? ? ? ? ? ? ? ? ? ? ?設(shè)備樹編寫完成以后使用“make dtbs”命令重新編譯設(shè)備樹,然后使用新編譯出來的
? ? ? ? ? ? ? ? ? ? ? ?imx6ull-alientek-emmc.dtb文件啟動Linux系統(tǒng)。啟動成功以后進入“/proc/device-
? ? ? ? ? ? ? ? ? ? ? ?tree”目錄中查看“gpioled”節(jié)點是否存在,如果存在的話就說明設(shè)備樹基本修改成
? ? ? ? ? ? ? ? ? ? ? ?功?(具體還要驅(qū)動驗證),結(jié)果如圖4所示:
?圖4??gpio子節(jié)點
5.運行測試
? ? 1)編譯驅(qū)動程序和測試APP
? ? ? ? ? ?1、編譯驅(qū)動程序
? ? ? ? ? ? ? ? ? ? ? ? 編寫Makefile文件,本章實驗的Makefile文件和之前
? ? ? ? ? ? ? ? ? ? ? ? 實驗基本一樣,只是將obj-m變量的值改為gpioled.o,Makefile內(nèi)容如下所示:
1 KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
......
4 obj-m := gpioled.o .o
......
11 clean:
12 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
? ? ? ? ? ? ? ? ? ? ? ? ?第4行,設(shè)置obj-m變量的值為gpioled.o。
? ? ? ? ? ? ? ? ? ? ? ? ? 輸入如下命令編譯出驅(qū)動模塊文件:
make -j32
? ? ? ? ? ? ? ? ? ? ? ? ?編譯成功以后就會生成一個名為“gpioled.ko”的驅(qū)動模塊文件。
? ? ? ? ? ? 2、編譯測試APP
? ? ? ? ? ? ? ? ? ? ? ? ?輸入如下命令編譯測試ledApp.c這個測試程序:
arm-linux-gnueabihf-gcc ledApp.c -o ledApp
? ? ? ? ? ? ? ? ? ? ? ? ? 編譯成功以后就會生成 ledApp這個應(yīng)用程序。
? ? 2)運行測試
? ? ? ? ? ? ? ?將上一小節(jié)編譯出來的gpioled.ko和ledApp這兩個文件拷貝到rootfs/lib/modules/4.1.15目
? ? ? ? ? ? ? ?錄中,重啟開發(fā)板,進入到目錄lib/modules/4.1.15中,輸入如下命令加載gpioled.ko驅(qū)動
? ? ? ? ? ? ? ?模塊:
depmod //第一次加載驅(qū)動的時候需要運行此命令
modprobe gpioled.ko //加載驅(qū)動
? ? ? ? ? ? ? ?驅(qū)動加載成功以后會在終端中輸出一些信息,如圖5所示:
?圖5?驅(qū)動加載成功以后輸出的信息
? ? ? ? ? ? ? ?從圖5可以看出,gpioled這個節(jié)點找到了,并且GPIO1_IO03這個GPIO的編號為3。驅(qū)動
? ? ? ? ? ? ? ?加載成功以后就可以使用ledApp軟件來測試驅(qū)動是否工作正常,輸入如下命令打開LED
? ? ? ? ? ? ? ?燈:?
./ledApp /dev/gpioled 1 //打開 LED 燈
? ? ? ? ? ? ? ?輸入上述命令以后觀察I.MX6U-ALPHA開發(fā)板上的紅色LED燈是否點亮,如果點亮的話說
? ? ? ? ? ? ? ?明驅(qū)動工作正常。在輸入如下命令關(guān)閉LED燈:
./ledApp /dev/gpioled 0 //打開 LED 燈
? ? ? ? ? ? ? ?輸入上述命令以后觀察I.MX6U-ALPHA開發(fā)板上的紅色LED燈是否熄滅。如果要卸載驅(qū)動
? ? ? ? ? ? ? ?的話輸入 如下命令即可:
rmmod gpioled.ko
總結(jié)
以上是生活随笔為你收集整理的pinctrl和gpio子系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bazel学习及覆盖率
- 下一篇: HDU1394(权值线段树)