Linux驅動開發(十一):pinctrl子系統和GPIO子系統

簡介

配置寄存器來控制IO的方式太過於原始,Linux內核提供了pinctrl子系統和gpio子系統用於GPIO驅動,當然pinctrl子系統負責的就不僅僅是GPIO的驅動了而是所有pin腳的配置。
pinctrl子系統是隨着設備樹的加入而加入的,依賴於設備樹。GPIO子系統在之前的內核中也是存在的,但是pinctrl子系統的加入GPIO子系統也是有很大的改變,之前的GPIO子系統需要芯片廠商提供的mach文件,而加入設備術後,GPIO子系統使用設備樹來實現。
接下來我們就分別來看一下pinctrl子系統和GPIO子系統

pinctrl子系統

概況

大多數SOC的PIN都是支持複用的,所以在配置時要考慮複用的設置,此外還要配置PIN的電氣特性,比如上下拉、速度、驅動等
pinctrl子系統的主要工作內容:

  • 獲取設備樹中pin信息
  • 根據獲得到的pin信息來設置pin的複用功能
  • 根據獲得到的pin信息來設置pin的電氣特性,比如上下拉、速度、驅動能力

對於我們使用者來說,只需要在設備樹裏面設置好某個pin的相關屬性即可,其他的初始化工作均由pinctrl子系統來完成
源碼目錄drivers/pinctrl

屬性

各廠家SOC的屬性不一定完全相同,要根據手冊來查看語法相關的信息

恩智浦IMX6

手冊參考\Documentation\devicetree\bindings\pinctrl\fsl,imx-pinctrl.txt
它的語法是這樣的

