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反推电量,会进行一次重新校准,和关机前有一定误差。如果希望电池电量和重新上电之前一致,则只能通过软件处理,比如在关机时将电池电量保存至文件中,开机时再去读。

CW2015电量计驱动分析相关推荐

  1. MSM8909 CW2015 电量计驱动调试

    1. dtsi添加: &i2c_5 {status = "okay";cw2015@62{compatible = "qcom,cw2015_gauge" ...

  2. rk3399平台电量计cw2015驱动分析

    rk3399平台电量计cw2015驱动分析 文章目录 rk3399平台电量计cw2015驱动分析 cw2015电路设计 cw2015 2芯电池设计参考 电路设计参考注意事项 板级配置 dts配置实例 ...

  3. 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇

    关键词:android 电池  电量计  MAX17040 任务初始化宏 power_supply 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0  ...

  4. max17040C语言,电池 电量计(MAX17040)驱动分析篇

    关键词:android 电池  电量计  MAX17040 任务初始化宏power_supply 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0 平台 ...

  5. android电池(五):电池 充电IC(PM2301)驱动分析篇

    android电池(五):电池 充电IC(PM2301)驱动分析篇 关键词:android 电池  电量计  PL2301任务初始化宏 power_supply 中断线程化 平台信息: 内核:linu ...

  6. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  7. Android10.0 Binder通信原理(五)-Binder驱动分析

    摘要:本节主要来讲解Android10.0 Binder的驱动层分析 阅读本文大约需要花费35分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Android的平台设计 ...

  8. linux 串口驱动 atmel_set_mctrl何时调用,linux uart serial使用驱动分析

    uart tty serial 驱动分析 内核版本3.14.23 以atmel为例: 起点: static int __init atmel_serial_init(void) { int ret; ...

  9. linux 网卡驱动分析,LINUX_网卡驱动分析

    LINUX_网卡驱动分析 (36页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 Linux DM9000网卡驱动程序完全分析说明仁 本文分 ...

最新文章

  1. python解析json
  2. Python设计模式-中介者模式
  3. CVPR 2017 全部及部分论文解读集锦
  4. 邮件群发工具的编写(二)数据的保存
  5. flv 自动播放 html autostart=true,《网页制作之FLV视频播放代码的编写.doc
  6. CSS3的radial-gradient(径向渐变)
  7. PhpExcel数组输出到Excel浏览器下载
  8. 20190809:旋转数组
  9. DIV+CSS的命名规则有利于SEO
  10. VS2017编译OpenJDK,编译通过的工程包下载链接
  11. WIN8下安装USB转串口驱动出现“文件的哈希值不在指定的目录”的解决办法
  12. 50行python代码写个计算器教程
  13. html放大镜原理,js放大镜效果原理
  14. Gentoo 教程:编译器选择
  15. 基于标记的分水岭分割算法
  16. 多种方法解决多个div并排显示的问题
  17. 资源|最新WEB前端开发全套视频教程
  18. 出现 NameError: name ‘re’ is not defined 的原因
  19. 如何一键制作css精灵图?
  20. codeforces 1669F

热门文章

  1. 案例研究 | 运用设计冲刺,解决俄罗斯家庭暴力问题
  2. 联想电脑Z460安装Win7
  3. 远程桌面系统管理员已经限制你登录的计算机,远程桌面由于帐户限制你无法登录问题...
  4. unity应用商店脱机怎么解决有vpn(新手小白感谢大佬)
  5. 毕业答辩模板PPT 医疗模板 科研展示 项目展示介绍 工作汇报 30套
  6. 我如何在 19 年校招中获得 15 家知名公司的 offer
  7. php鼠标悬浮显示,CSS3实现鼠标悬停显示扩展内容
  8. 张宇线代30讲学习笔记
  9. 0基础916高分上岸东南大学—萤火学长黄金贴
  10. Webots平台NAO机器人寻路避障实现