[置顶] 展讯充电管理模块浅析(一)

来源:互联网 发布:内网穿透软件 linux 编辑:程序博客网 时间:2024/06/05 05:48

展讯充电管理模块浅析

电池在电子产品中所占的地位就不用说了。不过电池在物理接口上比较简单,就两条线:正极、负极,这个小学生科普知识都知道;不过真正用到电子产品中时,有关电池方面的东西还是有点多的。

参考文档:

http://m.blog.csdn.net/blog/Baiduluckyboy/8813662

http://blog.csdn.net/xubin341719/article/details/8497830

      从三个方面介绍:

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

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

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

需要格外关注的文件sprd_power.c;sprd_8825_charge.c/sprd_8825_charge.h

充电驱动核心文件:power_supply_core.cpower_supply_sysfs.c

相关充电管理ic驱动代码bq27x00_battery.c,max17040_battery.c  ...

展讯充电管理ic模块集成在芯片内部,由各种寄存器直接操作!

一、锂电池充电基本原理篇

电池充电最重要的就是这三步:

A charge cycle begins whenthe voltage atVCHG pin rises above 4.5v . If the VBAT is lessthan 1.1v,the charger entersactive charge mode. Inthis mode, charger supplies approximately 5mA chargecurrent  to active the battery. If  the VBAT is more than 1.1v and less than 2.7v, the charger enters small currentcharge mode. In this mode, charger supplies approximately 50mA charge currentto bringthe battery voltage upto a safe level for full current charging. WhenVBAT voltage rises above 2.7v, the chargers enters full current charge mode andcharger uses a constant-current algorithm in both mode.  When VBAT approaches the final float voltage(4.2v), charger enters constant-voltage mode and the charge current beginstodecrease. When the charge current dropsto thetermination current(50mA~100mA)set bythesoftware,  the charge cycle ends, andtheend voltage could be very accurate if calibrated by the software or ATE.     

--摘自展讯TIGER externaldevicespec.pdf

锂离子电池一般都带有管理芯片和充电控制芯片。其中管理芯片中有一系列的寄存器,存有容量、温度、ID、充电状态、放电次数等数值。这些数值在使用中会逐渐变化。使用说明中的使用一个月左右应该全充放一次的做法主要的作用应该就是修正这些寄存器里不当的值。

第一步:判断电压<1.1V,要先进行预充电,5ma电流;

第二步:判断1.1V<电压<2.7V,要先进行预充电,50ma电流;

第三步:判断 2.7V<电压<4.2V,恒流充电500ma-800ma电流;

#defineSPRD_USB_CHG_CUR         SPRD_CHG_CUR_500MA

#if defined(CONFIG_COMB_PRODUCT_S6)

#defineSPRD_AC_CHG_CUR           SPRD_CHG_CUR_800MA

#else

#defineSPRD_AC_CHG_CUR           SPRD_CHG_CUR_600MA

#endif

/*batterystatus define*/

这里可以设置充电电流的大小!

第四步:判断电压>4.2V,恒压充电,电压为4.2V,电流随电压的增加而减少,直到充满。

voidsprd_set_sw(struct sprd_battery_data *data, int switchpoint)

{

         BUG_ON(switchpoint > 31);

         sci_adi_write(ANA_CHGR_CTRL1,

                         ((switchpoint <<CHGR_SW_POINT_SHIFT) &

                          CHGR_SW_POINT_MSK),(CHGR_SW_POINT_MSK));

}

uint32_tsprd_get_sw(struct sprd_battery_data *data)

{

         return ((sci_adi_read(ANA_CHGR_CTRL1)& CHGR_SW_POINT_MSK) >>

                   CHGR_SW_POINT_SHIFT);

}

uint32_tsprd_adjust_sw(struct sprd_battery_data * data, bool up_or_down)