Examples: usdhc@0219c000 { /* uSDHC4 */ non-removable;
	vmmc-supply = <&reg_3p3v>;
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usdhc4_1>; };
iomuxc@020e0000 { compatible = "fsl,imx6q-iomuxc";
	reg = <0x020e0000 0x4000>;
	/* shared pinctrl settings */
	usdhc4 { pinctrl_usdhc4_1: usdhc4grp-1 { 
		fsl,pins = < 
				MX6QDL_PAD_SD4_CMD__SD4_CMD    0x17059
				MX6QDL_PAD_SD4_CLK__SD4_CLK    0x10059 
				MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
				MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 
				MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
				MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 
				MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
				MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 
				MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
				MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 
				>; 
			};
	.... };

IMX6的pinctrl寫在iomuxc節點下面,它的名字“pinctrl_usdhc4_1“會在別的節點中被調用
對於PIN的配置分爲兩個部分“MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059”

  • MX6QDL_PAD_SD4_CMD__SD4_CMD這部分配置的是引腳的複用
  • 0x17059 這部分是對引腳的初始化,配置速度、上下拉、驅動能力等

MX6QDL_PAD_SD4_CMD__SD4_CMD,定義在\arch\arm\boot\dts\imx6ul-pinfunc.h
在這裏插入圖片描述
文件中的每一個宏定義是某一個引腳的某一個複用功能
IMX6實現IO複用的使用IOMUXC來實現的,我們看兩個寄存器
在這裏插入圖片描述
我們可以通過配置MUX_MODE來實現IO的複用,一個引腳最多可以配置九種功能
還有一個寄存器用來對IO初始化
在這裏插入圖片描述GPIO的框圖如下:
在這裏插入圖片描述
HYS:遲滯比較器,IO作爲輸入功能時有效,用於設置輸入接收器的施密特觸發器是否使能,用於輸入波形整型
PUS:設置上下拉電阻
PUE:上下拉還是狀態保持,保持就是斷電保持以前的狀態
PKE:用來使能或者靜止上下拉/狀態保持器功能
ODE:禁止或使能開路輸出
SPEED:速度
DSE:驅動能力
SRE:壓擺率,就是IO電平跳變所需要的時間,要過EMC可以使用低壓擺率,波形緩和,要進行高速通信可以使用高壓擺率

我們以一個爲例

#define MX6UL_PAD_GPIO1_IO00__I2C2_SCL                            0x005C 0x02E8 0x05AC 0x0 0x1

它的後面有五個值,這五個值分別是

<mux_reg conf_reg input_reg mux_mode input_val>
  • mux_reg爲複用配置寄存器偏移地址
  • conf_reg爲初始化配置寄存器的偏移地址
  • input_reg 有的外設有input_reg,有的話需要配置這個偏移地址
  • mux_mode 設置複用模式
  • input_val 輸入值

在使用它的時候後面還會再跟一個值

MX6QDL_PAD_SD4_CMD__SD4_CMD    0x17059

後面的值0x17059就是對IO的初始化

通過以上的操作我們就可以完成對一個引腳的複用配置以及初始化

三星4412

三星的配置就與恩智浦的配置不太一樣
三星的一般有一個xxx-pinctrl.dtsi文件,專門進行引腳的配置
例子如下:

pinctrl_0: pinctrl@11400000 {
	gpa0: gpa0 {
		gpio-controller;
		#gpio-cells = <2>;

		interrupt-controller;
		#interrupt-cells = <2>;
	};
...
};
uart1_data: uart1-data {
	samsung,pins = "gpa0-4", "gpa0-5";
	samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
	samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
	samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
};

Pin mux/config
這個是關鍵,選擇複用(pin function mode)以及初始化(上下拉、驅動能力)

  • property name : “samsung,pins”
  • pin names format: “[pin bank name]-[pin number within the bank]”,例:gpa0-0
  • 管腳複用屬性:“samsung,pin-function”
  • 屬性配置:
    samsung,pin-val: Initial value of pin output buffer.
    samsung,pin-pud: Pull up/down configuration.
    samsung,pin-drv: Drive strength configuration.
    samsung,pin-pud-pdn: Pull up/down configuration in power down mode.
    samsung,pin-drv-pdn: Drive strength configuration in power down mode.

調用pinctrl

調用pinctrl一般是在設備樹中進行的
各種板子的語法是差不多的,例子如下

gpioled {
		#address-cells = <1>; 
		#size-cells = <1>; 
		compatible = "atkalpha-gpioled"; 
		pinctrl-names = "default"; //關注
		pinctrl-0 = <&pinctrl_gpio_leds>; //關注
		led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; 
		status = "okay";
	};

我們只關注兩句,這兩句的意思就是引用我們前面配置的pinctrl節點
這樣如果你的引腳配置爲GPIO的話就可以設置GPIO屬性並在驅動中使用了

配置流程

想要配置某個外設而需要配置某一個引腳爲GPIO時,一般的配置流程是這樣的

  • 在IOMUXC/pinctrl中對某一個引腳進行配置,兩個部分(複用、初始化),在外設節點中調用
  • 在驅動中獲取設備節點以及GPIO
  • 對GPIO進行配置

GPIO子系統

概括

在以前的內核版本中,如果要配置GPIO的話一般要使用IC廠家實現的GPIO配置函數,例如三星的配置函數爲

/*設置爲輸入*/
s3c_gpio_cfgpin(EXYNOS4_GPC0(3),S3C_GPIO_INPUT);
/*不上拉不下拉*/
s3c_gpio_setpull(EXYNOS4_GPC0(3),S3C_GPIO_PULL_NONE);

這樣帶來的問題就是各家有各家的接口函數與實現方式,不但內核的代碼複用率低而且開發者很難記住這麼多的函數,如果要使用多種平臺的話背函數都是很麻煩的,所以在引入設備樹後對GPIO子系統進行了大的改造,使用設備樹來實現並提供統一的接口
通過GPIO子系統功能要實現:

  • 引腳功能的配置(設置爲GPIO,特殊功能,GPIO的方向,設置爲中斷等)
  • 實現軟硬件的分離(分離出硬件差異,有廠商提供的底層支持;軟件分層。驅動只需要調用接口API即可操作GPIO)
  • iommu內存管理(直接調用宏即可操作GPIO)

經過GPIO子系統,我們可以通過如下的方式來配置GPIO

gpio_request(leddev.led0, "led0");
gpio_direction_output(leddev.led0, 1);
gpio_set_value(leddev.led0, 0);
gpio_direction_input(key.irqkeydesc[0].gpio);
value = gpio_get_value(keydesc->gpio);

系統框圖

在這裏插入圖片描述
GPIO lib調用下層結構並對頂層的驅動提供結構

與pinctrl比較

結構和功能類似,內部有所差異
在這裏插入圖片描述

關係

pinctrl基於設備樹,gpio子系統依賴與pinctrl子系統來實現

總結

我這裏總結的是比較基本的pinctrl子系統和gpio子系統的應用,他們的好處就是大大簡化了驅動的編寫,不用去考慮過多的寄存器,考慮不同芯片的差別,大大提高的代碼的複用率

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