4. 设备树GPIO控制器节点标准绑定:gpio-controller、#gpio-cells、gpio-line-names等属性解析
在嵌入式Linux系统中,GPIO(通用输入输出)是最基础且使用最频繁的硬件资源之一。设备树通过一套标准化的绑定属性,将GPIO控制器的硬件信息、引脚数量、命名规则以及中断能力传递给内核。本章深入解析GPIO控制器节点中的三个核心属性:gpio-controller、#gpio-cells 和 gpio-line-names,并涵盖相关的 gpio-ranges、interrupt-controller 等辅助属性。
4.1 GPIO控制器节点核心属性
一个完整的GPIO控制器节点,必须包含以下两个核心属性来标识其身份和引脚寻址方式:
| 属性名 | 类型 | 必需性 | 描述 |
|---|---|---|---|
gpio-controller |
空属性(boolean) | 必需 | 标记该节点是一个GPIO控制器,无值 |
#gpio-cells |
u32 | 必需 | 指定GPIO specifier中cell的数量,通常为2 |
gpio-line-names |
string数组 | 可选 | 为每个GPIO引脚赋予功能名称,便于调试 |
gpio-ranges |
u32数组 | 推荐 | 建立GPIO编号与pinctrl子系统之间的映射关系 |
interrupt-controller |
空属性 | 可选 | 如果GPIO控制器同时提供中断功能,则需标记 |
#interrupt-cells |
u32 | 可选 | 与interrupt-controller配合,指定中断specifier的cell数 |
gpio-controller 属性是内核识别GPIO控制器的唯一标志。没有该属性,即使节点包含再多的寄存器信息,也不会被GPIO子系统识别。
4.2 gpio-controller 与 #gpio-cells 属性详解
4.2.1 gpio-controller:声明身份
gpio-controller 是一个无值属性(boolean property),其存在即表示该设备节点是一个GPIO控制器。内核在解析设备树时,会遍历所有节点,将包含此属性的节点注册到GPIO子系统框架中。
4.2.2 #gpio-cells:定义引脚寻址格式
#gpio-cells 指定了消费者节点在引用该控制器引脚时,需要提供多少个32位整数(cell)来描述一个GPIO引脚。最常见的值为2,其格式约定如下:
- 第一个cell(GPIO编号): 引脚在控制器内部的序号,从0开始。
- 第二个cell(GPIO标志位): 用于指定引脚的电平极性、默认状态等。常用宏定义:
GPIO_ACTIVE_HIGH = 0:高电平有效GPIO_ACTIVE_LOW = 1:低电平有效GPIO_OPEN_DRAIN = 2:开漏输出GPIO_OPEN_SOURCE = 4:开源输出
// 标准GPIO控制器节点示例(基于i.MX6ULL)
gpio1: gpio@209c000 {
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-ranges = <&iomuxc 0 23 10>;
};
// 消费者节点引用GPIO引脚
led-red {
compatible = "gpio-leds";
gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; // 引用gpio1的第5号引脚,低电平有效
};
#gpio-cells 设置为2,但消费者节点只提供了1个cell(例如只写了引脚号,未写标志位),内核在解析时会报错并拒绝注册该GPIO。
4.3 gpio-line-names:为引脚赋予可读名称
gpio-line-names 是一个字符串数组属性,用于为GPIO控制器的每个引脚提供一个人类可读的名称。该属性在调试、日志输出以及用户空间通过 /sys/kernel/debug/gpio 查看引脚状态时非常有用。
- 数组长度: 应与控制器支持的GPIO引脚数量一致。如果少于实际引脚数,未命名的引脚将显示为
unnamed。 - 命名规范: 通常使用硬件原理图中的网络标号或功能名称,如
"UART1_TXD"、"LED_RED"、"KEY_BOOT"。 - 调试价值: 当系统出现GPIO冲突时,通过名称可以快速定位到具体引脚,避免逐个数引脚编号。
// 带gpio-line-names的完整示例
gpio2: gpio@20a0000 {
compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
reg = <0x020a0000 0x4000>;
interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-ranges = <&iomuxc 0 33 10>;
gpio-line-names = "UART2_TXD", "UART2_RXD", "LCD_RESET",
"LCD_BACKLIGHT", "ETH_PHY_INT", "SD_CD",
"CAM_PWDN", "CAM_RST", "AUDIO_MCLK", "AUDIO_SCLK";
};
gpio-line-names。这不仅能提升调试效率,还能在编写用户空间应用程序时,通过名称而非硬编码编号来引用引脚,增强代码可移植性。
4.4 GPIO控制器节点标准绑定结构图
下图展示了GPIO控制器节点在设备树中的完整结构,以及它与消费者节点、pinctrl子系统之间的关系:
4.5 gpio-ranges:连接GPIO与pinctrl的桥梁
gpio-ranges 属性建立了GPIO子系统与pinctrl子系统之间的映射关系。它告诉内核:某个GPIO控制器的引脚,对应到pinctrl域中的哪些引脚。该属性是一个u32数组,每3个值构成一组映射:
gpio-ranges = <&pinctrl_phandle gpio_base pinctrl_base count>;
// 参数说明:
// pinctrl_phandle:指向pinctrl控制器的phandle
// gpio_base:GPIO控制器内部的起始引脚编号
// pinctrl_base:pinctrl域中的起始引脚编号
// count:映射的引脚数量
gpio-ranges = <&iomuxc 0 23 10>; 后,当驱动请求GPIO1_3时,内核会自动配置对应的IOMUXC引脚为GPIO功能。
4.6 消费者节点GPIO引用规范
消费者节点通过 *-gpios 或 gpios 属性引用GPIO引脚。属性值由三部分组成:
- phandle: 指向GPIO控制器节点的指针。
- GPIO编号: 控制器内部的引脚序号。
- 标志位: 电平极性、驱动类型等配置。
// 多种消费者引用示例
spi@100000 {
compatible = "spi-gpio";
cs-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>,
<&gpio2 5 GPIO_ACTIVE_LOW>; // 多片选
sck-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
mosi-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
miso-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
};
button@0 {
compatible = "gpio-keys";
gpios = <&gpio3 7 GPIO_ACTIVE_LOW>; // 按键,低电平触发
label = "USER_KEY";
linux,code = <KEY_ENTER>;
};
4.7 常见配置错误与排查方法
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 内核启动报 "gpiochip_find_base: cannot find free base" | GPIO编号冲突或 gpio-ranges 配置错误 |
检查 gpio-ranges 的基址和数量是否与其他控制器重叠 |
| 消费者驱动请求GPIO失败 | #gpio-cells 与消费者提供的cell数量不匹配 |
确认消费者节点中 gpios 属性包含正确的cell数量 |
| GPIO引脚无法输出预期电平 | pinctrl未正确配置或 gpio-ranges 映射缺失 |
检查pinctrl节点中该引脚的复用功能是否设置为GPIO模式 |
调试信息中引脚名称为 unnamed |
gpio-line-names 数组长度不足或未定义 |
补充或修正 gpio-line-names 数组,确保长度等于引脚数 |
cat /sys/kernel/debug/gpio 可以查看当前系统中所有GPIO控制器的引脚状态、名称和使用者。这是排查GPIO问题最直接的手段。
4.8 本章小结
GPIO控制器节点的标准绑定是设备树配置中最基础也最重要的部分。通过本章的学习,你应该掌握:
gpio-controller和#gpio-cells是声明GPIO控制器的必需属性。gpio-line-names为调试和维护提供了极大的便利。gpio-ranges是连接GPIO与pinctrl的关键桥梁,不可缺失。- 消费者节点通过
*-gpios属性按照#gpio-cells定义的格式引用引脚。 - 掌握常见错误的排查方法,能够快速定位并解决GPIO配置问题。