设备树修改

系统梳理一下设备树修改中涉及引脚功能配置的几类常见情况,并总结出修改时的通用规则。作为小白,你只需要理解"引脚在同一时刻只能做一件事"这个核心概念,然后按照步骤操作就可以了。


一、基础知识科普(必读)

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_PC5GPIO4_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. 修改引脚功能的一般步骤

  1. 找到原功能:在设备树中搜索该引脚,看它被哪个外设节点使用了(比如 I2C2、PWM5、UART8 等)。

  2. 禁用或移除原功能 :将原外设节点的 status = "disabled",或者直接删除/注释掉相关 pinctrl 配置。

  3. 为新功能添加配置:启用新外设节点(如果原来未启用),并正确设置 pinctrl 指向新的引脚组。

  4. 检查冲突:确保同一个引脚没有被两个外设同时要求使用。


二、你总结的四类修改类型及具体操作

类型1:原来是特殊 GPIO(如 5G 电源使能、复位、耳机检测),改成普通 GPIO

典型场景 :原先 5g-pwr5g-rstrk_headset 这些节点占用了一些 GPIO,当作特殊功能(输出电源使能、输入检测等)。现在你不想要这些功能了,想把引脚释放出来当作普通 GPIO 使用。

你需要修改的东西:

  1. 禁用对应的功能节点

    找到这些节点(通常在 / 节点下),将其 status 改为 disabled

    dts

    复制代码
    &5g-pwr {
        status = "disabled";
    };
    &5g-rst {
        status = "disabled";
    };
    &rk_headset {
        status = "disabled";
    };
  2. 删除或注释掉这些节点中引用的 pinctrl

    如果节点内有 pinctrl-0 指向某个引脚组,需要一并移除(或者确保那个引脚组不会生效)。禁用节点后,其 pinctrl 就不会被应用,引脚自动变为 GPIO 模式。

  3. 无需额外添加 GPIO 配置

    只要没有其他外设占用,内核会自动把它们当作普通 GPIO。你可以通过 /sys/class/gpio 或应用程序来操作它们。

规则:将原本有特殊功能的 GPIO 节点禁用,引脚就会恢复成普通 GPIO。


类型2:原来是其他外设功能(如 PWM、SPI_CS),改成普通 GPIO

典型场景:原先某个引脚被配置为 PWM 输出或 SPI 的片选(CS),现在你想把它当作普通 GPIO 来用。

你需要修改的东西:

  1. 禁用或移除该外设功能

    • 如果该引脚是某个外设(如 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 中移除。

  2. 释放引脚,改为 GPIO

    确保没有任何外设节点引用该引脚后,内核会自动把它当作普通 GPIO。无需额外配置。

规则:要彻底让引脚变成 GPIO,必须确保没有任何外设驱动还在占用它(包括节点状态、pinctrl 引用)。


类型3:原来是 I2C 功能,改成 CAN 功能

典型场景 :原先天板的 I2C2 总线使用了 GPIO4_B4GPIO4_B5,现在你想把这些引脚改为 CAN2 的 RX/TX。

你需要修改的东西:

  1. 禁用 I2C2 控制器

    dts

    复制代码
    &i2c2 {
        status = "disabled";
    };

    这会释放 I2C2 占用的引脚。

  2. 启用 CAN2 控制器

    dts

    复制代码
    &can2 {
        status = "okay";
        // ... 其他配置
    };
  3. 为 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>;
    };
  4. 注意引脚的电平匹配

    CAN 通常不需要上拉,但可能要根据硬件原理图选择合适的上下拉(&pcfg_pull_none 即可)。

规则:转换外设功能时,先禁用原功能,再启用新功能,并正确配置新功能的 pinctrl。


类型4:原来是 GPIO,改成 UART 等其他外设功能

典型场景:原来某个引脚是空着的(GPIO 状态),现在你要把它用作 UART9 的 TX/RX。

你需要修改的东西:

  1. 启用目标外设

    找到对应的 UART 节点(如 &uart9),将其 status 设为 okay

  2. 添加或修改 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>;
    };
  3. 在 UART 节点中引用该 pinctrl

    dts

    复制代码
    &uart9 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart9m1_xfer>;
    };
  4. 确保引脚没有被其他外设占用

    检查设备树中是否有其他节点也引用了这些引脚(比如原本作为 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 组,将引脚设为对应功能号。

核心心法

修改设备树就是告诉内核"这个引脚现在归谁管"。你要把旧主人赶走(禁用),再让新主人入住(启用并配置)。

相关推荐
晚风吹红霞1 小时前
进程调度深度解析:从优先级到O(1)调度算法
linux·运维
say_fall1 小时前
深入理解Linux内核进程调度:从基础概念到O(1)调度算法
linux·运维·服务器·算法·计算机组成
青梅橘子皮1 小时前
Linux---命令行参数和环境变量
linux·运维·服务器
艾莉丝努力练剑1 小时前
【Linux网络】Linux 网络编程:传输层TCP(四)
linux·运维·服务器·网络·tcp/ip·http
载数而行5201 小时前
linux 6 定时任务指令
linux
AOwhisky1 小时前
Ceph系列第四期:Ceph块存储(RBD)精讲
linux·运维·笔记·ceph·云计算·rbd
Shadow(⊙o⊙)1 小时前
库的制作与原理2.0---动静态链接,main全解析,CPU在执行文件时的作用,GOT表。
linux·运维·服务器
zincsweet1 小时前
System V 共享内存:原理剖析、代码架构分析与双端通信实战
linux·c++
lolo大魔王10 小时前
Linux 文件系统超全面详解(原理、结构、挂载、分区、inode、日志、管理命令)
linux·运维·服务器