pxa920 88pm860x充电

http://www.cnblogs.com/to7str/archive/2013/03/24/2978699.html


1.       引言

1.1.  编写目的

TF303充电部分做一个整理,内容涉及到电池的基础知识、8607中断、power supply子系统、 电池和充电电器驱动、充电流程和电量计算等。

 

1.2.  环境

硬件环境:TF303

软件环境:svn://172.16.0.70/svn_android/PXA920/branch/Kernel/W1225.03_8390_Kernel   版本8538

 

2.       充电基础知识

2.1.  名词解释

恒流充电:保持恒定电流对电池进行充电。

恒压充电:保持恒定电压对电池进行充电。

热敏电阻:对热敏感的半导体电阻,其阻值随温度变化的曲线呈非线性或线性。

记忆效应:电池的记忆效应是指在下一次充电时所能充电的百分比。为了消除电池的记忆效应,在下一次充电之前,必须先完全放电,然后再充电。只有这样,才能百分之百的充满电池。

涓流充电以一微小的电流对电池充电涓流充电用来先对完全放电的电池单元进行预充(恢复性充电)。。

电池容量:电池容量的国标单位为库仑,常用单位为mAh 1mAh=0.001安培*3600=3.6安培秒=3.6库仑,比如一颗900mAh的电池可以提供300mA恒流的持续3小时的供电能力.

 

2.2.  电池参数

电池的五个主要参数为:电池的容量、标称电压、内阻、放电终止电压和充电终止电压。

电池的容量:通常用mAh(毫安时)表示,1000mAh就是能在1000mA的电流下放电 1小时。

标称电压:通常指的是开路输出电压,也就是不接任何负载,没有电流输出的电压值。

 

2.3.  锂电池原理

电池由正极锂化合物、中间的电解质膜及负极碳组成。

clip_image002[1]

当电池充电时,锂离子从正极中脱嵌,在负极中嵌入,放电时反之。一般采用嵌锂过渡金属氧化物做正极,如LiCoO2LiNiO2LiMn2O4

 

2.4.  电量计算

常见的方法:ADC和库仑计

2.5.  ADC

   锂离子电池有一个对电量计量很有用的特性,就是在放电的时候,电池电压随电量的流逝会逐渐降低,并且有相当大的斜率.这就提供给我们另外一种近似的电量计量途径.

clip_image004[1]

clip_image006

   用电压来估计电池的剩余容量有以下几个不稳定性:

1.同一个电池,在同等剩余容量的情况下,电压值因放电电流的大小而变化放电电流越大,电压越低.在没有电流的情况下,电压最高.

2.环境温度对电池电压的影响温度越低,同等容量电池电压越低.

3.循环对电池放电平台的影响随着循环的进行,锂离子电池的放电平台趋于恶化.放电平台降低.所以相同电压所代表的容量也相应变化了.

4.不同厂家,不同容量的锂离子电池,其放电的平台略有差异.

5.不同类型的电极材料的锂离子电池,放电平台有较大差异.钴锂和锰锂的放电平台就完全不同.

 

2.6.  库仑计法

通过统计流入和流出电池的电荷数,使用库仑计时需要通过其他方法获得电池在使用前的电量。

 

2.7.  锂电池充电

锂电池的充电过程:涓充---恒流---恒压---停止

充电曲线

clip_image008[1]

 

2.8.  TF303充电电路

(1)80678606和电池的连接图

clip_image010[1]图摘自8607 datasheet

 

(2)8607中断引脚

8607PMIC_INTN引脚接到APPMIC_INT引脚

 

(3)i2c通信

86068607SCL引脚连接到APGPIO_53SDA连接到GPIO_53

 

 

3.       Android 电池管理

clip_image012[1]图摘自网络

kernel中,驱动会在文件系统中生成battery相关的文件,包括电池电量、状态等,驱动更新硬件信息时会调用power_supply提供的接口,power_supply收到这个事件后通过uevent机制利用netlink将这个event上报给app层,app层收event后再去读sysfs中的相关文件获取数据。

 

 

3.1.  相关代码

(1)java代码:

frameworks/base/services/java/com/android/server/BatteryService.java

frameworks/base/services/java/com/android/server/ SystemServer.java

frameworks/base/core/java/android/os/UEventObserver.java

 

(2)JNI代码:

frameworks/base/services/jni/com_android_server_BatteryService.cpp

hardware/libhardware_legacy/uevent/uevent.c

android底层代码

