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

时间:2023-02-27 14:17:45

关键词:android 电池  电量计  MAX17040 任务初始化宏 power_supply

平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0 
平台:samsung exynos 4210、exynos 4412 、exynos 5250

作者:xubin341719(欢迎转载,请注明作者)

欢迎指正错误,共同学习、共同进步!!

完整驱动代码&规格书下载:MAX17040_PL2301

android 电池(一):锂电池基本原理篇

android 电池(二):android关机充电流程、充电画面显示

android 电池(三):android电池系统

android电池(四):电池 电量计(MAX17040)驱动分析篇

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

电池电量计,库仑计,用max17040这颗电量IC去计量电池电量,这种方法比较合理。想起比较遥远的年代,做samsung s5pc110/sp5v210的时候,计量电量用一个AD口加两个分压电阻就做了,低电量的时候系统一直判断不准确,“低电关机”提示一会有,一会没有,客户那个郁闷呀,“到底是有电还是没电?”。

如下图,通过两个分压电阻,和一个AD脚去侦测VCC(电池)电压。

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

一、MAX17040的工作原理

电量计MAX17040,他通过芯片去测量电池电量,芯片本身集成的电路比较复杂,同时可以通过软件上的一些算法去实现一些处理,是测量出的电量更加准确。还有一个好处,就是他之接输出数字量,通过IIC直接读取,我们在电路设计、程序处理上更加的统一化。

如下图所示,MAX17040和电池盒主控的关系,一个AD脚接到电池VBAT+,检测到的电量信息,通过IIC传到主控。

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

下面是电路图,电路接口比较简单,VBAT+,接到max17040的CELL,IIC接到主控的IIC2接口,这个我们在程序中要配置。看这个器件比较简单吧。

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

看下max17040的内部结构,其实这也是一个AD转换的过程,单独一颗芯片去实现,这样看起来比较专业些。CELL接口,其实就是一个ADC转换的引脚,我们可以看到芯片内部有自己的时钟(time base),IIC控制器之类的,通过CELL采集到的模拟量,转换成数字量,传输给主控。

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

通过上面的介绍Max17040的硬件、原理我们基本上都了解了,比较简单,下面我们就重点去分析下驱动程序。

二、MAX17040 总体流程

电量计的工作流程比较简单,max17040通过CELL ADC转换引脚,把电池的相关信息,实时读取,存入max17040相应的寄存器,驱动申请一个定时器,记时结束,通过IIC去读取电池状态信息,和老的电池信息对比,如果用变化上报,然后重新计时;这样循环操作,流程如下所示:

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

三、MAX17040这个电量计驱动,我们主要用到以下知识点

1、IIC的注册(这个在TP、CAMERA中都有分析);

2、linux 中定时器的使用;

3、任务初始化宏;

4、linux定时器调度队列;

5、max17040测到电量后如何上传到系统(这个电池系统中有简要的分析);

6、AC、USB充电状态的上报,这个和电池电量是一种方法。

7、电池曲线的测量与加入;

1、IIC的注册

IIC这个总线,在工作中用的比较多,TP、CAMERA、电量计、充电IC、音频芯片、电源管理芯片、基本所有的传感器,所以这大家要仔细看下,后面有时间的话单独列一片介绍下IIC,从单片机时代都用的比较多,看来条总线的生命力很强,像C语言一样,很难被同类的东西替代到,至少现在应该是这样的。

看下他结构体的初始化与驱动的申请,这个比较统一,这里就不想想解释了。

(1)、IIC驱动的注册:

static const struct i2c_device_id max17040_id[] = {
{ "max17040", },
{ }
};
MODULE_DEVICE_TABLE(i2c, max17040_id); static struct i2c_driver max17040_i2c_driver = {
.driver = {
.name = "max17040",
},
.probe = max17040_probe,
.remove = __devexit_p(max17040_remove),
.suspend = max17040_suspend,
.resume = max17040_resume,
.id_table = max17040_id,
}; static int __init max17040_init(void)
{
printk("MAX17040 max17040_init !!\n");
wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
return i2c_add_driver(&max17040_i2c_driver);
}
module_init(max17040_init);

(2)在arch/arm/mach-exynos/mach-smdk4x12.c中,IC平台驱动的注册:

static struct i2c_board_info i2c_devs2[] __initdata = {
#if defined(CONFIG_BATTERY_MAX17040)
{
I2C_BOARD_INFO("max17040", 0x36),//IIC地址;
.platform_data = &max17040_platform_data,
},
#endif
……………………
};

下图就是我们IIC驱动注册生成的文件;

/sys/bus/i2c/drivers/max17040

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

2、linux 中定时器的使用

定时器,就是定一个时间, 比如:申请一个10秒定时器,linux系统开始计时,到10秒,请示器清零重新计时并发出信号告知系统计时完成,系统接到这个信号,做相应的处理;

#include <linux/delay.h>
#define MAX17040_DELAY msecs_to_jiffies(5000)

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

3、任务初始化宏

