RK3588平板电源管理:BQ25703充电与CW2015电量计DTS配置实战 做RK3588平板项目电源链路从来不是“能开机就行”那么简单。CPU、内存、屏幕、外设的功耗叠在一起电池要能充得进、放得出还要配合Type-C PD协议把快充跑起来这时候光靠主PMIC根本应付不过来。我最近一块RK3588平板方案里就同时用了TI的BQ25703做充电管理、赛微电子的CW2015做电量计两个器件都要在设备树DTS里把节点配好系统才能正确识别、充电、上报电量。这篇就按我实际移植的过程把这套DTS配置从头到尾捋一遍。写这篇的目的很简单很多朋友在RK3588上移植Ubuntu、调外设的时候一翻到电源相关DTS就头疼网上资料东一句西一句寄存器级的东西又多。其实BQ25703和CW2015的配置没有想象中那么玄只要你把硬件连接、驱动解析的字段、以及调试验证路径这三个点串起来基本就能一次跑通。需要说明一下本文不针对某一个固定SDK版本。我会以我手头这份RK3588 Linux 5.10内核的写法为主同时告诉你哪些字段在不同版本里可能改名、该如何自查。这样你换一套SDK、换一块板子也能沿着同样的方法把它搞定。文中涉及的具体节点参数都是基于常见实践的合理方案你拿到自己的板子后一定要对着原理图逐个核对。1. 先弄清楚BQ25703和CW2015在这块板子上到底各管什么1.1 BQ25703充电控制器而不是一颗简单的充电IC很多人第一次见BQ25703都会把它和TP4056这类线性充电IC相比但两者完全不是一个量级。BQ25703是TI的NVDC架构开关模式充电控制器支持1到4节锂离子/锂聚合物电池。它的核心价值在于“路径管理”当适配器接入时系统负载优先由适配器供电剩余电流再充给电池适配器移除时电池无间断接管系统供电。这个特性对平板这种频繁拔插适配器的产品太重要了系统不会因为电源切换而重启。BQ25703的所有充电参数包括充电电流、截止电压、输入电流限制、OTG输出电压等等都是通过I2C/SMBus接口写寄存器配置的。DTS的作用就是把驱动需要的信息——挂在哪个I2C总线、中断脚是哪根、默认电流电压多少——告诉内核驱动起来后再通过寄存器完成具体控制。这里有个点值得特别注意BQ25703内部有看门狗机制寄存器配置完成后如果一段时间内没有通过I2C刷新芯片会主动复位寄存器到默认状态充电过程可能因此中断。所以DTS里watchdog的时长、驱动是否持续刷新都要仔细设计。1.2 CW2015真正意义上的“电量计”CW2015是赛微电子CellWise的一颗单节锂电池电量计I2C接口默认7位地址是0x62。它和直接用ADC采电压、再查表推测电池百分比的做法完全不同。CW2015会根据电池的电压、电流、温度以及内置的电池特性参数profile用厂商的算法估算剩余容量。充电或放电过程中它还能对库仑计做动态补偿让SOC不会因为负载变化剧烈而疯狂跳变。不过CW2015的算法依赖一份电池profile配置。这份配置里包含满充电压、空电电压、内阻、OCV曲线等参数。如果DTS里没有正确写入profile或者写的是别的电芯的参数电量计工作起来的表现就是刚充到100%一拔充电器就掉到90%或者放完电自动关机之后再开机又显示20%。这些现象我后面排错部分会细讲这里先立个flagCW2015的DTS配置绝大多数坑都出在profile上。1.3 为什么RK3588平板方案喜欢这对组合做RK3588平板核心供电一般交给RK806这颗PMIC它负责给CPU、LPDDR、eMMC等提供多路电源。但RK806并不包含锂电池充电管理和电量计功能。平板产品需要有Type-C口充电需要支持PD快充需要显示电池百分比所以必须在外围搭charger加电量计BQ25703加CW2015就是非常典型的一套方案。把接线逻辑理清之后分工就非常清楚功能BQ25703CW2015充电电压/电流控制负责不参与输入限流、PD配合负责不参与OTG反向供电支持不参与剩余电量SOC估算不参与负责电池健康/温度采样部分ADC能力支持温度、电压、电流采样搞清楚了分工后续DTS里每个节点该放哪些属性心里就不会乱。这里多说一句有些方案会把电量计功能集成在charger里连I2C都省了但BQ25703本身不做电量算法所以需要CW2015这类专用电量计来补位这也是这套组合在RK3588公板上出现频率高的原因。2. 改DTS前先花十分钟做三件事2.1 先看原理图别急着打开dtsi改DTS最大的误区就是拿别人板子的节点过来直接抄。即便都是RK3588BQ25703可能挂在I2C0上也可能挂在I2C4上中断脚可能接GPIO1_B2也可能接GPIO3_C5。所以第一步永远是打开自己板子的原理图确认三件事两颗芯片分别挂在哪条I2C总线上。I2C地址是多少BQ25703一般是0x6BCW2015一般是0x62但硬件上的地址引脚不同实际地址可能有变化。有没有中断脚/Alert脚接到了SoC的哪个GPIO是高有效还是低有效。这些信息会直接对应DTS里的reg、interrupts、pinctrl三个字段。我自己就犯过一次错BQ25703的中断脚在原理图上是低有效但我在DTS里写成了IRQ_TYPE_LEVEL_HIGH现象是内核启动后中断风暴dmesg刷屏整机卡顿。这种问题不查原理图光靠猜能折腾你一下午。2.2 确认内核里有没有对应驱动Rockchip的Linux SDK和Android内核里通常会带BQ25703和CW2015的驱动但不同版本的SDK不一定都齐全。改节点之前先在内核源码里搜一下grep -rn bq25703 kernel/drivers/power/supply/ grep -rn cw2015 kernel/drivers/power/supply/如果没有对应驱动即使DTS写得再完美设备也挂不起来。这时候要么从上游Linux内核移植驱动要么看SDK里是否有相近的芯片驱动可以替换。这里提醒一点BQ25703在标准内核里有时候写作bq25700compatible可能是“ti,bq25700”这种细节要在驱动源码里看到实际解析的compatible再来决定DTS怎么写。2.3 想清楚设备树会烧到哪里RK3588平台常见有两种情况如果烧的是Linux SDK设备树一般会被打进boot.img里或者在单独的dtb分区如果用的是Android那通常还有一个dtbo overlay分区。改DTS之后编译和烧录方式完全不同。所以我每次改设备树前都会先确认当前板子的烧录方式避免出现“改了DTS、编译了内核、烧进去却没生效”的尴尬。具体怎么确定可以先看SDK的文档也可以直接把当前boot分区里的设备树dump出来反编译对比。这一步花不了几分钟但能省下后面大量的无效重启时间。3. BQ25703充电节点的DTS配置逐字段拆解3.1 一份可参考的BQ25703节点下面这份节点以我手头RK3588 Linux 5.10内核的写法为例主控I2C我放在i2c3上实际以你原理图为准i2c3 { status okay; bq25703: bq257036b { compatible ti,bq25703; reg 0x6b; interrupt-parent gpio1; interrupts RK_PB2 IRQ_TYPE_LEVEL_LOW; pinctrl-names default; pinctrl-0 bq25703_int_l; ti,charge-current 2000000; ti,max-charge-voltage 4400000; ti,input-current-limit 3000000; ti,watchdog-timeout-ms 40000; ti,otg-voltage 5000000; ti,otg-current 500000; }; };先说明一点不同SDK版本的BQ25703驱动of_property的命名不一定完全一致。你拿到的源码里可能叫ti,charge-current也可能叫ti,charge_current这是正常的。我建议先打开bq25703_charger.c文件搜索“of_property_read_u32”看看驱动到底解析了哪些字段再用实际字段名来填。下面的解释主要是帮你理解每个字段的业务含义理解之后不管字段名怎么变你都能认出来。3.2 字段含义不是“填个数”背后是电源策略reg 0x6b是芯片的7位I2C地址。BQ25703的地址一般由ADR引脚的电平决定。如果你确定走的是0x6B这条地址但i2cdetect扫不出设备先别怀疑地址错误优先查供电和I2C上拉。芯片没上电地址写对了也扫不到。interrupts和pinctrl-0是配套的。BQ25703有一个INT引脚充电状态变化、输入源插入、看门狗超时都会拉这个脚。DTS里必须把对应的GPIO复用配好否则驱动无法收到中断系统会出现“插上充电器界面没反应”的情况。中断有效电平的极性一定要对着原理图查这地方我踩过坑后面排错部分会详细说。ti,charge-current 2000000设置默认充电电流单位uA。默认2000mA对大多数平板电芯来说比较适中。如果你的电池规格是5000mAh常规0.5C充电就是2500mA可以设到2500000但前提是板子的充电散热要压得住。量产产品做高倍率充电时一定要实测电池温度和MOS管温度这个参数往往不是电池决定的而是整机热设计决定的。ti,max-charge-voltage 4400000这是截止电压。单节锂电常见4.2V、4.35V、4.4V取决于电芯化学体系。写高了对电池寿命有影响写低了充不满续航打折。这个值必须跟电池规格书核对千万不能拍脑袋。如果电池标注的充电限制电压是4.35V你给个4.4V短期看不出问题几十个循环后电池鼓包风险剧增。ti,input-current-limit 3000000输入电流限制单位uA。这个值决定了从适配器最大能抽多少电流对PD快充尤其关键。一般PD适配器会通过Type-C协商给到一个电流值但BQ25703本身还有一个静态的输入限流值兜底。两者之间驱动会按合理逻辑切换DTS里给的是一个默认档位。ti,watchdog-timeout-ms 40000看门狗超时时间。BQ25703的看门狗机制我前面提过如果超过设定时间没有I2C写操作芯片寄存器会全部回到默认状态。Rockchip的驱动一般会周期性刷新看门狗所以DTS里给一个40秒的超时是常见做法。如果设得太短比如5秒而又恰好碰到I2C总线拥堵芯片容易无故复位充电电流突然归零你会看到充电状态像抽风一样一下有一下没有。OTG相关字段如果平板支持OTG也就是要通过Type-C口反向给U盘、手柄这类设备供电就需要配置OTG电压和电流。BQ25703可以把电池电压升压从VBUS输出输出电压范围挺宽。不需要OTG的产品这里可以留空但如果你SDK的DTS模板里默认打开了OTG而硬件上又没有走BQ25703的VBUS路径一定要关掉否则可能影响正常充电。3.3 编译、烧录、快速验证DTS文件改完后在RK3588的Linux SDK中内核编译一般是cd kernel make ARCHarm64 rockchip_linux_defconfig make ARCHarm64 rk3588-evb.img -j$(nproc)这里rk3588-evb.img会包含内核和设备树。如果你想单独编译dtb可以用make ARCHarm64 dtbs编译产物在arch/arm64/boot/dts/rockchip/下对应你板子dts文件名。烧录方式要看你板子的引导策略。如果设备树是独立分区可以用fastboot或rkdeveloptool单独烧dtb分区如果是放在boot分区里就要整包烧boot。烧完开机后第一件事看dmesgdmesg | grep -i bq25703如果DTS节点成功匹配你会看到驱动probe成功、power_supply注册的日志。然后看sysfsls /sys/class/power_supply/ cat /sys/class/power_supply/bq25703-0/statusstatus能读到Charging / Not charging / Full这类状态就说明驱动已经正常工作。里面涉及的节点名因内核版本而异有可能叫bq25703-0也可能直接叫charger先ls再cat不要假设名字一定一样。4. CW2015电量计DTS配置参数对了百分比才靠谱4.1 基本节点结构CW2015我放在i2c2上节点写法如下i2c2 { status okay; cw2015: cw201562 { compatible cellwise,cw2015; reg 0x62; cm-i2c-tx-error-disable; interrupt-parent gpio0; interrupts RK_PB1 IRQ_TYPE_LEVEL_LOW; cw2015,irq-gpio gpio0 RK_PB1 GPIO_ACTIVE_LOW; bat_config_info 0x15 0x42 0x88 0x5e 0x70 0x60 0x55 0x5a 0x5d 0x66 0x65 0x66 0x6d 0x75 0x74 0x78 0x75 0x5f 0x4e 0x44 0x42 0x3f 0x3d 0x3c 0x3b 0x3a 0x39 0x38 0x37 0x36 ; }; };同样属性名要以你SDK里cw2015驱动为准。我见过内核里不同的写法有的用bat_config_info有的用cw2015,bat_config_info。但核心思路一致驱动需要从DTS拿到一份电池特性配置数组。4.2 最关键的bat_config_info是怎么来的这是CW2015配置里最核心、也最容易让人一头雾水的一步。上面那一长串十六进制数组不是随便写的而是根据电池厂商提供的电芯参数经过换算得到的一份“profile”。一般流程是找电池厂要电芯的OCV表、内阻数据和容量参数。用CellWise官方的配置工具CW2015 Configuration Tool导入这些数据工具会生成一个可以写入芯片RAM的配置块。在工具里导出为十六进制数组填进DTS的bat_config_info。如果你拿不到官方工具也可以找同容量、同体系电芯的接近参数先顶上但之后一定要实测校准。这里的实测校准包括充满到4.4V时电量计显示100%放电到截止电压时显示0%而且整个放电过程SOC曲线不能出现大跳变。我遇到过客户把3.7V平台的电芯参数硬套到4.4V电芯上结果电量计在40%时直接跳到0%导致平板提前关机这个体验是灾难级的。4.3 校准、报警阈值与上报间隔CW2015节点里如果驱动支持通常还有这几个参数可以调设计容量mAh单位用于SOC归一化计算。低电量报警阈值比如剩余10%时触发中断。采样/上报间隔多久更新一次容量、电压、电流值。平板产品上我一般会把低电量阈值设到8%到12%之间。设太高系统会频繁弹低电量提醒设太低用户在低电量下玩游戏电池瞬时跌到截止电压直接关机体验更差。这个值要跟产品定义走没有绝对标准。如果你做的是行业平板或者带备用电池的设备阈值策略还会更复杂但DTS层面能做的就是把中断阈值和initial capacity两个参数设对。4.4 如何用sysfs验证电量计真的在工作启动后先确认节点ls /sys/class/power_supply/cw2015-0/ cat /sys/class/power_supply/cw2015-0/capacity cat /sys/class/power_supply/cw2015-0/voltage_now cat /sys/class/power_supply/cw2015-0/current_now容量显示、电压值、充放电电流数值都在合理范围内就说明I2C链路没问题。接下来重点看动态表现插上充电器capacity应该缓慢上升拔掉充电器跑一个大型应用给电池放电capacity应该平滑下降。任何一步出现“卡住不动”或者“跳水”基本就是profile参数与电芯不匹配回到4.2去校准。这里有个小技巧用脚本每隔几秒记录一次voltage_now和capacity边放视频边跑能看出很明显的对应关系。5. 排错实录从“插电没反应”到“百分比跳变”的完整排查链5.1 i2cdetect扫不到芯片先别怀疑“DTS写错”现象开机后dmesg没有两个驱动的probe日志用i2cdetect扫也看不到设备地址。我的排查链路是这样走的确认I2C总线已使能。看DTS里对应I2C节点有没有status okay如果没有扫描当然一片空白。确认扫描的总线号正确。打开/sys/bus/i2c/devices/看控制器注册成i2c-几。很多人扫错总线查半天发现根本不是那一路。量硬件供电。BQ25703的VIN来自VBUS有些开发板上不插适配器时芯片整颗都不工作自然扫不到地址。CW2015通常由系统电源供电只要系统起来了它就该在总线上。查I2C上拉电阻。这个最容易忽略。I2C总线需要上拉电阻如果PCB上漏贴或者焊错总线被拉死或者信号畸形i2cdetect会扫到一堆随机地址或者直接超时。确认地址硬件无偏移。CW2015的地址引脚如果被外部拉高拉低0x62可能变掉用工具扫描整段总线是最快的方法。5.2 能充电但电流始终上不去现象插上支持快充的适配器BQ25703能充电但电流只有500mA。这个问题在RK3588平台上很典型常见原因有三类USB PD协商没有完成。Type-C口的PD协商是由SoC内部的PD控制器完成的协商结果要传递给充电驱动充电驱动再去设置BQ25703的输入电流和充电电流。如果PD驱动和charger驱动之间没有正确关联很多内核里是通过extcon或usb_role机制联动系统会一直按默认的USB 500mA来限流。DTS的input-current-limit设置过低。直接改大DTS里的默认输入限流通常能立竿见影。但要注意这个值不能盲目超过适配器能力否则适配器会被拉挂。BQ25703寄存器处于watchdog复位后的默认值。这个我遇到过一次驱动probe正常但看门狗没被周期性喂芯片寄存器回到默认的小电流模式。排查这类问题时我通常是边充电边反复cat几个节点cat /sys/class/power_supply/bq25703-0/status cat /sys/class/power_supply/bq25703-0/current_now cat /sys/class/power_supply/bq25703-0/input_current_limit如果input_current_limit显示只有500000而你的适配器是20W以上那问题多半在PD联动或者DTS默认值上。先在DTS里把默认input-current-limit提高到2000000以上通电看电流是否跟着变。如果不变说明驱动没有真正写入寄存器要去查I2C通信和看门狗刷新逻辑。5.3 电量百分比跳变问题基本锁定在profile现象电池充满显示100%拔掉充电器五分钟内掉到95%或者边充边玩时百分比从80%直接跳到87%又跳回来。这不是RK3588的问题而是CW2015这类电量计在profile不匹配时的典型症状。排查时我会做一次完整的充放电循环用恒流恒压电源把电池充到截止电压并保持到电流小于截止电流记录电量计显示的容量。静置1小时记录电压和SOC。以固定电流放电到截止电压记录放电曲线和SOC变化。把实测数据和DTS里的profile参数对比。最直接的修复方式就是拿到正确的电芯数据重新生成profile填进DTS。如果没有官方工具也可以用对比法选一个容量接近、电压平台一致的已有profile试跑一个循环看SOC曲线是否合理。注意不同电芯的OCV曲线在高低端差异很大不能靠猜。5.4 中断风暴与内核日志刷屏现象开机后系统卡顿dmesg里不停刷充电中断相关的日志/proc/interrupts里对应中断计数飞涨。这是中断配置极性不对的典型表现。BQ25703和CW2015的INT脚通常默认高电平事件发生时拉低。如果你的DTS里把IRQ_TYPE写成了LEVEL_HIGH芯片空闲时反而一直触发中断驱动在处理正常中断却永远清不掉。排查方式先在DTS里把中断改成IRQ_TYPE_LEVEL_LOW重启看症状是否消失。若还不行把该中断脚对应的pinctrl配置确认一遍看看GPIO是不是被复用成了其他功能。还可以在驱动里临时把这个中断请求去掉确认是硬件中断问题还是驱动中断处理函数的问题。我自己在处理BQ25703时还遇到过中断脚被另一个外设的pinctrl覆盖导致probe失败。最终定位的方式是把对应GPIO在DTS里单独建一个pinctrl group并在BQ25703节点里明确引用彻底断开和其他外设的复用冲突。下面这张表是我常用的排查对照现象可能原因优先检查项DTS里的解决位置i2cdetect扫不到I2C未使能/地址不对/硬件没供电总线号、地址、供电I2C节点status、reg充电电流只有500mAPD联动没建立/限流默认太低extcon/usb_role关联、input_current_limitinput-current-limit、PD相关节点电量百分比跳变profile不匹配充放电曲线对比bat_config_info中断刷屏中断极性/GPIO复用错误/proc/interrupts、dmesg极性interrupts、pinctrl-06. 从“能充”到“充得好”几个值得记录的调优经验把BQ25703和CW2015的DTS配到能开机、能充电、电量能显示这只是第一步。真正到量产阶段有几个点我会反复折腾。充电电流要和整机散热一起看。平板产品内部空间紧张BQ25703周边的电感、MOS管在2A以上电流时升温明显。我测过某块板子在3A充电时充电IC附近温度能到60多度。所以DTS里的charge-current不能只按电池能承受多大电流来填还要考虑壳温、充电时长和电池循环寿命。量产前的温度测试一定要做不能只在常温下看数据。CW2015的profile不是一劳永逸的。电池随着循环次数增加内阻会变大容量会衰减原始profile的精度会下降。产品如果支持OTA建议在系统里预留电量计校准入口如果不支持就要在出厂前把老化后的电芯数据也测一遍至少在配置上做一个折中。这里我个人的做法是拿全新的电芯和循环200次的电芯各测一组数据取一个中间配置保证整个生命周期里的SOC误差不会太离谱。DTS参数命名在不同SDK中真的会变。我见过同一个TI驱动在Rockchip 4.19内核里解析的是ti,charge-current在5.10里就换成了别的名字甚至有驱动直接不解析外部属性强制用宏定义。所以每次换SDK都要重新grep一遍驱动源码确认字段名、默认值、编译开关不要盲目沿用旧DTS。这个习惯能省下大量重复踩坑的时间。还有一个容易被忽略的点RK3588平台上的Type-C PD和充电驱动是两套子系统它们的耦合关系在不同内核版本里差异很大。如果你发现DTS配置都正确、驱动也加载正常但PD快充就是跑不起来多半要去查PD驱动的policy engine里有没有把协商得到的电流传递给充电驱动的回调。这个回调有时候是通过extcon事件上报有时候是通过direct charger接口方向找对了才能把“快充”这最后一公里走通。以我个人的实测感受这组充电和电量计配置只要把硬件原理图、驱动源码、sysfs验证三条线串起来DTS主体通常两个小时就能搞定。剩下的大量时间基本都花在profile精度和充电策略的细调上。这也是我一直强调的DTS不是抄完就结束关键是要理解每个字段背后的电源策略再用实测数据去校正它。希望这篇能把你在RK3588电源适配路上的弯路子都垫平一次就把BQ25703和CW2015跑稳。