3. GPIO 子系统:Linux GPIO 子系统架构、gpio-controller、gpio-cells、gpio-hog

在嵌入式 Linux 系统中,GPIO(General Purpose Input/Output)是最基础且使用最频繁的硬件资源之一。对于骁龙平台的 Sensor 上电时序控制,GPIO 的配置正确与否直接决定了 Sensor 能否在正确的时刻获得电源和复位信号。本章将深入剖析 Linux GPIO 子系统的软件架构,并重点讲解设备树中与 GPIO 相关的三个核心绑定:gpio-controller、#gpio-cells 和 gpio-hog。

3.1 Linux GPIO 子系统软件架构

Linux GPIO 子系统采用分层设计,从上到下依次为:GPIO 消费者(Consumer)、GPIO 核心层(Core) 和 GPIO 控制器驱动(Controller Driver)。这种分层架构使得驱动开发者无需关心底层硬件寄存器细节,只需通过标准 API 即可操作 GPIO。

架构核心思想: 消费者通过 gpiod_get() 等 API 获取 GPIO 描述符,核心层负责管理 GPIO 编号映射和引脚复用,控制器驱动则直接操作硬件寄存器。
Linux GPIO 子系统分层架构 GPIO 消费者(Consumer) Sensor 驱动 / LED 驱动 / 按键驱动 GPIO 核心层(Core) gpiolib:编号管理 / 描述符 / 中断 / 复用 GPIO 控制器驱动(Controller Driver) pinctrl / 寄存器读写 / 中断芯片 硬件寄存器(SoC GPIO Bank)

3.2 设备树中的 GPIO 绑定

设备树是描述硬件拓扑的静态数据结构。GPIO 相关的绑定主要涉及三个属性:gpio-controller、#gpio-cells 和 gpio-hog。理解这三个属性是正确配置 Sensor 上电时序的前提。

3.2.1 gpio-controller

gpio-controller 是一个布尔属性,用于标记该设备节点是一个 GPIO 控制器。当一个节点包含此属性时,Linux 内核会将其注册为 GPIO 芯片,并纳入 gpiolib 框架管理。

关键点: 只有标记了 gpio-controller 的节点才能被其他设备节点通过 <&gpioX ...> 方式引用。骁龙 SoC 通常有多个 GPIO 控制器,如 tlmm(Top Level Mode Multiplexer)和 pmic-gpio。

3.2.2 #gpio-cells

#gpio-cells 指定了 GPIO 描述符中需要的单元格数量。它决定了消费者在引用 GPIO 时必须提供的参数个数。最常见的值是 2,表示需要两个参数:GPIO 编号 和 GPIO 标志。

#gpio-cells 值 参数格式 典型场景
1 <GPIO_NUM> 仅指定引脚编号,无额外标志
2 <GPIO_NUM FLAGS> 指定编号 + 极性/驱动类型(最常用)
3 <GPIO_NUM FLAGS EXTRA> 某些特殊控制器需要额外参数
常见错误: 如果消费者节点引用的 GPIO 参数个数与 #gpio-cells 不匹配,内核会报错并导致 GPIO 申请失败。例如,#gpio-cells = <2> 的控制器,消费者必须写成 <&gpio1 5 0>,不能省略标志位。

3.2.3 gpio-hog

gpio-hog 是一种特殊的 GPIO 配置机制,允许在设备树中直接指定某个 GPIO 的初始状态(输出高/低、输入等),而无需编写额外的驱动代码。这对于 Sensor 上电时序中的电源使能引脚非常有用——可以在系统启动早期就完成 GPIO 初始化。

gpio-hog 子节点通常包含以下属性:

  • gpio-hog:布尔属性,标记该节点为 hog 节点。
  • gpios:指定要控制的 GPIO 引脚和标志。
  • output-high / output-low:设置输出电平。
  • input:设置为输入模式。
  • line-name:为这条 GPIO 线命名,便于调试。