hardware/libhardware_legacy/uevent/uevent.c

 

(3)krenel代码

与平台无关文件

kernel/drivers/power/power_supply_core.c

kernel/drivers/power/power_supply_sysfs.c

kernel/drivers/usb/gadget/mv_gadget.c

平台相关代码

kernel/drivers/power/88pm860x_battery.c

kernel/drivers/power/88pm860x_charger.c

kernel/drivers/usb/misc/88pm860x_vbus.c

kernel/drivers/mfd/88pm860x-core.c

kernel/drivers/mfd/88pm860x-i2c.c

 

3.2.  power系统文件

/sys/class/power_supply/battery/

/sys/class/power_supply/ac/

/sys/class/power_supply/usb/

 

 

 

3.3.  power supply子系统

3.3.1.   数据结构体

struct  power_supply结构体,如下图

clip_image014[1]

 

此结构体用于描述供电模块,系统中总过注册了三个power_supply,分别是:ACUSB hostbattery

下面以batterypower_supply初始化对该结构体成员做简单的说明

clip_image016[1]

如上图所示,其中的info->battery为一个struct  power_supply结构体

const char *name;用于描述模块的名称

enum power_supply_type type;用于描述类型,类型如下

clip_image018[1]

enum power_supply_property *properties;用于描述该供电模块有哪些属性

battery的属性如下

clip_image020[1]

 

char **supplied_to; 供电给那个模块

int (*get_property)(struct power_supply *psy,  enum power_supply_property psp, union power_supply_propval *val); 此函数指针将指向获得该模块说属性的接口函数

struct work_struct changed_work;工作队列的初始化是在power_supply注册函数中初始化的(详细见后)

 

 

3.3.2.   系统api

 

3.3.3.   power_supply_class_init

初始化函数原型如下

clip_image022[1]

Power驱动创建了一个叫struct class *power_supply_class的类容器并且初始化函数指针power_supply_class->dev_uevent 指向power_supply_uevent函数,供电模块的uevent环境变量的添加都是此函数中是实现的。

 

3.3.4.   power_supply_register

此函数是对外提供的API,作用是注册power_supply供电模块,系统中需要调用此函数来注册BatteryACUSB三个供电模块。函数的具体实现如下

clip_image024[1]

此函数的主要操作有:

(1)把该设备的class指向power_supply_class 

(2)调用device_add(dev);

(3)绑定函数power_supply_changed_work psy- >changed_work  工作队列。备注:BATTERY  AC  USB这三个供电模块的change_work都与power_supply_changed_work 函数绑定。

 

    在调用device_add(dev)(定义在:/kernel/drivers/base/core.c),会执行这一句代码:klist_add_tail(&dev- >knode_class,  &dev->class- >p- >class_devices); 因为在上面的函数中dev->class power_supply_class; ,所以device_add(dev) 会把dev- >knode_class 加入到power_supply_class klist链表中。也就是说会把usbaccharger三个的dev- >knode_class (备注:是个struct  klist_node结构体)注册到这个power_supply_class 链表中,到时候可以通过class_for_each_device 这个函数通过这个类来找到这三个device,然后通过device在找到power_supply

 

clip_image026[1]

 

3.3.5.   power_supply_uevent

power_supply_uevent 此函数的作用是通过调用uevent的接口函数add_uevent_var添加环境变量,为Battery AC USB准备好环境变量。

 

 

4.       中断

4.1.  8607中断

clip_image028[1]

clip_image030[1]

 

中断相关寄存器

8607中断状态寄存器0x030x04 05 中断使能寄存器 0x060x070x08

8607PMIC_INTN引脚接到APPMIC_INT引脚

 

4.2.  8607总中断注册

 

kernel/arch/arm/mach-mmp/raho_tf302_hwv0.c

clip_image032[1]

 

 

clip_image034[1]

clip_image036[1]

其中pm860x_irq8607总中断的处理函数

 

4.3.  8607子中断注册

 

8607子中断的资源定义

clip_image038[1]

clip_image040[1]

 

clip_image042[1]

clip_image044[1]

 

举例88pm860x_battery.c

clip_image046[1]

clip_image048[1]

 

4.4.  中断的执行流程

APPMIC_INTN引脚中断信号发生时,则调用8607的总中断处理函数pm860x_irq 在此函数中通过i2c来读8607中断状态寄存器,遍历860中断状态寄存器各个bit为,判断出具体哪个中断发生,pm860x_irq函数具体实现如下:

