pinctrl子系统介绍
一、介绍
Linux 内核中的 pinctrl子系统(Pin Control Subsystem)是一个用于统一和管理片上系统(SoC)引脚功能的框架。它主要解决引脚功能复杂、厂商差异大带来的驱动开发困难问题,负责引脚的复用、配置和状态管理 。
下表清晰地概括了 pinctrl 子系统的核心方面:

二、架构与工作原理
pinctrl 子系统的软件架构采用分层设计,以“求同存异”的方式平衡通用性和硬件特异性 。
- 核心层(pinctrl-core):作为中间层,它向上为其他驱动提供统一的API接口,向下定义了一套标准的操作函数集(如
"pinctrl_ops",
"pinmux_ops",
"pinconf_ops"),让底层驱动去实现。设备驱动通常通过
"devm_pinctrl_get"、
"pinctrl_lookup_state"、
"pinctrl_select_state" 等函数来获取和切换引脚状态 。
- 驱动层(pinctrl-driver):由芯片厂商或硬件开发人员实现,负责将具体的SoC引脚控制器抽象出来,并通过
"pinctrl_register()" 向核心层注册。它会实现核心层要求的各种操作函数,从而直接操作硬件寄存器 。
- 客户端(pinctrl-client):指那些需要使用引脚的设备驱动,如I2C、SPI驱动。它们通过在设备树中声明所需的引脚状态来使用pinctrl服务 。
三、设备树中的配置
pinctrl 的配置主要在设备树中完成,通常涉及两种节点 。
1. Pin Controller 设备节点:这个节点描述了SoC内部的引脚控制器,它定义了引脚或引脚组(pin group)可以被配置成何种功能(function)和电气特性。不同平台的格式可能不同 。
/* 示例:在Pin Controller节点中定义一组UART引脚配置 */
&iomuxc {
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART4_TX_DATA__UART1_DCE_TX 0x1b0b0
MX6UL_PAD_UART4_RX_DATA__UART1_DCE_RX 0x1b0b0
>;
};
};
2. Client Device 设备节点:在使用这些引脚的设备节点中,通过属性引用上面定义的配置。
/* 在UART设备节点中引用引脚配置 */
&uart1 {
pinctrl-names = "default", "sleep"; /* 定义两种状态 */
pinctrl-0 = <&pinctrl_uart1>; /* 默认状态使用上述配置 */
pinctrl-1 = <&pinctrl_uart1_sleep>; /* 休眠状态可能使用不同的配置 */
status = "okay";
};
四、在驱动中的使用
在设备驱动中,使用pinctrl有两种常见方式:
- 自动状态切换:这是最常用的方式。当驱动通过
"platform_driver_register" 注册设备后,内核在探测(probe)阶段会自动调用
"pinctrl_bind_pins" 函数,该函数会从设备树中解析出
"pinctrl-names" 里名为 "default" 的状态并自动应用。在系统挂起和恢复时,内核也会尝试自动切换到 "sleep" 和 "default" 状态 。
- 手动API调用:如果需要在驱动运行过程中主动切换状态,可以手动调用API 。
struct pinctrl *pctrl;
struct pinctrl_state *state_active, *state_sleep;
pctrl = devm_pinctrl_get(&pdev->dev);
state_active = pinctrl_lookup_state(pctrl, "default");
state_sleep = pinctrl_lookup_state(pctrl, "sleep");
// 切换到活跃状态
pinctrl_select_state(pctrl, state_active);
...
// 切换到休眠状态
pinctrl_select_state(pctrl, state_sleep);