{

         uint8_t current_switchpoint;

         uint8_t shift_bit;

         uint8_t chg_switchpoint;

 

         chg_switchpoint =

            (sci_adi_read(ANA_CHGR_CTRL1) & CHGR_SW_POINT_MSK) >>

            CHGR_SW_POINT_SHIFT;

         shift_bit = chg_switchpoint >> 4;

         current_switchpoint = chg_switchpoint& 0x0F;

 

         if (up_or_down) {

                   if (shift_bit > 0) {

                            if(current_switchpoint < 0xF) {

                                     current_switchpoint += 1;

                            }

                   } else {

                            if(current_switchpoint > 0) {

                                     current_switchpoint-= 1;

                            } else {

                                     shift_bit =1;

                            }

                   }

         } else {

                   if (shift_bit > 0) {

                            if(current_switchpoint > 0) {

                                     current_switchpoint-= 1;

                            } else {

                                     shift_bit =0;

                            }

                   } else {

                            if(current_switchpoint < 0xF) {

                                     current_switchpoint+= 1;

                            }

                   }

         }

 

         chg_switchpoint = (shift_bit <<4) | current_switchpoint;

 

         sci_adi_write(ANA_CHGR_CTRL1,

                         ((chg_switchpoint <<CHGR_SW_POINT_SHIFT) &

                          CHGR_SW_POINT_MSK),(CHGR_SW_POINT_MSK));

         return chg_switchpoint;

}

    展讯在CC_CV转换做的是自适应的swithpoint,也可以手动设置swithpoint,也可以读取软件设置的转换点!

 

电池温度检测:

#ifdef CONFIG_BATTERY_TEMP_DECT

       temp_value =sci_adc_get_value(ADC_CHANNEL_TEMP, false);

       if (temp_value < 0)

                goto out;

       put_temp_value(battery_data,temp_value);

       temp_value =get_temp_value(battery_data);

 

       temp =sprd_adc_to_temp(battery_data, temp_value);

/*abs is to get absolute value*/

       if(abs(battery_data->temp - temp) > 2) {

                battery_data->temp= temp;

                battery_notify= 1;

       }

 

       if (temp >OTP_OVER_HIGH || temp < OTP_OVER_LOW) {

                battery_data->over_temp_flag= 1;

                battery_notify= 1;

                printk(KERN_ERR"battery temperature out temp:%d\n", temp);

                charge_stop(battery_data);

       }

       if (!battery_data->charging&& !battery_data->in_precharge &&

           (usb_online || ac_online) &&battery_data->over_temp_flag) {

                if (temp >OTP_RESUME_LOW || temp < OTP_RESUME_HIGH) {

                          printk(KERN_ERR

                                 "battery recovery temperaturetemp:%d\n", temp);

                          battery_notify= 1;

                          battery_data->over_temp_flag= 0;

                          if(ac_online)

                                   enable_ac_charge(battery_data);

                          else

                                   enable_usb_charge(battery_data);

                }

       }

#endif

     当电池温度变化过大时,软件可中断充电!

电源状态的监控是用uevent事件实现的。Linux内核中,供电部分的框架(drivers/power目录下,power_supply_corepower_supply_sysfs)提供了uevent机制,驱动可以在电源状态发生变化时发送uevent事件到用户空间,从而通知系统做相应的处理。(对于内核空间与用户空间的uevent通信,用的始终是NETLINK_KOBJECT_UEVENT这个socket通道)。

 

二、android正常开机流程、关机充电流程

在写这篇文章之前我们先看两个流程:正常开机流程,关机充电系统启动流程

1、正常开机流程,按开机键。

可大致分成三部分

1)、OS_levelUBOOTkenrelinit这三步完成系统启动;

2)、Android_level这部分完成android部的初始化;

3)、Home Screen这部分就是我们看到的launcher部分。

2、关机充电系统启动流程

      与前面相比,这个流程只走到init这一部分,就没有往后走了,这部分我们会在后面的代码中分析。



二、关机充电逻辑硬件逻辑

1、插入DCcharger IC从硬件上唤醒系统,相当于长按开机键开机。

