gpio子系統

gpio子系統簡介

如果pinctrl子系統將一個PIN複用爲GPIO的話,就要用到GPIO子系統。gpio 子系統顧名思義,就是用於初始化 GPIO 並且提供相應的 API 函數,比如設置 GPIO爲輸入輸出,讀取 GPIO 的值等。 gpio 子系統的主要目的就是方便驅動開發者使用 gpio,驅動開發者在設備樹中添加 gpio 相關信息,然後就可以在驅動程序中使用 gpio 子系統提供的 API函數來操作 GPIO, Linux 內核向驅動開發者屏蔽掉了 GPIO 的設置過程,極大的方便了驅動開發者使用 GPIO

I.MX6ULL的gpio子系統驅動

設備樹中的 gpio 信息

I.MX6ULL-ALPHA 開發板上的 UART1_RTS_B 做爲 SD 卡的檢測引腳, UART1_RTS_B 複用爲 GPIO1_IO19,通過讀取這個 GPIO 的高低電平就可以知道 SD 卡有沒有插入。首先肯定是將 UART1_RTS_B 這個 PIN 複用爲 GPIO1_IO19,並且設置電氣屬性。打開dts文件,UART1_RTS_B 這個 PIN 的 pincrtl 設置如下:
== SD 卡 CD 引腳 PIN 配置參數==

316 pinctrl_hog_1: hoggrp-1 {
317	 	fsl,pins = <
318 		MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
	......
322 	>;
323 };

第 318 行,設置 UART1_RTS_B 這個 PIN 爲 GPIO1_IO19。
pinctrl 配置好以後就是設置 gpio 了, SD 卡驅動程序通過讀取 GPIO1_IO19 的值來判斷 SD卡有沒有插入,但是 SD 卡驅動程序怎麼知道 CD 引腳連接的 GPIO1_IO19 呢?肯定是需要設備樹告訴驅動啊!在設備樹中 SD 卡節點下添加一個屬性來描述 SD 卡的 CD 引腳就行了, SD卡驅動直接讀取這個屬性值就知道 SD 卡的 CD 引腳使用的是哪個 GPIO 了。 SD 卡連接在I.MX6ULL 的 usdhc1 接口上,在 .dts文件中 中找到名爲“usdhc1”的節點,這個節點就是 SD 卡設備節點,如下所示:

&usdhc1 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc1>;
	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
	cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
	keep-power-in-suspend;
	enable-sdio-wakeup;
	vmmc-supply = <&reg_sd1_vmmc>;
	status = "okay";
};

從上面看到沒有指定CD引腳的pinctrl信息,那麼SD卡驅動就沒辦法設置CD引腳定的複用功能?這個不用擔心,因爲在“iomuxc”節點下引用了pinctrl_hog_1這個節點,所以linux內核中的iomuxc驅動就會自動初始化pinctrl_hog_1節點下的所有PIN

屬性“cd-gpios”描述了 SD 卡的 CD 引腳使用的哪個 IO。屬性值一共有三個,我們來看一下這三個屬性值的含義,“&gpio1”表示 CD 引腳所使用的 IO 屬於 GPIO1 組,“19”表示 GPIO1 組的第 19 號 IO,通過這兩個值 SD 卡驅動程序就知道 CD 引腳使用了 GPIO1_IO19這 GPIO。“GPIO_ACTIVE_LOW”表示低電平有效,如果改爲“GPIO_ACTIVE_HIGH”就表示高電平有效。

根據上面信息,SD卡驅動程序就可以使用GPIO1_IO19來檢測SD卡的CD信號了
gpio1節點

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

505行: 設置 gpio1 節點的 compatible 屬性有兩個,分別爲“fsl,imx6ul-gpio”和“fsl,imx35-gpio”,在 Linux 內核中搜索這兩個字符串就可以找到 I.MX6UL 的 GPIO 驅動程序。

506 行,的 reg 屬性設置了 GPIO1 控制器的寄存器基地址爲 0X0209C000

509 行,“gpio-controller”表示 gpio1 節點是個 GPIO 控制器。

510 行,“#gpio-cells”屬性和“#address-cells”類似, #gpio-cells 應該爲 2,表示一共有兩個 cell,第一個 cell 爲 GPIO 編號,比如“&gpio1 3”就表示 GPIO1_IO03。第二個 cell 表示GPIO 極 性 , 如 果 爲 0(GPIO_ACTIVE_HIGH) 的 話 表 示 高 電 平 有 效 , 如 果 爲1(GPIO_ACTIVE_LOW)的話表示低電平有效。

gpio子系統API函數

設置好設備樹以後就可以使用 gpio 子系統提供的 API 函數來操作指定的 GPIO, gpio 子系統向驅動開發人員屏蔽了具體的讀寫寄存器過程。這就是驅動分層與分離的好處,大家各司其職,做好自己的本職工作即可。 gpio 子系統提供的常用的 API 函數有下面幾個:

  1. gpio_request函數
  2. gpio_free函數
  3. gpio_direction_input函數
  4. gpio_directionn_output函數
  5. gpio_get_value函數
  6. gpio_set_value 函數

