ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RK3588 Type-C PD充电调试实战:从DTS配置到内核驱动

RK3588 Type-C PD充电调试实战:从DTS配置到内核驱动 RK3588 这颗芯片这两年出镜率实在太高了平板、开发板、边缘计算盒子、甚至一些轻量级 NAS 都在用。我最近在 RK3588 Android 12 平台上调 Type-C PD 充电踩了一圈 DTS 和内核驱动的坑之后发现这块内容网上资料其实不少但大多零散且停留在“能亮屏能跑”的阶段真正把 PD 协商、充电通路、电池充电策略串起来的文章很少。这篇就把我实际调试中的配置、修改、日志分析和排查思路完整写出来给正在做 RK3588 平台 PD 充电开发的朋友一个可以直接参考的底稿。1. 项目概述与整体架构1.1 这个项目到底在解决什么问题RK3588 的典型应用场景决定了它离不开 Type-C PD。无论是做安卓平板还是边缘 AI 盒子整机功耗动不动十几瓦甚至几十瓦Type-C 口如果不走 PD 协议协商出 9V、12V、15V 甚至 20V 的高压档位单靠 5V 供电根本扛不住系统的峰值负载。更别说产品还要兼顾数据、视频输出、USB 外设这些功能Type-C 口本质上已经从“充电接口”变成了“多功能 IO 入口”。但硬件上把 Type-C 口设计出来只是一半另外一半全在软件层DTS 里面的设备树节点要描述清楚这颗 TCPC 芯片挂在哪个 I2C 上、中断脚在哪里、支持哪些 PDO 电压电流档位内核驱动要负责在 Type-C 线插入时完成 CC 检测、PD 协议报文交换、功率协商然后把协商结果送到 charger 驱动最终控制充电芯片给电池灌电流。整个过程任何一个环节掉了链子轻则充电功率只有 5W重则完全充不进电甚至系统供电不足直接关机。所以这个项目的核心问题不是“怎么让 Type-C 口工作”而是“怎么让 Type-C 口在 PD 协议下实现预期的功率档位切换同时保证充电流程和 Android 系统层面的电源管理无缝衔接”。当你拿到一块新的 RK3588 主板适配 Type-C PD 充电的第一步往往不是改代码而是把整条链路梳理清楚。1.2 Type-C PD 充电全链路拆解为了后面调试不迷路我先把 RK3588 Android 12 下 Type-C PD 充电的整条链路拆开。从外到内依次是外部设备端PD 适配器 / PC USB 口 / 其他 Type-C 设备提供电源和协商对象Type-C 物理接口CC1/CC2 引脚上的电阻配置决定端口角色D/D- 用于 USB2.0 通信SBU 用于 DP Alt ModeTCPC 芯片也就是 Type-C Port Controller负责 CC 检测、发送接收 PD 物理层信号常见的就是 FUSB302、TUSB422 这类RK 平台上 FUSB302 用得最多TCPMType-C Port Manager在内核里对应drivers/usb/typec/tcpm/tcpm.c负责整个 Type-C / PD 状态机调度包括 attach/detach、SOP 报文收发、PDO 协商、电源角色切换等Charger 驱动控制充电芯片输出到电池的电压和电流常见的有 BQ25700、SY6970、SG2001 等Power Supply 框架内核的power_supply子系统把 charger、tcpc、battery 等设备虚拟化成电源节点Android 上层通过 sysfs 和 Health Hal 读取电量与充电状态这里面最核心的枢纽是 TCPM它往底层走通过tcpc_dev接口跟 TCPC 芯片打交道往上层走通过tcpc提供的接口把协商好的电源参数传给 charger同时还通过 typec class 和 extcon 驱动管理数据角色和供电角色。数据流向大概是这样的适配器插入后TCPC 芯片检测到 CC 引脚上的 Rd 或 Rp 状态产生中断TCPM 开始跑 Type-C 连接状态机在 CC 上拉/下拉电阻做电缆检测、SRC/SNK 角色确定然后如果双方都支持 PD就会在 VBUS 上发送 SOP 的“source capabilities”报文列出所有支持的 PDO比如固定 5V/3A、9V/2A、12V/1.5A 这样的档位RK3588 平台作为 sink 端也会发送 sink capabilities 和请求报文选定一个 PDO 后用 GoodCRC 确认最终适配器端切换 VBUS 电压完成协商。协商完成后TCPM 会把协商得到的电压电流写进一个typec_power_supply设备charger 驱动通过power_supply框架读取这个值作为输入限制写入充电芯片的输入电流/电压寄存器。这样一来硬件上的充电电流大小本质上是由 PD 协商结果决定的。1.3 DTS 与内核驱动如何分工搞清楚链路之后DTS 和内核驱动的分工就非常简单了DTS 描述“硬件长什么样、允许怎么工作”内核驱动负责“实际怎么跑起来”。DTS 层面我们主要配置三块内容。第一是 TCPC 芯片节点本身把它的 I2C 地址、中断、复位引脚、供电、输入输出角色定义好第二是 PD 策略数据支持哪些 PDO 档位、是 dual-roleDRP还是仅 sink、是否支持 PPS、source 和 sink 的能力值这些参数直接影响协商结果第三是 charger 节点和电源路径参数比如充电芯片的 I2C 地址、输入限流、充电限流、OTG 配置等。内核驱动层面则是完成 TCPC 芯片的寄存器读写、TCPM 状态机的运行、PD 报文的收发解析、充电芯片控制等。对普通产品开发而言TCPM 和 typec class 这些内核通用框架基本不需要大动真正需要修改的多半是 charger 驱动、TCpc 芯片驱动里的厂商私有逻辑以及跟平台相关的电源管理策略。一句话总结就是DTS 决定“能协商出什么档位”内核决定“协商出来之后怎么把电送到电池”Android 上层应用则展示“充到多少、功率多大”。这三层只要有一层配置错误整条链路就会出问题。2. DTS 配置核心细节2.1 tcpc 节点配置要点RK3588 平台上TCPC 节点一般挂在 I2C 总线上以 FUSB302 为例设备树里大概是这样的结构i2c2 { status okay; fusb302: fusb30222 { compatible fcs,fusb302; reg 0x22; interrupt-parent gpio1; interrupts RK_PA0 IRQ_TYPE_LEVEL_LOW; pinctrl-names default; pinctrl-0 fusb302_int; tusb422 0; /* 0: fusb302, 1: tusb422 */ tcpc-role dual; tcpc-power-supply-candidate 1; /* 0: pwr supply 不参与PD协商 */ }; };这里的几个关键字段挨个说一下。reg 0x22是 FUSB302 的 I2C 从机地址跟具体芯片硬件有关买模块时问清楚或者看芯片手册。interrupt-parent和interrupts定义 TCPC 的中断引脚要求这颗 GPIO 必须具备电平触发能力FUSB302 的中断输出是低电平有效所以触发方式是IRQ_TYPE_LEVEL_LOW。pinctrl里的fusb302_int是引脚复用配置把 GPIO1_A0 配成普通输入功能。tcpc-role dual表示端口是双角色端口既可以当 Source比如OTG对外放电也可以当 Sink插入适配器充电对应 DRP 模式。如果只做纯设备端、永远从适配器取电那就改成sink。我个人建议即使产品不需要对外放电DTS 里也先保留 dual因为调试阶段有可能会用到 OTG 功能验证后面再根据产品需求收紧也不迟。真正决定 PD 协商档位的是 tcpc 节点下挂的pd-data和source-pdos/sink-pdos信息。以做 sink 设备为例配置如下fusb302_data: fusb302_data { status okay; tcpc-role dual; pd-data { sink-info { sink-pdo-size 2; sink-pdo-list PDO_FIXED_5V_3A 0x0c, PDO_FIXED_9V_3A 0x0c; }; source-info { source-pdo-size 1; source-pdo-list PDO_FIXED_5V_1A 0x0c; }; }; };这里的PDO_FIXED_5V_3A是内核提供的宏定义展开后是一个 32 位数表示一个固定电压 PDO电压 5000mV、最大电流 3000mA。PD 协议里每个 PDO 占 4 字节内容包括电压、电流、功率上限等字段内核宏把这些字段按协议格式编码好了设备树里直接用宏就行。有一点值得注意sink-pdo-list不能说只是给 USB-PD 协议看的“能力声明”它实际上也会影响 TCPM 在协商时优先选择哪个档位。PD 协商流程一般由 Source 端发 capabilitiesSink 端选择一个 PDO 发 request。TCPM 会根据本地 sink 能力、当前系统功耗需求、电池剩余电量等条件决定请求哪一个档位。如果你把 9V 档放在 5V 的前面系统可能优先去请求 9V这在很多场景下不是最优解。建议产品上严格根据适配器能力来同步调整 PDO 列表比如适配器只支持 5V/9V 两档就只写这两档不要多写一个 12V。我曾经碰到过因为多配置了一个不存在的 20V PDO导致适配器始终无法完成协商、系统一直走 5V 默认电压的问题原因就是适配器不支持对应档位却收到了过高电压请求协议层面不稳定。2.2 Charger 与电源路径配置TCPC 协商出电压电流档位之后电要送到电池中间还要过 charger 芯片这一关。RK3588 平台上常见的 charger 有 TI 的 BQ25700、BQ25601还有 SG 的 SG2001、SY 的 SY6970 等配置方式大同小异。以 BQ25700 为例它挂在 I2C0 上DTS 节点大概长这样i2c0 { status okay; bq25700: bq257006b { compatible ti,bq25700; reg 0x6b; interrupt-parent gpio0; interrupts RK_PB2 IRQ_TYPE_LEVEL_LOW; pinctrl-names default; pinctrl-0 charger_int; ti,charge-current 2000000; /* 2A 充电电流 */ ti,charge-voltage 4352000; /* 4.352V 浮充电压 */ ti,input-current 2000000; /* 2A 输入限流 */ ti,input-voltage 5000000; /* 5V 输入电压限制 */ ti,watchdog-timeout 5000; /* 看门狗单位 ms */ }; };这里ti,charge-current、ti,charge-voltage、ti,input-current和ti,input-voltage是 charger 芯片的初始配置值。PD 协商完成之后TCPM 会根据新协商出的电压电流动态更新这些值比如协商出 9V/3A那输入电压限制会升到 9V输入电流限制可能是 3A 或按系统策略降为 2.25A充电电流则按电池温度和 SOC 阶段调整。这三个电流限制的概念很容易混淆我举一个实际场景PD 适配器协商出 9V/3A意味着 VBUS 侧能提供 9V、最大 3A 输入。charger 芯片内部有一个输入电流限制寄存器BQ25700 会限制从端口抽的电流不超过设置值。同时还有一个充电电流限制限制灌入电池的电流大小。这两个不相等因为系统自身负载也会消耗电流。比如系统跑着屏幕、CPU 满载要消耗 1A那 charger 的输入限流如果设成 3A扣除系统 1A实际能给电池充电的电流只有 2A。所以在 USB 充电调试时看到软件里输入限流 3A 但电池充电电流只有 2A这完全是正常现象不是驱动 bug。电源路径上还有一个隐蔽但重要的配置就是typec-power-supply-candidate和tcpc-power-supply-candidate这类字段。它们的作用是告诉 TCPM“哪个 charger 设备是跟这个 Type-C 口相关联的电源输入路径”TCPM 协商完 PDO 之后要把新的电源参数写到这个 charger 上。如果你有多路输入USB 口 圆形 DC 口 无线充电必须明确指定 PD 协商结果该跟哪颗 charger 关联否则 TCPM 写错节点充电芯片根本收不到指令。2.3 一套可直接参考的完整 DTS 配置下面贴一套我实际用过的、完整的最小配置覆盖了 RK3588 平台上单 Type-C 口 单颗 FUSB302 单颗 BQ25700 的典型组合。我把核心部分抽出来方便参考/ { fusb302 { compatible fcs,fusb302; status okay; i2c-bus i2c2; irq-gpio gpio1 RK_PA0 IRQ_TYPE_LEVEL_LOW; pinctrl-names default; pinctrl-0 fusb302_int; tusb422 0; tcpc-role dual; tcpc-power-supply-candidate 1; typec-power-supply bq25700; pd-data { status okay; id 0x29; pd_id 0x201; source-pdo-size 1; source-pdo-list PDO_FIXED_5V_1A 0x0c; sink-pdo-size 3; sink-pdo-list PDO_FIXED_5V_3A 0x0c, PDO_FIXED_9V_3A 0x0c, PDO_FIXED_12V_3A 0x0c; }; }; }; i2c2 { status okay; clock-frequency 400000; }; i2c0 { status okay; bq25700: charger6b { compatible ti,bq25700; reg 0x6b; interrupt-parent gpio0; interrupts RK_PB2 IRQ_TYPE_LEVEL_LOW; pinctrl-names default; pinctrl-0 charger_int; ti,charge-current 2000000; ti,charge-voltage 4352000; ti,input-current 2000000; ti,input-voltage 5000000; ti,watchdog-timeout 5000; }; };这套配置里有一个容易被忽略的点就是typec-power-supply bq25700这一条。它的作用是把 TCPC 节点和 charger 节点绑定起来TCPM 在完成 PD 协商后把功率更新到这个 charger 提供的 power_supply 设备上。有些平台资料里会写成别的名字比如power-supply或pd-charger但本质上都是在告诉 TCPM 去操作哪个 charger。如果产品有多个 Type-C 口或者还有无线充电输入就需要在 TCPM 的代码或策略里做输入源选择这是一个更复杂的主题我这里先不展开。单 Type-C 口的产品上面的配置基本够用。2.4 DTS 宏定义与内核接口对应关系PDO 在设备树里用的宏最终会编译成 32 位整数。以PDO_FIXED_5V_3A为例它本质上是这样一个位域结构#define PDO_FIXED(mv, ma, flags) \ ((mv) | ((ma) 10) | ((flags) 28))展开后大概就是0x0002C05A这样的值。这个宏在include/dt-bindings/usb/pd.h或内核的usb/pd.h里定义DTS 和内核驱动共用同一套定义避免了手工编码 32 位数带来的出错风险。所以设备树里写PDO_FIXED_5V_3A和内核层面读出来的值是一一对应的。顺带提一句PD 协议除了固定电压 PDO还有 PPS可编程电源APDO。PPS 允许系统在一定范围内动态调整电压电流比如 5V-20V 连续可调常用于高功率快充。RK3588 平台的内核也是支持的配置时会有类似APDO_VARIABLE_5V_20V_5A的宏但实际调 PPS 需要适配器端也支持 PPS 协议而且 PPS 下电压切换对充电芯片的控制算法要求更高。如果产品没有明确的 PPS 需求我个人建议在 DTS 里先不配 PPS把固定 PDO 档位调好再说不然很容易引入额外的不稳定因素。3. 内核驱动适配与修改实战3.1 驱动调用链分析设备树配好之后真正的软件逻辑在内核驱动里。常见的 RK3588 平台 Android 12 内核中跟 Type-C PD 相关的代码路径有这么几块drivers/usb/typec/tcpm/fusb302.cFUSB302 芯片驱动实现tcpc_dev结构体里的 read/write/interrupt 等回调drivers/usb/typec/tcpm/tcpm.cTCPM 核心Type-C 状态机和 PD 协议状态机都在这里drivers/usb/typec/class.ctypec class 设备向上层暴露 typec port、partner、cable 等 sysfs 接口drivers/power/supply/charger/xxx.c具体 charger 芯片驱动drivers/power/supply/rockchip_typec.c或drivers/usb/typec/tcpm/tcpc_notify.c平台相关的中转代码把 TCPM 的 power supply 事件转发给 charger 驱动调用链大概是FUSB302 检测到插入中断后调用tcpci_irq()接口TCPM 里通过tcpm_do_irq_work处理这个中断进入tcpm_state_machine开始跑类型 C 状态机。当状态机推进到SNK_DISCOVERY、SNK_WAIT_CAPABILITIES、SNK_SELECT_CAPABILITY等状态时会调用tcpm_pd_send_request发送 PD 请求。PD 协商完成之后TCPM 会调用tcpsm_set_vbus或tcpc_set_power_supply这些函数最终把新的 VBUS 电压、电流限制值送到 charger 驱动。charger 驱动这边通常注册一个power_supply设备type 是POWER_SUPPLY_TYPE_USB或者POWER_SUPPLY_TYPE_MAINS。TCPM 通过power_supply_set_property或者直接操作 charger 驱动的私有接口更新POWER_SUPPLY_PROP_ONLINE、POWER_SUPPLY_PROP_VOLTAGE_MAX、POWER_SUPPLY_PROP_CURRENT_MAX等属性。charger 驱动收到这些属性变化后内部状态机会重算所有限流值并写入充电芯片寄存器。BQ25700 内部有寄存器和状态机需要周期性检查输入电压是否在合理范围如果系统负载突变导致输入电压跌到阈值以下BQ25700 需要降低输入电流或者设置最小输入电压限制。这个逻辑是 charger 驱动里的经典难点。3.2 常见修改点有哪些用户拿到的 SDK 大多已经带了一套默认的 DTS 和驱动但做产品时几乎总要改几处。第一处是 PDO 列表调整。客户提供的适配器支持什么档位DTS 里的sink-pdo-list就要同步调整否则会出现协商档位过高、充电不稳定或者协商档位过低、充电功率不足的问题。这个修改不是简单的增删 PDO还要注意顺序因为 TCPM 默认会按列表顺序去请求。第二处是充电曲线调整。BQ25700 这类芯片支持完整的充电管理逻辑包括 pre-charge、fast-charge、float voltage、charge termination 等。RK3588 平台默认的充电电压电流参数不一定是电池规格要求的最优值。比如电池浮充电压 4.4VSDK 默认 4.352V虽然也能充但电池充不满如果电池支持快充充电电流也可以从 2A 提到 3A 甚至更高。这里要跟硬件工程师核对电池数据手册稳妥起见还是按照电池规格逐一验证。第三处是输入限流策略。PD 协商出 9V/3A 之后实际输入限流不一定直接设为 3A因为系统负载、充电芯片发热、电池温度等都会影响安全电流。很多产品会做一个“动态输入限流”策略比如屏幕亮起时输入限流降低息屏待机时才允许最大输入限流。这个逻辑通常放在 charger 驱动的set_property回调里跟 TCPM 联动。第四处是兼容性的适配器兼容处理。市面上不少 QC2.0/QC3.0 的适配器也实现了 Type-C 口的 DCP/CDP 模式但不一定完整支持 PD 协议。那 TCPM 在拔掉适配器或适配器遇到异常时就要能回退到默认的 5V 充电模式这个回退逻辑如果不完善产品可能在某几个特定适配器上出现无法充电或充得很慢的问题。3.3 日志、节点与常见调试手段内核驱动改完之后怎么验证配置生效光看系统设置里的“正在充电”完全不够。我建议优先打开这几类内核日志和节点TCPM 驱动有独立的 debug 开关。内核配置里打开CONFIG_TYPEC_DP_DBG或者直接在内核 cmdline 中传入tcpm.dbg1可以在dmesg里看到详细的 PD 状态切换记录。我实际最常用的命令# 查看 USB/PD 相关内核输出 dmesg | grep -E tcpm|fusb|typec|charger|bq25700|pd|usb日志里通常会出现类似这样的关键行[ 12.345678] tcpm: source capabilities: 5000mV 3000mA [ 12.346000] tcpm: sink capabilities: 5000mV 3000mA, 9000mV 3000mA [ 12.347111] tcpm: cc10 cc23 vbus0 - SNK_DISCOVERY [ 12.348222] tcpm: Got source caps: 5000mV, 9000mV, 12000mV [ 12.349333] tcpm: Requesting 9000mV 3000mA [ 12.351111] tcpm: PD_RESET, returning to SNK_UNATTACHED日志里如果停在Requesting 9000mV但没有出现VBUS changed或者适配器不响应那多半是 PDO 匹配失败或适配器不支持该电压档位。此时会反复PD_RESET日志会一直刷状态机重跑的信息。除了 dmesgsysfs 节点也是快速判断协商结果的好工具。插入适配器后可以查看# 查看 typec port 当前连接状态 cat /sys/class/typec/port0/port_type cat /sys/class/typec/port0/power_role cat /sys/class/typec/port0/data_role cat /sys/class/typec/port0/partner/source_caps # 查看 charger 的输入限制和充电状态 cat /sys/class/power_supply/usb/voltage_max cat /sys/class/power_supply/usb/current_max cat /sys/class/power_supply/main_charger/statussource_caps是适配器宣告的能力voltage_max和current_max是当前协商出的输入上限。这两组数值一对比就能立刻看出协商档位是不是符合预期。如果voltage_max还是 5000000说明 9V 档位根本没协商成功。4. 常见问题与排查实录4.1 问题速查表我把调试中遇到的高频问题做成了速查表按现象、可能原因、定位方法、解决办法四列整理方便你按图索骥。现象可能原因定位方法解决办法插适配器完全无充电反应TCPC 中断脚错误 / I2C 通不上 / 硬件 CC 上下拉不对dmesg 看 fusb302 是否 probe 成功、是否有 IRQ 触发核对 DTS 里 interrupt 和 pinctrlI2C 上先独立读寄存器验证通路一直 5V 充电无法协商到 9V/12V适配器不支持 PD / PDO 列表不匹配 / TCPM 未进入 PD 协商流程查看 source_caps 是否只列出 5V确认适配器规格和 sink 能力一致检查 TCPM firmware 版本协商到 9V 后系统重启或保护charger 输入电压限制或系统负载超过了电源能力示波器抓 VBUS 波形查看 charger 寄存器 OVP/UVP 状态降低 PDO 电流档位调整 charger 输入限流增加 VBUS 电容充电电流远小于预期输入限流被压低 / 系统负载吃掉电流 / 电池温度限制查看 main_charger/type 的 current_max 与 charge_current检查动态限流策略核对电池温度曲线拔线后系统立即掉电关机VBUS 掉电时序差 / 充电路径未及时切换 / PMIC 掉电检测不对抓拔线瞬间波形、看 dmesg 有没有 PD_DISCONNECT检查 TCPM 的 disconnect 处理VBUS 掉电时及时切换到电池供电dmesg 中fusb302: probe failedI2C 地址错误 / 供电没上 / 总线挂死I2C 工具独立读地址确认硬件电路检查 DTS 中 reg 值和实际 I2C 地址4.2 典型排查案例我挑三个实际项目里印象比较深的排查过程仔细写一写。第一个是“DTS 里配了 9V/3A但实际协商只能到 5V/2A”。当时用的是某品牌 65W 氮化镓适配器支持标准的 PPS 和 5V/9V/12V/15V/20V 固定档。DTS 里 sink-pdo-size 写的是 3配置了 5V/3A、9V/3A、12V/3A。结果 dmesg 里 source capabilities 确实列出了 5V、9V、12V、20V但 TCPM 请求 9V 后适配器端没回应反复 PD_RESET系统最终回退到 5V/2A。后来查了半天发现是一个很傻的坑sink-pdo-list的每一项都应该带0x0c这样的高低字节标志但我第三组 PDO 后面没带导致内核解析出错。这类格式类问题DTS 写完后一定要先用dtc编译确认字节码正确再烧到板子上。第二个是“协商到 9V 后整机电流哗哗涨charge 电流反而上不去”。这个案例背后是热设计问题Type-C PD 协商拉到 9V/3A 之后输入功率到 27W整机系统负载在 10W 左右理论上电池快充电流可以到 3A 以上。但实际测出来充电电流只有 1.2A。后来查日志发现charger 驱动里的charge_current被电池温度曲线限制了电池温度到了 45℃被策略压低了充电电流。这不是软件 bug而是产品定义里的温控策略开发时如果不知道这层策略很容易误判为驱动问题。第三个是“拔线后系统直接关机”。这个案例很折腾现象是适配器在系统满载时被拔掉RK3588 整机立刻掉电重启。抓波形发现 VBUS 电压跌落的瞬间系统负载还挂在 VBUS 侧而 battery 的电能通路还没切换过来。后来在 charger 驱动里加了掉电中断快速切换逻辑当检测到输入源拔出时先把 VSYS 切换到电池供电再处理 PD 断开事件。这个顺序必须在驱动里显式控制否则 PMIC 的掉电检测比 TCPM 状态机快还没来得及切电池系统就已经欠压掉电了。4.3 一些实在的调试经验最后说几个调试过程中的通用经验这些在很多平台上都适用。第一个是善用 sysfs 节点而不是一上来就抓协议分析仪。协议分析仪能精确看到 SOP 报文内容和时序但对板级工程师来说成本太高、操作也繁琐。先用/sys/class/typec和/sys/class/power_supply这两个目录里的节点快速判断协议走没走通、档位有没有协商成功大多数问题在 sysfs 层面就能定位到 80%。只有遇到协议层疑难杂症时再上 TCPDump 或者协议分析仪效率反而更高。第二个是把 DTS 的改动记录跟 git log 绑定每一次 PDO 调整、每一个限流参数变化都写清楚 commit 说明。PD 充电涉及到电源策略和电池安全跟其他驱动的调试不一样参数改动如果靠“大概试一下”的心态后面把电池充胀了或者把充电芯片烧了才后悔。我自己的习惯是每次改完参数先做一轮 10 分钟满载充电测试确认 VBUS、VSYS、电池电压都稳定之后再做 5V/9V/12V 各档位的切换测试。第三个是看重启前后差异。有些问题只在冷启动时出现有些问题只在热重启后出现。比如 TCPC 芯片和 charger 芯片的 I2C 初始化时序如果 PMIC 的某个 rail 供电晚于 I2C 总线初始化charger 驱动 probe 时读寄存器会失败系统可能进入一个异常的默认状态。遇到这种问题dmesg 和 sysfs 都看不出明显错误但热重启后完全正常冷机必现基本就是供电时序的问题需要硬件工程师配合确认上电顺序软件上通过 DTS 里 regulator 的regulator-boot-on和regulator-always-on配置来做初步规避。第四个是强烈建议给充电链路加一层“黑盒测试脚本”就是用 shell 脚本定期检查 sysfs 节点状态在自动化测试或者远程调试时有奇效。比如惊讶到一个适配器的 source_caps 变化、charger 的 current_max 保持在预期值、电池电压在充电时缓慢上升等。把这层监控加在项目的编译产物里哪怕只是跑一晚上第二天翻 log 也能发现很多随机性充电问题而不是一天到晚蹲在实验室里插拔适配器。5. 后续扩展方向Type-C PD 充电调通之后很多衍生功能就顺理成章了。一方面可以做 OTG 反向供电把 RK3588 设备变成一个大功率移动电源类型的外设另一方面可以对接 DP Alt Mode把 Type-C 口用于视频输出这时候 PD 的 dual-role 切换和 DP 带宽协商会更有意思。如果整机还支持无线充电或其他 DC 输入那电源路径管理Power Path Management和输入源切换Input Source Selection就会变成新挑战而 PD 协商的参数也会参与这些调度。根据我个人经验第一次调通 PD 充电一定要把协议栈层次理清楚多借助 sysfs 和 dmesg 观察而不是盲目改驱动代码。DTS 里的 PDO 列表和电源策略配置值得花一个星期时间去逐一推敲和实测这段投入会在后面整机可靠性测试里省下大把时间。这篇文章里的 DTS 片段和驱动调用链都是我实际调试时用过的或观察到的通用实践虽然具体寄存器数值还是要以你手里的硬件原理图和 SDK 版本为准但整体框架和排查思路换哪颗 charger、换哪种 TCPC 芯片都是通用的。希望这些内容能帮你少踩几个坑让 Type-C PD 充电在 RK3588 平台上一把点亮。
返回列表