设备树修改
系统梳理一下设备树修改中涉及引脚功能配置的几类常见情况,并总结出修改时的通用规则。作为小白,你只需要理解“引脚在同一时刻只能做一件事”这个核心概念,然后按照步骤操作就可以了。
一、基础知识科普(必读)
1. 什么是引脚复用?
芯片的每一个物理引脚(比如GPIO4_B5)通常可以支持多种功能,比如:
作为普通GPIO(输入输出)
作为I2C的时钟线(SCL)
作为UART的发送脚(TX)
作为PWM的输出
作为CAN的接收脚(RX)
这种一个引脚可以切换不同功能的能力,叫做引脚复用。设备树就是告诉内核:“我这个引脚现在要当什么用”。
2. 设备树中如何控制引脚功能?
通常通过pinctrl(Pin Control)子系统来描述。例如:
dts
&uart9 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart9m1_xfer>; };pinctrl-0指向一个自定义的引脚组,该组中定义了具体引脚以及要切换到的功能编号(Alt0、Alt1、Alt2…)。
一个引脚组的定义通常像这样:
dts
uart9m1_xfer: uart9m1-xfer { rockchip,pins = <4 RK_PC5 4 &pcfg_pull_up>, <4 RK_PC6 4 &pcfg_pull_up>; };意思是将GPIO4_PC5和GPIO4_PC6设置为功能号4(即 UART9_TX / UART9_RX),并带上拉。
3. 如何把一个引脚变成普通 GPIO?
不需要特殊配置,只要没有任何外设节点占用该引脚,并且pinctrl 没有强制设置复用功能,内核默认就会把它当作普通 GPIO 处理。
如果想显式地设置它为 GPIO,可以用
rockchip,pins中的RK_FUNC_GPIO(通常函数号为0):
dts
my_gpio: my-gpio { rockchip,pins = <1 RK_PB1 0 &pcfg_pull_none>; };4. 修改引脚功能的一般步骤
找到原功能:在设备树中搜索该引脚,看它被哪个外设节点使用了(比如 I2C2、PWM5、UART8 等)。
禁用或移除原功能:将原外设节点的
status = "disabled",或者直接删除/注释掉相关 pinctrl 配置。为新功能添加配置:启用新外设节点(如果原来未启用),并正确设置 pinctrl 指向新的引脚组。
检查冲突:确保同一个引脚没有被两个外设同时要求使用。
二、你总结的四类修改类型及具体操作
类型1:原来是特殊 GPIO(如 5G 电源使能、复位、耳机检测),改成普通 GPIO
典型场景:原先5g-pwr、5g-rst、rk_headset这些节点占用了一些 GPIO,当作特殊功能(输出电源使能、输入检测等)。现在你不想要这些功能了,想把引脚释放出来当作普通 GPIO 使用。
你需要修改的东西:
禁用对应的功能节点:
找到这些节点(通常在/节点下),将其status改为disabled:dts
&5g-pwr { status = "disabled"; }; &5g-rst { status = "disabled"; }; &rk_headset { status = "disabled"; };删除或注释掉这些节点中引用的 pinctrl:
如果节点内有pinctrl-0指向某个引脚组,需要一并移除(或者确保那个引脚组不会生效)。禁用节点后,其 pinctrl 就不会被应用,引脚自动变为 GPIO 模式。无需额外添加 GPIO 配置:
只要没有其他外设占用,内核会自动把它们当作普通 GPIO。你可以通过/sys/class/gpio或应用程序来操作它们。
规则:将原本有特殊功能的 GPIO 节点禁用,引脚就会恢复成普通 GPIO。
类型2:原来是其他外设功能(如 PWM、SPI_CS),改成普通 GPIO
典型场景:原先某个引脚被配置为 PWM 输出或 SPI 的片选(CS),现在你想把它当作普通 GPIO 来用。
你需要修改的东西:
禁用或移除该外设功能:
如果该引脚是某个外设(如
pwm5)的一部分,你不能直接禁用 PWM 控制器(因为可能还有其他引脚在用),只能去掉这个引脚在外设中的使用。对于PWM:通常每个 PWM 通道对应一个引脚。如果你不想要这个通道,可以直接在设备树中删除该 PWM 节点的引用。例如,
pwm5对应的背光节点dsi1_backlight使用了它,你可以禁用背光节点,这样 PWM5 就没有消费者了,但 PWM 控制器本身还开着,引脚仍然被 PWM 硬件占用。正确做法:在&pwm5节点中删除或注释掉该通道的引脚定义?实际上 PWM 控制器的引脚是在其父节点pinctrl中定义的,你可以修改&pwm5的 pinctrl-0 指向一个空组,或者直接禁用&pwm5节点(如果其他功能不需要它)。但这样可能影响其他依赖同一 PWM 控制器的外设。更简单、安全的做法:禁用整个外设节点,比如
&pwm5 { status = "disabled"; };。但这样会影响所有使用该 PWM 的功能,你需要权衡。对于SPI_CS:如果该引脚是 SPI 控制器的一个片选脚,你可以:
如果该片选对应的 SPI 设备不再使用,直接删除该 SPI 子节点(比如删除
spi@1)。如果 SPI 控制器本身还在用其他片选,你不能禁用整个 SPI,只能修改引脚配置,将其从 SPI 的 pinctrl 中移除。
释放引脚,改为 GPIO:
确保没有任何外设节点引用该引脚后,内核会自动把它当作普通 GPIO。无需额外配置。
规则:要彻底让引脚变成 GPIO,必须确保没有任何外设驱动还在占用它(包括节点状态、pinctrl 引用)。
类型3:原来是 I2C 功能,改成 CAN 功能
典型场景:原先天板的 I2C2 总线使用了GPIO4_B4、GPIO4_B5,现在你想把这些引脚改为 CAN2 的 RX/TX。
你需要修改的东西:
禁用 I2C2 控制器:
dts
&i2c2 { status = "disabled"; };这会释放 I2C2 占用的引脚。
启用 CAN2 控制器:
dts
&can2 { status = "okay"; // ... 其他配置 };为 CAN2 配置正确的 pinctrl:
新增一个引脚组,将引脚切换到 CAN 功能:dts
can2_m0_pins: can2-m0-pins { rockchip,pins = <4 RK_PB4 3 &pcfg_pull_none>, <4 RK_PB5 3 &pcfg_pull_none>; };然后在
&can2中引用:dts
&can2 { pinctrl-names = "default"; pinctrl-0 = <&can2_m0_pins>; };注意引脚的电平匹配:
CAN 通常不需要上拉,但可能要根据硬件原理图选择合适的上下拉(&pcfg_pull_none即可)。
规则:转换外设功能时,先禁用原功能,再启用新功能,并正确配置新功能的 pinctrl。
类型4:原来是 GPIO,改成 UART 等其他外设功能
典型场景:原来某个引脚是空着的(GPIO 状态),现在你要把它用作 UART9 的 TX/RX。
你需要修改的东西:
启用目标外设:
找到对应的 UART 节点(如&uart9),将其status设为okay。添加或修改 pinctrl 配置:
如果原来没有该外设的引脚组,需要新增(如uart9m1_xfer),并将引脚切换到对应功能(Alt4 等):dts
uart9m1_xfer: uart9m1-xfer { rockchip,pins = <4 RK_PC5 4 &pcfg_pull_up>, <4 RK_PC6 4 &pcfg_pull_up>; };在 UART 节点中引用该 pinctrl:
dts
&uart9 { pinctrl-names = "default"; pinctrl-0 = <&uart9m1_xfer>; };确保引脚没有被其他外设占用:
检查设备树中是否有其他节点也引用了这些引脚(比如原本作为 GPIO 输出,或者被其他 I2C/SPI 占用)。如有冲突,需要先禁用或移除冲突配置。
规则:从 GPIO 变成外设功能,只需找到合适的外设节点,启用并配置正确的 pinctrl 即可。
三、通用规则和注意事项(小白必看)
1. 引脚互斥原则
一个引脚在同一时间只能被一个外设占用。如果你想把引脚从一种功能改为另一种,必须确保原来的功能彻底消失(禁用节点、删除 pinctrl 引用)。
2. 如何知道一个引脚当前被谁使用?
查看设备树,搜索引脚名(如
RK_PB1)或 GPIO 编号(如gpio1 9)。烧写设备树后,通过命令查看实际 pinmux 状态:
bash
cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins
可以看到每个引脚当前是哪个驱动的功能。
3. 修改后不生效怎么办?
重新编译设备树(
make dtbs),确保新的.dtb被烧写进开发板。重启后检查 pinmux 状态是否改变。
如果仍然不对,检查是否还有其他节点还在引用该引脚(比如
pinctrl-1等)。
4. 关于“改为普通 GPIO”的特别注意
不需要在设备树中为每个 GPIO 写配置,只要没有外设占用,它就是 GPIO。
但如果你需要指定该 GPIO 的默认方向(输入/输出)或默认值,可以使用
gpio-hog子节点,例如:dts
&gpio1 { gpio-hog { gpio-hog; gpios = <9 GPIO_ACTIVE_HIGH>; output-low; line-name = "my-gpio"; }; };一般在应用层通过
/sys/class/gpio操作即可,无需 hog。
5. 查看某个引脚的功能编号(AltX)
查阅芯片数据手册或厂商提供的引脚复用表。
常见规律:Alt0 = GPIO,Alt1、Alt2、Alt3… 对应不同外设。例如在 RK3568 上,UART9 的 TX 可能是 Alt4。
6. 修改前做好备份
每次修改设备树前,备份原始文件。建议使用 Git 管理。
四、总结表格
| 修改类型 | 原功能 | 新功能 | 修改要点 |
|---|---|---|---|
| 类型1 | 特殊 GPIO(5G 使能、复位、耳机检测) | 普通 GPIO | 禁用原功能节点(status="disabled"),移除 pinctrl 引用;引脚自动变成 GPIO。 |
| 类型2 | PWM / SPI_CS 等外设 | 普通 GPIO | 禁用或修改使用该引脚的外设节点(删除子节点、禁用 PWM 通道等),确保无驱动占用;释放后即为 GPIO。 |
| 类型3 | I2C | CAN | 禁用 I2C 控制器,启用 CAN 控制器,添加 CAN 的 pinctrl 配置(功能号正确)。 |
| 类型4 | GPIO(未使用) | UART 等外设 | 启用外设节点,为其添加或修改 pinctrl 组,将引脚设为对应功能号。 |
核心心法:
修改设备树就是告诉内核“这个引脚现在归谁管”。你要把旧主人赶走(禁用),再让新主人入住(启用并配置)。
