
泰山派PD充电&放电+电量计方案验证
简介
支持对内PD充电,对外放电。应用场景一个C口可以充电和插入USB设备并对USB放电
简介:支持对内PD充电,对外放电。应用场景一个C口可以充电和插入USB设备并对USB放电开源协议
:GPL 3.0
描述
PD快充+电量计验证板
1. 介绍
支持PD快充协议,可以自定义申请PD协议电压和电流参数,支持参数自定修改充电的电流、截止电压、等参数。
且支持自动切换充电和放电,插入PD充电头则充电,插入USB或者用电器则对外放电5V(U盘则是个典型例子)。
这样就可以实现一个Type-C口实现既可以给电池PD充电,和支持插入USB设备给USB放电Linux系统则可以实现USB的设备识别。
1.1 BQ25890
充电IC采用: BQ25890 具有MaxChargeTM 技术实现高输入电压和可调电压 USB On-the-Go
升压模式的 I2C 控制型单节电池 5A 快速充电器,放电模式下最高5.5V + 2.4A最大输出,设备树可调参数。

1.2 MAX17048G+T10
MAX17048是微型、微功耗电流电量计,适用于手持和便携式设备中的锂离子 (Li+) 电池
I2C通讯接口,电路极其简单无需分压电阻

1.3 FUSB302BMPX
Fusb302是可编程的USB Type-C控制器,支持识别各种USB 设备和对应的状态;且支持最高100W的PD协议。
Fusb302用CC1/CC2引脚与typeC电源适配器通信,通过PD协议来设置电源适配器的输出电压和电流,从而达到控制充电电压电流,实现快充的目的。

2. 验证模块方案图解

<img src="//image.lceda.cn/oshwhub/a240ac5ba779486fb6ec79c57ef6cdf2.jpg" width="60%"/>
<img src="//image.lceda.cn/oshwhub/c6d515033678419a81f0304f698f90d6.jpg" width="60%"/>
从上图可以看出外接电池需要接入10K的热敏电阻,作为温度保护,忽略则直接无法充电指示灯快闪提示错误。
如果你不想接10K的热敏电阻可以将如下电阻加上:

3. 测试12V的PD申请+充电功率
<img src="//image.lceda.cn/oshwhub/76aeb3c170de43e895be1074f287c887.jpg" width="60%"/>
4. 泰山派移植成功的电量计驱动打印输出信息

使用linux电池管理子系统注册驱动,可以在/sys/class/power_supply/battery/内查看电压和SOC占比
5. 驱动移植
本次使用的是泰山派I2C2接口,IO使用情况如下图所示