gpio-hog 在 Sensor 上电时序中的应用 设备树节点(tlmm) gpio-controller; #gpio-cells = <2>; sensor_en { gpio-hog; gpios = <5 0>; output-high; line-name = "sensor-pwr"; }; 内核 gpiolib 解析 of_gpio_hog() 遍历子节点 申请 GPIO 5,设置为输出高 注册 line-name "sensor-pwr" 在 pinctrl 初始化后立即生效 硬件效果:Sensor 电源引脚提前拉高 确保 Sensor 在驱动 probe 前完成上电

3.3 完整设备树示例:Sensor 上电 GPIO 配置

以下是一个针对骁龙平台的典型 Sensor 上电 GPIO 配置片段。该配置使用 gpio-hog 在系统启动早期将 Sensor 的电源使能引脚拉高,确保后续 Sensor 驱动 probe 时电源已经稳定。

/* 骁龙平台 TLMM GPIO 控制器节点 */
tlmm: pinctrl@f100000 {
    compatible = "qcom,msm8998-pinctrl";
    reg = <0x0f100000 0x300000>;
    interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;
    #interrupt-cells = <2>;

    /* Sensor 电源使能:使用 gpio-hog 提前初始化 */
    sensor_pwr_hog {
        gpio-hog;
        gpios = <92 0>;          /* GPIO 92,标志 0 表示高电平有效 */
        output-high;              /* 输出高电平,使能 Sensor 电源 */
        line-name = "sensor-pwr-enable";
    };

    /* Sensor 复位引脚:使用 gpio-hog 保持非复位状态 */
    sensor_rst_hog {
        gpio-hog;
        gpios = <93 0>;
        output-high;              /* 拉高复位引脚,Sensor 正常工作 */
        line-name = "sensor-reset";
    };
};

/* Sensor 设备节点:引用 GPIO 进行后续控制 */
i2c@c175000 {
    status = "okay";
    sensor@48 {
        compatible = "vendor,sensor-xyz";
        reg = <0x48>;
        /* 这里引用 GPIO 93 作为复位控制,驱动中可动态操作 */
        reset-gpios = <&tlmm 93 GPIO_ACTIVE_LOW>;
        vdd-supply = <&pm8994_lvs1>;
    };
};
配置要点:
  • gpio-hog 节点必须放在 GPIO 控制器节点内部,作为其子节点。
  • gpios 中的标志位 0 表示高电平有效,GPIO_ACTIVE_LOW 在消费者节点中使用。
  • line-name 在 /sys/kernel/debug/gpio 中可见,便于调试。
  • hog 节点的初始化发生在 pinctrl 设置之后、其他驱动 probe 之前,非常适合时序敏感场景。

3.4 调试与验证

配置完成后,可以通过以下方法验证 GPIO 状态是否符合预期:

调试方法 命令/路径 预期输出
查看 GPIO 概览 cat /sys/kernel/debug/gpio 显示所有 GPIO 芯片、引脚、标签和当前值
检查特定引脚 cat /sys/class/gpio/gpio92/value 应为 1(输出高)
查看设备树解析 dtc -I fs -O dts /proc/device-tree 确认 hog 节点已展开且属性正确
内核日志 dmesg | grep gpio 显示 "hogging GPIO 92 as sensor-pwr-enable"
时序陷阱: 如果 Sensor 驱动 probe 时发现 GPIO 尚未初始化(例如 hog 节点写错导致解析失败),Sensor 可能因电源未就绪而通信失败。此时应优先检查 dmesg 中是否有 "gpio-hog" 相关的错误信息,并确认 #gpio-cells 与消费者参数个数一致。

通过本章的学习,你应该能够理解 Linux GPIO 子系统的分层设计,掌握设备树中 gpio-controller、#gpio-cells 和 gpio-hog 的配置方法,并能够利用这些知识解决骁龙平台上 Sensor 上电时序的 GPIO 初始化问题。