1.參考文檔
a. 內核 Documentation\devicetree\bindings\Pinctrl\ 目錄下: Pinctrl-bindings.txt b. 內核 Documentation\gpio 目錄下: Pinctrl-bindings.txt c. 內核 Documentation\devicetree\bindings\gpio 目錄下: gpio.txt
2.Pinctrl子系統概念
linux下的pintcrl和gpio子系統就類似於ST的“BSP庫”。引入“設備樹”之后,使用一個外設時,對於pin引腳的初始化和管理,只需通過設備樹描述即可,然后由pin子系統管理;對於gpio則由gpio子系統管理。
因此,與CPU引腳“關聯”的設備驅動,最終都會調用pincrtl和gpio子系統。二者是設備驅動的基礎,這二者也是一個設備驅動。
CPU的gpio引腳除了的方向、速度、上下拉、驅動能力等基本的電氣特性外,一般會包括復用功能,即該引腳既可以作為普通gpio,還可能復位為i2c引腳、uart引腳等。如果采用直接配置寄存器的方式進行驅動開發,會非常繁瑣,每更改一個功能就得重新翻閱手冊配一遍寄存器,另一方面還可能存在“沖突”問題,比如該引腳已被復用為i2c在使用,但被驅動工程師忽略了,再去使用該gpio時會導致未知預期的問題。引入pintctrl子系統就可以解決諸如此類問題,結合設備樹的使用,只需把pin信息在設備樹描述清楚,即由pinctrl子系統介入管理。
從設備樹開始學習 Pintrl 會比較容易。
主要參考文檔是:內核 Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt。
這會涉及 2 個對象:pin controller、client device。
前者提供服務:可以用它來復用引腳、配置引腳。
后者使用服務:聲明自己要使用哪些引腳的哪些功能,怎么配置它們。
2.1 pin controller
在芯片手冊里你找不到 pin controller,它是一個軟件上的概念,你可以認為它對應IOMUX──用來復用引腳,還可以配置引腳(比如上下拉電阻等)。
注意,pin controller 和 GPIO Controller 不是一回事,前者控制的引腳可用於 GPIO 功能、I2C 功能;后者只是把引腳配置為輸出、輸出等簡單的功能。
2.2 client device
“客戶設備”,誰的客戶?Pinctrl 系統的客戶,那就是使用 Pinctrl 系統的設備,使用引腳的設備。它在設備樹里會被定義為一個節點,在節點里聲明要用哪些引腳。
下面這個圖就可以把幾個重要概念理清楚:
上圖中,左邊是 pincontroller 節點,右邊是 client device 節點:

pin state:
對於一個“client device”來說,比如對於一個 UART 設備,它有多個“狀態”:default、sleep等,那對應的引腳也有這些狀態。
怎么理解?
比如默認狀態下,UART 設備是工作的,那么所用的引腳就要復用為 UART 功能。
在休眠狀態下,為了省電,可以把這些引腳復用為 GPIO 功能;或者直接把它們配置輸出高電平。
上圖中,pinctrl-names 里定義了 2 種狀態:default、sleep。
第 0 種狀態用到的引腳在 pinctrl-0 中定義,它是 state_0_node_a,位於 pincontroller 節點中。
第 1 種狀態用到的引腳在 pinctrl-1 中定義,它是 state_1_node_a,位於 pincontroller 節點中。
當這個設備處於 default 狀態時,pinctrl 子系統會自動根據上述信息把所用引腳復用為uart0 功能。
當這這個設備處於 sleep 狀態時,pinctrl 子系統會自動根據上述信息把所用引腳配置為高電平
groups 和 function:
一個設備會用到一個或多個引腳,這些引腳就可以歸為一組(group);
這些引腳可以復用為某個功能:function。
當然:一個設備可以用到多能引腳,比如 A1、A2 兩組引腳,A1 組復用為 F1 功能,A2組復用為 F2 功能。
Generic pin multiplexing node 和 Generic pin configuration node:
在上圖左邊的 pin controller 節點中,有子節點或孫節點,它們是給 client device 使用的。
可以用來描述復用信息:哪組(group)引腳復用為哪個功能(function);
可以用來描述配置信息:哪組(group)引腳配置為哪個設置功能(setting),比如上拉、下拉等。
注意:pin controller 節點的格式,沒有統一的標准!!!!每家芯片都不一樣
3.GPIO系統
pinctrl子系統主要是管理pin的電氣屬性和復用功能,而gpio子系統則是管理gpio的申請釋放、控制輸入輸出、io中斷等功能。gpio子系統屏蔽了gpio相關寄存器的配置過程,換而提供了常用的接口函數給驅動工程師使用,方便gpio相關的驅動開發。
gpio子系統功能
- 對於驅動層,屏蔽gpio寄存器配置細節,提供統一gpio操作接口
- 對於BSP層,統一框架,方便不同CPU接入,只需更換pinctrl子系統的驅動
3.1 GPIO子系統常用函數
gpio子系統對於驅動層的API位於“/kernel/include/linux/gpio.h”中。
(1)檢查gpio是否可用
int gpio_is_valid(int number); number: gpio序號 返回: 可用返回true,不可用返回false
(2)申請使用一個gpio
使用一個gpio前,必須向內核申請該gpio。 int gpio_request(unsigned gpio, const char *label) gpio: 待申請gpio序號 label:gpio命名 返回: 成功返回0,失敗返回負數
(3)釋放已申請gpio
如果不使用該gpio,則需要釋放,否則其他模塊申請不到該gpio序號。 int gpio_free(unsigned gpio) gpio:待釋放gpio序號
返回:成功返回0,失敗返回負數
(4)設置gpio輸入模式
int gpio_direction_input(unsigned gpio) gpio:待設置gpio序號 返回:成功返回0,失敗返回負數
(5)設置gpio輸出模式
void gpio_set_value(unsigned gpio, int value) gpio:待設置gpio序號 value:默認輸出狀態
(6)讀取 gpio狀態
int gpio_get_value(unsigned int gpio) gpio:待讀取gpio序號 返回:成功返回gpio狀態(1/0),失敗返回負數
(7)設置 gpio狀態
void gpio_set_value(unsigned int gpio, int value) gpio:待設置gpio序號 value:待設置值
(8)中斷號映射
int gpio_to_irq(unsigned gpio) gpio:待設置gpio序號 返回:成功返回中斷號,失敗返回負數
如果使用該 GPIO 時,不會動態的切換輸入輸出,建議在開始時就設置好 GPIO 輸出方向,后面拉高拉低時使用 gpio_set_value()接口,而不建議使用gpio_direction_output(), 因為 gpio_direction_output 接口里面有 mutex 鎖,對中斷上下文調用會有錯誤異常,且相比 gpio_set_value,gpio_direction_output 所做事情更多,浪費。