电池驱动

本文以 bq40z50 电池为例,介绍在 RK 平台上使用电池驱动的相关配置与实现。

设备树配置

结合电路原理图分析,确认电池挂载在 I2C3总线上。通常情况下,电池设备挂载在 I2C总线上,因此只需配置 I2C 子节点即可。下面是设备树配置示例:

确认I2C设备挂载的地址为0b.示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
&i2c3{
status = "okay";
i2c-scl-rising-time-ns = <345>;
i2c-scl-falling-time-ns = <11>;
// 时钟频率设置为 100kHz
clock-frequency = <100000>;

// i2c地址
battery0: bq28z610@0b{
status = "disabled";
compatible ="ti,bq28z610";
reg = <0x0b>;

};
battery1: bq40z50@0b{
status = "okay";
compatible ="ti,bq40z50";
reg = <0x0b>;

};
};

设备树可以同时定义多个电池子节点,如上例的 battery0 和 battery1。驱动会根据 compatible 属性加载相应的驱动程序。

clock-frequency: 时钟频率,根据电池规格设置。注意:如果使用 SMBus 协议,时钟频率只能设置为 100kHz。
**reg:**设备在 I2C 总线中的地址。

在RK平台上,可以通过修改linux_defconfig配置文件来启用驱动编译。也可以使用 menuconfig 单独编译内核驱动。

电池驱动代码

电池驱动代码一般由厂商提供参考,以下是适配好的驱动代码流程,仅为个人记录。
电池bq40z50驱动流程

  • bq_fg_probe
    • devm_kzalloc()给自定义电池结构体分配内存
    • i2c_set_clientdata() 设置自定义电池I2C结构体
    • devm_request_threaded_irq()开启线程
      • fg_btp_irq_thread 子线程函数
        • fg_read_status 读取电池状态
        • fg_update_status 更新电池状态
          • fg_read_rsoc
          • fg_read_volt
          • fg_read_current
          • fg_read_temperature
          • fg_read_rm
    • enable_irq_wake 唤醒线程
    • device_init_wakeup 设置设备能否唤醒
    • fg_read_fw_version 读取电池版本号
    • fg_psy_register 注册电池
      • devm_power_supply_register 注册电池psy
    • sysfs_create_group 创建sysfs组
    • determine_initial_status 再次启动线程
      • fg_update_status 更新电池状态
      • fg_btp_irq_thread 子线程函数
    • INIT_DELAYED_WORK 初始化延时队列 增加
    • schedule_delayed_work 开启队列

可以看到大致流程:创建结构体->使用线程读取电池状态->唤醒线程->注册电池->创建sysfs节点->延时队列主动上报信息

如果对电池信息更新的频率较高,可以增加延时队列,在延时队列中定时上报。

在适配usb电池时,需要查看该usb供电属于哪种供电类型

USB供电类型

某些电路设计中,会采样是否有电源供电,以实现适应不同的充电需求。

1
2
3
4
5
6
7
8
9
10
11
12
13
enum power_supply_type {
POWER_SUPPLY_TYPE_UNKNOWN = 0,
POWER_SUPPLY_TYPE_BATTERY,
POWER_SUPPLY_TYPE_UPS,
POWER_SUPPLY_TYPE_MAINS,
POWER_SUPPLY_TYPE_USB, /* 标准下行端口 */
POWER_SUPPLY_TYPE_USB_DCP, /* 专用充电端口 */
POWER_SUPPLY_TYPE_USB_CDP, /* 充电下行端口 */
POWER_SUPPLY_TYPE_USB_ACA, /* 附件充电器适配器 */
POWER_SUPPLY_TYPE_WIRELESS, /* 无线充电 */
POWER_SUPPLY_TYPE_BMS, /* 电池监控系统 */
POWER_SUPPLY_TYPE_USB_PARALLEL,/* USB 并行路径 */
};
  • POWER_SUPPLY_TYPE_UNKNOWN: 未知供电类型。
  • POWER_SUPPLY_TYPE_BATTERY: 电池供电,常见于嵌入式设备、手持智能设备。
  • POWER_SUPPLY_TYPE_UPS: 不间断电源供电,一般用于服务器等设备。
  • POWER_SUPPLY_TYPE_MAINS: 主供电设备,如笔记本电脑的适配器。
  • POWER_SUPPLY_TYPE_USB: 标准下行端口。
  • POWER_SUPPLY_TYPE_USB_DCP: 专用充电端口,仅支持充电,不传输数据。
  • POWER_SUPPLY_TYPE_USB_CDP: 充电下行端口,支持 500mA 和 1.5A 两种电流。
  • POWER_SUPPLY_TYPE_USB_ACA: 附件充电器适配器,支持充电和 OTG 功能。
  • POWER_SUPPLY_TYPE_WIRELESS: 无线充电。
  • POWER_SUPPLY_TYPE_BMS: 电池监控系统。
  • POWER_SUPPLY_TYPE_USB_PARALLEL: USB 并行路径。

我们注册电池时使用的是POWER_SUPPLY_TYPE_BATTERY类型,根据实际情况选择。

寄存器解读

根据电池数据手册,我总结了一些寄存器有关信息,以下加粗是驱动主要用到的寄存器,其他寄存器根据需求使用。

寄存器地址 功能描述
0x08 电池温度 (Temperature)
0x09 电池电压 (Voltage)
0x0A 电池电流 (Current)
0x0B 平均电流 (AverageCurrent)
0x0D 相对状态电量 (RelativeStateOfCharge)
0x0E 绝对状态电量 (AbsoluteStateOfCharge)
0x0F 剩余容量 (RemainingCapacity)
0x10 满充电容量 (FullChargeCapacity)
0x16 电池状态 (BatteryStatus)
0x17 循环计数 (CycleCount)
0x18 设计容量 (DesignCapacity)
0x19 设计电压 (DesignVoltage)
0x1A 规格信息 (SpecificationInfo)
0x1B 制造日期 (ManufacturerDate)
0x1C 序列号 (SerialNumber)
0x20 制造商名称 (ManufacturerName)
0x21 设备名称 (DeviceName)
0x22 设备化学类型 (DeviceChemistry)

这些寄存器同样可以使用ti提供的上位机工具,查看寄存器的值,并且设置。

问题

1、筛选i2c日志,出现被串口占用

1
2
3
4
5
[    0.607156] input: rk805 pwrkey as /devices/platform/fdd40000.i2c/i2c-0/0-0020/rk805-pwrkey/input/input1
[ 0.616071] rockchip-pinctrl pinctrl: pin gpio1-1 already requested by fe670000.serial; cannot claim for fe5c0000.i2c
[ 0.616094] rockchip-pinctrl pinctrl: pin-33 (fe5c0000.i2c) status -22
[ 0.616103] rockchip-pinctrl pinctrl: could not request pin 33 (gpio1-1) from group i2c3m0-xfer on device rockchip-pinctrl

该引脚与uart3复用,定位关闭uart3即可。

2、I2C通讯异常过后,电量等数据读取异常

3、低温试验问题

  • 低温禁止充电
  • 低温试验后恢复电量异常

待续…