0001 Chinese translated version of Documentation/admin-guide/gpio
0002
0003 If you have any comment or update to the content, please contact the
0004 original document maintainer directly. However, if you have a problem
0005 communicating in English you can also ask the Chinese maintainer for
0006 help. Contact the Chinese maintainer if this translation is outdated
0007 or if there is a problem with the translation.
0008
0009 Maintainer: Grant Likely <grant.likely@secretlab.ca>
0010 Linus Walleij <linus.walleij@linaro.org>
0011 Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
0012 ---------------------------------------------------------------------
0013 Documentation/admin-guide/gpio 的繁體中文翻譯
0014
0015 如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
0016 交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
0017 者翻譯存在問題,請聯繫繁體中文版維護者。
0018
0019 英文版維護者: Grant Likely <grant.likely@secretlab.ca>
0020 Linus Walleij <linus.walleij@linaro.org>
0021 繁體中文版維護者: 胡皓文 Hu Haowen <src.res@email.cn>
0022 繁體中文版翻譯者: 胡皓文 Hu Haowen <src.res@email.cn>
0023 繁體中文版校譯者: 胡皓文 Hu Haowen <src.res@email.cn>
0024
0025 以下爲正文
0026 ---------------------------------------------------------------------
0027 GPIO 接口
0028
0029 本文檔提供了一個在Linux下訪問GPIO的公約概述。
0030
0031 這些函數以 gpio_* 作爲前綴。其他的函數不允許使用這樣的前綴或相關的
0032 __gpio_* 前綴。
0033
0034
0035 什麼是GPIO?
0036 ==========
0037 "通用輸入/輸出口"(GPIO)是一個靈活的由軟體控制的數位訊號。他們可
0038 由多種晶片提供,且對於從事嵌入式和定製硬體的 Linux 開發者來說是
0039 比較熟悉。每個GPIO 都代表一個連接到特定引腳或球柵陣列(BGA)封裝中
0040 「球珠」的一個位。電路板原理圖顯示了 GPIO 與外部硬體的連接關係。
0041 驅動可以編寫成通用代碼,以使板級啓動代碼可傳遞引腳配置數據給驅動。
0042
0043 片上系統 (SOC) 處理器對 GPIO 有很大的依賴。在某些情況下,每個
0044 非專用引腳都可配置爲 GPIO,且大多數晶片都最少有一些 GPIO。
0045 可編程邏輯器件(類似 FPGA) 可以方便地提供 GPIO。像電源管理和
0046 音頻編解碼器這樣的多功能晶片經常留有一些這樣的引腳來幫助那些引腳
0047 匱乏的 SOC。同時還有通過 I2C 或 SPI 串行總線連接的「GPIO擴展器」
0048 晶片。大多數 PC 的南橋有一些擁有 GPIO 能力的引腳 (只有BIOS
0049 固件才知道如何使用他們)。
0050
0051 GPIO 的實際功能因系統而異。通常用法有:
0052
0053 - 輸出值可寫 (高電平=1,低電平=0)。一些晶片也有如何驅動這些值的選項,
0054 例如只允許輸出一個值、支持「線與」及其他取值類似的模式(值得注意的是
0055 「開漏」信號)
0056
0057 - 輸入值可讀(1、0)。一些晶片支持引腳在配置爲「輸出」時回讀,這對於類似
0058 「線與」的情況(以支持雙向信號)是非常有用的。GPIO 控制器可能有輸入
0059 去毛刺/消抖邏輯,這有時需要軟體控制。
0060
0061 - 輸入通常可作爲 IRQ 信號,一般是沿觸發,但有時是電平觸發。這樣的 IRQ
0062 可能配置爲系統喚醒事件,以將系統從低功耗狀態下喚醒。
0063
0064 - 通常一個 GPIO 根據不同產品電路板的需求,可以配置爲輸入或輸出,也有僅
0065 支持單向的。
0066
0067 - 大部分 GPIO 可以在持有自旋鎖時訪問,但是通常由串行總線擴展的 GPIO
0068 不允許持有自旋鎖。但某些系統也支持這種類型。
0069
0070 對於給定的電路板,每個 GPIO 都用於某個特定的目的,如監控 MMC/SD 卡的
0071 插入/移除、檢測卡的防寫狀態、驅動 LED、配置收發器、模擬串行總線、
0072 復位硬體看門狗、感知開關狀態等等。
0073
0074
0075 GPIO 公約
0076 =========
0077 注意,這個叫做「公約」,因爲這不是強制性的,不遵循這個公約是無傷大雅的,
0078 因爲此時可移植性並不重要。GPIO 常用於板級特定的電路邏輯,甚至可能
0079 隨著電路板的版本而改變,且不可能在不同走線的電路板上使用。僅有在少數
0080 功能上才具有可移植性,其他功能是平台特定。這也是由於「膠合」的邏輯造成的。
0081
0082 此外,這不需要任何的執行框架,只是一個接口。某個平台可能通過一個簡單地
0083 訪問晶片寄存器的內聯函數來實現它,其他平台可能通過委託一系列不同的GPIO
0084 控制器的抽象函數來實現它。(有一些可選的代碼能支持這種策略的實現,本文檔
0085 後面會介紹,但作爲 GPIO 接口的客戶端驅動程序必須與它的實現無關。)
0086
0087 也就是說,如果在他們的平台上支持這個公約,驅動應儘可能的使用它。同時,平台
0088 必須在 Kconfig 中選擇 ARCH_REQUIRE_GPIOLIB 或者 ARCH_WANT_OPTIONAL_GPIOLIB
0089 選項。那些調用標準 GPIO 函數的驅動應該在 Kconfig 入口中聲明依賴GENERIC_GPIO。
0090 當驅動包含文件:
0091
0092 #include <linux/gpio.h>
0093
0094 則 GPIO 函數是可用,無論是「真實代碼」還是經優化過的語句。如果你遵守
0095 這個公約,當你的代碼完成後,對其他的開發者來說會更容易看懂和維護。
0096
0097 注意,這些操作包含所用平台的 I/O 屏障代碼,驅動無須顯式地調用他們。
0098
0099
0100 標識 GPIO
0101 ---------
0102 GPIO 是通過無符號整型來標識的,範圍是 0 到 MAX_INT。保留「負」數
0103 用於其他目的,例如標識信號「在這個板子上不可用」或指示錯誤。未接觸底層
0104 硬體的代碼會忽略這些整數。
0105
0106 平台會定義這些整數的用法,且通常使用 #define 來定義 GPIO,這樣
0107 板級特定的啓動代碼可以直接關聯相應的原理圖。相對來說,驅動應該僅使用
0108 啓動代碼傳遞過來的 GPIO 編號,使用 platform_data 保存板級特定
0109 引腳配置數據 (同時還有其他須要的板級特定數據),避免可能出現的問題。
0110
0111 例如一個平台使用編號 32-159 來標識 GPIO,而在另一個平台使用編號0-63
0112 標識一組 GPIO 控制器,64-79標識另一類 GPIO 控制器,且在一個含有
0113 FPGA 的特定板子上使用 80-95。編號不一定要連續,那些平台中,也可以
0114 使用編號2000-2063來標識一個 I2C 接口的 GPIO 擴展器中的 GPIO。
0115
0116 如果你要初始化一個帶有無效 GPIO 編號的結構體,可以使用一些負編碼
0117 (如"-EINVAL"),那將使其永遠不會是有效。來測試這樣一個結構體中的編號
0118 是否關聯一個 GPIO,你可使用以下斷言:
0119
0120 int gpio_is_valid(int number);
0121
0122 如果編號不存在,則請求和釋放 GPIO 的函數將拒絕執行相關操作(見下文)。
0123 其他編號也可能被拒絕,比如一個編號可能存在,但暫時在給定的電路上不可用。
0124
0125 一個平台是否支持多個 GPIO 控制器爲平台特定的實現問題,就像是否可以
0126 在 GPIO 編號空間中有「空洞」和是否可以在運行時添加新的控制器一樣。
0127 這些問題會影響其他事情,包括相鄰的 GPIO 編號是否存在等。
0128
0129 使用 GPIO
0130 ---------
0131 對於一個 GPIO,系統應該做的第一件事情就是通過 gpio_request()
0132 函數分配它,見下文。
0133
0134 接下來是設置I/O方向,這通常是在板級啓動代碼中爲所使用的 GPIO 設置
0135 platform_device 時完成。
0136
0137 /* 設置爲輸入或輸出, 返回 0 或負的錯誤代碼 */
0138 int gpio_direction_input(unsigned gpio);
0139 int gpio_direction_output(unsigned gpio, int value);
0140
0141 返回值爲零代表成功,否則返回一個負的錯誤代碼。這個返回值需要檢查,因爲
0142 get/set(獲取/設置)函數調用沒法返回錯誤,且有可能是配置錯誤。通常,
0143 你應該在進程上下文中調用這些函數。然而,對於自旋鎖安全的 GPIO,在板子
0144 啓動的早期、進程啓動前使用他們也是可以的。
0145
0146 對於作爲輸出的 GPIO,爲其提供初始輸出值,對於避免在系統啓動期間出現
0147 信號毛刺是很有幫助的。
0148
0149 爲了與傳統的 GPIO 接口兼容, 在設置一個 GPIO 方向時,如果它還未被申請,
0150 則隱含了申請那個 GPIO 的操作(見下文)。這種兼容性正在從可選的 gpiolib
0151 框架中移除。
0152
0153 如果這個 GPIO 編碼不存在,或者特定的 GPIO 不能用於那種模式,則方向
0154 設置可能失敗。依賴啓動固件來正確地設置方向通常是一個壞主意,因爲它可能
0155 除了啓動Linux,並沒有做更多的驗證工作。(同理, 板子的啓動代碼可能需要
0156 將這個復用的引腳設置爲 GPIO,並正確地配置上拉/下拉電阻。)
0157
0158
0159 訪問自旋鎖安全的 GPIO
0160 -------------------
0161 大多數 GPIO 控制器可以通過內存讀/寫指令來訪問。這些指令不會休眠,可以
0162 安全地在硬(非線程)中斷例程和類似的上下文中完成。
0163
0164 對於那些用 gpio_cansleep()測試總是返回失敗的 GPIO(見下文),使用
0165 以下的函數訪問:
0166
0167 /* GPIO 輸入:返回零或非零 */
0168 int gpio_get_value(unsigned gpio);
0169
0170 /* GPIO 輸出 */
0171 void gpio_set_value(unsigned gpio, int value);
0172
0173 GPIO值是布爾值,零表示低電平,非零表示高電平。當讀取一個輸出引腳的值時,
0174 返回值應該是引腳上的值。這個值不總是和輸出值相符,因爲存在開漏輸出信號和
0175 輸出延遲問題。
0176
0177 以上的 get/set 函數無錯誤返回值,因爲之前 gpio_direction_*()應已檢查過
0178 其是否爲「無效GPIO」。此外,還需要注意的是並不是所有平台都可以從輸出引腳
0179 中讀取數據,對於不能讀取的引腳應總返回零。另外,對那些在原子上下文中無法
0180 安全訪問的 GPIO (譯者註:因爲訪問可能導致休眠)使用這些函數是不合適的
0181 (見下文)。
0182
0183 在 GPIO 編號(還有輸出、值)爲常數的情況下,鼓勵通過平台特定的實現來優化
0184 這兩個函數來訪問 GPIO 值。這種情況(讀寫一個硬體寄存器)下只需要幾條指令
0185 是很正常的,且無須自旋鎖。這種優化函數比起那些在子程序上花費許多指令的
0186 函數可以使得模擬接口(譯者注:例如 GPIO 模擬 I2C、1-wire 或 SPI)的
0187 應用(在空間和時間上都)更具效率。
0188
0189
0190 訪問可能休眠的 GPIO
0191 -----------------
0192 某些 GPIO 控制器必須通過基於總線(如 I2C 或 SPI)的消息訪問。讀或寫這些
0193 GPIO 值的命令需要等待其信息排到隊首才發送命令,再獲得其反饋。期間需要
0194 休眠,這不能在 IRQ 例程(中斷上下文)中執行。
0195
0196 支持此類 GPIO 的平台通過以下函數返回非零值來區分出這種 GPIO。(此函數需要
0197 一個之前通過 gpio_request 分配到的有效 GPIO 編號):
0198
0199 int gpio_cansleep(unsigned gpio);
0200
0201 爲了訪問這種 GPIO,內核定義了一套不同的函數:
0202
0203 /* GPIO 輸入:返回零或非零 ,可能會休眠 */
0204 int gpio_get_value_cansleep(unsigned gpio);
0205
0206 /* GPIO 輸出,可能會休眠 */
0207 void gpio_set_value_cansleep(unsigned gpio, int value);
0208
0209
0210 訪問這樣的 GPIO 需要一個允許休眠的上下文,例如線程 IRQ 處理例程,並用以上的
0211 訪問函數替換那些沒有 cansleep()後綴的自旋鎖安全訪問函數。
0212
0213 除了這些訪問函數可能休眠,且它們操作的 GPIO 不能在硬體 IRQ 處理例程中訪問的
0214 事實,這些處理例程實際上和自旋鎖安全的函數是一樣的。
0215
0216 ** 除此之外 ** 調用設置和配置此類 GPIO 的函數也必須在允許休眠的上下文中,
0217 因爲它們可能也需要訪問 GPIO 控制器晶片: (這些設置函數通常在板級啓動代碼或者
0218 驅動探測/斷開代碼中,所以這是一個容易滿足的約束條件。)
0219
0220 gpio_direction_input()
0221 gpio_direction_output()
0222 gpio_request()
0223
0224 ## gpio_request_one()
0225 ## gpio_request_array()
0226 ## gpio_free_array()
0227
0228 gpio_free()
0229 gpio_set_debounce()
0230
0231
0232
0233 聲明和釋放 GPIO
0234 ----------------------------
0235 爲了有助於捕獲系統配置錯誤,定義了兩個函數。
0236
0237 /* 申請 GPIO, 返回 0 或負的錯誤代碼.
0238 * 非空標籤可能有助於診斷.
0239 */
0240 int gpio_request(unsigned gpio, const char *label);
0241
0242 /* 釋放之前聲明的 GPIO */
0243 void gpio_free(unsigned gpio);
0244
0245 將無效的 GPIO 編碼傳遞給 gpio_request()會導致失敗,申請一個已使用這個
0246 函數聲明過的 GPIO 也會失敗。gpio_request()的返回值必須檢查。你應該在
0247 進程上下文中調用這些函數。然而,對於自旋鎖安全的 GPIO,在板子啓動的早期、
0248 進入進程之前是可以申請的。
0249
0250 這個函數完成兩個基本的目標。一是標識那些實際上已作爲 GPIO 使用的信號線,
0251 這樣便於更好地診斷;系統可能需要服務幾百個可用的 GPIO,但是對於任何一個
0252 給定的電路板通常只有一些被使用。另一個目的是捕獲衝突,查明錯誤:如兩個或
0253 更多驅動錯誤地認爲他們已經獨占了某個信號線,或是錯誤地認爲移除一個管理著
0254 某個已激活信號的驅動是安全的。也就是說,申請 GPIO 的作用類似一種鎖機制。
0255
0256 某些平台可能也使用 GPIO 作爲電源管理激活信號(例如通過關閉未使用晶片區和
0257 簡單地關閉未使用時鐘)。
0258
0259 對於 GPIO 使用 pinctrl 子系統已知的引腳,子系統應該被告知其使用情況;
0260 一個 gpiolib 驅動的 .request()操作應調用 pinctrl_gpio_request(),
0261 而 gpiolib 驅動的 .free()操作應調用 pinctrl_gpio_free()。pinctrl
0262 子系統允許 pinctrl_gpio_request()在某個引腳或引腳組以復用形式「屬於」
0263 一個設備時都成功返回。
0264
0265 任何須將 GPIO 信號導向適當引腳的引腳復用硬體的編程應該發生在 GPIO
0266 驅動的 .direction_input()或 .direction_output()函數中,以及
0267 任何輸出 GPIO 值的設置之後。這樣可使從引腳特殊功能到 GPIO 的轉換
0268 不會在引腳產生毛刺波形。有時當用一個 GPIO 實現其信號驅動一個非 GPIO
0269 硬體模塊的解決方案時,就需要這種機制。
0270
0271 某些平台允許部分或所有 GPIO 信號使用不同的引腳。類似的,GPIO 或引腳的
0272 其他方面也需要配置,如上拉/下拉。平台軟體應該在對這些 GPIO 調用
0273 gpio_request()前將這類細節配置好,例如使用 pinctrl 子系統的映射表,
0274 使得 GPIO 的用戶無須關注這些細節。
0275
0276 還有一個值得注意的是在釋放 GPIO 前,你必須停止使用它。
0277
0278
0279 注意:申請一個 GPIO 並沒有以任何方式配置它,只不過標識那個 GPIO 處於使用
0280 狀態。必須有另外的代碼來處理引腳配置(如控制 GPIO 使用的引腳、上拉/下拉)。
0281 考慮到大多數情況下聲明 GPIO 之後就會立即配置它們,所以定義了以下三個輔助函數:
0282
0283 /* 申請一個 GPIO 信號, 同時通過特定的'flags'初始化配置,
0284 * 其他和 gpio_request()的參數和返回值相同
0285 *
0286 */
0287 int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
0288
0289 /* 在單個函數中申請多個 GPIO
0290 */
0291 int gpio_request_array(struct gpio *array, size_t num);
0292
0293 /* 在單個函數中釋放多個 GPIO
0294 */
0295 void gpio_free_array(struct gpio *array, size_t num);
0296
0297 這裡 'flags' 當前定義可指定以下屬性:
0298
0299 * GPIOF_DIR_IN - 配置方向爲輸入
0300 * GPIOF_DIR_OUT - 配置方向爲輸出
0301
0302 * GPIOF_INIT_LOW - 在作爲輸出時,初始值爲低電平
0303 * GPIOF_INIT_HIGH - 在作爲輸出時,初始值爲高電平
0304 * GPIOF_OPEN_DRAIN - gpio引腳爲開漏信號
0305 * GPIOF_OPEN_SOURCE - gpio引腳爲源極開路信號
0306
0307 * GPIOF_EXPORT_DIR_FIXED - 將 gpio 導出到 sysfs,並保持方向
0308 * GPIOF_EXPORT_DIR_CHANGEABLE - 同樣是導出, 但允許改變方向
0309
0310 因爲 GPIOF_INIT_* 僅有在配置爲輸出的時候才存在,所以有效的組合爲:
0311
0312 * GPIOF_IN - 配置爲輸入
0313 * GPIOF_OUT_INIT_LOW - 配置爲輸出,並初始化爲低電平
0314 * GPIOF_OUT_INIT_HIGH - 配置爲輸出,並初始化爲高電平
0315
0316 當設置 flag 爲 GPIOF_OPEN_DRAIN 時,則假設引腳是開漏信號。這樣的引腳
0317 將不會在輸出模式下置1。這樣的引腳需要連接上拉電阻。通過使能這個標誌,gpio庫
0318 將會在被要求輸出模式下置1時將引腳變爲輸入狀態來使引腳置高。引腳在輸出模式下
0319 通過置0使其輸出低電平。
0320
0321 當設置 flag 爲 GPIOF_OPEN_SOURCE 時,則假設引腳爲源極開路信號。這樣的引腳
0322 將不會在輸出模式下置0。這樣的引腳需要連接下拉電阻。通過使能這個標誌,gpio庫
0323 將會在被要求輸出模式下置0時將引腳變爲輸入狀態來使引腳置低。引腳在輸出模式下
0324 通過置1使其輸出高電平。
0325
0326 將來這些標誌可能擴展到支持更多的屬性。
0327
0328 更進一步,爲了更簡單地聲明/釋放多個 GPIO,'struct gpio'被引進來封裝所有
0329 這三個領域:
0330
0331 struct gpio {
0332 unsigned gpio;
0333 unsigned long flags;
0334 const char *label;
0335 };
0336
0337 一個典型的用例:
0338
0339 static struct gpio leds_gpios[] = {
0340 { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默認開啓 */
0341 { 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* 默認關閉 */
0342 { 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* 默認關閉 */
0343 { 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* 默認關閉 */
0344 { ... },
0345 };
0346
0347 err = gpio_request_one(31, GPIOF_IN, "Reset Button");
0348 if (err)
0349 ...
0350
0351 err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
0352 if (err)
0353 ...
0354
0355 gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
0356
0357
0358 GPIO 映射到 IRQ
0359 --------------------
0360 GPIO 編號是無符號整數;IRQ 編號也是。這些構成了兩個邏輯上不同的命名空間
0361 (GPIO 0 不一定使用 IRQ 0)。你可以通過以下函數在它們之間實現映射:
0362
0363 /* 映射 GPIO 編號到 IRQ 編號 */
0364 int gpio_to_irq(unsigned gpio);
0365
0366 /* 映射 IRQ 編號到 GPIO 編號 (儘量避免使用) */
0367 int irq_to_gpio(unsigned irq);
0368
0369 它們的返回值爲對應命名空間的相關編號,或是負的錯誤代碼(如果無法映射)。
0370 (例如,某些 GPIO 無法做爲 IRQ 使用。)以下的編號錯誤是未經檢測的:使用一個
0371 未通過 gpio_direction_input()配置爲輸入的 GPIO 編號,或者使用一個
0372 並非來源於gpio_to_irq()的 IRQ 編號。
0373
0374 這兩個映射函數可能會在信號編號的加減計算過程上花些時間。它們不可休眠。
0375
0376 gpio_to_irq()返回的非錯誤值可以傳遞給 request_irq()或者 free_irq()。
0377 它們通常通過板級特定的初始化代碼存放到平台設備的 IRQ 資源中。注意:IRQ
0378 觸發選項是 IRQ 接口的一部分,如 IRQF_TRIGGER_FALLING,系統喚醒能力
0379 也是如此。
0380
0381 irq_to_gpio()返回的非錯誤值大多數通常可以被 gpio_get_value()所使用,
0382 比如在 IRQ 是沿觸發時初始化或更新驅動狀態。注意某些平台不支持反映射,所以
0383 你應該儘量避免使用它。
0384
0385
0386 模擬開漏信號
0387 ----------------------------
0388 有時在只有低電平信號作爲實際驅動結果(譯者注:多個輸出連接於一點,邏輯電平
0389 結果爲所有輸出的邏輯與)的時候,共享的信號線需要使用「開漏」信號。(該術語
0390 適用於 CMOS 管;而 TTL 用「集電極開路」。)一個上拉電阻使信號爲高電平。這
0391 有時被稱爲「線與」。實際上,從負邏輯(低電平爲真)的角度來看,這是一個「線或」。
0392
0393 一個開漏信號的常見例子是共享的低電平使能 IRQ 信號線。此外,有時雙向數據總線
0394 信號也使用漏極開路信號。
0395
0396 某些 GPIO 控制器直接支持開漏輸出,還有許多不支持。當你需要開漏信號,但
0397 硬體又不直接支持的時候,一個常用的方法是用任何即可作輸入也可作輸出的 GPIO
0398 引腳來模擬:
0399
0400 LOW: gpio_direction_output(gpio, 0) ... 這代碼驅動信號並覆蓋
0401 上拉配置。
0402
0403 HIGH: gpio_direction_input(gpio) ... 這代碼關閉輸出,所以上拉電阻
0404 (或其他的一些器件)控制了信號。
0405
0406 如果你將信號線「驅動」爲高電平,但是 gpio_get_value(gpio)報告了一個
0407 低電平(在適當的上升時間後),你就可以知道是其他的一些組件將共享信號線拉低了。
0408 這不一定是錯誤的。一個常見的例子就是 I2C 時鐘的延長:一個需要較慢時鐘的
0409 從設備延遲 SCK 的上升沿,而 I2C 主設備相應地調整其信號傳輸速率。
0410
0411
0412 這些公約忽略了什麼?
0413 ================
0414 這些公約忽略的最大一件事就是引腳復用,因爲這屬於高度晶片特定的屬性且
0415 沒有可移植性。某個平台可能不需要明確的復用信息;有的對於任意給定的引腳
0416 可能只有兩個功能選項;有的可能每個引腳有八個功能選項;有的可能可以將
0417 幾個引腳中的任何一個作爲給定的 GPIO。(是的,這些例子都來自於當前運行
0418 Linux 的系統。)
0419
0420 在某些系統中,與引腳復用相關的是配置和使能集成的上、下拉模式。並不是所有
0421 平台都支持這種模式,或者不會以相同的方式來支持這種模式;且任何給定的電路板
0422 可能使用外置的上拉(或下拉)電阻,這時晶片上的就不應該使用。(當一個電路需要
0423 5kOhm 的拉動電阻,晶片上的 100 kOhm 電阻就不能做到。)同樣的,驅動能力
0424 (2 mA vs 20 mA)和電壓(1.8V vs 3.3V)是平台特定問題,就像模型一樣在
0425 可配置引腳和 GPIO 之間(沒)有一一對應的關係。
0426
0427 還有其他一些系統特定的機制沒有在這裡指出,例如上述的輸入去毛刺和線與輸出
0428 選項。硬體可能支持批量讀或寫 GPIO,但是那一般是配置相關的:對於處於同一
0429 塊區(bank)的GPIO。(GPIO 通常以 16 或 32 個組成一個區塊,一個給定的
0430 片上系統一般有幾個這樣的區塊。)某些系統可以通過輸出 GPIO 觸發 IRQ,
0431 或者從並非以 GPIO 管理的引腳取值。這些機制的相關代碼沒有必要具有可移植性。
0432
0433 當前,動態定義 GPIO 並不是標準的,例如作爲配置一個帶有某些 GPIO 擴展器的
0434 附加電路板的副作用。
0435
0436 GPIO 實現者的框架 (可選)
0437 =====================
0438 前面提到了,有一個可選的實現框架,讓平台使用相同的編程接口,更加簡單地支持
0439 不同種類的 GPIO 控制器。這個框架稱爲"gpiolib"。
0440
0441 作爲一個輔助調試功能,如果 debugfs 可用,就會有一個 /sys/kernel/debug/gpio
0442 文件。通過這個框架,它可以列出所有註冊的控制器,以及當前正在使用中的 GPIO
0443 的狀態。
0444
0445
0446 控制器驅動: gpio_chip
0447 -------------------
0448 在框架中每個 GPIO 控制器都包裝爲一個 "struct gpio_chip",他包含了
0449 該類型的每個控制器的常用信息:
0450
0451 - 設置 GPIO 方向的方法
0452 - 用於訪問 GPIO 值的方法
0453 - 告知調用其方法是否可能休眠的標誌
0454 - 可選的 debugfs 信息導出方法 (顯示類似上拉配置一樣的額外狀態)
0455 - 診斷標籤
0456
0457 也包含了來自 device.platform_data 的每個實例的數據:它第一個 GPIO 的
0458 編號和它可用的 GPIO 的數量。
0459
0460 實現 gpio_chip 的代碼應支持多控制器實例,這可能使用驅動模型。那些代碼要
0461 配置每個 gpio_chip,並發起gpiochip_add()。卸載一個 GPIO 控制器很少見,
0462 但在必要的時候可以使用 gpiochip_remove()。
0463
0464 大部分 gpio_chip 是一個實例特定結構體的一部分,而並不將 GPIO 接口單獨
0465 暴露出來,比如編址、電源管理等。類似編解碼器這樣的晶片會有複雜的非 GPIO
0466 狀態。
0467
0468 任何一個 debugfs 信息導出方法通常應該忽略還未申請作爲 GPIO 的信號線。
0469 他們可以使用 gpiochip_is_requested()測試,當這個 GPIO 已經申請過了
0470 就返回相關的標籤,否則返回 NULL。
0471
0472
0473 平台支持
0474 -------
0475 爲了支持這個框架,一個平台的 Kconfig 文件將會 "select"(選擇)
0476 ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,並讓它的
0477 <asm/gpio.h> 包含 <asm-generic/gpio.h>,同時定義三個方法:
0478 gpio_get_value()、gpio_set_value()和 gpio_cansleep()。
0479
0480 它也應提供一個 ARCH_NR_GPIOS 的定義值,這樣可以更好地反映該平台 GPIO
0481 的實際數量,節省靜態表的空間。(這個定義值應該包含片上系統內建 GPIO 和
0482 GPIO 擴展器中的數據。)
0483
0484 ARCH_REQUIRE_GPIOLIB 意味著 gpiolib 核心在這個構架中將總是編譯進內核。
0485
0486 ARCH_WANT_OPTIONAL_GPIOLIB 意味著 gpiolib 核心默認關閉,且用戶可以
0487 使能它,並將其編譯進內核(可選)。
0488
0489 如果這些選項都沒被選擇,該平台就不通過 GPIO-lib 支持 GPIO,且代碼不可以
0490 被用戶使能。
0491
0492 以下這些方法的實現可以直接使用框架代碼,並總是通過 gpio_chip 調度:
0493
0494 #define gpio_get_value __gpio_get_value
0495 #define gpio_set_value __gpio_set_value
0496 #define gpio_cansleep __gpio_cansleep
0497
0498 這些定義可以用更理想的實現方法替代,那就是使用經過邏輯優化的內聯函數來訪問
0499 基於特定片上系統的 GPIO。例如,若引用的 GPIO (寄存器位偏移)是常量「12」,
0500 讀取或設置它可能只需少則兩或三個指令,且不會休眠。當這樣的優化無法實現時,
0501 那些函數必須使用框架提供的代碼,那就至少要幾十條指令才可以實現。對於用 GPIO
0502 模擬的 I/O 接口, 如此精簡指令是很有意義的。
0503
0504 對於片上系統,平台特定代碼爲片上 GPIO 每個區(bank)定義並註冊 gpio_chip
0505 實例。那些 GPIO 應該根據晶片廠商的文檔進行編碼/標籤,並直接和電路板原理圖
0506 對應。他們應該開始於零並終止於平台特定的限制。這些 GPIO(代碼)通常從
0507 arch_initcall()或者更早的地方集成進平台初始化代碼,使這些 GPIO 總是可用,
0508 且他們通常可以作爲 IRQ 使用。
0509
0510 板級支持
0511 -------
0512 對於外部 GPIO 控制器(例如 I2C 或 SPI 擴展器、專用晶片、多功能器件、FPGA
0513 或 CPLD),大多數常用板級特定代碼都可以註冊控制器設備,並保證他們的驅動知道
0514 gpiochip_add()所使用的 GPIO 編號。他們的起始編號通常跟在平台特定的 GPIO
0515 編號之後。
0516
0517 例如板級啓動代碼應該創建結構體指明晶片公開的 GPIO 範圍,並使用 platform_data
0518 將其傳遞給每個 GPIO 擴展器晶片。然後晶片驅動中的 probe()例程可以將這個
0519 數據傳遞給 gpiochip_add()。
0520
0521 初始化順序很重要。例如,如果一個設備依賴基於 I2C 的(擴展)GPIO,那麼它的
0522 probe()例程就應該在那個 GPIO 有效以後才可以被調用。這意味著設備應該在
0523 GPIO 可以工作之後才可被註冊。解決這類依賴的的一種方法是讓這種 gpio_chip
0524 控制器向板級特定代碼提供 setup()和 teardown()回調函數。一旦所有必須的
0525 資源可用之後,這些板級特定的回調函數將會註冊設備,並可以在這些 GPIO 控制器
0526 設備變成無效時移除它們。
0527
0528
0529 用戶空間的 Sysfs 接口(可選)
0530 ========================
0531 使用「gpiolib」實現框架的平台可以選擇配置一個 GPIO 的 sysfs 用戶接口。
0532 這不同於 debugfs 接口,因爲它提供的是對 GPIO方向和值的控制,而不只顯示
0533 一個GPIO 的狀態摘要。此外,它可以出現在沒有調試支持的產品級系統中。
0534
0535 例如,通過適當的系統硬體文檔,用戶空間可以知道 GIOP #23 控制 Flash
0536 存儲器的防寫(用於保護其中 Bootloader 分區)。產品的系統升級可能需要
0537 臨時解除這個保護:首先導入一個 GPIO,改變其輸出狀態,然後在重新使能防寫
0538 前升級代碼。通常情況下,GPIO #23 是不會被觸及的,並且內核也不需要知道他。
0539
0540 根據適當的硬體文檔,某些系統的用戶空間 GPIO 可以用於確定系統配置數據,
0541 這些數據是標準內核不知道的。在某些任務中,簡單的用戶空間 GPIO 驅動可能是
0542 系統真正需要的。
0543
0544 注意:標準內核驅動中已經存在通用的「LED 和按鍵」GPIO 任務,分別是:
0545 "leds-gpio" 和 "gpio_keys"。請使用這些來替代直接訪問 GPIO,因爲集成在
0546 內核框架中的這類驅動比你在用戶空間的代碼更好。
0547
0548
0549 Sysfs 中的路徑
0550 --------------
0551 在/sys/class/gpio 中有 3 類入口:
0552
0553 - 用於在用戶空間控制 GPIO 的控制接口;
0554
0555 - GPIOs 本身;以及
0556
0557 - GPIO 控制器 ("gpio_chip" 實例)。
0558
0559 除了這些標準的文件,還包含「device」符號連結。
0560
0561 控制接口是只寫的:
0562
0563 /sys/class/gpio/
0564
0565 "export" ... 用戶空間可以通過寫其編號到這個文件,要求內核導出
0566 一個 GPIO 的控制到用戶空間。
0567
0568 例如: 如果內核代碼沒有申請 GPIO #19,"echo 19 > export"
0569 將會爲 GPIO #19 創建一個 "gpio19" 節點。
0570
0571 "unexport" ... 導出到用戶空間的逆操作。
0572
0573 例如: "echo 19 > unexport" 將會移除使用"export"文件導出的
0574 "gpio19" 節點。
0575
0576 GPIO 信號的路徑類似 /sys/class/gpio/gpio42/ (對於 GPIO #42 來說),
0577 並有如下的讀/寫屬性:
0578
0579 /sys/class/gpio/gpioN/
0580
0581 "direction" ... 讀取得到 "in" 或 "out"。這個值通常運行寫入。
0582 寫入"out" 時,其引腳的默認輸出爲低電平。爲了確保無故障運行,
0583 "low" 或 "high" 的電平值應該寫入 GPIO 的配置,作爲初始輸出值。
0584
0585 注意:如果內核不支持改變 GPIO 的方向,或者在導出時內核代碼沒有
0586 明確允許用戶空間可以重新配置 GPIO 方向,那麼這個屬性將不存在。
0587
0588 "value" ... 讀取得到 0 (低電平) 或 1 (高電平)。如果 GPIO 配置爲
0589 輸出,這個值允許寫操作。任何非零值都以高電平看待。
0590
0591 如果引腳可以配置爲中斷信號,且如果已經配置了產生中斷的模式
0592 (見"edge"的描述),你可以對這個文件使用輪詢操作(poll(2)),
0593 且輪詢操作會在任何中斷觸發時返回。如果你使用輪詢操作(poll(2)),
0594 請在 events 中設置 POLLPRI 和 POLLERR。如果你使用輪詢操作
0595 (select(2)),請在 exceptfds 設置你期望的文件描述符。在
0596 輪詢操作(poll(2))返回之後,既可以通過 lseek(2)操作讀取
0597 sysfs 文件的開始部分,也可以關閉這個文件並重新打開它來讀取數據。
0598
0599 "edge" ... 讀取得到「none」、「rising」、「falling」或者「both」。
0600 將這些字符串寫入這個文件可以選擇沿觸發模式,會使得輪詢操作
0601 (select(2))在"value"文件中返回。
0602
0603 這個文件僅有在這個引腳可以配置爲可產生中斷輸入引腳時,才存在。
0604
0605 "active_low" ... 讀取得到 0 (假) 或 1 (真)。寫入任何非零值可以
0606 翻轉這個屬性的(讀寫)值。已存在或之後通過"edge"屬性設置了"rising"
0607 和 "falling" 沿觸發模式的輪詢操作(poll(2))將會遵循這個設置。
0608
0609 GPIO 控制器的路徑類似 /sys/class/gpio/gpiochip42/ (對於從#42 GPIO
0610 開始實現控制的控制器),並有著以下只讀屬性:
0611
0612 /sys/class/gpio/gpiochipN/
0613
0614 "base" ... 與以上的 N 相同,代表此晶片管理的第一個 GPIO 的編號
0615
0616 "label" ... 用於診斷 (並不總是只有唯一值)
0617
0618 "ngpio" ... 此控制器所管理的 GPIO 數量(而 GPIO 編號從 N 到
0619 N + ngpio - 1)
0620
0621 大多數情況下,電路板的文檔應當標明每個 GPIO 的使用目的。但是那些編號並不總是
0622 固定的,例如在擴展卡上的 GPIO會根據所使用的主板或所在堆疊架構中其他的板子而
0623 有所不同。在這種情況下,你可能需要使用 gpiochip 節點(儘可能地結合電路圖)來
0624 確定給定信號所用的 GPIO 編號。
0625
0626
0627 從內核代碼中導出
0628 -------------
0629 內核代碼可以明確地管理那些已通過 gpio_request()申請的 GPIO 的導出:
0630
0631 /* 導出 GPIO 到用戶空間 */
0632 int gpio_export(unsigned gpio, bool direction_may_change);
0633
0634 /* gpio_export()的逆操作 */
0635 void gpio_unexport();
0636
0637 /* 創建一個 sysfs 連接到已導出的 GPIO 節點 */
0638 int gpio_export_link(struct device *dev, const char *name,
0639 unsigned gpio)
0640
0641 在一個內核驅動申請一個 GPIO 之後,它可以通過 gpio_export()使其在 sysfs
0642 接口中可見。該驅動可以控制信號方向是否可修改。這有助於防止用戶空間代碼無意間
0643 破壞重要的系統狀態。
0644
0645 這個明確的導出有助於(通過使某些實驗更容易來)調試,也可以提供一個始終存在的接口,
0646 與文檔配合作爲板級支持包的一部分。
0647
0648 在 GPIO 被導出之後,gpio_export_link()允許在 sysfs 文件系統的任何地方
0649 創建一個到這個 GPIO sysfs 節點的符號連結。這樣驅動就可以通過一個描述性的
0650 名字,在 sysfs 中他們所擁有的設備下提供一個(到這個 GPIO sysfs 節點的)接口。
0651