2. pinctrl子系统概述

pinctrl(Pin Control)子系统是 Linux 内核中负责管理 SoC 引脚复用、电气特性与引脚分组的核心框架。它位于硬件与驱动层之间,为设备驱动提供统一的引脚配置接口,避免各驱动直接操作寄存器导致的冲突。

2.1 pinctrl 的核心角色

pinctrl 子系统主要承担以下三项职责:

  • 引脚复用(Pin Muxing):将 SoC 的物理引脚配置为 GPIO、I2C、SPI、UART 等特定功能。
  • 引脚电气属性(Pin Configuration):设置驱动强度、上拉/下拉、施密特触发、 slew rate 等参数。
  • 引脚分组(Pin Groups):将多个引脚组合为一个逻辑组,便于批量配置与状态切换。
关键概念:pinctrl 不直接管理 GPIO 的输入/输出值或中断,它只负责“引脚属于哪个功能”以及“引脚的电学参数”。GPIO 的读写与中断逻辑由 GPIO 子系统处理。
设计意图:pinctrl 将引脚配置从设备驱动中解耦,使得同一驱动可以在不同 SoC 上通过设备树描述复用关系,无需修改驱动代码。

2.2 pinctrl 与 GPIO 子系统的关系

pinctrl 与 GPIO 子系统在逻辑上相互独立,但在硬件层面紧密耦合。一个物理引脚通常既可以作为 GPIO,也可以作为其他外设功能引脚。两者的协作通过设备树中的 pinctrl-* 属性和 gpio-controller 节点实现。

维度 pinctrl 子系统 GPIO 子系统
职责 引脚复用、电气配置、分组管理 GPIO 输入/输出值、中断处理
核心数据结构 pinctrl_dev、pinctrl_map、pinctrl_state gpio_chip、irq_chip
设备树属性 pinctrl-0、pinctrl-names gpios、interrupts
用户空间接口 通常不直接暴露,通过驱动间接使用 /sys/class/gpio、libgpiod
依赖关系 GPIO 驱动需先通过 pinctrl 将引脚配置为 GPIO 功能 依赖 pinctrl 完成引脚复用配置
常见误区:不要认为 pinctrl 是 GPIO 子系统的子模块。两者是平级关系,pinctrl 负责“引脚是什么”,GPIO 子系统负责“引脚怎么用”。配置顺序上,pinctrl 必须先于 GPIO 操作。

2.3 软件架构分层

下图展示了 pinctrl 子系统在内核中的位置及其与 GPIO 子系统的交互关系:

pinctrl 与 GPIO 子系统软件架构 用户空间 (User Space) 内核空间 (Kernel Space) 设备驱动 (I2C/SPI/UART) GPIO 驱动 / 中断控制器 pinctrl 核心 (pinctrl-core) pinctrl_register / pinctrl_select_state / pinctrl_gpio_request pinctrl 硬件驱动 (pinctrl-hw) SoC 硬件寄存器 (Pin Mux / Pad Control / GPIO Regs) 核心 枢纽 层

2.4 设备树中的协作示例

以下是一个典型设备树片段,展示 pinctrl 与 GPIO 子系统如何协同工作:

/* pinctrl 节点:定义引脚复用与电气配置 */
&pinctrl {
    uart0_pins: uart0-pins {
        pinmux = <0x10 0x11>;   /* 引脚复用为 UART0 TX/RX */
        bias-pull-up;
        drive-strength = <4>;
    };

    gpio_led_pins: gpio-led-pins {
        pinmux = <0x30>;        /* 引脚复用为 GPIO */
        bias-disable;
        drive-strength = <2>;
    };
};

/* 设备节点:引用 pinctrl 配置并使用 GPIO */
&uart0 {
    pinctrl-0 = <&uart0_pins>;   /* 激活 UART 引脚复用 */
    pinctrl-names = "default";
    status = "okay";
};

/ {
    led {
        compatible = "gpio-leds";
        pinctrl-0 = <&gpio_led_pins>;  /* 先配置为 GPIO 功能 */
        pinctrl-names = "default";
        gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;  /* 再使用 GPIO 编号 */
    };
};
流程说明:当 led 设备驱动 probe 时,pinctrl 子系统首先根据 pinctrl-0 将引脚配置为 GPIO 功能,然后 GPIO 子系统通过 gpios 属性获取引脚号并控制输出电平。两个子系统通过设备树中的 pinctrl-* 和 gpios 属性实现解耦协作。

2.5 关键 API 与调用链

pinctrl 子系统对外提供以下核心 API,供 GPIO 驱动和其他外设驱动调用:

API 函数 功能描述 调用方
pinctrl_select_state() 切换引脚到指定状态(default/sleep/idle) 设备驱动 probe/suspend/resume
pinctrl_gpio_request() 将引脚从复用功能切换为 GPIO 模式 GPIO 子系统 gpio_request()
pinctrl_gpio_free() 释放 GPIO 模式,恢复默认复用 GPIO 子系统 gpio_free()
pinctrl_gpio_direction_input/output() 配置 GPIO 方向(需先完成复用切换) GPIO 子系统内部
pinctrl_register() 注册 pinctrl 控制器驱动 SoC 厂商 pinctrl 驱动初始化
调试技巧:在 /sys/kernel/debug/pinctrl/ 目录下可以查看当前所有 pinctrl 控制器的引脚复用状态、已激活的引脚组和电气配置,是排查引脚冲突的第一手工具。

2.6 本章小结

  • pinctrl 子系统负责引脚复用、电气配置和分组管理,是 SoC 引脚资源的统一管理者。
  • GPIO 子系统依赖 pinctrl 将引脚切换为 GPIO 功能后,才能进行输入/输出和中断操作。
  • 两者通过设备树中的 pinctrl-* 属性和 gpios 属性实现配置分离与协作。
  • 理解 pinctrl 与 GPIO 的职责边界,是正确配置引脚和调试中断的前提。