DC插入,其实相当于关机状态下按开机键开机。第一步要走UBOOTkernelandroid init这一流程。

a:如何判断是DC插入;在函数dwc_otg_pcd_linux.cusb_detect_works()函数中对usb插入做检测。

b:在cmd_cboot.c中有定义函数决定到底是什么方式启动开机,这个参数相当重要,这个参数决定系统是正常启动、还是关机充电状态。

三、android电池系统

创建相关的驱动交互驱动节点:

static intsprd_battery_probe(struct platform_device *pdev)

{

         int ret = -ENODEV;

         struct sprd_battery_data *data;

         int adc_value;

         int voltage_value;

         int i;

         struct resource *res = NULL;

         unsigned int efuse_cal_data[2] = { 0 };

 

         data = kzalloc(sizeof(*data),GFP_KERNEL);

         if (data == NULL) {

                   ret = -ENOMEM;

                   goto err_data_alloc_failed;

         }

     … …

}

staticstruct platform_driver sprd_battery_device = {

         .probe = sprd_battery_probe,

         .remove = sprd_battery_remove,

         .resume = sprd_battery_resume,

         .driver = {

                      .name = "sprd-battery"}

};

 

static int__init sprd_battery_init(void)

{

#ifdefCHGR_STEADY

         device_create(class_create(THIS_MODULE, "battery_capcity_dev"), NULL,MKDEV(register_chrdev(0,"battery_capcity_dev",&battery_capcity_fops),0),0, "battery_capcity_dev",0);

#endif

#ifdefined(CONFIG_GPIO_SWITCH_USB_HEADSET_SUPPORT)

         if (GPIO_HEADSET_USB_SWITCH > 0) {

                   gpio_request(GPIO_HEADSET_USB_SWITCH,"usb headset switch 137");

                   pr_err("failed to allocgpio %d\n", GPIO_HEADSET_USB_SWITCH);

         }

#endif

        

         returnplatform_driver_register(&sprd_battery_device);

}}

module_init(sprd_battery_init);

module_exit(sprd_battery_exit);

 

 

向上层传输电池相关信息:

#ifdefCHGR_STEADY

static intbattery_capcity_open(struct inode *ind, struct file *filp)

{

         return 0;

}

staticssize_t  battery_capcity_read(struct file*filp, char *buf, size_t size, loff_t *lofp)

{

         int res = -1;

         char tmp=50;

         printk("<0>copybattery_capcity to the user space\n");

         down_interruptible(&(battery_data->capacity_sema));

                   res = copy_to_user(buf,&battery_data->capcity_reference, size);

         if (res == 0)

         {

                   return size;

         }

         else

         {

                   return 0;

         }

}

staticssize_t  battery_capcity_write(structfile *filp, const char *buf, size_t size, loff_t *lofp)

{

         int res = -1;

         char tmp;

         printk("write test databattery_capcity\n");

         down_interruptible(&(battery_data->capacity_sema));

                   res =copy_from_user(&battery_data->capcity_reference, buf, size);

         if (res == 0)

         {

                   return size;

         }

         else

         {

                   return 0;

         }

}

 

structfile_operations battery_capcity_fops =

{

         .owner=THIS_MODULE,

         .open = battery_capcity_open,

         .read = battery_capcity_read,

         .write =  battery_capcity_write,

};

#endif

Java部分主要是BatteryService,作为电池及充电相关的服务,它的主要功能就是监听power_supply的uenvnt事件,读取sysfs中电池信息,然后通过intent广播给所有相关Activity。

JNI部分提供接口给上层的 battery_service.java 调用,直接读取设备文件,取得信息后,用来更新battery状态。

驱动部分kernel部分又可分为两部分:power_supply_core以及具体芯片的battery driver。

展讯电源管理芯片ic集成在芯片内部,由具体的寄存器操作,power_supply_core主要提供统一设备文件的创建以及发送power_supply相关的uevent;battery driver主要提供具体的电池信息。

 ....未完待续.....