clip_image050[1]

handle_nested_irq函数说明:该函数用于实现一种中断共享机制,当多个中断共享某一根中断线时,我们可以把这个中断线作为父中断,共享该中断的各个设备作为子中断,在父中断的中断线程中决定和分发响应哪个设备的请求,在得出真正发出请求的子设备后,调用handle_nested_irq来响应子中断。

 

5.       battery

 

5.1.  数据结构

电池d信息的数据结构

clip_image052[1]

 

5.2.  Battery init相关

5.2.1.   Probe函数

 

clip_image054

 

 

函数的主要操作有:

电池初始化,将在后面介绍

初始化并注册电池的struct  power_supply结构体

注册8607子中断PM8607_IRQ_CC的处理函数为pm860x_coulomb_handler

注册8607子中断PM8607_IRQ_BAT的处理函数为pm860x_batt_handler

初始化monitor_workchanged_work两个工作 ,其中monitor_work主要用于每隔30s刷新电池信息到用户空间,changed_work用于更新的电池的状态。 

 

5.2.2.   pm860x_init_battery

clip_image056

 

 

5.3.  Battery measure api

5.3.1.   测量vbatt

int measure_vbatt(struct pm860x_battery_info *infoint stateint *data);

此函数通过measure_12bit_voltage 函数去读8607vbatt寄存器PM8607_VBAT_MEAS1 (0x6D)。然后通过校验算法计算出vbatt的值。

 

5.3.2.   测量ibatt

int measure_current(struct pm860x_battery_info *infoint *data);

通过86070x68  0x6c计算出ibatt

 

5.3.3.   计算开路电压

static int calc_ocv(struct pm860x_battery_info *infoint *ocv);

开路电压值是通过测出的电压、电流和内阻计算而来

 

 

5.3.4.   库仑计计数

(1)数据结构

struct ccnt {

unsigned long long int pos;

unsigned long long int neg;

unsigned int spos;

unsigned int sneg;

int total_chg/*充电统计*/

int total_dischg/*放电统计*/

};

 

(2)库仑计计算

static int calc_ccnt(struct pm860x_battery_info *infostruct ccnt *ccnt);

此函数通过86070x470x95寄存器算出total_chgtotal_dischg

 

 

5.3.5.   计算电量

接口函数:static int calc_capacity(struct pm860x_battery_info *infoint *cap);

函数的内部实现如下图

clip_image058

 

 

5.3.6.   ADC计算电量

接口函数:static int calc_soc(struct pm860x_battery_info *infoint stateint *soc);

函数的流程为:通过ADC测出电压,然后再查array_soc 电量与电压的对应关系表,从而得出电量值

clip_image060[1]

 

 

5.3.7.   充电完成时更新soc

接口函数:int pm860x_battery_update_soc(void)

函数功能:在充电彻底终止后,将库仑计清零,并将start_soc设为100

clip_image062

 

5.4.  GET电池属性API

接口函数:static int pm860x_batt_get_prop(struct power_supply *psyenum power_supply_property psp,

union power_supply_propval *val);

文件系统中,所有电池相关的设备文件都是通过此API来获取数据,此函数在pm860x_battery_probe  中注册info->battery.get_property =pm860x_batt_get_prop;  此函数会调用电池相关的测量函数。

 

5.5.  Battery work

Power supply子系统通过uevent机制把信息传输到用户空间上去,当battery的状态发生改变的时候会向用户空间上报一个uevent,这样的话用户空间就可以知道什么时候去抓信息

5.5.1.   Driver定时更新battery信息机制

battery driver使用工作队列来定时更新电池信息,工作队列定义在struct pm860x_battery_info struct delayed_work monitor_work;成员。monitor_work初始化在如下函数中,相关代码如下:

 

static __devinit int pm860x_battery_probe(struct platform_device *pdev){

    ...

    INIT_DELAYED_WORK_DEFERRABLE(&info->monitor_workpm860x_battery_work);

    queue_delayed_work(chip->monitor_wqueue&info->monitor_work, MONITOR_INTERVAL);

    ...

}

绑定pm860x_battery_work 函数到monitor_work 工作上,延时30s后将 monitor_work 加入到 monitor_wqueue 工作队列中。

 

 

static void pm860x_battery_work(struct work_struct *work)

{

struct pm860x_battery_info *info container_of(work,

struct pm860x_battery_infomonitor_work.work);

int capvocvitemp;

power_supply_changed(&info->battery);

queue_delayed_work(info->chip->monitor_wqueue&info->monitor_workMONITOR_INTERVAL);

}

