Chinese translated version of Documentation/admin-guide/gpio If you have any comment or update to the content, please contact the original document maintainer directly. However, if you have a problem communicating in English you can also ask the Chinese maintainer for help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. Maintainer: Grant Likely <grant.likely@secretlab.ca> Linus Walleij <linus.walleij@linaro.org> Chinese maintainer: Fu Wei <tekkamanninja@gmail.com> --------------------------------------------------------------------- Documentation/admin-guide/gpio çš„ä¸æ–‡ç¿»è¯‘ 如果想评论或更新本文的内容,请直接è”ç³»åŽŸæ–‡æ¡£çš„ç»´æŠ¤è€…ã€‚å¦‚æžœä½ ä½¿ç”¨è‹±æ–‡ äº¤æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘䏿–‡ç‰ˆç»´æŠ¤è€…求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻 译å˜åœ¨é—®é¢˜ï¼Œè¯·è”ç³»ä¸æ–‡ç‰ˆç»´æŠ¤è€…。 英文版维护者: Grant Likely <grant.likely@secretlab.ca> Linus Walleij <linus.walleij@linaro.org> 䏿–‡ç‰ˆç»´æŠ¤è€…: 傅炜 Fu Wei <tekkamanninja@gmail.com> 䏿–‡ç‰ˆç¿»è¯‘者: 傅炜 Fu Wei <tekkamanninja@gmail.com> 䏿–‡ç‰ˆæ ¡è¯‘者: 傅炜 Fu Wei <tekkamanninja@gmail.com> ä»¥ä¸‹ä¸ºæ£æ–‡ --------------------------------------------------------------------- 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_set_debounce() 声明和释放 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 使用 pinctrl å系统已知的引脚,å系统应该被告知其使用情况; 一个 gpiolib 驱动的 .request()æ“作应调用 pinctrl_gpio_request(), 而 gpiolib 驱动的 .free()æ“作应调用 pinctrl_gpio_free()。pinctrl å系统å…许 pinctrl_gpio_request()在æŸä¸ªå¼•脚或引脚组以å¤ç”¨å½¢å¼â€œå±žäºŽâ€ 一个设备时都æˆåŠŸè¿”å›žã€‚ 任何须将 GPIO ä¿¡å·å¯¼å‘适当引脚的引脚å¤ç”¨ç¡¬ä»¶çš„编程应该å‘生在 GPIO 驱动的 .direction_input()或 .direction_output()函数ä¸ï¼Œä»¥åŠ ä»»ä½•è¾“å‡º GPIO 值的设置之åŽã€‚è¿™æ ·å¯ä½¿ä»Žå¼•脚特殊功能到 GPIO çš„è½¬æ¢ ä¸ä¼šåœ¨å¼•脚产生毛刺波形。有时当用一个 GPIO 实现其信å·é©±åŠ¨ä¸€ä¸ªéž GPIO 硬件模å—的解决方案时,就需è¦è¿™ç§æœºåˆ¶ã€‚ æŸäº›å¹³å°å…许部分或所有 GPIO ä¿¡å·ä½¿ç”¨ä¸åŒçš„引脚。类似的,GPIO 或引脚的 å…¶ä»–æ–¹é¢ä¹Ÿéœ€è¦é…置,如上拉/下拉。平å°è½¯ä»¶åº”该在对这些 GPIO 调用 gpio_request()å‰å°†è¿™ç±»ç»†èŠ‚é…置好,例如使用 pinctrl åç³»ç»Ÿçš„æ˜ å°„è¡¨ï¼Œ 使得 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); /* æ˜ å°„ IRQ ç¼–å·åˆ° GPIO ç¼–å· (å°½é‡é¿å…使用) */ int irq_to_gpio(unsigned irq); 它们的返回值为对应命å空间的相关编å·ï¼Œæˆ–是负的错误代ç (å¦‚æžœæ— æ³•æ˜ å°„)。 (例如,æŸäº› GPIO æ— æ³•åšä¸º IRQ 使用。)以下的编å·é”™è¯¯æ˜¯æœªç»æ£€æµ‹çš„:使用一个 未通过 gpio_direction_input()é…置为输入的 GPIO ç¼–å·ï¼Œæˆ–者使用一个 å¹¶éžæ¥æºäºŽgpio_to_irq()çš„ IRQ ç¼–å·ã€‚ è¿™ä¸¤ä¸ªæ˜ å°„å‡½æ•°å¯èƒ½ä¼šåœ¨ä¿¡å·ç¼–å·çš„åŠ å‡è®¡ç®—过程上花些时间。它们ä¸å¯ä¼‘çœ ã€‚ gpio_to_irq()返回的éžé”™è¯¯å€¼å¯ä»¥ä¼ 递给 request_irq()或者 free_irq()。 它们通常通过æ¿çº§ç‰¹å®šçš„åˆå§‹åŒ–代ç å˜æ”¾åˆ°å¹³å°è®¾å¤‡çš„ IRQ 资æºä¸ã€‚注æ„:IRQ 触å‘选项是 IRQ 接å£çš„一部分,如 IRQF_TRIGGER_FALLING,系统唤醒能力 也是如æ¤ã€‚ irq_to_gpio()返回的éžé”™è¯¯å€¼å¤§å¤šæ•°é€šå¸¸å¯ä»¥è¢« gpio_get_value()所使用, 比如在 IRQ æ˜¯æ²¿è§¦å‘æ—¶åˆå§‹åŒ–或更新驱动状æ€ã€‚æ³¨æ„æŸäº›å¹³å°ä¸æ”¯æŒåæ˜ å°„,所以 ä½ åº”è¯¥å°½é‡é¿å…使用它。 模拟开æ¼ä¿¡å· ---------------------------- æœ‰æ—¶åœ¨åªæœ‰ä½Žç”µå¹³ä¿¡å·ä½œä¸ºå®žé™…驱动结果(译者注:多个输出连接于一点,逻辑电平 结果为所有输出的逻辑与)的时候,共享的信å·çº¿éœ€è¦ä½¿ç”¨â€œå¼€æ¼â€ä¿¡å·ã€‚(è¯¥æœ¯è¯ é€‚ç”¨äºŽ CMOS 管;而 TTL 用“集电æžå¼€è·¯â€ã€‚)一个上拉电阻使信å·ä¸ºé«˜ç”µå¹³ã€‚è¿™ 有时被称为“线与â€ã€‚实际上,从负逻辑(低电平为真)的角度æ¥çœ‹ï¼Œè¿™æ˜¯ä¸€ä¸ªâ€œçº¿æˆ–â€ã€‚ 一个开æ¼ä¿¡å·çš„常è§ä¾‹å是共享的低电平使能 IRQ ä¿¡å·çº¿ã€‚æ¤å¤–,有时åŒå‘æ•°æ®æ€»çº¿ ä¿¡å·ä¹Ÿä½¿ç”¨æ¼æžå¼€è·¯ä¿¡å·ã€‚ æŸäº› GPIO 控制器直接支æŒå¼€æ¼è¾“å‡ºï¼Œè¿˜æœ‰è®¸å¤šä¸æ”¯æŒã€‚å½“ä½ éœ€è¦å¼€æ¼ä¿¡å·ï¼Œä½† 硬件åˆä¸ç›´æŽ¥æ”¯æŒçš„æ—¶å€™ï¼Œä¸€ä¸ªå¸¸ç”¨çš„æ–¹æ³•是用任何å³å¯ä½œè¾“入也å¯ä½œè¾“出的 GPIO å¼•è„šæ¥æ¨¡æ‹Ÿ: LOW: gpio_direction_output(gpio, 0) ... 这代ç 驱动信å·å¹¶è¦†ç›– 上拉é…置。 HIGH: gpio_direction_input(gpio) ... 这代ç å…³é—输出,所以上拉电阻 (或其他的一些器件)控制了信å·ã€‚ å¦‚æžœä½ å°†ä¿¡å·çº¿â€œé©±åЍâ€ä¸ºé«˜ç”µå¹³ï¼Œä½†æ˜¯ gpio_get_value(gpio)报告了一个 低电平(åœ¨é€‚å½“çš„ä¸Šå‡æ—¶é—´åŽ)ï¼Œä½ å°±å¯ä»¥çŸ¥é“是其他的一些组件将共享信å·çº¿æ‹‰ä½Žäº†ã€‚ è¿™ä¸ä¸€å®šæ˜¯é”™è¯¯çš„。一个常è§çš„例å就是 I2C 时钟的延长:一个需è¦è¾ƒæ…¢æ—¶é’Ÿçš„ 从设备延迟 SCK çš„ä¸Šå‡æ²¿ï¼Œè€Œ I2C 主设备相应地调整其信å·ä¼ 输速率。 这些公约忽略了什么? ================ 这些公约忽略的最大一件事就是引脚å¤ç”¨ï¼Œå› 为这属于高度芯片特定的属性且 没有å¯ç§»æ¤æ€§ã€‚æŸä¸ªå¹³å°å¯èƒ½ä¸éœ€è¦æ˜Žç¡®çš„å¤ç”¨ä¿¡æ¯ï¼›æœ‰çš„对于任æ„给定的引脚 å¯èƒ½åªæœ‰ä¸¤ä¸ªåŠŸèƒ½é€‰é¡¹ï¼›æœ‰çš„å¯èƒ½æ¯ä¸ªå¼•脚有八个功能选项;有的å¯èƒ½å¯ä»¥å°† å‡ ä¸ªå¼•è„šä¸çš„任何一个作为给定的 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 ç¼–å·ã€‚ ä»Žå†…æ ¸ä»£ç ä¸å¯¼å‡º ------------- å†…æ ¸ä»£ç å¯ä»¥æ˜Žç¡®åœ°ç®¡ç†é‚£äº›å·²é€šè¿‡ gpio_request()申请的 GPIO 的导出: /* 导出 GPIO 到用户空间 */ int gpio_export(unsigned gpio, bool direction_may_change); /* gpio_export()的逆æ“作 */ void gpio_unexport(); /* 创建一个 sysfs 连接到已导出的 GPIO 节点 */ int gpio_export_link(struct device *dev, const char *name, unsigned gpio) åœ¨ä¸€ä¸ªå†…æ ¸é©±åŠ¨ç”³è¯·ä¸€ä¸ª GPIO 之åŽï¼Œå®ƒå¯ä»¥é€šè¿‡ gpio_export()使其在 sysfs 接å£ä¸å¯è§ã€‚该驱动å¯ä»¥æŽ§åˆ¶ä¿¡å·æ–¹å‘是å¦å¯ä¿®æ”¹ã€‚这有助于防æ¢ç”¨æˆ·ç©ºé—´ä»£ç æ— æ„é—´ ç ´åé‡è¦çš„系统状æ€ã€‚ 这个明确的导出有助于(通过使æŸäº›å®žéªŒæ›´å®¹æ˜“æ¥)调试,也å¯ä»¥æä¾›ä¸€ä¸ªå§‹ç»ˆå˜åœ¨çš„æŽ¥å£ï¼Œ 与文档é…åˆä½œä¸ºæ¿çº§æ”¯æŒåŒ…的一部分。 在 GPIO 被导出之åŽï¼Œgpio_export_link()å…许在 sysfs 文件系统的任何地方 创建一个到这个 GPIO sysfs 节点的符å·é“¾æŽ¥ã€‚è¿™æ ·é©±åŠ¨å°±å¯ä»¥é€šè¿‡ä¸€ä¸ªæè¿°æ€§çš„ åå—,在 sysfs ä¸ä»–们所拥有的设备下æä¾›ä¸€ä¸ª(到这个 GPIO sysfs 节点的)接å£ã€‚