前面的兩篇文章(寄存器配置點亮LED與設(shè)備樹版的點亮LED),其本質(zhì)都是通過寄存器配置,來控制LED的亮滅。
使用直接操作寄存器的方式,是將與LED有關(guān)的寄存器信息,直接寫到了LED的驅(qū)動代碼中,這也是一種比較常規(guī)的控制方式。但當(dāng)芯片的寄存器發(fā)了變動,就要對底層的驅(qū)動進(jìn)行重寫。
使用設(shè)備樹的方式,是將與LED有關(guān)的寄存器信息,寫到了設(shè)備樹文件中,這樣,當(dāng)設(shè)備的信息修改了,還可以通過設(shè)備樹的接口函數(shù),來獲取設(shè)備信息,提高了驅(qū)動代碼的復(fù)用能力。
本篇介紹的Pinctrl子系統(tǒng)與GPIO子系統(tǒng)的方式,不需要再直接操作寄存器了,因為這兩個子系統(tǒng)已經(jīng)替我們實現(xiàn)了對寄存器的操作,我們只需要操作這兩個子系統(tǒng)提供的API函數(shù)即可。
1 Pinctrl子系統(tǒng)
Pintrl子系統(tǒng),顧名思義,就是管理pin引腳的一個系統(tǒng),比如要點亮LED,即要控制LED對應(yīng)引腳的高低電平,就要先通過Pintrl子系統(tǒng)將LED對應(yīng)的引腳復(fù)用為GPIO功能(這一點是不是和之前寄存器配置時使用的MUX寄存器的功能有點像)。
1.1 設(shè)備樹中iomuxc節(jié)點
如何使用Pintrl子系統(tǒng)呢?其實它也是要依賴設(shè)備樹的,先來了解一下設(shè)備樹里的iomuxc節(jié)點,這個節(jié)點是IOMUXC外設(shè)對應(yīng)的節(jié)點,負(fù)責(zé)IO功能的復(fù)用。
打開自己開發(fā)板對應(yīng)的設(shè)備樹文件(我的是imx6ull-myboard.dts),然后找到iomuxc節(jié)點,先來看一下其基本結(jié)構(gòu):
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog_1>;
imx6ul-evk {
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */
>;
};
pinctrl_csi1: csi1grp {
fsl,pins = <
MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088
MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088
MX6UL_PAD_CSI_VSYNC__CSI_VSYNC 0x1b088
MX6UL_PAD_CSI_HSYNC__CSI_HSYNC 0x1b088
MX6UL_PAD_CSI_DATA00__CSI_DATA02 0x1b088
MX6UL_PAD_CSI_DATA01__CSI_DATA03 0x1b088
MX6UL_PAD_CSI_DATA02__CSI_DATA04 0x1b088
MX6UL_PAD_CSI_DATA03__CSI_DATA05 0x1b088
MX6UL_PAD_CSI_DATA04__CSI_DATA06 0x1b088
MX6UL_PAD_CSI_DATA05__CSI_DATA07 0x1b088
MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088
MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088
>;
};
//省略...
這里以pinctrl_hog_1插拔子節(jié)點為例進(jìn)行分析,它是和熱插拔有關(guān)的Pin集合,比如USB OTG的ID引腳,pinctrl_csi1子節(jié)點是csi外設(shè)所使用的PIN,本篇需要控制LED的亮滅,就需要新建一個對應(yīng)的節(jié)點,然后將這個自定義外設(shè)的所有Pin配置信息都放到這個子節(jié)點中。
1.2 宏定義的含義解析
對于pinctrl_hog_1這個字節(jié)點,注意其中的:
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
這就是對Pin引腳的配置,配置包括兩方面:一是設(shè)置Pin的復(fù)用功能,二是設(shè)置Pin的電氣特性。
前面的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)
![pYYBAGKI7KCAX6zqAAJnWJhOezU948.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI7KCAX6zqAAJnWJhOezU948.png)
這里一共有8 個以MX6UL_PAD_UART1_RTS_B開頭的宏定義,分別代表這個IO的8種不同的功能。
另外,這個宏定義的值,被分為了5段,每段的值都有具體的含義:
0x0090 mux_reg寄存器偏移地址
![pYYBAGKI7KiAfUv1AAF6aSF6lvg586.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI7KiAfUv1AAF6aSF6lvg586.png)
0x031C conf_reg寄存器偏移地址
![pYYBAGKI7K6AXIfiAAGNVxBLOL0527.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI7K6AXIfiAAGNVxBLOL0527.png)
0x0000 input_reg寄存器偏移地址(這里無效)
0x5 mux_reg寄存器的值
![poYBAGKI7LWAYSWXAANuxScJUAM153.png](https://file.elecfans.com/web2/M00/45/0B/poYBAGKI7LWAYSWXAANuxScJUAM153.png)
0x0 input_reg寄存器值(這里無效)
2 GPIO子系統(tǒng)
GPIO子系統(tǒng),顧名思義,就是管理GPIO功能的一個系統(tǒng),其作用是初始化配置GPIO(這一點是不是和之前寄存器配置時使用的PAD寄存器的功能有點像),并提供對外的API接口。使用GPIO子系統(tǒng)后,就不需要自己操作寄存器,通過調(diào)用GPIO子系統(tǒng)提供的API函數(shù)即可實現(xiàn)對GPIO的控制。
2.1 設(shè)備樹中g(shù)pio信息
仍以熱插拔節(jié)點為例:
![poYBAGKI7LuAQ-JjAADyIuPUmdQ560.png](https://file.elecfans.com/web2/M00/45/0B/poYBAGKI7LuAQ-JjAADyIuPUmdQ560.png)
UART1_RTS_B復(fù)用為GPIO1_IO19,通過讀取其高低電平來判斷SD卡有沒有插入。
那SD卡驅(qū)動程序怎么知道CD引腳連接的GPIO1_IO19呢?還是需要設(shè)備樹告訴驅(qū)動,在設(shè)備樹中SD卡節(jié)點下添加一個屬性來描述SD卡的 CD 引腳就行了:
![poYBAGKI7MKAbYQ6AAEsBfUxedI148.png](https://file.elecfans.com/web2/M00/45/0B/poYBAGKI7MKAbYQ6AAEsBfUxedI148.png)
屬cd-gpios描述了SD卡的CD引腳使用的哪個IO,屬性值一共有三個:
&gpio1 表示CD引腳所使用的IO屬于GPIO1組
19 表示GPIO1組的第19號IO
根據(jù)上面這些信息,SD卡驅(qū)動程序就可以使用GPIO1_IO19來檢測SD卡的CD信號了
2.2 gpio子系統(tǒng)API函數(shù)
2.2.1 gpio_request/free
gpio_request
用于申請一個GPIO管腳
/**
* gpio: 要申請的gpio標(biāo)號(使用of_get_named_gpio函數(shù)從設(shè)備樹獲取指定GPIO屬性信息時返回的標(biāo)號)
* label: 給gpio設(shè)置個名字
* return: 0-申請成功 其他值-申請失敗
*/
int gpio_request(unsigned gpio, const char *label)
gpio_free
用于釋放一個GPIO管腳
/**
* gpio: 要釋放的gpio標(biāo)號
* return
*/
void gpio_free(unsigned gpio)
2.2.2 gpio_direction_input/output
gpio_direction_input
用于設(shè)置某個GPIO為輸入
/**
* gpio: 要設(shè)置為輸入的GPIO標(biāo)號
* return: 0-設(shè)置成功 負(fù)值-設(shè)置失敗
*/
int gpio_direction_input(unsigned gpio)
gpio_direction_output
此函數(shù)用于設(shè)置某個GPIO為輸出,并且設(shè)置默認(rèn)輸出值
/**
* gpio: 要設(shè)置為輸出的GPIO標(biāo)號
* value: GPIO默認(rèn)輸出值
* return 0-設(shè)置成功 負(fù)值-設(shè)置失敗
*/
int gpio_direction_output(unsigned gpio, int value)
2.2.3 gpio_get_value/set_value
gpio_get_value
此函數(shù)用于獲取某個GPIO的值(0 或 1)
#define gpio_get_value __gpio_get_value
/**
* gpio: 要獲取的gpio標(biāo)號
* return: 非負(fù)值-得到的gpio值 負(fù)值-獲取失敗
*/
int __gpio_get_value(unsigned gpio)
gpio_set_value
用于設(shè)置某個GPIO的值
#define gpio_set_value __gpio_set_value
/**
* gpio: 要設(shè)置的gpio標(biāo)號
* value: 要設(shè)置的值
* return
*/
void __gpio_set_value(unsigned gpio, int value)
2.3 與gpio相關(guān)的OF函數(shù)
2.3.1 of_gpio_named_count
用于獲取設(shè)備樹某個屬性里面定義了幾個GPIO信息
/**
* np: 設(shè)備節(jié)點
* propname: 要統(tǒng)計的gpio屬性
* return: 正值-統(tǒng)計到的gpio數(shù)量 負(fù)值-失敗
*/
int of_gpio_named_count(struct device_node *np, const char *propname)
2.3.2 of_gpio_count
統(tǒng)計“gpios”這個屬性的gpio數(shù)量
/**
* np: 設(shè)備節(jié)點
* return: 正值-統(tǒng)計到的gpio數(shù)量 負(fù)值-失敗
*/
int of_gpio_count(struct device_node *np)
2.3.3 of_get_named_gpio
獲取GPIO編號
/**
* np: 設(shè)備節(jié)點
* propname: 包含要獲取gpio信息的屬性名
* index: gpio索引(一個屬性里面可能包含多個gpio)
* return: 正值-獲取到的gpio編號 負(fù)值-失敗
*/
int of_get_named_gpio(struct device_node *np,
const char *propname,
int index)
3 Pinctr版LED驅(qū)動程序
上面介紹了Pinctrl子系統(tǒng)與GPIO子系統(tǒng)的基本情況,下面就來使用它們來實現(xiàn)LED的亮滅控制。
3.1 修改設(shè)備樹文件
修改imx6ull-myboard.dts,在iomuxc節(jié)點的imx6ull-evk字節(jié)點下創(chuàng)建一個名為pinctrl_led的子節(jié)點,節(jié)點內(nèi)容如下:
pinctrl_gpioled: ledgrp{
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x10b0
>;
};
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 表示將該io復(fù)用為GPIO
0x10b0 表示對PAD寄存器的配置值,具體含義為如下,之前的文章(驅(qū)動開發(fā)4--點亮LED(寄存器版))介紹過。
/*寄存器SW_PAD_SNVS_TAMPER3設(shè)置IO屬性
*bit 16:0 HYS關(guān)閉
*bit [15:14]: 00 默認(rèn)下拉
*bit [13]: 0 kepper功能
*bit [12]: 1 pull/keeper使能
*bit [11]: 0 關(guān)閉開路輸出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 110 R0/6驅(qū)動能力
*bit [0]: 0 低轉(zhuǎn)換率
*/
![poYBAGKI7M-ACpQxAAE0T6VcuZ4075.png](https://file.elecfans.com/web2/M00/45/0B/poYBAGKI7M-ACpQxAAE0T6VcuZ4075.png)
在根節(jié)點下創(chuàng)建名為gpioled的LED節(jié)點,內(nèi)容如下:
/*pinctrl led*/
gpioled {
compatible = "myboard,gpioled";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpioled>;
led-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
status = "okay";
};
pinctrl-0 設(shè)置 LED所使用的PIN對應(yīng)的pinctrl節(jié)點
led-gpio 指定了LED所使用的GPIO,這里是GPIO5的IO03,低電平有效
![pYYBAGKI7NaARIqgAAGYrHgGx_w745.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI7NaARIqgAAGYrHgGx_w745.png)
3.2 檢查引腳是否使用沖突
因為我的開發(fā)板使用的設(shè)備樹文件(imx6ull-myboard.dts)是從NXP官方提供的設(shè)備樹文件(imx6ull-14x14-evk.dts)上修改而來的,可能某些引腳的配置與自己的開發(fā)板不一樣,需要檢查一下是否有使用沖突。
本次添加的這個MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03
與文件中的其它引腳沒有出現(xiàn)沖突,因此無需修改。
3.3 修改LED驅(qū)動文件
在上一篇的設(shè)備樹版的驅(qū)動文件上進(jìn)行修改,主要修改內(nèi)容如下。
頭文件需要添加一個:
#include
設(shè)備結(jié)構(gòu)體改為gpio_led:
/* gpioled設(shè)備結(jié)構(gòu)體 */
struct gpioled_dev{
dev_t devid; /* 設(shè)備號 */
struct cdev cdev; /* cdev */
struct class *class; /* 類 */
struct device *device; /* 設(shè)備 */
int major; /* 主設(shè)備號 */
int minor; /* 次設(shè)備號 */
struct device_node *nd; /* 設(shè)備節(jié)點 */
int led_gpio; /* led使用的GPIO編號*/
};
struct gpioled_dev gpioled; /* led設(shè)備 */
硬件初始化部分是主要修改的內(nèi)容,這次就不需要從設(shè)備樹讀取寄存器操作了,也不需要自己再進(jìn)行I/O內(nèi)存映射了,而實使用gpio子系統(tǒng)的API函數(shù)來對LED的GPIO進(jìn)行配置:
static int gpioled_hardware_init(void)
{
int ret;
/* 獲取設(shè)備樹中的屬性數(shù)據(jù) */
/* 1、獲取設(shè)備節(jié)點:gpioled */
gpioled.nd = of_find_node_by_path("/gpioled");
if(gpioled.nd == NULL)
{
printk("gpioled node not find!\r\n");
return -EINVAL;
}
else
{
printk("gpioled node find!\r\n");
}
/* 2、獲取gpio屬性, 得到LED編號 */
gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0);
if(gpioled.led_gpio < 0)
{
printk("can't get led-gpio!\r\n");
return -EINVAL;
}
else
{
printk("led-gpio num = %d\r\n", gpioled.led_gpio);
}
/* 3、設(shè)置GPIO為輸出, 并默認(rèn)關(guān)閉LED */
ret = gpio_direction_output(gpioled.led_gpio, 1);
if(ret < 0)
{
printk("can't set led-gpio!\r\n");
}
return 0;
}
開關(guān)LED時,也不需要再直接操作寄存器了,也是使用API函數(shù)來操作:
static ssize_t gpioled_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
//省略...
if(ledstat == LEDON)
{
gpio_set_value(dev->led_gpio, 0); /* 打開LED燈 */
printk("led on!\n");
}
else if(ledstat == LEDOFF)
{
gpio_set_value(dev->led_gpio, 1); /* 關(guān)閉LED燈 */
printk("led off!\n");
}
return 0;
}
4 實驗測試
4.1 編譯程序
編譯設(shè)備樹文件(.dtb),和上篇設(shè)備樹點亮LED的實驗一樣,先將設(shè)備樹文件復(fù)制到nfs文件系統(tǒng)位置,再從網(wǎng)絡(luò)啟動開發(fā)板,串口中查看設(shè)備樹中是否有添加的gpioled節(jié)點:
![pYYBAGKI7OKAaZFuAABvQHK0vHw773.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI7OKAaZFuAABvQHK0vHw773.png)
編譯LED驅(qū)動文件(.ko),復(fù)制到rootfs/lib/modules/4.1.15目錄中:
![pYYBAGKI7OyAIPOwAACPQEKA2AU916.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI7OyAIPOwAACPQEKA2AU916.png)
LED應(yīng)用程序不需要改,仍使用之前寄存器版點亮LED實驗時使用的程序即可。
4.2 測試
測試方式與之前的一樣,都是先加載驅(qū)動文件,然后調(diào)用應(yīng)用程序來控制LED的亮滅:
![pYYBAGKI7PSAbdXZAADcDOZLJgU848.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI7PSAbdXZAADcDOZLJgU848.png)
效果和之前的寄存器版點亮LED與設(shè)備樹版點亮LED的效果一樣
![pYYBAGKI60aAYOiNAAC-QqGhKlk901.png](https://file.elecfans.com/web2/M00/45/0B/pYYBAGKI60aAYOiNAAC-QqGhKlk901.png)
5 總結(jié)
本篇介紹了使用Pinctrl子系統(tǒng)與GPIO子系統(tǒng)的方式來點亮LED,與之前的寄存器版點亮LED與設(shè)備樹版點亮LED的最大區(qū)別在于不需要直接操作寄存器了,而是使用API函數(shù)來配置GPIO,具體操作寄存器在過程在API函數(shù)內(nèi)部實現(xiàn),我們無需在進(jìn)行繁瑣的寄存器操作。
本篇與上一篇的設(shè)備樹版點亮LED的程序編寫流程基本一致,因為都是要使用設(shè)備樹,與上一篇的主要區(qū)別就在于,不需要將寄存器信息寫入設(shè)備樹,再從設(shè)備樹獲取出來手動配置寄存器了。
審核編輯:符乾江
-
嵌入式
+關(guān)注
關(guān)注
5094文章
19185瀏覽量
307904 -
驅(qū)動
+關(guān)注
關(guān)注
12文章
1852瀏覽量
85675 -
Linux
+關(guān)注
關(guān)注
87文章
11350瀏覽量
210477
發(fā)布評論請先 登錄
相關(guān)推薦
i.MX6ULL 驅(qū)動開發(fā)7—按鍵輸入捕獲與GPIO輸入配置與高低電平讀取
![<b class='flag-5'>i.MX6ULL</b> <b class='flag-5'>驅(qū)動</b><b class='flag-5'>開發(fā)</b>7—按鍵輸入捕獲與<b class='flag-5'>GPIO</b>輸入配置與高低電平讀取](https://file.elecfans.com//web2/M00/45/54/poYBAGKLpr6AdGfGAADTB0hubAU186.png)
使用i.MX6ULL開發(fā)板進(jìn)行Linux根文件系統(tǒng)的完善
移植NXP官方linux 5.4內(nèi)核到i.MX6ULL開發(fā)板
I.MX6ULL終結(jié)者開發(fā)板裸機仿真jlink調(diào)試
i.MX6ULL開發(fā)板硬件資源
初識 i.MX6ULL 寄存器
關(guān)于i.MX6ULL配置GPIO
飛凌i.MX6ULL開發(fā)板的評測,再次進(jìn)階擁有更高的性價比
![飛凌<b class='flag-5'>i.MX6ULL</b><b class='flag-5'>開發(fā)</b>板的評測,再次進(jìn)階擁有更高的性價比](https://file.elecfans.com/web1/M00/CC/50/pIYBAF-XmfmAURl5AACodGrXx4o999.png)
基于NXP i.MX6ULL處理器的FETMX6ULL-C核心板
![基于NXP <b class='flag-5'>i.MX6ULL</b>處理器的FETMX<b class='flag-5'>6ULL</b>-C核心板](https://file.elecfans.com/web2/M00/3C/77/pYYBAGJT1yCAGTGzAAHLFHSi_KQ838.png)
基于i.MX6ULL點亮LED
使用pinctrl和gpio子系統(tǒng)實現(xiàn)LED燈驅(qū)動
基于i.MX6ULL的掉電檢測設(shè)計與軟件測試
![基于<b class='flag-5'>i.MX6ULL</b>的掉電檢測設(shè)計與軟件測試](https://file1.elecfans.com/web2/M00/AD/29/wKgaomVMRLyAA2QaAAAn19at1kE447.png)
評論