1.gpio_request函數
gpio_request 函數用於申請一個 GPIO 管腳,在使用一個 GPIO 之前一定要使用 gpio_request進行申請,函數原型如下:
int gpio_request(unsigned gpio, const char *label)
函數參數和返回值含義如下:
gpio: 要申請的 gpio 標號,使用 of_get_named_gpio 函數從設備樹獲取指定 GPIO 屬性信息,此函數會返回這個 GPIO 的標號。
label: 給 gpio 設置個名字。
返回值: 0,申請成功;其他值,申請失敗。

2.gpio_free 函數
如果不使用某個 GPIO 了,那麼就可以調用 gpio_free 函數進行釋放。函數原型如下:
void gpio_free(unsigned gpio)
函數參數和返回值含義如下:
gpio: 要釋放的 gpio 標號。
返回值:

3.gpio_direction_input 函數
此函數用於設置某個 GPIO 爲輸入,函數原型如下所示:
int gpio_direction_input(unsigned gpio)
函數參數和返回值含義如下:
gpio:要設置爲輸入的 GPIO 標號。
返回值: 0,設置成功;負值,設置失敗

4.gpio_direction_output 函數
此函數用於設置某個 GPIO 爲輸出,並且設置默認輸出值,函數原型如下:
int gpio_direction_output(unsigned gpio, int value)
函數參數和返回值含義如下:
gpio:要設置爲輸出的 GPIO 標號。
value: GPIO 默認輸出值。
返回值: 0,設置成功;負值,設置失敗。

5.gpio_get_value 函數
此函數用於獲取某個 GPIO 的值(0 或 1),此函數是個宏,定義所示:
#define gpio_get_value __gpio_get_value int __gpio_get_value(unsigned gpio)
函數參數和返回值含義如下:
gpio:要獲取的 GPIO 標號
返回值: 非負值,得到的 GPIO 值;負值,獲取失敗

6.gpio_set_value 函數
此函數用於設置某個 GPIO 的值,此函數是個宏,定義如下
#define gpio_set_value __gpio_set_value void __gpio_set_value(unsigned gpio, int value)
函數參數和返回值含義如下:
gpio: 要設置的 GPIO 標號。
value: 要設置的值。
返回值: 無

設備樹中添加gpio節點模塊

  1. 創建test設備節點
    在根節點“/”下創建test設備子節點,如下所示:
    test {
    /*節點內容*/
    };
    
  2. 添加pinctrl信息
    在pinctrl子系統的筆記中,創建了pinctrl_test節點,此節點描述了test設備所使用的GPIO1_IO00 這個 PIN 的信息,我們要將這節點添加到 test 設備節點中,如下所示:
test {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_test>;
	/* 其他節點內容 */
};
  1. 添加GPIO屬性信息
    我們最後需要在 test 節點中添加 GPIO 屬性信息,表明 test 所使用的 GPIO 是哪個引腳,添加完成以後如下所示:
test {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_test>;
	gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
};

與 gpio 相關的 OF 函數

我們定義了一個名爲“gpio”的屬性, gpio 屬性描述了 test 這個設備所使用的 GPIO。在驅動程序中需要讀取 gpio 屬性內容, Linux 內核提供了幾個與 GPIO 有關的 OF 函數,常用的幾個 OF 函數如下所示:

  1. of_gpio_named_count 函數
  2. of_gpio_count 函數
  3. of_get_named_gpio 函數

1.of_gpio_named_count 函數
of_gpio_named_count 函數用於獲取設備樹某個屬性裏面定義了幾個 GPIO 信息,要注意的是空的 GPIO 信息也會被統計到,比如:

gpios = <0
		&gpio1 1 2
		0 &
		gpio2 3 4>;

上述代碼的“gpios”節點一共定義了 4 個 GPIO,但是有 2 個是空的,沒有實際的含義。通過 of_gpio_named_count 函數統計出來的 GPIO 數量就是 4 個,此函數原型如下:
int of_gpio_named_count(struct device_node *np, const char *propname)
函數參數和返回值含義如下:
np:設備節點。
propname:要統計的 GPIO 屬性。
返回值: 正值,統計到的 GPIO 數量;負值,失敗。

2. of_gpio_count 函數
和 of_gpio_named_count 函數一樣,但是不同的地方在於,此函數統計的是“gpios”這個性的 GPIO 數量,而 of_gpio_named_count 函數可以統計任意屬性的 GPIO 信息,函數原型如下所示:
int of_gpio_count(struct device_node *np)
函數參數和返回值含義如下:
np:設備節點。
返回值: 正值,統計到的 GPIO 數量;負值,失敗

3.of_get_named_gpio 函數
此函數獲取 GPIO 編號,因爲 Linux 內核中關於 GPIO 的 API 函數都要使用 GPIO 編號,此函數會將設備樹中類似<&gpio5 7 GPIO_ACTIVE_LOW>的屬性信息轉換爲對應的 GPIO 編號,此函數在驅動中使用很頻繁!函數原型如下:
int of_get_named_gpio(struct device_node *np,const char *propname,int index)
函數參數和返回值含義如下:
np:設備節點。
propname:包含要獲取 GPIO 信息的屬性名。
index: GPIO 索引,因爲一個屬性裏面可能包含多個 GPIO,此參數指定要獲取哪個 GPIO的編號,如果只有一個 GPIO 信息的話此參數爲 0。
返回值: 正值,獲取到的 GPIO 編號;負值,失敗。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章