GPIO 子系统引言:GPIO 与 pinctrl 各管什么
依据:2026-10-14《GPIO子系统-引言》课堂录音、学习系统
06_GPIO子系统/笔记.md及其配图。本文整理老师的宏观思路和一个 LED 小例子;不代表已在你的板子上新增验证。
一句话记住
pinctrl 先决定管脚用什么功能、具有什么电气配置;GPIO 子系统再让驱动用统一接口申请这根 GPIO、设方向和读写电平。以前 LED 驱动直接算寄存器地址和位,现在把这些芯片差异交给管脚控制器驱动、GPIO 控制器驱动处理。Linux pinctrl 文档、Linux GPIO 接口
图是概念框图:右侧的
device_create("led")等写法只是课件简写,并非可直接编译的完整函数调用;/sys/devices/led也不是固定的 LED 路径。下面按实际职责理解。
1. 它接在前面哪一节后面
| 已学内容 | 解决什么问题 | 仍需解决什么 |
|---|---|---|
| 字符设备 | 用/dev/led和open/ioctl等操作给应用一个入口 | 早期驱动仍可能写死 GPIO 寄存器 |
| 平台设备 + 设备树 | 设备与驱动匹配,板级硬件信息由 DTS 描述 | 只搬走基地址,驱动可能仍要算不同管脚的偏移和位 |
| GPIO 子系统 | 用gpiod_*统一申请、方向、数值等操作 | 管脚若复用成其他功能,还要检查 pinctrl |
| pinctrl 子系统 | 管脚复用及上拉、下拉、驱动能力等配置 | 具体能选哪些功能,由芯片硬件决定 |
这是老师录音约 00:06—05:42 的出发点。老师用“PF7 换成 PC2”说明:若应用逻辑仍是让 LED 亮灭,驱动不应重新计算每个寄存器偏移。换管脚后“只改设备树”有前提:新管脚确实接到目标硬件、DTS 中 GPIO 与 pinctrl 都配置正确、GPIO 控制器驱动支持它,且没有资源冲突;不能只改一个编号就保证灯亮。
2. GPIO 子系统:把“怎么操作这根线”统一起来
LED/按键等设备驱动(GPIO 使用者) │ gpiod_get()、gpiod_direction_output()、gpiod_set_value() ▼ gpiolib(统一的 GPIO 框架) │ 调用对应 gpio_chip 的操作 ▼ Tegra GPIO 控制器驱动(厂商/BSP 提供) │ 按该芯片的寄存器布局操作 ▼ GPIO 硬件老师把框架称为“GPIO 库”,把底层称为“GPIO chip driver”(录音约 06:44—09:37)。我们写 LED 驱动时是使用者:通常只需要知道拿哪根 GPIO、设输入还是输出、读写什么逻辑值。控制器驱动负责该 SoC 的寄存器地址、偏移、位号等细节。GPIO 子系统还涉及中断等能力,这节先抓住方向与电平即可。Linux GPIO 控制器驱动
小例子:把 LED 管脚换掉
前面你的 Tegra LED 例子用设备树描述“这盏灯接哪根线”:
yhai-led-gpiod { compatible = "yhai,led_gpiod"; status = "okay"; gpios = <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_HIGH>; };驱动的关键语句是(只展示 GPIO 部分,不是完整驱动):
gpiod=gpiod_get(&pdev->dev,NULL,GPIOD_OUT_LOW);if(IS_ERR(gpiod))returnPTR_ERR(gpiod);gpiod_set_value(gpiod,1);/* 输出逻辑 1;此 DTS 极性为 ACTIVE_HIGH *//* 不再使用这根线时:gpiod_put(gpiod); */这里gpios属性对应gpiod_get(..., NULL, ...);GPIOD_OUT_LOW已设为输出且初值为逻辑 0。换到另一根可用管脚时,驱动中这几句可以保持不变,改设备树的 GPIO 指向,并核对新管脚的 pinctrl 配置、接线与有效电平。如果 LED 接法是低电平点亮,可在 DTS 中用GPIO_ACTIVE_LOW表示,gpiod_set_value(gpiod, 1)仍表示“逻辑有效”。Linux GPIO 消费者接口
三个名字别混淆:PJ7是 Tegra 的端口/管脚写法,I2S0_SCLK是笔记里同一焊盘的功能/信号名,gpio-79是老师当时内核显示的旧式全局 GPIO 编号;三者不是“第 79 个物理针脚”。驱动用gpio_desc后,通常无需依赖那个全局编号。
3. pinctrl 子系统:先把管脚配置对
同一个物理管脚可能在芯片设计中支持GPIO、UART、SPI、I²C 等预设功能,但某一时刻通常只能选合适的一种。pinctrl 主要处理两类事(录音约 10:00—15:05):
- 复用 pinmux:这根管脚当前交给 GPIO,还是 UART/SPI 等外设。
- 电气配置 pinconf:上拉、下拉、驱动能力、开漏等,具体项目由芯片支持情况决定。“高阻态”也与芯片的输出使能等设置相关,不能简单理解为“开了高阻就能驱动 LED”。
老师说的“状态/配置清单”可以这样理解:
/* 概念写法:led_default、led_sleep 必须先在本板 pinctrl 节点中定义 */ pinctrl-names = "default", "sleep"; pinctrl-0 = <&led_default>; pinctrl-1 = <&led_sleep>;default描述正常工作状态,通常在设备probe()前由设备核心选择;sleep描述休眠状态,仅写进 DTS 并不会自动在每次休眠时切换,还取决于驱动/电源管理路径。Tegra 的具体引脚名、属性和值必须查该板 DTS 和芯片资料,不能直接把上面的占位标签复制到工程里。Linux pinctrl 状态与设备树
把它和 STM32 对照:选 GPIO/复用功能、上拉下拉类似配置 GPIO 模式与 AF;设置输出高低类似HAL_GPIO_WritePin()。Linux 多了一层 DTS 与内核子系统,使设备驱动尽量少碰芯片寄存器。
4. 课堂图中三个应用层入口,不要混成一个
| 入口 | 用来做什么 | 本节要记住的边界 |
|---|---|---|
/dev/led | 你之前自定义字符设备的应用接口 | 由字符设备的file_operations处理open/ioctl等 |
/sys/class/...下的属性文件 | 向用户空间展示/设置简单设备属性 | 创建 class/device 不等于自动有led可写属性;还需定义属性及show/store回调 |
/sys/kernel/debug/pinctrl/ | 查看管脚复用、占用等调试信息 | 属于debugfs,需内核支持并挂载;不能当稳定应用接口 |
老师说的echo 1 > 某属性文件会走该属性的store();cat 某属性文件会走show()。这是一个可选的 sysfs 属性接口示意,和echo 1 > /dev/led、ioctl(/dev/led, ...)不是同一套回调。实际文件名和路径由驱动创建,不能预设为/sys/devices/led。课件提到的device_create_file()、设备属性组等,是后续实现这类接口的方法。Linux sysfs 属性
你笔记中的/sys/class/gpio/export → gpio79/direction → gpio79/value是旧式 GPIO sysfs 接口的课堂例子。79是老师当时那套板子上的内核 GPIO 编号,不是所有板都用 79;若管脚已被 LED 驱动申请,也不能再按这个方法重复占用。此接口已被标为弃用,学习时用来理解“通过文件操作硬件”即可。Linux GPIO sysfs 说明
若要只查看板上当前状态,先确认 debugfs 已挂载,再看是否存在/sys/kernel/debug/gpio和/sys/kernel/debug/pinctrl/;目录为空时先查内核配置与挂载状态。debugfs 内容偏向调试,具体文件因内核和厂商驱动而异。Linux debugfs 文档
最后复述一遍
设备树告诉内核“选哪根线、采用什么状态” → pinctrl 配好复用与电气属性 → GPIO 使用者用gpiod_*申请、设方向、读写逻辑值 → 控制器驱动操作寄存器。/dev、sysfs、debugfs 则分别给应用操作、属性展示和开发调试提供不同入口。
接前一节:GPIO 控制通用化:从寄存器到 gpiod。