CW2015电量计驱动分析

news/2024/11/24 19:13:44/

Chip:CW2015
SoC:RK3288
Platform:Android 5.1


PSY

一般power supply分为三种:DC,USB,battery
本文着重分析battery,并介绍CW2015电量计调试的相关经验

probe()函数

分析驱动毫无疑问从probe()函数开始,函数原型:

static int cw_bat_probe(struct i2c_client *client,const struct i2c_device_id *id)

进入probe()后,首先需要获取电量计相关gpio,调用函数cw2015_parse_dt(),目的:

  • 获取电池信息
  • DC检测脚
  • 低电量中断脚
  • 是否支持DC充电
  • 是否支持USB充电

然后调用cw_bat_gpio_init()初始化各gpio的值。随后,进入电量计的初始化函数cw_init()。

cw_init()

cw2015的初始化流程可参考datasheet,其操作流程如下:

1. WAKE UP使其退出上电默认的sleep状态
2. 设置容量门限值ATHD
3. 检查UPDATE_FLAG标志位- 如果UPDATE_FLAG有置位,检查电池信息是否一致
   - 如果没有置位,写入电池信息,并置位UPDATE_FLAG
4. 判断SOC是否合法,不合法cw2015进入sleep状态

流程图如下
这里写图片描述

CW2015初始化成功后,填充struct power_supply各字段,注册三种power_supply设备,这里只关注battery部分:

    cw_bat->rk_bat.name = "rk-bat";cw_bat->rk_bat.type = POWER_SUPPLY_TYPE_BATTERY;cw_bat->rk_bat.properties = rk_battery_properties;cw_bat->rk_bat.num_properties = ARRAY_SIZE(rk_battery_properties);cw_bat->rk_bat.get_property = rk_battery_get_property;ret = power_supply_register(&client->dev, &cw_bat->rk_bat);if (ret < 0) {dev_err(&cw_bat->client->dev,"power supply register rk_bat error\n");goto rk_bat_register_fail;}

get_property:get_property方法提供了sys用户接口获取电池信息,调用rk_battery_get_property。该方法通过power_supply_register注册进power supply core,用户层读取时再回调。

get_property的sys接口可参考power supply sys

power_supply_register:初始化电池uevent change工作队列,注册power supply设备。

INIT_WORK(&psy->changed_work, power_supply_changed_work);

注册完power supply设备,各个功能就可以正常工作了,然后通过工作队列更新电池信息。

电池相关处理

电池信息相关处理主要由几个工作队列和中断来完成:

  • cw_bat_work-更新电池信息
  • dc_detect_do_wakeup-DC状态中断函数
  • bat_low_detect_do_wakeup-低电压处理

本文只分析cw_bat_work()电池信息更新部分。

cw_bat_work

