欢迎关注,每周更新!
本合集分享的是,我当初学习Linux驱动的来时路——《《驱动之路》开篇:自序&前言》。
正文
在嵌入式 Linux 开发中,你是否遇到过这些困惑:
为什么同样一个 GPIO引脚,既能做普通输入输出,又能做 I2C 的 SDA、SPI 的 CS 等功能?
驱动中没写引脚配置代码,芯片却能自动切换引脚功能,底层是怎么实现的?
设备树中pinctrl-0 pinctrl-names这些属性到底有什么用?
这一切的答案,都藏在 Linux 内核的Pinctrl 子系统里。它是管理芯片引脚的 “总管家”,负责引脚的复用配置、电气属性设置,让驱动开发者彻底摆脱 “寄存器操作引脚” 的繁琐。
1 为什么需要 Pinctrl 子系统?
如果没有 Pinctrl 子系统,嵌入式引脚配置全靠 “硬编码”,痛点极其明显:
(1)引脚复用冲突
芯片的引脚资源有限,一个引脚往往对应多种功能(如 GPIO、I2C、UART、SPI)。比如 RK3576 的GPIO2_PB4,支持如下功能复用。

如果驱动直接操作寄存器配置功能,很容易出现 “多个驱动抢占同一引脚” 的冲突。
(2)配置繁琐且易出错
引脚配置不仅要选 “功能”,还要设置电气属性:
上拉 / 下拉电阻(如 I2C 引脚需要上拉);
驱动能力(如大电流引脚需要增强驱动能力);
电平标准(如 LVCMOS3.3V、LVDS)。
这些都需要操作复杂的寄存器,不同芯片的寄存器地址还不一样,移植性极差。
(3)驱动与硬件耦合严重
驱动代码中硬编码引脚配置,更换硬件平台或修改引脚时,必须修改驱动代码,违背了 “硬件描述与驱动分离” 的设计思想。
而 Pinctrl 子系统的核心目标,就是解决这些问题:
统一管理引脚:集中处理引脚复用、电气属性配置,避免冲突;
设备树驱动解耦:引脚配置写在设备树中,驱动无需关心硬件细节;
标准化接口:提供统一的内核 API,驱动通过设备树即可获取引脚配置。
2 Pinctrl 的 3 个关键术语
想要理解 Pinctrl,必须先搞懂这 3 个核心概念,否则后续流程会 confusion:
(1)Pin(引脚)
指芯片物理引脚的抽象,每个引脚都有唯一的编号(如 RK3576 的GPIO2_PB4对应引脚编号52)。Pinctrl 子系统通过 “引脚编号” 识别和管理硬件引脚。
(2)Pinmux(引脚复用)
“Pin Multiplexing” 的缩写,核心作用是选择引脚的功能模式。比如:
把GPIO2_PB4配置为 “普通 GPIO 模式”;
把GPIO2_PB4配置为 “UART7_CTSN 模式”;
把GPIO2_PB4配置为 “SPI4_MOSI 模式”。
每个引脚的可用模式,由芯片的 datasheet 明确规定(如瑞芯微提供的 RK3576_PinOut 表格)。
(3)Pinctrl(引脚配置)
“Pin Control” 的缩写,核心作用是设置引脚的电气属性,常见配置包括:
上拉电阻(pull-up):引脚默认拉高,如 I2C、按键引脚;
下拉电阻(pull-down):引脚默认拉低,如复位引脚;
驱动能力(drive strength):引脚输出电流大小,如 LED 引脚需要 10mA 驱动;
电平标准(voltage level):如 LVCMOS3.3V、LVCMOS1.8V;
slew rate(转换速率):引脚电平变化的快慢,高频场景需调整。
简单总结:Pinmux 负责 “引脚做什么功能”,Pinctrl 负责 “引脚的电气特性是什么”,两者结合完成引脚的完整配置。
3 Pinctrl 工作流程
Pinctrl 子系统的工作,本质是 “设备树配置 → 内核解析 → 驱动使用” 的流程。
步骤 1:设备树中定义引脚配置
开发者需要在设备树中,为每个设备(如 I2C、SPI、传感器)定义 “引脚复用 + 电气属性”,核心是 3 类节点:
(1)Pinctrl 控制器节点
描述芯片的引脚控制器硬件信息,由芯片厂商在 dtsi 文件中预定义(无需开发者修改)。例如 RK3576 的 rk3576.dtsi(如下图)。
核心作用:告诉内核 “引脚控制器的硬件位置、支持的功能”,内核通过该节点初始化 Pinctrl 驱动。
(2)引脚配置子节点
在&pinctrl节点下(rk3576-pinctrl.dtsi),定义具体的引脚配置(复用 + 电气属性),通常以 “功能 + 场景”命名。例如 I2C0 的引脚配置:

(3)设备节点引用引脚配置
在具体设备节点(如 I2C0)中,通过pinctrl-names和pinctrl-0引用上述配置:
步骤 2:内核解析设备树,初始化引脚配置
Linux 内核启动时,Pinctrl 子系统会执行以下操作:
解析&pinctrl控制器节点,加载对应的 Pinctrl 驱动(如drivers/pinctrl/pinctrl-rockchip.c);
解析引脚配置子节点(如i2c0_default),提取pinmux(功能)和pinconf(电气属性)信息;
检查引脚是否被其他设备占用(避免复用冲突);
若引脚空闲,通过 Pinctrl 驱动操作寄存器,配置引脚的复用模式和电气属性;
把配置好的引脚与设备节点(如&i2c0)绑定,等待驱动使用。
步骤 3:驱动匹配成功,直接使用配置好的引脚
当设备节点(如&i2c0)与驱动(如 I2C 驱动)匹配成功后,驱动无需再配置引脚 ——Pinctrl 子系统已提前完成所有工作:
I2C 驱动直接通过 I2C 控制器收发数据,SDA/SCL 引脚已被配置为 I2C 功能,且启用了上拉电阻;
传感器驱动通过devm_gpiod_get获取复位引脚时,该引脚已被配置为 GPIO 功能,无需手动设置复用。
这就是为什么驱动中不用写引脚配置代码 ——Pinctrl 子系统已经 “提前打理好一切”。
总结
Pinctrl 子系统的本质是 “内核提供的引脚管理框架”,核心作用是统一处理引脚复用和电气属性配置,实现 “硬件描述与驱动分离”。
关键要点回顾:
3 个核心概念:Pin(引脚)、Pinmux(复用)、Pinconf(配置);
工作流程:设备树定义配置 → 内核解析初始化 → 驱动直接使用;
开发重点:在设备树中正确定义引脚组、功能、电气属性,并让设备节点引用。
记住:嵌入式 Linux 中,所有引脚的复用和配置,都应该通过 Pinctrl 子系统实现,而非驱动硬编码 —— 这是规范,也是避免踩坑的关键。
(完)
本人专注 Linux 驱动 & Linux/Android BSP 开发调试,可接外包项目/技术支持/问题定位。有需求或交个朋友可加微信:【Chen_WeChat2026】。
更多原创技术文章:《README 2026》。
审核编辑 黄宇