任务结构体的初始化完成后,接下来要将任务安排进工作队列。 可采用多种方法来完成这一操作。 首先,利用 queue_work 简单地将任务安排进工作队列(这将任务绑定到当前的 CPU)。 或者,可以通过 queue_work_on 来指定处理程序在哪个 CPU 上运行。 两个附加的函数为延迟任务提供相同的功能(其结构体装入结构体 work_struct 之中,并有一个 计时器用于任务延迟 )。

4、linux定时器调度队列

5、max17040测到电量后如何上传到系统(这个电池系统中有简要的分析);

4中的定时器记时完成,就可以调度队列,chip->work执行:max17040_work函数,把改读取的信息上传,我们看下max17040_work函数的实现:

(1)、保存老的电池信息,如电量、AC、USB是否插入

(2)、读取电池新的状态信息

    max17040_get_online(chip->client);//读取是否有AC插入;
max17040_get_vcell(chip->client);//读取电池电压;(这个地方原来写错,多谢细心网友,更正!!)
max17040_get_soc(chip->client);//读取电池电量;
max17040_get_status(chip->client);//读取状态;

(3)、如果电池信息有变化,就上报系统

    if ((old_vcell != chip->vcell) || (old_soc != chip->soc)) {
/* printk(KERN_DEBUG "power_supply_changed for battery\n"); */
power_supply_changed(&chip->battery);
}

power_supply_changed这个函数比较重要, 我们后面分析;

(4)、如果用PM2301充电IC,USB充电功能不用

这个是由于我们的系统耗电比较大,用USB充电时,电流过小,所以出现越充越少的现象,所以这个功能给去掉了。

(5)、如果有DC插入,则跟新充电状态

    power_supply_changed(&chip->ac);

6、AC、USB充电状态怎么更新到应用

如上面所说,通过power_supply_changed上报;

7、电池曲线的测量与加入

电池曲线,就是电池的冲放电信息,就是用专业的设备,对电池连续充放电几天,测出一个比较平均的值。然后转换成针对电量IC(如我们用的max17040)的数字量,填入一个数组中,如下图所示:

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

下面数据时针对电池曲线的数字量,和相关参数。如上图所示,为160小时的电池信息,包括:不同颜色分别代表不同的曲线:如temperature ,reference SOC ,fuel gauge SOC,Vcell,Empty Voltage

数据表格如下:

加入驱动中的值:

/driver/power/max17040_common.c中

四、驱动分析

1、Probe函数分析

上面我们简单了解驱动中用到的主要知识点,后面我们把这些点串起来,驱动还是从probe说起;

static int __devinit max17040_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct max17040_chip *chip;
int ret;
printk("MAX17040 probe !!\n"); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -EIO; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip)
return -ENOMEM; g_chip = chip;
g_i2c_client = client;//(1)、IIC 驱动部分client 申请; chip->client = client;
chip->pdata = client->dev.platform_data;
i2c_set_clientdata(client, chip);
chip->battery.name = "battery";//(2)、chip name;
chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
chip->battery.get_property = max17040_get_property;//(3)、获取电池信息;
chip->battery.properties = max17040_battery_props;//(4)、电池各种信息;
chip->battery.num_properties = ARRAY_SIZE(max17040_battery_props);
chip->battery.external_power_changed = NULL;
ret = power_supply_register(&client->dev, &chip->battery);//(5)、battery加入power_supply
if (ret)
goto err_battery_failed; chip->ac.name = "ac"
chip->ac.type = POWER_SUPPLY_TYPE_MAINS;
chip->ac.get_property = adapter_get_property;
chip->ac.properties = adapter_get_props;
chip->ac.num_properties = ARRAY_SIZE(adapter_get_props);
chip->ac.external_power_changed = NULL;
ret = power_supply_register(&client->dev, &chip->ac);//(6)、和battery相似,把ac加入power_supply
if (ret)
goto err_ac_failed; #if !defined(CONFIG_CHARGER_PM2301)
chip->usb.name = "usb";
chip->usb.type = POWER_SUPPLY_TYPE_USB;
chip->usb.get_property = usb_get_property;
chip->usb.properties = usb_get_props;
chip->usb.num_properties = ARRAY_SIZE(usb_get_props);
chip->usb.external_power_changed = NULL;
ret = power_supply_register(&client->dev, &chip->usb);//(7)、和battery相似,把usb加入power_supply
if (ret)
goto err_usb_failed; if (chip->pdata->hw_init && !(chip->pdata->hw_init())) {
dev_err(&client->dev, "hardware initial failed.\n");
goto err_hw_init_failed;
}
#endif #ifdef MAX17040_SUPPORT_CURVE
g_TimeCount = ;
handle_model();
#endif
max17040_get_version(client);
battery_initial = ; INIT_DELAYED_WORK_DEFERRABLE(&chip->work, max17040_work);//(8)、任务宏初始化,max17040加入chip->work队列;
schedule_delayed_work(&chip->work, MAX17040_DELAY);//(9)、通过定时器调度队列; printk("MAX17040 probe success!!\n");
return ; err_hw_init_failed:
power_supply_unregister(&chip->usb);
err_usb_failed:
power_supply_unregister(&chip->ac);
err_ac_failed:
power_supply_unregister(&chip->battery);
err_battery_failed:
dev_err(&client->dev, "failed: power supply register\n");
i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
}

