.. SPDX-License-Identifier: GPL-2.0 .. include:: ../../disclaimer-zh_CN.rst :Original: Documentation/driver-api/gpio/legacy.rst :翻译: å‚…ç‚œ Fu Wei <tekkamanninja@gmail.com> å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: ä¼ ç»ŸGPIOæŽ¥å£ ============ 本文档概述了Linux下的GPIO访问公约。 这些函数以 gpio_* 作为å‰ç¼€ã€‚其他的函数ä¸å…è®¸ä½¿ç”¨è¿™æ ·çš„å‰ç¼€æˆ–相关的 __gpio_* å‰ç¼€ã€‚ 什么是GPIO? ============ "通用输入/输出å£"(GPIO)是一个çµæ´»çš„由软件控制的数å—ä¿¡å·ã€‚ä»–ä»¬å¯ ç”±å¤šç§èŠ¯ç‰‡æä¾›,且对于从事嵌入å¼å’Œå®šåˆ¶ç¡¬ä»¶çš„ Linux å¼€å‘者æ¥è¯´æ˜¯ 比较熟悉。æ¯ä¸ªGPIO 都代表一个连接到特定引脚或çƒæ …阵列(BGA)å°è£…ä¸ â€œçƒç â€çš„一个ä½ã€‚电路æ¿åŽŸç†å›¾æ˜¾ç¤ºäº† GPIO 与外部硬件的连接关系。 驱动å¯ä»¥ç¼–写æˆé€šç”¨ä»£ç ,以使æ¿çº§å¯åŠ¨ä»£ç å¯ä¼ 递引脚é…置数æ®ç»™é©±åŠ¨ã€‚ 片上系统 (SOC) 处ç†å™¨å¯¹ GPIO 有很大的ä¾èµ–。在æŸäº›æƒ…况下,æ¯ä¸ª éžä¸“用引脚都å¯é…置为 GPIO,且大多数芯片都最少有一些 GPIO。 å¯ç¼–程逻辑器件(类似 FPGA) å¯ä»¥æ–¹ä¾¿åœ°æä¾› GPIO。åƒç”µæºç®¡ç†å’Œ 音频编解ç å™¨è¿™æ ·çš„å¤šåŠŸèƒ½èŠ¯ç‰‡ç»å¸¸ç•™æœ‰ä¸€äº›è¿™æ ·çš„引脚æ¥å¸®åŠ©é‚£äº›å¼•è„š 匮ä¹çš„ SOC。åŒæ—¶è¿˜æœ‰é€šè¿‡ I2C 或 SPI 串行总线连接的“GPIO扩展器†芯片。大多数 PC çš„å—桥有一些拥有 GPIO 能力的引脚 (åªæœ‰BIOS 固件æ‰çŸ¥é“如何使用他们)。 GPIO çš„å®žé™…åŠŸèƒ½å› ç³»ç»Ÿè€Œå¼‚ã€‚é€šå¸¸ç”¨æ³•æœ‰: - 输出值å¯å†™ (高电平=1,低电平=0)。一些芯片也有如何驱动这些值的选项, 例如åªå…许输出一个值ã€æ”¯æŒâ€œçº¿ä¸Žâ€åŠå…¶ä»–å–值类似的模å¼(值得注æ„的是 “开æ¼â€ä¿¡å·) - 输入值å¯è¯»(1ã€0)。一些芯片支æŒå¼•è„šåœ¨é…置为“输出â€æ—¶å›žè¯»ï¼Œè¿™å¯¹äºŽç±»ä¼¼ “线与â€çš„情况(以支æŒåŒå‘ä¿¡å·)是éžå¸¸æœ‰ç”¨çš„。GPIO 控制器å¯èƒ½æœ‰è¾“å…¥ 去毛刺/消抖逻辑,这有时需è¦è½¯ä»¶æŽ§åˆ¶ã€‚ - 输入通常å¯ä½œä¸º IRQ ä¿¡å·,一般是沿触å‘,但有时是电平触å‘ã€‚è¿™æ ·çš„ IRQ å¯èƒ½é…置为系统唤醒事件,以将系统从低功耗状æ€ä¸‹å”¤é†’。 - 通常一个 GPIO æ ¹æ®ä¸åŒäº§å“电路æ¿çš„需求,å¯ä»¥é…置为输入或输出,也有仅 支æŒå•å‘的。 - 大部分 GPIO å¯ä»¥åœ¨æŒæœ‰è‡ªæ—‹é”时访问,但是通常由串行总线扩展的 GPIO ä¸å…许æŒæœ‰è‡ªæ—‹é”。但æŸäº›ç³»ç»Ÿä¹Ÿæ”¯æŒè¿™ç§ç±»åž‹ã€‚ 对于给定的电路æ¿,æ¯ä¸ª GPIO 都用于æŸä¸ªç‰¹å®šçš„目的,如监控 MMC/SD å¡çš„ æ’å…¥/移除ã€æ£€æµ‹å¡çš„写ä¿æŠ¤çŠ¶æ€ã€é©±åŠ¨ LEDã€é…置收å‘器ã€æ¨¡æ‹Ÿä¸²è¡Œæ€»çº¿ã€ å¤ä½ç¡¬ä»¶çœ‹é—¨ç‹—ã€æ„ŸçŸ¥å¼€å…³çŠ¶æ€ç‰ç‰ã€‚ GPIO 公约 ========= 注æ„,这个å«åšâ€œå…¬çº¦â€ï¼Œå› 为这ä¸æ˜¯å¼ºåˆ¶æ€§çš„,ä¸éµå¾ªè¿™ä¸ªå…¬çº¦æ˜¯æ— 伤大雅的, å› ä¸ºæ¤æ—¶å¯ç§»æ¤æ€§å¹¶ä¸é‡è¦ã€‚GPIO 常用于æ¿çº§ç‰¹å®šçš„电路逻辑,甚至å¯èƒ½ éšç€ç”µè·¯æ¿çš„版本而改å˜ï¼Œä¸”ä¸å¯èƒ½åœ¨ä¸åŒèµ°çº¿çš„电路æ¿ä¸Šä½¿ç”¨ã€‚仅有在少数 功能上æ‰å…·æœ‰å¯ç§»æ¤æ€§ï¼Œå…¶ä»–功能是平å°ç‰¹å®šã€‚这也是由于“胶åˆâ€çš„é€»è¾‘é€ æˆçš„。 æ¤å¤–,这ä¸éœ€è¦ä»»ä½•çš„执行框架,åªæ˜¯ä¸€ä¸ªæŽ¥å£ã€‚æŸä¸ªå¹³å°å¯èƒ½é€šè¿‡ä¸€ä¸ªç®€å•åœ° 访问芯片寄å˜å™¨çš„内è”函数æ¥å®žçŽ°å®ƒï¼Œå…¶ä»–å¹³å°å¯èƒ½é€šè¿‡å§”托一系列ä¸åŒçš„GPIO 控制器的抽象函数æ¥å®žçŽ°å®ƒã€‚(有一些å¯é€‰çš„代ç 能支æŒè¿™ç§ç–略的实现,本文档 åŽé¢ä¼šä»‹ç»ï¼Œä½†ä½œä¸º GPIO 接å£çš„客户端驱动程åºå¿…é¡»ä¸Žå®ƒçš„å®žçŽ°æ— å…³ã€‚) 也就是说,如果在他们的平å°ä¸Šæ”¯æŒè¿™ä¸ªå…¬çº¦ï¼Œé©±åŠ¨åº”å°½å¯èƒ½çš„使用它。åŒæ—¶ï¼Œå¹³å° 必须在 Kconfig ä¸é€‰æ‹© ARCH_REQUIRE_GPIOLIB 或者 ARCH_WANT_OPTIONAL_GPIOLIB é€‰é¡¹ã€‚é‚£äº›è°ƒç”¨æ ‡å‡† GPIO 函数的驱动应该在 Kconfig å…¥å£ä¸å£°æ˜Žä¾èµ–GENERIC_GPIO。 当驱动包å«æ–‡ä»¶: #include <linux/gpio.h> 则 GPIO 函数是å¯ç”¨,æ— è®ºæ˜¯â€œçœŸå®žä»£ç â€è¿˜æ˜¯ç»ä¼˜åŒ–过的è¯å¥ã€‚å¦‚æžœä½ éµå®ˆ è¿™ä¸ªå…¬çº¦ï¼Œå½“ä½ çš„ä»£ç 完æˆåŽï¼Œå¯¹å…¶ä»–çš„å¼€å‘者æ¥è¯´ä¼šæ›´å®¹æ˜“看懂和维护。 注æ„,这些æ“作包å«æ‰€ç”¨å¹³å°çš„ I/O å±éšœä»£ç ï¼Œé©±åŠ¨æ— é¡»æ˜¾å¼åœ°è°ƒç”¨ä»–们。 æ ‡è¯† GPIO --------- GPIO æ˜¯é€šè¿‡æ— ç¬¦å·æ•´åž‹æ¥æ ‡è¯†çš„,范围是 0 到 MAX_INT。ä¿ç•™â€œè´Ÿâ€æ•° 用于其他目的,ä¾‹å¦‚æ ‡è¯†ä¿¡å·â€œåœ¨è¿™ä¸ªæ¿å上ä¸å¯ç”¨â€æˆ–指示错误。未接触底层 硬件的代ç 会忽略这些整数。 å¹³å°ä¼šå®šä¹‰è¿™äº›æ•´æ•°çš„用法,且通常使用 #define æ¥å®šä¹‰ GPIOï¼Œè¿™æ · æ¿çº§ç‰¹å®šçš„å¯åŠ¨ä»£ç å¯ä»¥ç›´æŽ¥å…³è”相应的原ç†å›¾ã€‚相对æ¥è¯´ï¼Œé©±åŠ¨åº”该仅使用 å¯åŠ¨ä»£ç ä¼ é€’è¿‡æ¥çš„ GPIO ç¼–å·ï¼Œä½¿ç”¨ platform_data ä¿å˜æ¿çº§ç‰¹å®š 引脚é…ç½®æ•°æ® (åŒæ—¶è¿˜æœ‰å…¶ä»–é¡»è¦çš„æ¿çº§ç‰¹å®šæ•°æ®),é¿å…å¯èƒ½å‡ºçŽ°çš„问题。 例如一个平å°ä½¿ç”¨ç¼–å· 32-159 æ¥æ ‡è¯† GPIO,而在å¦ä¸€ä¸ªå¹³å°ä½¿ç”¨ç¼–å·0-63 æ ‡è¯†ä¸€ç»„ GPIO 控制器,64-79æ ‡è¯†å¦ä¸€ç±» GPIO 控制器,且在一个å«æœ‰ FPGA 的特定æ¿å上使用 80-95。编å·ä¸ä¸€å®šè¦è¿žç»,那些平å°ä¸ï¼Œä¹Ÿå¯ä»¥ 使用编å·2000-2063æ¥æ ‡è¯†ä¸€ä¸ª I2C 接å£çš„ GPIO 扩展器ä¸çš„ GPIO。 å¦‚æžœä½ è¦åˆå§‹åŒ–ä¸€ä¸ªå¸¦æœ‰æ— æ•ˆ GPIO ç¼–å·çš„结构体,å¯ä»¥ä½¿ç”¨ä¸€äº›è´Ÿç¼–ç (如"-EINVAL"),那将使其永远ä¸ä¼šæ˜¯æœ‰æ•ˆã€‚æ¥æµ‹è¯•è¿™æ ·ä¸€ä¸ªç»“构体ä¸çš„ç¼–å· æ˜¯å¦å…³è”一个 GPIOï¼Œä½ å¯ä½¿ç”¨ä»¥ä¸‹æ–言:: int gpio_is_valid(int number); 如果编å·ä¸å˜åœ¨ï¼Œåˆ™è¯·æ±‚和释放 GPIO 的函数将拒ç»æ‰§è¡Œç›¸å…³æ“作(è§ä¸‹æ–‡)。 其他编å·ä¹Ÿå¯èƒ½è¢«æ‹’ç»,比如一个编å·å¯èƒ½å˜åœ¨ï¼Œä½†æš‚时在给定的电路上ä¸å¯ç”¨ã€‚ 一个平å°æ˜¯å¦æ”¯æŒå¤šä¸ª GPIO 控制器为平å°ç‰¹å®šçš„实现问题,就åƒæ˜¯å¦å¯ä»¥ 在 GPIO ç¼–å·ç©ºé—´ä¸æœ‰â€œç©ºæ´žâ€å’Œæ˜¯å¦å¯ä»¥åœ¨è¿è¡Œæ—¶æ·»åŠ æ–°çš„æŽ§åˆ¶å™¨ä¸€æ ·ã€‚ 这些问题会影å“其他事情,包括相邻的 GPIO ç¼–å·æ˜¯å¦å˜åœ¨ç‰ã€‚ 使用 GPIO --------- 对于一个 GPIO,系统应该åšçš„第一件事情就是通过 gpio_request() 函数分é…它,è§ä¸‹æ–‡ã€‚ 接下æ¥æ˜¯è®¾ç½®I/Oæ–¹å‘,这通常是在æ¿çº§å¯åŠ¨ä»£ç ä¸ä¸ºæ‰€ä½¿ç”¨çš„ GPIO 设置 platform_device 时完æˆ:: /* 设置为输入或输出, 返回 0 或负的错误代ç */ int gpio_direction_input(unsigned gpio); int gpio_direction_output(unsigned gpio, int value); 返回值为零代表æˆåŠŸï¼Œå¦åˆ™è¿”回一个负的错误代ç 。这个返回值需è¦æ£€æŸ¥ï¼Œå› 为 get/set(获å–/设置)函数调用没法返回错误,且有å¯èƒ½æ˜¯é…置错误。通常, ä½ åº”è¯¥åœ¨è¿›ç¨‹ä¸Šä¸‹æ–‡ä¸è°ƒç”¨è¿™äº›å‡½æ•°ã€‚然而,对于自旋é”安全的 GPIO,在æ¿å å¯åŠ¨çš„早期ã€è¿›ç¨‹å¯åŠ¨å‰ä½¿ç”¨ä»–们也是å¯ä»¥çš„。 对于作为输出的 GPIO,为其æä¾›åˆå§‹è¾“出值,对于é¿å…在系统å¯åŠ¨æœŸé—´å‡ºçŽ° ä¿¡å·æ¯›åˆºæ˜¯å¾ˆæœ‰å¸®åŠ©çš„。 ä¸ºäº†ä¸Žä¼ ç»Ÿçš„ GPIO 接å£å…¼å®¹, 在设置一个 GPIO æ–¹å‘时,如果它还未被申请, 则éšå«äº†ç”³è¯·é‚£ä¸ª GPIO çš„æ“作(è§ä¸‹æ–‡)。这ç§å…¼å®¹æ€§æ£åœ¨ä»Žå¯é€‰çš„ gpiolib 框架ä¸ç§»é™¤ã€‚ 如果这个 GPIO ç¼–ç ä¸å˜åœ¨ï¼Œæˆ–者特定的 GPIO ä¸èƒ½ç”¨äºŽé‚£ç§æ¨¡å¼ï¼Œåˆ™æ–¹å‘ 设置å¯èƒ½å¤±è´¥ã€‚ä¾èµ–å¯åŠ¨å›ºä»¶æ¥æ£ç¡®åœ°è®¾ç½®æ–¹å‘通常是一个å主æ„ï¼Œå› ä¸ºå®ƒå¯èƒ½ 除了å¯åŠ¨Linux,并没有åšæ›´å¤šçš„验è¯å·¥ä½œã€‚(åŒç†, æ¿åçš„å¯åŠ¨ä»£ç å¯èƒ½éœ€è¦ 将这个å¤ç”¨çš„引脚设置为 GPIO,并æ£ç¡®åœ°é…置上拉/下拉电阻。) 访问自旋é”安全的 GPIO --------------------- 大多数 GPIO 控制器å¯ä»¥é€šè¿‡å†…å˜è¯»/写指令æ¥è®¿é—®ã€‚这些指令ä¸ä¼šä¼‘çœ ,å¯ä»¥ 安全地在硬(éžçº¿ç¨‹)ä¸æ–例程和类似的上下文ä¸å®Œæˆã€‚ 对于那些用 gpio_cansleep()测试总是返回失败的 GPIO(è§ä¸‹æ–‡),使用 以下的函数访问:: /* GPIO 输入:返回零或éžé›¶ */ int gpio_get_value(unsigned gpio); /* GPIO 输出 */ void gpio_set_value(unsigned gpio, int value); GPIO值是布尔值,零表示低电平,éžé›¶è¡¨ç¤ºé«˜ç”µå¹³ã€‚当读å–一个输出引脚的值时, 返回值应该是引脚上的值。这个值ä¸æ€»æ˜¯å’Œè¾“å‡ºå€¼ç›¸ç¬¦ï¼Œå› ä¸ºå˜åœ¨å¼€æ¼è¾“出信å·å’Œ 输出延迟问题。 以上的 get/set å‡½æ•°æ— é”™è¯¯è¿”å›žå€¼ï¼Œå› ä¸ºä¹‹å‰ gpio_direction_*()应已检查过 其是å¦ä¸ºâ€œæ— 效GPIOâ€ã€‚æ¤å¤–,还需è¦æ³¨æ„的是并ä¸æ˜¯æ‰€æœ‰å¹³å°éƒ½å¯ä»¥ä»Žè¾“出引脚 ä¸è¯»å–æ•°æ®ï¼Œå¯¹äºŽä¸èƒ½è¯»å–的引脚应总返回零。å¦å¤–,对那些在原å上下文ä¸æ— 法 安全访问的 GPIO (è¯‘è€…æ³¨ï¼šå› ä¸ºè®¿é—®å¯èƒ½å¯¼è‡´ä¼‘çœ )使用这些函数是ä¸åˆé€‚çš„ (è§ä¸‹æ–‡)。 在 GPIO ç¼–å·(还有输出ã€å€¼)为常数的情况下,鼓励通过平å°ç‰¹å®šçš„实现æ¥ä¼˜åŒ– 这两个函数æ¥è®¿é—® GPIO 值。这ç§æƒ…况(读写一个硬件寄å˜å™¨)下åªéœ€è¦å‡ æ¡æŒ‡ä»¤ 是很æ£å¸¸çš„,ä¸”æ— é¡»è‡ªæ—‹é”。这ç§ä¼˜åŒ–函数比起那些在å程åºä¸ŠèŠ±è´¹è®¸å¤šæŒ‡ä»¤çš„ 函数å¯ä»¥ä½¿å¾—模拟接å£(译者注:例如 GPIO 模拟 I2Cã€1-wire 或 SPI)çš„ 应用(在空间和时间上都)更具效率。 访问å¯èƒ½ä¼‘çœ çš„ GPIO ------------------- æŸäº› GPIO 控制器必须通过基于总线(如 I2C 或 SPI)的消æ¯è®¿é—®ã€‚读或写这些 GPIO 值的命令需è¦ç‰å¾…其信æ¯æŽ’到队首æ‰å‘é€å‘½ä»¤ï¼Œå†èŽ·å¾—å…¶åé¦ˆã€‚æœŸé—´éœ€è¦ ä¼‘çœ ï¼Œè¿™ä¸èƒ½åœ¨ IRQ 例程(ä¸æ–上下文)ä¸æ‰§è¡Œã€‚ 支æŒæ¤ç±» GPIO çš„å¹³å°é€šè¿‡ä»¥ä¸‹å‡½æ•°è¿”回éžé›¶å€¼æ¥åŒºåˆ†å‡ºè¿™ç§ GPIO。(æ¤å‡½æ•°éœ€è¦ 一个之å‰é€šè¿‡ gpio_request 分é…到的有效 GPIO ç¼–å·):: int gpio_cansleep(unsigned gpio); ä¸ºäº†è®¿é—®è¿™ç§ GPIO,å†…æ ¸å®šä¹‰äº†ä¸€å¥—ä¸åŒçš„函数:: /* GPIO 输入:返回零或éžé›¶ ,å¯èƒ½ä¼šä¼‘çœ */ int gpio_get_value_cansleep(unsigned gpio); /* GPIO 输出,å¯èƒ½ä¼šä¼‘çœ */ void gpio_set_value_cansleep(unsigned gpio, int value); è®¿é—®è¿™æ ·çš„ GPIO 需è¦ä¸€ä¸ªå…è®¸ä¼‘çœ çš„ä¸Šä¸‹æ–‡ï¼Œä¾‹å¦‚çº¿ç¨‹ IRQ 处ç†ä¾‹ç¨‹ï¼Œå¹¶ç”¨ä»¥ä¸Šçš„ 访问函数替æ¢é‚£äº›æ²¡æœ‰ cansleep()åŽç¼€çš„自旋é”安全访问函数。 除了这些访问函数å¯èƒ½ä¼‘çœ ï¼Œä¸”å®ƒä»¬æ“作的 GPIO ä¸èƒ½åœ¨ç¡¬ä»¶ IRQ 处ç†ä¾‹ç¨‹ä¸è®¿é—®çš„ 事实,这些处ç†ä¾‹ç¨‹å®žé™…上和自旋é”å®‰å…¨çš„å‡½æ•°æ˜¯ä¸€æ ·çš„ã€‚ ** 除æ¤ä¹‹å¤– ** 调用设置和é…ç½®æ¤ç±» GPIO 的函数也必须在å…è®¸ä¼‘çœ çš„ä¸Šä¸‹æ–‡ä¸ï¼Œ å› ä¸ºå®ƒä»¬å¯èƒ½ä¹Ÿéœ€è¦è®¿é—® GPIO 控制器芯片 (这些设置函数通常在æ¿çº§å¯åŠ¨ä»£ç 或者 驱动探测/æ–开代ç ä¸ï¼Œæ‰€ä»¥è¿™æ˜¯ä¸€ä¸ªå®¹æ˜“满足的约æŸæ¡ä»¶ã€‚) :: gpio_direction_input() gpio_direction_output() gpio_request() ## gpio_request_one() ## gpio_request_array() ## gpio_free_array() gpio_free() 声明和释放 GPIO ---------------- 为了有助于æ•èŽ·ç³»ç»Ÿé…置错误,定义了两个函数:: /* 申请 GPIO, 返回 0 或负的错误代ç . * éžç©ºæ ‡ç¾å¯èƒ½æœ‰åŠ©äºŽè¯Šæ–. */ int gpio_request(unsigned gpio, const char *label); /* 释放之å‰å£°æ˜Žçš„ GPIO */ void gpio_free(unsigned gpio); å°†æ— æ•ˆçš„ GPIO ç¼–ç ä¼ é€’ç»™ gpio_request()会导致失败,申请一个已使用这个 函数声明过的 GPIO 也会失败。gpio_request()çš„è¿”å›žå€¼å¿…é¡»æ£€æŸ¥ã€‚ä½ åº”è¯¥åœ¨ 进程上下文ä¸è°ƒç”¨è¿™äº›å‡½æ•°ã€‚然而,对于自旋é”安全的 GPIO,在æ¿åå¯åŠ¨çš„早期〠进入进程之å‰æ˜¯å¯ä»¥ç”³è¯·çš„。 这个函数完æˆä¸¤ä¸ªåŸºæœ¬çš„ç›®æ ‡ã€‚ä¸€æ˜¯æ ‡è¯†é‚£äº›å®žé™…ä¸Šå·²ä½œä¸º GPIO 使用的信å·çº¿ï¼Œ è¿™æ ·ä¾¿äºŽæ›´å¥½åœ°è¯Šæ–;系统å¯èƒ½éœ€è¦æœåŠ¡å‡ 百个å¯ç”¨çš„ GPIO,但是对于任何一个 给定的电路æ¿é€šå¸¸åªæœ‰ä¸€äº›è¢«ä½¿ç”¨ã€‚å¦ä¸€ä¸ªç›®çš„是æ•èŽ·å†²çªï¼ŒæŸ¥æ˜Žé”™è¯¯:如两个或 更多驱动错误地认为他们已ç»ç‹¬å 了æŸä¸ªä¿¡å·çº¿,或是错误地认为移除一个管ç†ç€ æŸä¸ªå·²æ¿€æ´»ä¿¡å·çš„驱动是安全的。也就是说,申请 GPIO 的作用类似一ç§é”机制。 æŸäº›å¹³å°å¯èƒ½ä¹Ÿä½¿ç”¨ GPIO 作为电æºç®¡ç†æ¿€æ´»ä¿¡å·(例如通过关é—未使用芯片区和 简å•åœ°å…³é—未使用时钟)。 对于 GPIO 使用引脚控制å系统已知的引脚,å系统应该被告知其使用情况; 一个 gpiolib 驱动的 .request()æ“作应调用 pinctrl_gpio_request(), 而 gpiolib 驱动的 .free()æ“作应调用 pinctrl_gpio_free()。引脚控制 å系统å…许 pinctrl_gpio_request()在æŸä¸ªå¼•è„šæˆ–引脚组以å¤ç”¨å½¢å¼â€œå±žäºŽâ€ 一个设备时都æˆåŠŸè¿”回。 任何须将 GPIO ä¿¡å·å¯¼å‘适当引脚的引脚å¤ç”¨ç¡¬ä»¶çš„编程应该å‘生在 GPIO 驱动的 .direction_input()或 .direction_output()函数ä¸ï¼Œä»¥åŠ 任何输出 GPIO 值的设置之åŽã€‚è¿™æ ·å¯ä½¿ä»Žå¼•è„šç‰¹æ®ŠåŠŸèƒ½åˆ° GPIO çš„è½¬æ¢ ä¸ä¼šåœ¨å¼•è„šäº§ç”Ÿæ¯›åˆºæ³¢å½¢ã€‚有时当用一个 GPIO 实现其信å·é©±åŠ¨ä¸€ä¸ªéž GPIO 硬件模å—的解决方案时,就需è¦è¿™ç§æœºåˆ¶ã€‚ æŸäº›å¹³å°å…许部分或所有 GPIO ä¿¡å·ä½¿ç”¨ä¸åŒçš„引脚。类似的,GPIO 或引脚的 其他方é¢ä¹Ÿéœ€è¦é…置,如上拉/下拉。平å°è½¯ä»¶åº”该在对这些 GPIO 调用 gpio_request()å‰å°†è¿™ç±»ç»†èŠ‚é…置好,例如使用引脚控制åç³»ç»Ÿçš„æ˜ å°„è¡¨ï¼Œ 使得 GPIO çš„ç”¨æˆ·æ— é¡»å…³æ³¨è¿™äº›ç»†èŠ‚ã€‚ 还有一个值得注æ„的是在释放 GPIO å‰ï¼Œä½ å¿…é¡»åœæ¢ä½¿ç”¨å®ƒã€‚ 注æ„:申请一个 GPIO 并没有以任何方å¼é…置它,åªä¸è¿‡æ ‡è¯†é‚£ä¸ª GPIO 处于使用 状æ€ã€‚必须有å¦å¤–的代ç æ¥å¤„ç†å¼•è„šé…ç½®(如控制 GPIO 使用的引脚ã€ä¸Šæ‹‰/下拉)。 考虑到大多数情况下声明 GPIO 之åŽå°±ä¼šç«‹å³é…置它们,所以定义了以下三个辅助函数:: /* 申请一个 GPIO ä¿¡å·, åŒæ—¶é€šè¿‡ç‰¹å®šçš„'flags'åˆå§‹åŒ–é…ç½®, * 其他和 gpio_request()çš„å‚æ•°å’Œè¿”å›žå€¼ç›¸åŒ * */ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); /* 在å•ä¸ªå‡½æ•°ä¸ç”³è¯·å¤šä¸ª GPIO */ int gpio_request_array(struct gpio *array, size_t num); /* 在å•ä¸ªå‡½æ•°ä¸é‡Šæ”¾å¤šä¸ª GPIO */ void gpio_free_array(struct gpio *array, size_t num); 这里 'flags' 当å‰å®šä¹‰å¯æŒ‡å®šä»¥ä¸‹å±žæ€§: * GPIOF_DIR_IN - é…置方å‘为输入 * GPIOF_DIR_OUT - é…置方å‘为输出 * GPIOF_INIT_LOW - 在作为输出时,åˆå§‹å€¼ä¸ºä½Žç”µå¹³ * GPIOF_INIT_HIGH - 在作为输出时,åˆå§‹å€¼ä¸ºé«˜ç”µå¹³ * GPIOF_OPEN_DRAIN - gpio引脚为开æ¼ä¿¡å· * GPIOF_OPEN_SOURCE - gpio引脚为æºæžå¼€è·¯ä¿¡å· * GPIOF_EXPORT_DIR_FIXED - å°† gpio 导出到 sysfs,并ä¿æŒæ–¹å‘ * GPIOF_EXPORT_DIR_CHANGEABLE - åŒæ ·æ˜¯å¯¼å‡º, 但å…许改å˜æ–¹å‘ å› ä¸º GPIOF_INIT_* 仅有在é…置为输出的时候æ‰å˜åœ¨,所以有效的组åˆä¸º: * GPIOF_IN - é…置为输入 * GPIOF_OUT_INIT_LOW - é…置为输出,并åˆå§‹åŒ–为低电平 * GPIOF_OUT_INIT_HIGH - é…置为输出,并åˆå§‹åŒ–为高电平 当设置 flag 为 GPIOF_OPEN_DRAIN 时,则å‡è®¾å¼•è„šæ˜¯å¼€æ¼ä¿¡å·ã€‚è¿™æ ·çš„å¼•è„š å°†ä¸ä¼šåœ¨è¾“出模å¼ä¸‹ç½®1ã€‚è¿™æ ·çš„å¼•è„šéœ€è¦è¿žæŽ¥ä¸Šæ‹‰ç”µé˜»ã€‚é€šè¿‡ä½¿èƒ½è¿™ä¸ªæ ‡å¿—ï¼Œgpio库 将会在被è¦æ±‚输出模å¼ä¸‹ç½®1时将引脚å˜ä¸ºè¾“入状æ€æ¥ä½¿å¼•è„šç½®é«˜ã€‚引脚在输出模å¼ä¸‹ 通过置0使其输出低电平。 当设置 flag 为 GPIOF_OPEN_SOURCE 时,则å‡è®¾å¼•è„šä¸ºæºæžå¼€è·¯ä¿¡å·ã€‚è¿™æ ·çš„å¼•è„š å°†ä¸ä¼šåœ¨è¾“出模å¼ä¸‹ç½®0ã€‚è¿™æ ·çš„å¼•è„šéœ€è¦è¿žæŽ¥ä¸‹æ‹‰ç”µé˜»ã€‚é€šè¿‡ä½¿èƒ½è¿™ä¸ªæ ‡å¿—ï¼Œgpio库 将会在被è¦æ±‚输出模å¼ä¸‹ç½®0时将引脚å˜ä¸ºè¾“入状æ€æ¥ä½¿å¼•è„šç½®ä½Žã€‚引脚在输出模å¼ä¸‹ 通过置1使其输出高电平。 å°†æ¥è¿™äº›æ ‡å¿—å¯èƒ½æ‰©å±•åˆ°æ”¯æŒæ›´å¤šçš„属性。 更进一æ¥,为了更简å•åœ°å£°æ˜Ž/释放多个 GPIO,'struct gpio'被引进æ¥å°è£…所有 这三个领域:: struct gpio { unsigned gpio; unsigned long flags; const char *label; }; 一个典型的用例:: static struct gpio leds_gpios[] = { { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* é»˜è®¤å¼€å¯ */ { 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* é»˜è®¤å…³é— */ { 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* é»˜è®¤å…³é— */ { 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* é»˜è®¤å…³é— */ { ... }, }; err = gpio_request_one(31, GPIOF_IN, "Reset Button"); if (err) ... err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios)); if (err) ... gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios)); GPIO æ˜ å°„åˆ° IRQ ---------------- GPIO ç¼–å·æ˜¯æ— 符å·æ•´æ•°;IRQ ç¼–å·ä¹Ÿæ˜¯ã€‚这些构æˆäº†ä¸¤ä¸ªé€»è¾‘上ä¸åŒçš„命å空间 (GPIO 0 ä¸ä¸€å®šä½¿ç”¨ IRQ 0)ã€‚ä½ å¯ä»¥é€šè¿‡ä»¥ä¸‹å‡½æ•°åœ¨å®ƒä»¬ä¹‹é—´å®žçŽ°æ˜ å°„:: /* æ˜ å°„ GPIO ç¼–å·åˆ° IRQ ç¼–å· */ int gpio_to_irq(unsigned gpio); 它们的返回值为对应命å空间的相关编å·ï¼Œæˆ–是负的错误代ç (å¦‚æžœæ— æ³•æ˜ å°„)。 (例如,æŸäº› GPIO æ— æ³•åšä¸º IRQ 使用。)以下的编å·é”™è¯¯æ˜¯æœªç»æ£€æµ‹çš„:使用一个 未通过 gpio_direction_input()é…置为输入的 GPIO ç¼–å·ï¼Œæˆ–者使用一个 并éžæ¥æºäºŽgpio_to_irq()çš„ IRQ ç¼–å·ã€‚ è¿™ä¸¤ä¸ªæ˜ å°„å‡½æ•°å¯èƒ½ä¼šåœ¨ä¿¡å·ç¼–å·çš„åŠ å‡è®¡ç®—过程上花些时间。它们ä¸å¯ä¼‘çœ ã€‚ gpio_to_irq()返回的éžé”™è¯¯å€¼å¯ä»¥ä¼ 递给 request_irq()或者 free_irq()。 它们通常通过æ¿çº§ç‰¹å®šçš„åˆå§‹åŒ–代ç å˜æ”¾åˆ°å¹³å°è®¾å¤‡çš„ IRQ 资æºä¸ã€‚注æ„:IRQ 触å‘选项是 IRQ 接å£çš„一部分,如 IRQF_TRIGGER_FALLING,系统唤醒能力 也是如æ¤ã€‚ 模拟开æ¼ä¿¡å· ------------ 有时在åªæœ‰ä½Žç”µå¹³ä¿¡å·ä½œä¸ºå®žé™…驱动结果(译者注:多个输出连接于一点,逻辑电平 结果为所有输出的逻辑与)的时候,共享的信å·çº¿éœ€è¦ä½¿ç”¨â€œå¼€æ¼â€ä¿¡å·ã€‚(è¯¥æœ¯è¯ é€‚ç”¨äºŽ CMOS 管;而 TTL 用“集电æžå¼€è·¯â€ã€‚)一个上拉电阻使信å·ä¸ºé«˜ç”µå¹³ã€‚è¿™ 有时被称为“线与â€ã€‚实际上,从负逻辑(低电平为真)的角度æ¥çœ‹ï¼Œè¿™æ˜¯ä¸€ä¸ªâ€œçº¿æˆ–â€ã€‚ 一个开æ¼ä¿¡å·çš„常è§ä¾‹å是共享的低电平使能 IRQ ä¿¡å·çº¿ã€‚æ¤å¤–,有时åŒå‘æ•°æ®æ€»çº¿ ä¿¡å·ä¹Ÿä½¿ç”¨æ¼æžå¼€è·¯ä¿¡å·ã€‚ æŸäº› GPIO 控制器直接支æŒå¼€æ¼è¾“出,还有许多ä¸æ”¯æŒã€‚å½“ä½ éœ€è¦å¼€æ¼ä¿¡å·ï¼Œä½† 硬件åˆä¸ç›´æŽ¥æ”¯æŒçš„时候,一个常用的方法是用任何å³å¯ä½œè¾“入也å¯ä½œè¾“出的 GPIO 引脚æ¥æ¨¡æ‹Ÿ: LOW: gpio_direction_output(gpio, 0) ... 这代ç 驱动信å·å¹¶è¦†ç›– 上拉é…置。 HIGH: gpio_direction_input(gpio) ... 这代ç å…³é—输出,所以上拉电阻 (或其他的一些器件)控制了信å·ã€‚ å¦‚æžœä½ å°†ä¿¡å·çº¿â€œé©±åŠ¨â€ä¸ºé«˜ç”µå¹³ï¼Œä½†æ˜¯ gpio_get_value(gpio)报告了一个 低电平(在适当的上å‡æ—¶é—´åŽ)ï¼Œä½ å°±å¯ä»¥çŸ¥é“是其他的一些组件将共享信å·çº¿æ‹‰ä½Žäº†ã€‚ è¿™ä¸ä¸€å®šæ˜¯é”™è¯¯çš„。一个常è§çš„例å就是 I2C 时钟的延长:一个需è¦è¾ƒæ…¢æ—¶é’Ÿçš„ 从设备延迟 SCK 的上å‡æ²¿ï¼Œè€Œ I2C 主设备相应地调整其信å·ä¼ 输速率。 GPIO控制器和引脚控制å系统 -------------------------- SOC上的GPIO控制器å¯èƒ½ä¸Žå¼•è„šæŽ§åˆ¶å系统紧密结åˆï¼Œå³å¼•è„šå¯ä»¥ä¸Žå¯é€‰çš„gpio功 能一起被其他功能使用。我们已ç»æ¶µç›–äº†è¿™æ ·çš„æƒ…å†µï¼Œä¾‹å¦‚ä¸€ä¸ªGPIO控制器需è¦ä¿ 留一个引脚或通过调用以下任何一个引脚æ¥è®¾ç½®å…¶æ–¹å‘:: pinctrl_gpio_request() pinctrl_gpio_free() pinctrl_gpio_direction_input() pinctrl_gpio_direction_output() 但是,引脚控制å系统是如何将GPIOå·ç (这是一个全局事项)与æŸä¸ªå¼•è„šæŽ§åˆ¶å™¨ 上的æŸä¸ªå¼•è„šäº¤å‰å…³è”的? 这是通过注册引脚的“范围â€æ¥å®žçŽ°çš„,这基本上是交å‰å‚考表。这些æ述是在 Documentation/driver-api/pin-control.rst 虽然引脚分é…完全由引脚控制å系统管ç†ï¼Œä½†gpio(在gpiolib下)ä»ç”±gpio驱动 维护。å¯èƒ½å‘生的情况是,SoCä¸çš„ä¸åŒå¼•è„šèŒƒå›´ç”±ä¸åŒçš„gpio驱动器管ç†ã€‚ 这使得在调用 "pinctrl_gpio_request" 之å‰ï¼Œè®©gpio驱动å‘pin ctrlåç³» 统宣布它们的引脚范围是åˆç†çš„,以便在使用任何gpio之å‰è¦æ±‚引脚控制å系统准 备相应的引脚。 为æ¤ï¼Œgpio控制器å¯ä»¥ç”¨å¼•è„šæŽ§åˆ¶å系统注册其引脚范围。目å‰æœ‰ä¸¤ç§æ–¹æ³•ï¼šæœ‰æˆ– æ— DT。 关于对DT的支æŒï¼Œè¯·å‚考 Documentation/devicetree/bindings/gpio/gpio.txt. 对于éžDT支æŒï¼Œç”¨æˆ·å¯ä»¥ç”¨é€‚当的å‚数调用gpiochip_add_pin_range(),将一 系列的gpio引脚注册到引脚控制驱动上。为æ¤ï¼Œå¿…须将引脚控制设备的å称å—符串 作为å‚æ•°ä¹‹ä¸€ä¼ ç»™è¿™ä¸ªç¨‹åºã€‚ 这些公约忽略了什么? ==================== 这些公约忽略的最大一件事就是引脚å¤ç”¨ï¼Œå› 为这属于高度芯片特定的属性且 没有å¯ç§»æ¤æ€§ã€‚æŸä¸ªå¹³å°å¯èƒ½ä¸éœ€è¦æ˜Žç¡®çš„å¤ç”¨ä¿¡æ¯ï¼›æœ‰çš„对于任æ„给定的引脚 å¯èƒ½åªæœ‰ä¸¤ä¸ªåŠŸèƒ½é€‰é¡¹ï¼›æœ‰çš„å¯èƒ½æ¯ä¸ªå¼•è„šæœ‰å…«ä¸ªåŠŸèƒ½é€‰é¡¹ï¼›æœ‰çš„å¯èƒ½å¯ä»¥å°† å‡ ä¸ªå¼•è„šä¸çš„任何一个作为给定的 GPIO。(是的,这些例å都æ¥è‡ªäºŽå½“å‰è¿è¡Œ Linux 的系统。) 在æŸäº›ç³»ç»Ÿä¸,与引脚å¤ç”¨ç›¸å…³çš„是é…置和使能集æˆçš„上ã€ä¸‹æ‹‰æ¨¡å¼ã€‚并ä¸æ˜¯æ‰€æœ‰ å¹³å°éƒ½æ”¯æŒè¿™ç§æ¨¡å¼,或者ä¸ä¼šä»¥ç›¸åŒçš„æ–¹å¼æ¥æ”¯æŒè¿™ç§æ¨¡å¼ï¼›ä¸”ä»»ä½•ç»™å®šçš„ç”µè·¯æ¿ å¯èƒ½ä½¿ç”¨å¤–置的上拉(或下拉)电阻,这时芯片上的就ä¸åº”该使用。(å½“ä¸€ä¸ªç”µè·¯éœ€è¦ 5kOhm 的拉动电阻,芯片上的 100 kOhm 电阻就ä¸èƒ½åšåˆ°ã€‚)åŒæ ·çš„,驱动能力 (2 mA vs 20 mA)和电压(1.8V vs 3.3V)是平å°ç‰¹å®šé—®é¢˜,å°±åƒæ¨¡åž‹ä¸€æ ·åœ¨ å¯é…置引脚和 GPIO 之间(没)有一一对应的关系。 还有其他一些系统特定的机制没有在这里指出,例如上述的输入去毛刺和线与输出 选项。硬件å¯èƒ½æ”¯æŒæ‰¹é‡è¯»æˆ–写 GPIO,但是那一般是é…置相关的:对于处于åŒä¸€ å—区(bank)çš„GPIO。(GPIO 通常以 16 或 32 个组æˆä¸€ä¸ªåŒºå—,一个给定的 ç‰‡ä¸Šç³»ç»Ÿä¸€èˆ¬æœ‰å‡ ä¸ªè¿™æ ·çš„åŒºå—。)æŸäº›ç³»ç»Ÿå¯ä»¥é€šè¿‡è¾“出 GPIO è§¦å‘ IRQ, 或者从并éžä»¥ GPIO 管ç†çš„引脚å–值。这些机制的相关代ç 没有必è¦å…·æœ‰å¯ç§»æ¤æ€§ã€‚ 当å‰ï¼ŒåŠ¨æ€å®šä¹‰ GPIO 并ä¸æ˜¯æ ‡å‡†çš„,例如作为é…置一个带有æŸäº› GPIO 扩展器的 é™„åŠ ç”µè·¯æ¿çš„副作用。 GPIO 实现者的框架(å¯é€‰ï¼‰ ========================= å‰é¢æ到了,有一个å¯é€‰çš„实现框架,让平å°ä½¿ç”¨ç›¸åŒçš„编程接å£ï¼Œæ›´åŠ 简å•åœ°æ”¯æŒ ä¸åŒç§ç±»çš„ GPIO 控制器。这个框架称为"gpiolib"。 作为一个辅助调试功能,如果 debugfs å¯ç”¨ï¼Œå°±ä¼šæœ‰ä¸€ä¸ª /sys/kernel/debug/gpio 文件。通过这个框架,它å¯ä»¥åˆ—出所有注册的控制器,以åŠå½“å‰æ£åœ¨ä½¿ç”¨ä¸çš„ GPIO 的状æ€ã€‚ 控制器驱动: gpio_chip --------------------- 在框架ä¸æ¯ä¸ª GPIO 控制器都包装为一个 "struct gpio_chip",他包å«äº† 该类型的æ¯ä¸ªæŽ§åˆ¶å™¨çš„常用信æ¯: - 设置 GPIO æ–¹å‘的方法 - 用于访问 GPIO 值的方法 - 告知调用其方法是å¦å¯èƒ½ä¼‘çœ çš„æ ‡å¿— - å¯é€‰çš„ debugfs ä¿¡æ¯å¯¼å‡ºæ–¹æ³• (显示类似上拉é…ç½®ä¸€æ ·çš„é¢å¤–状æ€) - 诊æ–æ ‡ç¾ ä¹ŸåŒ…å«äº†æ¥è‡ª device.platform_data çš„æ¯ä¸ªå®žä¾‹çš„æ•°æ®ï¼šå®ƒç¬¬ä¸€ä¸ª GPIO çš„ ç¼–å·å’Œå®ƒå¯ç”¨çš„ GPIO çš„æ•°é‡ã€‚ 实现 gpio_chip 的代ç 应支æŒå¤šæŽ§åˆ¶å™¨å®žä¾‹ï¼Œè¿™å¯èƒ½ä½¿ç”¨é©±åŠ¨æ¨¡åž‹ã€‚那些代ç è¦ é…ç½®æ¯ä¸ª gpio_chip,并å‘èµ·gpiochip_add()。å¸è½½ä¸€ä¸ª GPIO 控制器很少è§ï¼Œ 但在必è¦çš„时候å¯ä»¥ä½¿ç”¨ gpiochip_remove()。 大部分 gpio_chip 是一个实例特定结构体的一部分,而并ä¸å°† GPIO 接å£å•ç‹¬ 暴露出æ¥,比如编å€ã€ç”µæºç®¡ç†ç‰ã€‚类似编解ç å™¨è¿™æ ·çš„èŠ¯ç‰‡ä¼šæœ‰å¤æ‚çš„éž GPIO 状æ€ã€‚ 任何一个 debugfs ä¿¡æ¯å¯¼å‡ºæ–¹æ³•é€šå¸¸åº”该忽略还未申请作为 GPIO çš„ä¿¡å·çº¿ã€‚ 他们å¯ä»¥ä½¿ç”¨ gpiochip_is_requested()测试,当这个 GPIO å·²ç»ç”³è¯·è¿‡äº† å°±è¿”å›žç›¸å…³çš„æ ‡ç¾ï¼Œå¦åˆ™è¿”回 NULL。 å¹³å°æ”¯æŒ -------- 为了支æŒè¿™ä¸ªæ¡†æž¶ï¼Œä¸€ä¸ªå¹³å°çš„ Kconfig 文件将会 "select"(选择) ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,并让它的 <asm/gpio.h> åŒ…å« <asm-generic/gpio.h>,åŒæ—¶å®šä¹‰ä¸‰ä¸ªæ–¹æ³•: gpio_get_value()ã€gpio_set_value()å’Œ gpio_cansleep()。 它也应æ供一个 ARCH_NR_GPIOS çš„å®šä¹‰å€¼ï¼Œè¿™æ ·å¯ä»¥æ›´å¥½åœ°åæ˜ è¯¥å¹³å° GPIO 的实际数é‡,节çœé™æ€è¡¨çš„空间。(这个定义值应该包å«ç‰‡ä¸Šç³»ç»Ÿå†…建 GPIO å’Œ GPIO 扩展器ä¸çš„æ•°æ®ã€‚) ARCH_REQUIRE_GPIOLIB æ„å‘³ç€ gpiolib æ ¸å¿ƒåœ¨è¿™ä¸ªæž„æž¶ä¸å°†æ€»æ˜¯ç¼–è¯‘è¿›å†…æ ¸ã€‚ ARCH_WANT_OPTIONAL_GPIOLIB æ„å‘³ç€ gpiolib æ ¸å¿ƒé»˜è®¤å…³é—,且用户å¯ä»¥ 使能它,å¹¶å°†å…¶ç¼–è¯‘è¿›å†…æ ¸(å¯é€‰)。 如果这些选项都没被选择,该平å°å°±ä¸é€šè¿‡ GPIO-lib æ”¯æŒ GPIO,且代ç ä¸å¯ä»¥ 被用户使能。 以下这些方法的实现å¯ä»¥ç›´æŽ¥ä½¿ç”¨æ¡†æž¶ä»£ç ,并总是通过 gpio_chip 调度:: #define gpio_get_value __gpio_get_value #define gpio_set_value __gpio_set_value #define gpio_cansleep __gpio_cansleep 这些定义å¯ä»¥ç”¨æ›´ç†æƒ³çš„实现方法替代,那就是使用ç»è¿‡é€»è¾‘优化的内è”函数æ¥è®¿é—® 基于特定片上系统的 GPIO。例如,若引用的 GPIO (寄å˜å™¨ä½å移)是常é‡â€œ12â€ï¼Œ 读å–或设置它å¯èƒ½åªéœ€å°‘则两或三个指令,且ä¸ä¼šä¼‘çœ ã€‚å½“è¿™æ ·çš„ä¼˜åŒ–æ— æ³•å®žçŽ°æ—¶ï¼Œ 那些函数必须使用框架æ供的代ç ,那就至少è¦å‡ åæ¡æŒ‡ä»¤æ‰å¯ä»¥å®žçŽ°ã€‚对于用 GPIO 模拟的 I/O 接å£, 如æ¤ç²¾ç®€æŒ‡ä»¤æ˜¯å¾ˆæœ‰æ„义的。 对于片上系统,平å°ç‰¹å®šä»£ç 为片上 GPIO æ¯ä¸ªåŒº(bank)定义并注册 gpio_chip 实例。那些 GPIO åº”è¯¥æ ¹æ®èŠ¯ç‰‡åŽ‚商的文档进行编ç /æ ‡ç¾,并直接和电路æ¿åŽŸç†å›¾ 对应。他们应该开始于零并终æ¢äºŽå¹³å°ç‰¹å®šçš„é™åˆ¶ã€‚这些 GPIO(代ç )通常从 arch_initcall()或者更早的地方集æˆè¿›å¹³å°åˆå§‹åŒ–代ç ,使这些 GPIO 总是å¯ç”¨ï¼Œ 且他们通常å¯ä»¥ä½œä¸º IRQ 使用。 æ¿çº§æ”¯æŒ -------- 对于外部 GPIO 控制器(例如 I2C 或 SPI 扩展器ã€ä¸“用芯片ã€å¤šåŠŸèƒ½å™¨ä»¶ã€FPGA 或 CPLD),大多数常用æ¿çº§ç‰¹å®šä»£ç 都å¯ä»¥æ³¨å†ŒæŽ§åˆ¶å™¨è®¾å¤‡ï¼Œå¹¶ä¿è¯ä»–ä»¬çš„é©±åŠ¨çŸ¥é“ gpiochip_add()所使用的 GPIO ç¼–å·ã€‚他们的起始编å·é€šå¸¸è·Ÿåœ¨å¹³å°ç‰¹å®šçš„ GPIO ç¼–å·ä¹‹åŽã€‚ 例如æ¿çº§å¯åŠ¨ä»£ç 应该创建结构体指明芯片公开的 GPIO 范围,并使用 platform_data å°†å…¶ä¼ é€’ç»™æ¯ä¸ª GPIO 扩展器芯片。然åŽèŠ¯ç‰‡é©±åŠ¨ä¸çš„ probe()例程å¯ä»¥å°†è¿™ä¸ª æ•°æ®ä¼ 递给 gpiochip_add()。 åˆå§‹åŒ–顺åºå¾ˆé‡è¦ã€‚例如,如果一个设备ä¾èµ–基于 I2C çš„(扩展)GPIO,那么它的 probe()例程就应该在那个 GPIO 有效以åŽæ‰å¯ä»¥è¢«è°ƒç”¨ã€‚è¿™æ„味ç€è®¾å¤‡åº”该在 GPIO å¯ä»¥å·¥ä½œä¹‹åŽæ‰å¯è¢«æ³¨å†Œã€‚解决这类ä¾èµ–的的一ç§æ–¹æ³•æ˜¯è®©è¿™ç§ gpio_chip 控制器å‘æ¿çº§ç‰¹å®šä»£ç æä¾› setup()å’Œ teardown()回调函数。一旦所有必须的 资æºå¯ç”¨ä¹‹åŽï¼Œè¿™äº›æ¿çº§ç‰¹å®šçš„回调函数将会注册设备,并å¯ä»¥åœ¨è¿™äº› GPIO 控制器 设备å˜æˆæ— 效时移除它们。 用户空间的 Sysfs 接å£ï¼ˆå¯é€‰ï¼‰ ============================= 使用“gpiolibâ€å®žçŽ°æ¡†æž¶çš„å¹³å°å¯ä»¥é€‰æ‹©é…置一个 GPIO çš„ sysfs 用户接å£ã€‚ è¿™ä¸åŒäºŽ debugfs 接å£ï¼Œå› 为它æ供的是对 GPIOæ–¹å‘和值的控制,而ä¸åªæ˜¾ç¤º 一个GPIO 的状æ€æ‘˜è¦ã€‚æ¤å¤–,它å¯ä»¥å‡ºçŽ°åœ¨æ²¡æœ‰è°ƒè¯•æ”¯æŒçš„产å“级系统ä¸ã€‚ 例如,通过适当的系统硬件文档,用户空间å¯ä»¥çŸ¥é“ GIOP #23 控制 Flash å˜å‚¨å™¨çš„写ä¿æŠ¤(用于ä¿æŠ¤å…¶ä¸ Bootloader 分区)。产å“的系统å‡çº§å¯èƒ½éœ€è¦ 临时解除这个ä¿æŠ¤ï¼šé¦–先导入一个 GPIO,改å˜å…¶è¾“出状æ€ï¼Œç„¶åŽåœ¨é‡æ–°ä½¿èƒ½å†™ä¿æŠ¤ å‰å‡çº§ä»£ç 。通常情况下,GPIO #23 是ä¸ä¼šè¢«è§¦åŠçš„ï¼Œå¹¶ä¸”å†…æ ¸ä¹Ÿä¸éœ€è¦çŸ¥é“他。 æ ¹æ®é€‚当的硬件文档,æŸäº›ç³»ç»Ÿçš„用户空间 GPIO å¯ä»¥ç”¨äºŽç¡®å®šç³»ç»Ÿé…置数æ®ï¼Œ 这些数æ®æ˜¯æ ‡å‡†å†…æ ¸ä¸çŸ¥é“的。在æŸäº›ä»»åŠ¡ä¸ï¼Œç®€å•çš„用户空间 GPIO 驱动å¯èƒ½æ˜¯ 系统真æ£éœ€è¦çš„。 注æ„ï¼šæ ‡å‡†å†…æ ¸é©±åŠ¨ä¸å·²ç»å˜åœ¨é€šç”¨çš„“LED 和按键â€GPIO 任务,分别是: "leds-gpio" å’Œ "gpio_keys"。请使用这些æ¥æ›¿ä»£ç›´æŽ¥è®¿é—® GPIOï¼Œå› ä¸ºé›†æˆåœ¨ å†…æ ¸æ¡†æž¶ä¸çš„è¿™ç±»é©±åŠ¨æ¯”ä½ åœ¨ç”¨æˆ·ç©ºé—´çš„ä»£ç 更好。 Sysfs ä¸çš„路径 -------------- 在/sys/class/gpio ä¸æœ‰ 3 类入å£: - 用于在用户空间控制 GPIO 的控制接å£; - GPIOs 本身;ä»¥åŠ - GPIO 控制器 ("gpio_chip" 实例)。 é™¤äº†è¿™äº›æ ‡å‡†çš„æ–‡ä»¶,还包å«â€œdeviceâ€ç¬¦å·é“¾æŽ¥ã€‚ 控制接å£æ˜¯åªå†™çš„: /sys/class/gpio/ "export" ... 用户空间å¯ä»¥é€šè¿‡å†™å…¶ç¼–å·åˆ°è¿™ä¸ªæ–‡ä»¶ï¼Œè¦æ±‚å†…æ ¸å¯¼å‡º 一个 GPIO 的控制到用户空间。 例如: å¦‚æžœå†…æ ¸ä»£ç 没有申请 GPIO #19,"echo 19 > export" 将会为 GPIO #19 创建一个 "gpio19" 节点。 "unexport" ... 导出到用户空间的逆æ“作。 例如: "echo 19 > unexport" 将会移除使用"export"文件导出的 "gpio19" 节点。 GPIO ä¿¡å·çš„路径类似 /sys/class/gpio/gpio42/ (对于 GPIO #42 æ¥è¯´), 并有如下的读/写属性: /sys/class/gpio/gpioN/ "direction" ... 读å–得到 "in" 或 "out"。这个值通常è¿è¡Œå†™å…¥ã€‚ 写入"out" æ—¶,其引脚的默认输出为低电平。为了确ä¿æ— æ•…éšœè¿è¡Œï¼Œ "low" 或 "high" 的电平值应该写入 GPIO çš„é…置,作为åˆå§‹è¾“出值。 注æ„:å¦‚æžœå†…æ ¸ä¸æ”¯æŒæ”¹å˜ GPIO çš„æ–¹å‘ï¼Œæˆ–è€…åœ¨å¯¼å‡ºæ—¶å†…æ ¸ä»£ç 没有 明确å…许用户空间å¯ä»¥é‡æ–°é…ç½® GPIO æ–¹å‘,那么这个属性将ä¸å˜åœ¨ã€‚ "value" ... 读å–得到 0 (低电平) 或 1 (高电平)。如果 GPIO é…置为 输出,这个值å…许写æ“作。任何éžé›¶å€¼éƒ½ä»¥é«˜ç”µå¹³çœ‹å¾…。 如果引脚å¯ä»¥é…置为ä¸æ–ä¿¡å·ï¼Œä¸”如果已ç»é…置了产生ä¸æ–çš„æ¨¡å¼ ï¼ˆè§"edge"çš„æè¿°ï¼‰ï¼Œä½ å¯ä»¥å¯¹è¿™ä¸ªæ–‡ä»¶ä½¿ç”¨è½®è¯¢æ“作(poll(2)), 且轮询æ“作会在任何ä¸æ–触å‘æ—¶è¿”å›žã€‚å¦‚æžœä½ ä½¿ç”¨è½®è¯¢æ“作(poll(2)), 请在 events ä¸è®¾ç½® POLLPRI å’Œ POLLERRã€‚å¦‚æžœä½ ä½¿ç”¨è½®è¯¢æ“作 (select(2)),请在 exceptfds è®¾ç½®ä½ æœŸæœ›çš„æ–‡ä»¶æ述符。在 轮询æ“作(poll(2))返回之åŽï¼Œæ—¢å¯ä»¥é€šè¿‡ lseek(2)æ“ä½œè¯»å– sysfs 文件的开始部分,也å¯ä»¥å…³é—这个文件并é‡æ–°æ‰“开它æ¥è¯»å–æ•°æ®ã€‚ "edge" ... 读å–得到“noneâ€ã€â€œrisingâ€ã€â€œfallingâ€æˆ–者“bothâ€ã€‚ 将这些å—符串写入这个文件å¯ä»¥é€‰æ‹©æ²¿è§¦å‘模å¼ï¼Œä¼šä½¿å¾—轮询æ“作 (select(2))在"value"文件ä¸è¿”回。 这个文件仅有在这个引脚å¯ä»¥é…置为å¯äº§ç”Ÿä¸æ–输入引脚时,æ‰å˜åœ¨ã€‚ "active_low" ... 读å–得到 0 (å‡) 或 1 (真)。写入任何éžé›¶å€¼å¯ä»¥ 翻转这个属性的(读写)值。已å˜åœ¨æˆ–之åŽé€šè¿‡"edge"属性设置了"rising" å’Œ "falling" 沿触å‘模å¼çš„轮询æ“作(poll(2))将会éµå¾ªè¿™ä¸ªè®¾ç½®ã€‚ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO 开始实现控制的控制器),并有ç€ä»¥ä¸‹åªè¯»å±žæ€§: /sys/class/gpio/gpiochipN/ "base" ... 与以上的 N 相åŒ,代表æ¤èŠ¯ç‰‡ç®¡ç†çš„第一个 GPIO çš„ç¼–å· "label" ... ç”¨äºŽè¯Šæ– (并ä¸æ€»æ˜¯åªæœ‰å”¯ä¸€å€¼) "ngpio" ... æ¤æŽ§åˆ¶å™¨æ‰€ç®¡ç†çš„ GPIO æ•°é‡(而 GPIO ç¼–å·ä»Ž N 到 N + ngpio - 1) 大多数情况下,电路æ¿çš„æ–‡æ¡£åº”å½“æ ‡æ˜Žæ¯ä¸ª GPIO 的使用目的。但是那些编å·å¹¶ä¸æ€»æ˜¯ 固定的,例如在扩展å¡ä¸Šçš„ GPIOä¼šæ ¹æ®æ‰€ä½¿ç”¨çš„主æ¿æˆ–æ‰€åœ¨å †å 架构ä¸å…¶ä»–çš„æ¿å而 有所ä¸åŒã€‚在这ç§æƒ…况下,ä½ å¯èƒ½éœ€è¦ä½¿ç”¨ gpiochip 节点(å°½å¯èƒ½åœ°ç»“åˆç”µè·¯å›¾)æ¥ ç¡®å®šç»™å®šä¿¡å·æ‰€ç”¨çš„ GPIO ç¼–å·ã€‚ APIå‚考 ======= 本节ä¸åˆ—出的函数已被废弃。在新的代ç ä¸åº”该使用基于GPIOæ述符的API。