函数说明:先调用power_supply_changed 函数,延时30s后将 monitor_work 再加入到 monitor_wqueue 工作队列中。 操作的结果就是每隔30s会调用一次pm860x_battery_workpower_supply_changed函数

 

5.5.2.   Power supply子系统更新battery信息机制

 

void power_supply_changed(struct power_supply *psy)函数中通过schedule_work(&psy- >changed_work); 去执行changed_work绑定的函数, 此工作队是在如下函数中初始化。

 

 

int power_supply_register(struct device *parentstruct power_supply *psy){

       INIT_WORK(&psy- >changed_workpower_supply_changed_work)

       ....

}

 

static void power_supply_changed_work(struct work_struct *work){

struct power_supply *psy container_of(workstruct power_supply,    changed_work);

kobject_uevent(&psy- >dev- >kobjKOBJ_CHANGE);

…..

}

 

kobject_uevent  将调用kobject_uevent_env  函数将power_supply_uevent  函数中准备好的环境变量通过netlink发送的app层。

 

 

6.       charger

6.1.  数据结构

clip_image064[1]

 

 

6.2.  中断

中断

处理函数

功能

PM8607_IRQ_CHG

pm860x_charger_handler

charger detect

PM8607_IRQ_CHG_DONE

pm860x_done_handler

charging done

PM8607_IRQ_CHG_FAIL

pm860x_exception_handler

charging timeout

PM8607_IRQ_CHG_FAULT

pm860x_exception_handler

charging fault

PM8607_IRQ_GPADC1

pm860x_temp_handler

battery temperature

PM8607_IRQ_VBAT

pm860x_vbattery_handler

battery voltage

PM8607_IRQ_VCHG

pm860x_vchg_handler

vchg voltage

 

 

 

 

6.2.1.   pm860x_charger_handler

插入充电器会执行此中断

clip_image066

 

 

6.2.2.   pm860x_done_handler

当充电彻底终止后,此中断会发生。

clip_image068

6.2.3.   pm860x_vbattery_handler

VBATT_INT中断处理函数

clip_image070

 

6.2.4.   pm860x_vchg_handler

VCHG_INT中断处理函数

clip_image072

 

6.3.  charger init

6.3.1.   probe函数

clip_image074

 

 

6.3.2.   pm860x_init_charger

 

clip_image076

 

 

6.4.  charger api

6.4.1.   pm860x_set_charger_type

接口函数:void  pm860x_set_charger_type(enum enum_charger_type type);   

函数功能:设置充电器类型

函数入参为要设置的充电器的类型有:

USB_CHARGER

AC_STANDARD_CHARGER

AC_OTHER_CHARGER

 

函数的内部实现如下图

clip_image078

 

 

6.4.2.   set_vchg_threshold

函数原型:static void set_vchg_threshold(struct pm860x_charger_info *info,  int minint max)

函数功能:设置VCHG_INT中断触发条件,即pm860x_vchg_handler中断函数的触发条件。

clip_image080

 

 

6.4.3.   set_vbatt_threshold

函数原型:static void set_vbatt_threshold(struct pm860x_charger_info *info,

int minint max)

函数功能:设置VBAT_INT中断触发条件pm860x_vbattery_handler中断函数的触发条件。

内部实现如下:

clip_image082

 

 

6.4.4.   set_charging_fsm

函数原型:static int set_charging_fsm(struct pm860x_charger_info *info)

函数功能:维护充电状态机

函数的内部实现如下图:

clip_image084

 

 

 

 

 

 

 

 

 

将程序流程图整理成fsm如下图

 

clip_image086

 

 

6.5.  充电的步骤

 

6.5.1.   预充

当电池的电压太低,比如过放保护的电池,需要通过预充一段时间后,再转入快充。

预充的实现函数是:static int start_precharge(struct pm860x_charger_info *info) 

函数的内部实现如下图:

clip_image088

 

 

6.6.  快充

快充主要有两个过程先恒流再恒压,通过设置86068607相关寄存器来控制恒流和恒压的过程。函数实现:int start_fastcharge(struct pm860x_charger_info *info)

函数的内部实现如下图:

clip_image090

 

6.7.  停充

接口函数是:static ssize_t stop_charging(struct device *devstruct device_attribute *attr,

const char *bufsize_t count)

 

clip_image092

 

 

7.       关于电量计算

 

clip_image094

 


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值