(1)、IIC 驱动部分client 申请;

(2)、chip name;

(3)、获取电池信息;

通过传递下来的参数,来读取结构体中相应的状态,这个函数实现比较简单。

(4)电池各种信息

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

static enum power_supply_property max17040_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
/*POWER_SUPPLY_PROP_ONLINE,*/
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_TEMP,
};

(5)、battery加入power_supply;

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

(6)、和battery相似,把ac加入power_supply;

(7)、和battery相似,把usb加入power_supply;

(8)、max17040加入chip->work队列;

前面已经分析;

(9)、通过定时器调度队列;

前面已经分析;

2、power_supply_changed简要分析

如:把电池电量信息上报:我们在max17040_work队列调度函数中, 如果有电池信息、状态变化,则上用power_supply_changed上报。

power_supply_changed(&chip->battery);

Kernel/drivers/power/power_supply_core.c中:

【转】android电池(四):电池 电量计(MAX17040)驱动分析篇的更多相关文章

  1. android电池(四):电池 电量计&lpar;MAX17040&rpar;驱动分析篇【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/8969369 电池电量计,库仑计,用max17040这颗电量IC去计量电池电量,这种方法 ...

  2. 【转】android电池(五):电池 充电IC(PM2301)驱动分析篇

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

  3. android电池(五):电池 充电IC(PM2301)驱动分析篇【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/8970363 android充电这块,有的电源管理芯片内部包含充电管理,如s5pv210 ...

  4. 【转】android 电池(一):锂电池基本原理篇

    关键词:android  电池关机充电 androidboot.mode charger 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV3 ...

  5. 【转】Android LCD&lpar;四&rpar;:LCD驱动调试篇

    关键词:android LCD TFTSN75LVDS83B  TTL-LVDS LCD电压背光电压 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台 ...

  6. 【转】android camera&lpar;四&rpar;:camera 驱动 GT2005

    关键词:android  camera CMM 模组 camera参数  GT2005 摄像头常见问题 平台信息: 内核:linux系统:android 平台:S5PV310(samsung exyn ...

  7. android系统平台显示驱动开发简要:LCD驱动调试篇『四』

    平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...

  8. 【转】android 电容屏(三):驱动调试之驱动程序分析篇

    关键词:android  电容屏 tp 工作队列 中断 坐点计算  电容屏主要参数平台信息:内核:linux2.6/linux3.0系统:android/android4.0  平台:S5PV310( ...

  9. &lbrack;Android6&period;0&rsqb;&lbrack;RK3399&rsqb; 电池系统(三)电量计 CW2015 驱动流程分析【转】

    本文转载自:http://blog.csdn.net/dearsq/article/details/72770295 Platform: RK3399 OS: Android 6.0 Kernel: ...

随机推荐

  1. Linux中设置服务自启动的三种方式

    有时候我们需要Linux系统在开机的时候自动加载某些脚本或系统服务 主要用三种方式进行这一操作: ln -s                       在/etc/rc.d/rc*.d目录中建立/e ...

  2. AtCoder Grand Contest 6

    A - Prefix and Suffix 题意:输入一个整形变量n和两个字符串s,t,使用一些规则求满足条件的最短字符串的长度:规则如下:这个最短字符串的长度不能小于n:它的前n个字符必须与s相同: ...

  3. myIsEqualToString

    BOOL myisEqualToString(NSString * str1 , NSString * str2){ //1.如果两个字符串,指针地址相等,就说明一定是相等 if(str1 == st ...

  4. C&num; 在RichTextBox中滚动鼠标时滚动的是父窗口的滚动条

    1. RichTextBox u2 = new RichTextBox(); 2. 先记住日RichTextBox没有显示滚动条时的总宽度和显示宽度 u2.Width - u2.ClientSize. ...

  5. html冲刺

    html知识点回顾与面试题<!--1.<DOCTYPE>告诉浏览器当前文档要以何种HTML或者XHTML规范解析2.语义标签strong 粗体em 斜体del 删除线ins 下划线 ...

  6. MyBatis全局配置文件MyBatis-config&period;xml代码

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC ...

  7. Linux关闭IPV6

    Linux关闭IPV6的方法 修改配置文件/etc/sysctl.conf添加以下1行 net.ipv6.conf.all.disable_ipv6 = 1 设置生效 sysctl -p 查看没有IP ...

  8. linux&amp&semi;php:ubuntu安装php-7&period;2

    1.下载php源码,地址:http://www.php.net/downloads.php 这里下载的是tar.gz的包 2.解压安装 将安装包解压到/usr/local/php 安装C的编译工具 s ...

  9. 单点登录(SSO)

    单点登录SSO(SingleSign-On)是身份管理中的一部分.SSO的一种较为通俗的定义是:SSO是指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后, ...

  10. Mybatis之是如何执行你的SQL的(SQL执行过程,参数解析过程,结果集封装过程)

    Myabtis的SQL的执行是通过SqlSession.默认的实现类是DefalutSqlSession.通过源码可以发现,selectOne最终会调用selectList这个方法. @Overrid ...