Linux 內核:GPIO子系統(1)軟件框架
背景
在很多驅動開發中,GPIO用得很多,因此學習一下;也會順便看看pinctrl 子系統。
原文(有刪改):http://www.wowotech.net/gpio_subsystem/io-port-control.html/comment-page-2#comments
前言
雖然GPIO子系統相關的硬件比較簡單,沒有復雜的協議,不過,對於軟件抽象而言,其分層次的軟件思想是每個嵌入式軟件工程師需要掌握的內容。
我更傾向使用GPIO系統這個名字來代替GPIO driver這個名字,GPIO driver僅僅包含了pin signal狀態控制和讀取的內容,而GPIO系統包括了pin multiplexing、pin configuration、GPIO control、GPIO interrupt control等內容。
本文主要是以3.14內核作為例子,講述linux kernel中GPIO系統的軟件框架。
GPIO相關硬件有哪些差異
嵌入式工程師總是要處理各種各樣的target board,每個target board上的GPIO總是存在不同。
和CPU的連接方式不同
對於ARM的嵌入式硬件平台,SOC本身可以提供大量的IO port,SOC上的GPIO controller是通過SOC的總線(AMBA)連接到CPU的。
對於嵌入式系統而言,除了SOC的IO port,一些外設芯片也可能會提供IO port,例如:
(1)有些key controller芯片、codec或者PMU的芯片會提供I/O port
(2)有些專用的IO expander芯片可以擴展16個或者32個GPIO
從硬件角度看,這些IO和SOC提供的那些IO完全不同,CPU和IO expander是通過I2C(也有可能是SPI等其他類型的bus)連接的,在這種情況下,訪問這些SOC之外的GPIO需要I2C的操作,而控制SOC上的GPIO只需要寫寄存器的操作。
不要小看這個不同,寫一個SOC memory map的寄存器非常快,但是通過I2C來操作IO就不是那么快了,甚至,如果總線繁忙有可能阻塞當前進程,這種情況下,內核同步機制必須有所區別(如果操作GPIO可能導致sleep,那么同步機制不能采用spinlock)。
訪問方式不同
SOC片內的GPIO controller和SOC片外的IO expander的訪問當然不一樣,不過,即便都是SOC片內的GPIO controller,不同的ARM芯片,其訪問方式也不完全相同,例如:有些SOC的GPIO controller會提供一個寄存器來控制輸出電平。向寄存器寫1就是set high,向寄存器寫0就是set low。但是有些SOC的GPIO controller會提供兩個寄存器來控制輸出電平。向其中一個寄存器寫一就是set high,向另外一個寄存器寫一就是set low。
配置方式不同
即便是使用了同樣的硬件(例如都使用同樣的某款SOC),不同硬件系統上GPIO的配置不同。
在一個系統上配置為輸入,在另外的系統上可能配置為輸出。
GPIO特性不同
這些特性包括:
(1)是否能觸發中斷。對一個SOC而言,並非所有的IO port都支持中斷功能,可能某些處理器只有一兩組GPIO有中斷功能。
(2)如果能夠觸發中斷,那么該GPIO是否能夠將CPU從sleep狀態喚醒
(3)有些有軟件可控的上拉或者下拉電阻的特性,有的GPIO不支持這種特性。在設定為輸入的時候,有的GPIO可以設定debouce的算法,有的則不可以。
5、多功能復用
有的GPIO就是單純的作為一個GPIO出現,有些GPIO有其他的復用的功能。例如IO expander上的GPIO只能是GPIO,但是SOC上的某個GPIO除了做普通的IO pin腳,還可以是SPI上clock信號線。
硬件功能分類
ARM based SOC的datasheet中總有一個章節叫做GPIO controller(或者I/O ports)的章節來描述如何配置、使用SOC的引腳。
雖然GPIO controller的硬件描述中充滿了大量的寄存器的描述,但是這些寄存器的功能大概分成下面三個類別:
1、有些硬件邏輯是和IO port本身的功能設定相關的,我們稱這個HW block為pin controller。軟件通過設定pin controller這個硬件單元的寄存器可以實現:
(1)引腳功能配置。例如該I/O pin是一個普通的GPIO還是一些特殊功能引腳(例如memeory bank上CS信號)。
(2)引腳特性配置。例如pull-up/down電阻的設定,drive-strength的設定等。
2、如果一組GPIO被配置成SPI,那么這些pin腳被連接到了SPI controller,如果配置成GPIO,那么控制這些引腳的就是GPIO controller。通過訪問GPIO controller的寄存器,軟件可以:
(1)配置GPIO的方向
(2)如果是輸出,可以配置high level或者low level
(3)如果是輸入,可以獲取GPIO引腳上的電平狀態
3、如果一組gpio有中斷控制器的功能,雖然控制寄存器在datasheet中的I/O ports章節描述,但是實際上這些GPIO已經被組織成了一個interrupt controller的硬件block,它更像是一個GPIO type的中斷控制器,通過訪問GPIO type的中斷控制器的寄存器,軟件可以:
(1)中斷的enable和disable(mask和unmask)
(2)觸發方式
(3)中斷狀態清除
Linux是如何通過軟件抽象來掩蓋GPIO在硬件差異的
傳統的GPIO driver是負責上面三大類的控制,而新的linux kernel中的GPIO subsystem則用三個軟件模塊來對應上面三類硬件功能:
(1)pin control subsystem。驅動pin controller硬件的軟件子系統。
(2)GPIO subsystem。驅動GPIO controller硬件的軟件子系統。
(3)GPIO interrupt chip driver。這個模塊是作為一個interrupt subsystem中的一個底層硬件驅動模塊存在的。
本文主要描述前兩個軟件模塊,具體GPIO interrupt chip driver以及interrupt subsystem請參考本站其他相關文檔。
pin control subsystem block diagram
下圖描述了pin control subsystem的模塊圖:
底層的pin controller driver是硬件相關的模組,初始化的時候會向pin control core模塊注冊pin control設備(通過pinctrl_register這個bootom level interface)。
pin control core模塊是一個硬件無關模塊,它抽象了所有pin controller的硬件特性,僅僅從用戶(各個driver就是pin control subsystem的用戶)角度給出了top level的接口函數,這樣,各個driver不需要關注pin controller的底層硬件相關的內容。
GPIO subsystem block diagram
下圖描述了GPIO subsystem的模塊圖:
基本上這個軟件框架圖和pin control subsystem是一樣的,其軟件抽象的思想也是一樣的,當然其內部具體的實現不一樣,我們會在后續的文章中描述。