5.1 修改设备树
修改文件: tspi-rk3566-user-v10-linux.dts
增加如下代码段
&pinctrl {
........
fusb30 {
fusb0_int_: fusb0-int2 {
rockchip,pins = <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
bq25890_p{
bq25890_int: bq25890-int{
rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
//END
};
添加I2C节点
//用户I2C2
&i2c2 {
status = "okay";
..................
fusb0: fusb30x@22 {
compatible = "fairchild,fusb302";
reg = <0x22>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&fusb0_int_>;
interrupt-parent = <&gpio3>;
interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
int-n-gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_HIGH>;
// charge-dev = <&bq25890>;
};
bq25890:bq25890@6a{
status = "okay";
compatible = "ti,bq25890";
reg = <0x6a>;
// extcon = <&fusb0>;
interrupt-parent = <&gpio3>;
interrupts = <RK_PA1 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&bq25890_int>;
ti,battery-regulation-voltage = <4200000>;
ti,charge-current = <2000000>;
ti,termination-current = <50000>;
ti,precharge-current = <128000>;
ti,minimum-sys-voltage = <3700000>;
ti,boost-voltage = <5000000>;
ti,boost-max-current = <3000000>;
ti,use-ilim-pin;
ti,thermal-regulation-threshold = <120>;
};
max17048:max17048@36{
status = "okay";
compatible = "max17048";
reg = <0x36>;
};
};
内核中配置开启bq25890的驱动支持。
在kernel目录下执行命令: make ARCH=arm64 menuconfig 输入/打开搜索搜索bq25890开启 “[*] ”编译到内核.
执行: make ARCH=arm64 savedefconfig
覆盖配置: mv defconfig arch/arm64/configs/rockchip_linux_defconfig
复制电量计驱动文件(见底部附件)到指定目录:
kernel/drivers/power/supply/max17048_battery.c
修改文件:kernel/drivers/power/supply/Makefile 最后一行添加内容:
obj-y += max17048_battery.o
修改驱动文件:kernel/drivers/mfd/fusb302.c
修改方法名:static int fusb302_set_pos_power_by_charge_ic(struct fusb30x_chip *chip)
int max_vol, max_cur;
max_vol = 12000; //12V
max_cur = 3000; //3A
if (max_vol > 0 && max_cur > 0)
fusb_set_pos_power(chip, max_vol, max_cur);
return 0;
<img src="//image.lceda.cn/oshwhub/47c2d94ae4fb455aa2399b57308c9b15.png" width="50%"/>
添加打印信息:
printk("fusb302---->%s:get vol = %d\n", __func__,CAP_FPDO_VOLTAGE(chip->rec_load[tmp]) * 50);
printk("fusb302---->%s:get cur = %d\n", __func__,CAP_FPDO_CURRENT(chip->rec_load[tmp]) * 10);

编译内核: ./build.sh kernel
烧录boot镜像。
启动开发板,设置日志打印级别: dmesg -n 7
查看电量计的打印数据。
2. 版本修改记录
2.1 20240803: 修改驱动适配自动充电+自动对外放电能力
原始bq25890的驱动代码中的自动对外放电函数是获取USB-PHY节点监听ID事件的
源码代码是这样写的:
/* OTG reporting */
//USB_PHY_TYPE_USB2 USB 2.0 PHY。这段枚举定义了 Linux 内核中使用的 USB PHY 类型,用于描述 USB 控制器所连接的 PHY 的类型
bq->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
if (!IS_ERR_OR_NULL(bq->usb_phy)) {
dev_info(dev, "找到USB控制器");
INIT_WORK(&bq->usb_work, bq25890_usb_work);
bq->usb_nb.notifier_call = bq25890_usb_notifier;
usb_register_notifier(bq->usb_phy, &bq->usb_nb);
} else {
dev_info(dev, "没有找到USB控制器 %ld\n",(unsigned long)bq->usb_phy);
}
稍微解释下原厂的写法逻辑:
- 从内核中获取Type是USB_PHY_TYPE_USB2 USB2.0的 usbPhy驱动。
- 如果找到usbPhy则注册监听事件,监听的是USB的引脚ID被拉低事件,这里有个问题我们用的type-c不是MicroUSB接口没有ID引脚。且bq->usb_phy始终返回找不到usbPhy设备,我在内部的代码循环中加入日志打印,发现根本没进入到循环说明usbPhy内部根本没有RK USB设备注册过,具体原因不明白RK内部的usb驱动用的其他什么方法。这里就不研究了因为ID拉低事件监听不现实。
源码的监听实现充电自动这样写的:
<img src="//image.lceda.cn/oshwhub/09c8ac3ccd8647ea809534209554284c.png" width="70%"/>
那么对外输出电压是如何实现的呢?我直接根据文档总结就两点
OTG引脚给高电平 && OTG_CFG寄存器给1, 不满足则是充电模式。
解决思路: 默认直接让它OTG_CFG是1,然后我们控制OTG引脚的高低实现充电和放电的控制。
那么问题来了,如果知道插入的是充电器还是用电器(例如U盘)?
方案:
借助FUSB302驱动内部实现,来看下FUSB302驱动内部的一段代码


原来fusb302已经预料这个需求了,所以内部其实已经设计好了。
我们只要修改bq25890驱动默认让OTG_CFG设置1,然后让FUSB自己控制OTG引脚就好了。
摸明白后原来这么简单,切~ so easy
代码修改部分来咯:
- 修改bq25890 路径:kernel/drivers/power/supply/bq25890_charger.c
在 static int bq25890_probe(struct i2c_client *client,const struct i2c_device_id *id)函数最后一行添加代码
dev_info(bq->dev,"USB开启OTG Boost mode");
bq25890_field_write(bq, F_OTG_CFG, 1);
如下图所示
<img src="//image.lceda.cn/oshwhub/74bc769691334f489b4f4a1868a43f5f.png" width="50%"/>
修改设备树添加代码两处:
<img src="//image.lceda.cn/oshwhub/8a9128ffac344eed8fe004aeb465fac9.png" width="70%"/>

实测了下C2C USB设备是没问题的,然后我有一个VFD屏幕内部做了CC1和CC2通过5.1K下拉到地的设计发现直接连接C2C无法触发放电,但是如果加上C转A接口然后插入线材是A2C就可以对我那个设备放电了。
然后我又用C2C连接固态盒子也是可以正常放电的。
插入的放电提示:
[ 3297.073050] fusb302 2-0022: 设置OTG—PIN电平:1
[ 3297.073953] fusb302 2-0022: CC connected in CC1 as DFP
设计图
未生成预览图,请在编辑器重新保存一次BOM
暂无BOM
克隆工程知识产权声明&复刻说明
本项目为开源硬件项目,其相关的知识产权归创作者所有。创作者在本平台上传该硬件项目仅供平台用户用于学习交流及研究,不包括任何商业性使用,请勿用于商业售卖或其他盈利性的用途;如您认为本项目涉嫌侵犯了您的相关权益,请点击上方“侵权投诉”按钮,我们将按照嘉立创《侵权投诉与申诉规则》进行处理。
请在进行项目复刻时自行验证电路的可行性,并自行辨别该项目是否对您适用。您对复刻项目的任何后果负责,无论何种情况,本平台将不对您在复刻项目时,遇到的任何因开源项目电路设计问题所导致的直接、间接等损害负责。










