GPIO 控制器节点基础
GPIO(General Purpose Input/Output)控制器是嵌入式系统中最基础、最常用的外设之一。在设备树中,GPIO 控制器节点必须按照标准规范进行描述,以便内核能够正确识别、初始化并管理这些引脚资源。本节将详细解析 GPIO 控制器节点的标准定义、核心属性及其语义。
2.1 标准节点结构
一个完整的 GPIO 控制器节点通常包含以下核心属性:
| 属性名 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
compatible |
字符串列表 | 必需 | 指定驱动兼容性,格式为 "厂商,型号" |
reg |
地址/长度对 | 必需 | 描述控制器寄存器基地址和地址范围 |
gpio-controller |
空属性 | 必需 | 标记该节点为 GPIO 控制器 |
#gpio-cells |
整数 | 必需 | 指定 GPIO 描述符所需的单元数 |
interrupt-parent |
phandle | 可选 | 指定中断控制器父节点 |
interrupts |
中断描述符 | 可选 | 描述 GPIO 控制器的中断线 |
ngpios |
整数 | 可选 | 指定该控制器管理的 GPIO 引脚总数 |
关键概念:
gpio-controller 是一个布尔属性,只要存在即表示该节点是 GPIO 控制器;#gpio-cells 则定义了引用该控制器时每个 GPIO 描述符需要几个 32 位整数单元。
2.2 典型节点定义示例
以下是一个基于 ARM 平台(如 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>;
ngpios = <32>;
};
该示例中:
- compatible:使用 fallback 机制,优先匹配 "fsl,imx6ul-gpio",若不匹配则回退到 "fsl,imx35-gpio"。
- reg:寄存器基地址为 0x0209c000,地址范围为 0x4000(16KB)。
- interrupts:该控制器支持两路中断(通常对应低 16 位和高 16 位引脚)。
- #gpio-cells = <2>:每个 GPIO 描述符由两个单元组成——第一个单元为引脚号,第二个单元为标志位。
- ngpios:明确声明该控制器管理 32 个 GPIO 引脚。
2.3 #gpio-cells 的语义解析
#gpio-cells 的值决定了其他设备节点如何引用该 GPIO 控制器的引脚。最常见的值为 2,其单元含义如下:
| 单元索引 | 名称 | 描述 | 示例值 |
|---|---|---|---|
| 0 | 引脚号 | 从 0 开始的 GPIO 引脚索引 | 15 |
| 1 | 标志位 | GPIO 配置标志(低电平有效、上拉等) | 0x0000(默认) |
标志位(flags)的常用定义(Linux 内核 gpio.h):
0x0000:默认,高电平有效,无特殊配置。GPIO_ACTIVE_LOW (0x0001):低电平有效。GPIO_OPEN_DRAIN (0x0010):开漏输出。GPIO_OPEN_SOURCE (0x0020):开源输出。GPIO_PULL_UP (0x0040):内部上拉使能。GPIO_PULL_DOWN (0x0080):内部下拉使能。
实践建议: 当
#gpio-cells = <1> 时,引用方只需提供引脚号,标志位默认为 0。这种简化适用于不需要特殊配置的简单 GPIO 使用场景。
2.4 GPIO 控制器节点结构图
下图展示了 GPIO 控制器节点在设备树中的位置及其与周边节点的关系:
2.5 属性详解与常见陷阱
2.5.1 compatible 属性
该属性是驱动匹配的关键。推荐使用"厂商,型号"格式,并保留 fallback 兼容字符串:
compatible = "vendor,soc-gpio", "vendor,family-gpio";
内核驱动匹配时,会按照字符串顺序依次尝试,直到找到匹配的驱动。
2.5.2 reg 属性
描述 GPIO 控制器的寄存器地址空间。对于 32 位 ARM 平台,格式为 <基地址 地址长度>:
reg = <0x0209c000 0x4000>; // 基地址 0x0209c000,长度 16KB
常见错误: 地址长度设置过小会导致内核无法完整访问寄存器空间,引发驱动初始化失败。务必参考芯片手册确认 GPIO 模块的寄存器地址范围。
2.5.3 gpio-controller 与 #gpio-cells
这两个属性必须成对出现。缺少 gpio-controller 会导致其他节点无法引用该控制器的 GPIO;#gpio-cells 值错误会导致 GPIO 描述符解析异常。
2.6 多控制器实例对比
| 控制器 | compatible | #gpio-cells | ngpios | 中断支持 |
|---|---|---|---|---|
| GPIO1 | fsl,imx6ul-gpio | 2 | 32 | 是(2 路) |
| GPIO2 | fsl,imx6ul-gpio | 2 | 32 | 是(2 路) |
| GPIO5 | fsl,imx6ul-gpio | 2 | 8 | 是(1 路) |
从表中可以看出,同一 SoC 的不同 GPIO 控制器可能具有不同的引脚数量和中断能力,这些差异都需要在设备树中准确描述。
2.7 引用 GPIO 控制器的标准方式
其他设备节点通过 gpios 或 xxx-gpios 属性引用 GPIO 引脚:
leds {
compatible = "gpio-leds";
led-red {
label = "red-led";
gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
linux,default-trigger = "heartbeat";
};
};
button {
compatible = "gpio-keys";
power-key {
label = "power";
gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
linux,code = <KEY_POWER>;
};
};
引用格式解析:&gpio1 指向 GPIO 控制器节点,15 为引脚号,GPIO_ACTIVE_LOW 为标志位。这三个值正好对应 #gpio-cells = <2> 的规格。
2.8 本章小结
- GPIO 控制器节点必须包含
compatible、reg、gpio-controller和#gpio-cells四个核心属性。 #gpio-cells决定了 GPIO 描述符的格式,最常见的值为 2(引脚号 + 标志位)。- 标志位用于配置 GPIO 的电气特性,如电平有效极性、上下拉、开漏等。
- 其他设备通过
gpios属性引用 GPIO 引脚,格式必须与目标控制器的#gpio-cells一致。 - 准确的节点定义是 GPIO 子系统正常工作的基础,任何属性缺失或错误都可能导致驱动加载失败或引脚操作异常。