1. GPIO子系统概述:Linux GPIO子系统架构、GPIO硬件基础、GPIO控制器与引脚编号
1.1 GPIO硬件基础
GPIO(General Purpose Input/Output,通用输入输出)是嵌入式系统中最基础、最常用的外设接口。每个GPIO引脚可以独立配置为输入或输出模式,在输入模式下读取外部电平(高/低),在输出模式下驱动外部设备(LED、继电器等)。
核心硬件特性:
- 方向控制:通过寄存器配置引脚为输入或输出
- 电平检测:数字信号高电平(通常为3.3V/1.8V)或低电平(0V)
- 内部上拉/下拉:防止引脚浮空,提供确定的默认电平
- 中断触发:支持上升沿、下降沿、高电平、低电平触发
- 驱动能力:通常为4mA~20mA,不同SoC有所差异
下图展示了一个典型的GPIO引脚内部结构,包含输入缓冲器、输出驱动器和可配置的上拉/下拉电阻:
1.2 Linux GPIO子系统软件架构
Linux GPIO子系统采用分层设计,从硬件到用户空间共分为四层,每一层都封装了特定的职责:
架构设计要点:GPIO核心层(gpiolib)是Linux GPIO子系统的中枢,它向上提供统一的系统调用接口(字符设备、sysfs),向下定义gpio_chip结构体回调函数,驱动开发者只需实现硬件相关的寄存器操作即可。
1.3 GPIO控制器与引脚编号
在Linux系统中,每个GPIO引脚都有一个全局唯一的编号,称为GPIO编号。这个编号由系统启动时动态分配,或者通过设备树静态指定。GPIO控制器(gpio_chip)负责管理一组连续的GPIO引脚。
1.3.1 引脚编号分配机制
| 编号范围 | 所属控制器 | 典型SoC示例 | 说明 |
|---|---|---|---|
| 0 ~ 31 | GPIO0 (P0组) | i.MX6ULL | 第一个GPIO控制器的32个引脚 |
| 32 ~ 63 | GPIO1 (P1组) | i.MX6ULL | 第二个GPIO控制器的32个引脚 |
| 64 ~ 95 | GPIO2 (P2组) | i.MX6ULL | 第三个GPIO控制器的32个引脚 |
| 96 ~ 127 | GPIO3 (P3组) | i.MX6ULL | 第四个GPIO控制器的32个引脚 |
| 128 ~ 159 | GPIO4 (P4组) | i.MX6ULL | 第五个GPIO控制器的32个引脚 |
注意事项:不同SoC的GPIO控制器数量和引脚编号范围差异很大。例如,STM32MP157有12个GPIO控制器(PA~PK),每个控制器16个引脚;而i.MX6ULL只有5个GPIO控制器,每个32个引脚。编写驱动时务必查阅芯片手册。
1.3.2 gpio_chip结构体核心字段
每个GPIO控制器在内核中对应一个struct gpio_chip实例,驱动开发者需要填充以下关键字段:
struct gpio_chip {
const char *label; // 控制器名称,如 "GPIO1"
struct device *parent; // 父设备
struct module *owner; // THIS_MODULE
int base; // 引脚编号起始值
u16 ngpio; // 本控制器管理的引脚数量
// 方向控制回调
int (*direction_input)(struct gpio_chip *gc, unsigned int offset);
int (*direction_output)(struct gpio_chip *gc, unsigned int offset, int value);
// 读写回调
int (*get)(struct gpio_chip *gc, unsigned int offset);
void (*set)(struct gpio_chip *gc, unsigned int offset, int value);
// 中断相关回调
int (*to_irq)(struct gpio_chip *gc, unsigned int offset);
// 资源管理回调
int (*request)(struct gpio_chip *gc, unsigned int offset);
void (*free)(struct gpio_chip *gc, unsigned int offset);
};
1.3.3 设备树中的GPIO控制器描述
在设备树中,GPIO控制器通过gpio-controller属性标识,#gpio-cells指定引脚描述所需的参数个数:
// i.MX6ULL 设备树中的GPIO控制器节点示例
gpio1: gpio@0209c000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>; // 两个参数:引脚偏移 + 标志
interrupt-controller;
#interrupt-cells = <2>; // 两个参数:中断类型 + 标志
};
// 引用GPIO引脚示例(LED控制)
led-red {
compatible = "gpio-leds";
gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; // GPIO1_IO15
};
1.4 GPIO子系统核心数据结构关系
下图展示了GPIO子系统中核心数据结构之间的关联关系:
1.5 本章小结
- GPIO硬件基础:每个引脚包含输入缓冲器、输出驱动器、可配置上拉/下拉电阻和中断检测逻辑。
- 软件架构:Linux GPIO子系统分为用户空间接口、gpiolib核心层、gpio_chip驱动层和硬件寄存器层。
- 引脚编号:全局唯一编号由base+offset组成,不同SoC的控制器数量和引脚范围差异较大。
- 核心数据结构:gpio_chip描述控制器硬件能力,gpio_desc描述单个引脚状态,irq_desc管理中断映射。
工程实践提示:在开始编写GPIO驱动前,务必通过芯片手册确认以下信息:GPIO控制器数量、每个控制器的引脚范围、中断控制器连接方式、以及设备树中gpio-cells的格式。这些信息将直接影响驱动实现的正确性。