
本文是设备树驱动修改系列的第二篇基于真实的RK3568开发板OK3568-C案例手把手演示如何将多个引脚从原有功能PWM、PCIE、SPI、I2C改为普通GPIO或新的外设功能CAN、UART。通过对比修改前后的设备树文件和GPIO状态带你理解每一步的操作及原理。一、背景与需求在实际嵌入式开发中我们经常需要根据硬件设计变更来调整引脚功能。比如原本用作PWM背光的引脚现在不需要背光想当作普通GPIO控制LED。原本用于PCIE复位/唤醒的引脚由于未使用PCIE希望释放为GPIO。原本用于SPI的第二个片选因为只挂了一个设备多余片选改为GPIO。原本用于I2C2的引脚需要改为CAN2通信。原本空闲的GPIO需要配置为UART9的收发引脚。本文以OK3568-C开发板为例基于Rockchip RK3568平台详细介绍如何通过修改设备树实现上述功能切换。二、修改前的准备工作2.1 获取原始设备树文件板级设备树通常位于内核源码arch/arm64/boot/dts/rockchip/目录下本例中文件名为OK3568-C-common-old.dts修改前和OK3568-C-common.dts修改后。2.2 查看当前引脚状态通过debugfs可以查看每个引脚的当前复用功能bashcat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins我们将修改前后的输出分别保存为原GPIO状态.txt和新GPIO状态.txt用于对比验证。2.3 准备芯片手册需要查阅RK3568数据手册中的“引脚复用表”确认每个引脚的功能号Alt0~Alt5。例如GPIO0_C4 的 Alt0 GPIOAlt1 PWM5GPIO4_B4 的 Alt0 GPIOAlt1 I2C2_SDA_M1Alt3 CAN2_RX_M0提示不同的功能对应不同的Alt值修改时必须填写正确的数字。三、逐项修改详解下面按照用户提供的6个修改点逐一说明设备树中需要改动的位置并给出修改前后的代码片段及引脚状态变化。修改点1GPIO0_C4 从 PWM5 改为 GPIO原功能PWM5输出用于DSI屏幕背光。新功能普通GPIO。设备树修改在原设备树中PWM5被使能且被背光节点使用dtspwm5 { status okay; }; dsi1_backlight: dsi1-backlight { compatible pwm-backlight; pwms pwm5 0 20000 0; ... };我们需要禁用PWM5控制器或者至少不让它占用引脚禁用依赖PWM5的背光节点确保没有其他节点引用该引脚作为PWM功能。修改后dtspwm5 { status disabled; }; dsi1_backlight: dsi1-backlight { ... // 注意这里我们没有删除整个节点只是将其禁用可以添加 status disabled status disabled; };注意仅禁用PWM控制器即可释放引脚不需要额外配置GPIO。内核会自动将该引脚视为普通GPIO。引脚状态变化修改前textpin 20 (gpio0-20): fe6e0010.pwm (GPIO UNCLAIMED) function pwm5 group pwm5-pins修改后textpin 20 (gpio0-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)可以看到fe6e0010.pwm的占用消失变为(MUX UNCLAIMED)表示该引脚已回归GPIO模式。修改点2GPIO0_C5、GPIO0_C6 从 PCIE 功能改为 GPIO原功能GPIO0_C5 (pin 29)PCIE30X2_WAKEn_M0PCIe唤醒GPIO0_C6 (pin 30)PCIE30X2_PERSTn_M0PCIe复位新功能普通GPIO。设备树修改原设备树中这两个引脚被PCIe控制器占用dtspcie3x2 { reset-gpios gpio0 RK_PC6 GPIO_ACTIVE_HIGH; enable-gpios gpio0 RK_PA5 GPIO_ACTIVE_HIGH; vpcie3v3-supply vcc3v3_sys; status okay; };注意reset-gpios使用了 GPIO0_C6而 GPIO0_C5 可能通过 pinctrl 被配置为 PCIE30X2_WAKEn_M0。要释放这两个引脚我们需要禁用PCIe控制器如果不需要PCIe功能或修改其pinctrl配置。本例中直接禁用了PCIe3x2以及相关的PCIe30phydtspcie30phy { status disabled; }; pcie3x2 { status disabled; };同时检查pinctrl中是否有为该引脚定义的特殊组如果有也需要移除或禁用。原文件中未发现单独引用因此禁用PCIe节点后引脚自动释放。引脚状态变化修改前textpin 29 (gpio0-29): (MUX UNCLAIMED) (GPIO UNCLAIMED) // 实际上原GPIO状态文件中未显示占用检查原文件发现并没有显示PCIE占用可能是因为PCIE未实际启用但为了安全我们仍按计划禁用。实际上在原GPIO状态中这两个引脚显示为未占用但为了确保万无一失我们还是禁用了PCIe节点。修改后状态不变仍然是GPIO。修改点3GPIO2_D4 从 SPI2_CS1_M1 改为 GPIO原功能SPI2的第二个片选信号CS1。新功能普通GPIO。设备树修改原设备树中SPI2控制器配置了两个片选并使用两组pinctrldtsspi2 { pinctrl-names default, high_speed; pinctrl-0 spi2m1_cs0 spi2m1_cs1 spi2m1_pins; pinctrl-1 spi2m1_cs0 spi2m1_cs1 spi2m1_pins_hs; status okay; spi0 { ... }; spi1 { ... }; // 第二个SPI设备使用CS1 };要释放CS1引脚有两种方法删除第二个SPI子节点spi1并移除pinctrl中的spi2m1_cs1引用。保留子节点但修改其使用的片选不推荐。本例采用删除子节点并移除CS1引脚组的方法dtsspi2 { pinctrl-names default, high_speed; pinctrl-0 spi2m1_cs0 spi2m1_pins; // 删除了 spi2m1_cs1 pinctrl-1 spi2m1_cs0 spi2m1_pins_hs; status okay; spi0 { compatible rockchip,spidev; reg 0; spi-max-frequency 50000000; }; // 删除了 spi1 节点 };此外还需要在pinctrl中确认spi2m1_cs1的定义是否被其他地方使用如果没有也可以删除该组定义以保持整洁。但本例中仅移除引用即可。引脚状态变化修改前textpin 92 (gpio2-28): fe630000.spi (GPIO UNCLAIMED) function spi2 group spi2m1-cs1修改后textpin 92 (gpio2-28): (MUX UNCLAIMED) (GPIO UNCLAIMED)CS1引脚不再被SPI控制器占用变为GPIO。修改点4GPIO3_C4 从 PWM14 改为 GPIO原功能PWM14输出用于LVDS背光。新功能普通GPIO。设备树修改与PWM5类似需要禁用PWM14控制器以及引用它的背光节点。dtspwm14 { status disabled; }; lvds_backlight: lvds-backlight { status disabled; };原设备树中lvds_backlight节点使用了pwms pwm14 0 20000 0禁用背光节点后PWM14不再有使用者但为了彻底释放引脚直接禁用PWM14控制器。引脚状态变化修改前textpin 116 (gpio3-20): fe700020.pwm (GPIO UNCLAIMED) function pwm14 group pwm14m0-pins修改后textpin 116 (gpio3-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)引脚回归GPIO。修改点5GPIO4_B4、GPIO4_B5 从 I2C2 改为 CAN2原功能I2C2的SDA/SCL信号。新功能CAN2的RX/TX。设备树修改首先禁用I2C2控制器因为引脚被占用dtsi2c2 { status disabled; };注意原设备树中I2C2上挂载了摄像头、触摸屏等多个设备禁用I2C2意味着这些设备将无法使用。如果仍需使用需迁移到其他I2C总线。接着启用CAN2控制器并配置正确的pinctrldtscan2 { status okay; compatible rockchip,can-1.0; assigned-clocks cru CLK_CAN2; assigned-clock-rates 200000000; pinctrl-names default; pinctrl-0 can2_m0_pins; };然后在pinctrl中新增can2_m0_pins组将引脚设置为Alt3CAN2功能dtspinctrl { can2_m0_pins: can2-m0-pins { rockchip,pins 4 RK_PB4 3 pcfg_pull_none, 4 RK_PB5 3 pcfg_pull_none; }; };注意功能号3来源于数据手册GPIO4_B4的Alt3 CAN2_RX_M0GPIO4_B5的Alt3 CAN2_TX_M0。引脚状态变化修改前textpin 140 (gpio4-12): fe5b0000.i2c (GPIO UNCLAIMED) function i2c2 group i2c2m1-xfer pin 141 (gpio4-13): fe5b0000.i2c (GPIO UNCLAIMED) function i2c2 group i2c2m1-xfer修改后textpin 140 (gpio4-12): (MUX UNCLAIMED) (GPIO UNCLAIMED) // 注意新状态文件中这两行显示为未占用实际上新GPIO状态文件中 pin 140/141 显示为 (MUX UNCLAIMED)但 CAN2 的引脚应该被 fe6d0000.can 占用检查新状态文件pin 140/141 确实是 UNCLAIMED而 pin 148 和 149 是 uart9pin 146/147 是 can1。说明 CAN2 可能没有被启用但是用户提供的修改后设备树中 can2 是启用的且定义了 can2_m0_pins按理应该占用 GPIO4_B4/B5。为什么新状态中还是 UNCLAIMED可能因为编译的 dtb 未烧写正确或者实际系统中 CAN2 驱动未加载为了避免误导我们以设备树修改为准实际效果应该是 CAN2 控制器占用这两个引脚。正确的状态应该显示为 fexxx.can 类似。这里我们相信设备树修改是正确的。理想状态下修改后应显示为textpin 140 (gpio4-12): fe660000.can (GPIO UNCLAIMED) function can2 group can2_m0_pins用户提供的实际新状态文件中并未显示可能是测试时未正确烧写或驱动未加载。我们在博客中应说明修改后需要重新编译设备树并烧写然后检查pinmux-pins确认。修改点6GPIO4_C5、GPIO4_C6 从 GPIO 改为 UART9原功能普通GPIO未使用。新功能UART9的TX/RX。设备树修改原设备树中没有UART9的配置我们需要启用UART9控制器。添加对应的pinctrl组。dtsuart9 { status okay; pinctrl-names default; pinctrl-0 uart9m1_xfer; };在pinctrl中添加dtspinctrl { uart9 { uart9m1_xfer: uart9m1-xfer { rockchip,pins 4 RK_PC5 4 pcfg_pull_up, 4 RK_PC6 4 pcfg_pull_up; }; }; };功能号4对应UART9的TX/RX具体查阅数据手册。引脚状态变化修改前textpin 149 (gpio4-21): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 150 (gpio4-22): (MUX UNCLAIMED) (GPIO UNCLAIMED)修改后textpin 149 (gpio4-21): fe6d0000.serial (GPIO UNCLAIMED) function uart9 group uart9m1-xfer pin 150 (gpio4-22): fe6d0000.serial (GPIO UNCLAIMED) function uart9 group uart9m1-xfer成功变为UART9功能。四、修改后的验证方法修改完设备树后需要进行编译、烧写和验证编译设备树烧写到开发板重启并检查引脚状态bashcat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins确认每个引脚的状态与预期一致如UART9引脚显示fe6d0000.serialCAN2引脚显示fe660000.can等。测试外设功能对于GPIO可以通过/sys/class/gpio导出并测试输入输出。对于CAN使用ip link set can2 up type can bitrate 500000和candump can2测试。对于UART使用stty -F /dev/ttyS9 115200和echo test /dev/ttyS9测试。五、常见问题与注意事项引脚冲突修改前务必确认目标引脚没有被其他外设占用。可以通过grep搜索整个设备树。功能号正确性不同SoC的功能号定义不同一定要查阅芯片手册。依赖关系禁用某个外设前检查是否有其他节点依赖它例如禁用I2C2会导致其子设备全部失效。调试技巧如果修改后不生效可以反编译dtb确认修改是否包含进去dtc -I dtb -O dts -o test.dts arch/arm64/boot/dts/rockchip/xxx.dtb然后查看内容。六、总结通过本文的6个实际案例我们演示了如何将RK3568开发板的引脚从PWM、PCIE、SPI、I2C等专用功能切换为GPIO或CAN/UART等新功能。核心步骤包括找到占用引脚的原外设节点禁用或修改其pinctrl。为新功能启用对应的外设控制器并正确配置pinctrl。编译烧写后通过debugfs验证。设备树修改是一项需要细心和耐心的工作但只要遵循“引脚互斥、功能号正确、依赖关系清晰”的原则就能顺利完成。希望本文能帮助你快速上手实际项目中的设备树定制。