首先会判断是否支持DC充电和USB充电(dts配置),如下:

    if (cw_bat->plat_data.is_dc_charge == 1) {   //支持DC充电ret = rk_ac_update_online(cw_bat);if (ret == 1)power_supply_changed(&cw_bat->rk_ac);}if (cw_bat->plat_data.is_usb_charge == 1) {  //支持usb充电ret = rk_usb_update_online(cw_bat);if (ret == 1) {power_supply_changed(&cw_bat->rk_usb);power_supply_changed(&cw_bat->rk_ac);}}

支持DC充电时(usb充电暂不分析),调用rk_ac_update_online(),进行状态的切换,如下:

    /*判断dc_det_pin是否有效*/if (!gpio_is_valid(cw_bat->plat_data.dc_det_pin)) {  cw_bat->dc_online = 0;pr_info("%s dc charger without dc_det_pin\n", __func__);return 0;}/*判断dc是否插入,接入DC时该脚拉低,只接电池或OTG时该脚为高电平dc_online只判断一次,也就是DC插拔时电池status只切换一次*/if (gpio_get_value(cw_bat->plat_data.dc_det_pin) ==    //为0表示接入了DC,DC充电模式cw_bat->plat_data.dc_det_level) {   //dc_det_level为GPIO_ACTIVE_LOWif (cw_bat->dc_online != 1) {cw_update_time_member_charge_start(cw_bat);cw_bat->dc_online = 1;if (cw_bat->charger_mode != AC_CHARGER_MODE)cw_bat->charger_mode = AC_CHARGER_MODE;ret = 1;}} else {    //为1表示未接入DC,bat放电模式if (cw_bat->dc_online != 0) {cw_update_time_member_charge_start(cw_bat);cw_bat->dc_online = 0;if (cw_bat->usb_online == 0)cw_bat->charger_mode = 0;ret = 1;}}

然后会调用rk_bat_update_status()更新电池状态:充电,充满,放电

    if (cw_bat->charger_mode > 0) {if (cw_bat->capacity >= 100)status = POWER_SUPPLY_STATUS_FULL;    //充满elsestatus = POWER_SUPPLY_STATUS_CHARGING;   //充电} else {status = POWER_SUPPLY_STATUS_NOT_CHARGING;   //放电}if (cw_bat->status != status) {cw_bat->status = status;cw_bat->bat_change = 1;}

如果电池状态发生改变时,调用power_supply_changed(),该函数中调度changed_work工作队列,实际任务函数为power_supply_changed_work(),在注册power supply时初始化。
调用rk_bat_update_capacity()更新电池容量SOC,电池容量的获取主要是读取CW2015的0x4,0x5寄存器。实现逻辑为函数cw_get_capacity()
调用rk_bat_update_vol()更新电池电压VCELL,实现逻辑为函数cw_get_vol()
调用rk_bat_update_time_to_empty()更新系统可运行时间RRT,实现逻辑为函数cw_get_time_to_empty()
最后判断电池状态是否改变,若电池状态改变则调度changed_work工作队列。

power_supply_changed_work

每当电池状态或电池容量SOC,电压VCELL等发生改变时,最终都会调用power_supply_changed_work()通知uevent事件给上层。Android HAL由healthd负责监听。函数如下:

static void power_supply_changed_work(struct work_struct *work)
{unsigned long flags;struct power_supply *psy = container_of(work, struct power_supply,changed_work);dev_dbg(psy->dev, "%s\n", __func__);spin_lock_irqsave(&psy->changed_lock, flags);if (psy->changed) {psy->changed = false;spin_unlock_irqrestore(&psy->changed_lock, flags);class_for_each_device(power_supply_class, NULL, psy,__power_supply_changed_work);power_supply_update_leds(psy);kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);spin_lock_irqsave(&psy->changed_lock, flags);}if (!psy->changed)pm_relax(psy->dev);spin_unlock_irqrestore(&psy->changed_lock, flags);
}

至此,CW2015驱动主要部分已分析完。但是在调试时需要注意:CW2015电量计需要配置电池信息,电池信息bat_config_info需由原厂配合电量计调校得出正确的电池信息,并在初始化时将电池信息写入CW2015,否则重启后获取到的电池容量SOC不准确。

SYS节点

CW201X驱动提供了以下几个字段来获取battery状态,实际上HAL uevent也是获取这几个接口的值,接口如下:

ls  /sys/class/power_supply/rk-bat/
capacity
device
health
power
present
status
subsystem
technology
time_to_empty_now
type
uevent
voltage_now

Capacity:电池容量百分比,该值会上报Android,设置中打开时,状态栏即显示该值。
Health:电池健康情况,平台默认为POWER_SUPPLY_HEALTH_GOOD,即返回Good
Status:电池充电状态。
Technology:电池采用的技术,平台默认为POWER_SUPPLY_TECHNOLOGY_LION,即返回Li-ion
Time_to_empty_now:电池电压。
Type:电池充电类型。
以上值除了平台默认的,其余的均从struct cw_battery中获取,电池信息的工作队列会一直更新struct cw_battery中的相关值。

问题

  1. 系统重启后电量计显示不准确
    写入CW2015中的电池信息bat_config_info不正确
  2. 拔掉电池与DC,再重新接上电池上电,电量计获取的值不准确。
    拔掉电池后PMIC完全掉电,此时再重新上电只能根据bat_config_info反推电量,会进行一次重新校准,和关机前有一定误差。如果希望电池电量和重新上电之前一致,则只能通过软件处理,比如在关机时将电池电量保存至文件中,开机时再去读。

http://www.ppmy.cn/news/520205.html

相关文章

CW32F030相关内容调研

内核:ARM Cortex-M0+ 最高主频 64MHz • 工作温度:-40℃ 至 105℃;工作电压:1.65V 至 5.5V • 存储容量最大 64K 字节 FLASH,数据保持 25 年 @85℃最大 8K 字节 RAM,支持奇偶校验128 字节 OTP 存储器 • CRC 硬件计算单元 • 复位和电源管理低功耗模式(Sleep,DeepSleep…

电机的CW与CCW是什么意思呢?

电机的CW与CCW是什么意思呢&#xff1f; CW&#xff1a;clockwise 顺时针 CCW&#xff1a;counterclockwise 逆时针

CW2015 linux 锂电池驱动源码

linux 驱动 描述&#xff1a;cw2015驱动源码在实际项目中验证过&#xff0c;可以放心使用&#xff0c;驱动代码功能正常。 CW2015 驱动源码 #include <linux/module.h> #include <linux/i2c.h> #include <linux/power_supply.h> #include <linux/regmap.h…

VS2008开发之宽字符集和多字节字符集之间的相互转换

1、需要包含头文件&#xff1a; #include <atlstr.h> 2、将宽字符集&#xff08;Unicode&#xff09;转化为多字符集&#xff08;ASCII&#xff09;&#xff0c;使用CW2A 3、将多字符集&#xff08;ASCII&#xff09;转化为宽字符集&#xff08;Unicode&#xff09;&am…

cw2015 arduino esp32程序

CW2015是一款超紧凑、低成本电量计IC&#xff0c;适用于手持式和便携式设备中的锂离子&#xff08;Li&#xff09;电池。 cw2015.cpp #include "cw2015.h"CW2015::CW2015(TwoWire *pWire) {_pWire pWire; }void CW2015::initCW2015(void)//初始化IIC {_pWire->be…

cw脉冲matlab产生,CW脉冲和LFM信号Matlab仿真.pdf

CW脉冲和LFM信号Matlab仿真.pdf 一 CW信号 一、程序 t-0.05:0.0001:0.05; f01000; k25000; s cos(2.*pi.*f0.*t); nwgn(1,1001,2); s1sn; h cos(2.*pi.*f0.*(-t)); c1conv(s,h); c2conv(s1,h); figure(1); plot(n); figure(2); plot(s); figure(3); plot(c1); figure(4); plot(…

利用计算机进行CW收发报的技术,让你成为CW高手

作者:BD4RFK 使用的是最新版本软件: 这是俄罗斯HAM UA9OV编写的软件,软件体积小巧,短小精悍。(如有需要留下E-mail我会发给你) CwGet v1.5 CwType v1.36 CwGet v1.45特别版 下载本软件请到我的网络硬盘下载 软件安装完毕之后,同时打开接收和编码两部分。 软件CwType默认安…

Qt编写跨平台的推流工具(支持win/linux/mac/嵌入式linux/安卓等)

一、前言 跨平台的推流工具当属OBS最牛逼&#xff0c;功能也是最强大的&#xff0c;唯一的遗憾就是多路推流需要用到插件&#xff0c;而且CPU占用比较高&#xff0c;默认OBS的规则是将对应画布中的视频画面和设定的音频一起重新编码再推流&#xff0c;意味着肯定占用不少CPU资…