转自:http://blog.csdn.net/baidu_34021173/article/details/51105223
主要涉及代码:
Kernel:
kernel-3.10\drivers\power\mediatek\
kernel-3.10\drivers\misc\mediatek\mach\mt6580\<project_name>\power\
MTK Battery框架结构图
通过上层通过读取创建一系列的设备节点获取电池相关的状态信息
Android电源管理系统
/sys/class/power_supply/ac/online //AC 电源连接状态 交流电 即电源插座
/sys/class/power_supply/usb/online //USB电源连接状态
/sys/class/power_supply/battery/status //充电状态
/sys/class/power_supply/battery/health //电池状态
/sys/class/power_supply/battery/present //使用状态
/sys/class/power_supply/battery/capacity //电池 level
/sys/class/power_supply/battery/batt_vol //电池电压
/sys/class/power_supply/battery/batt_temp //电池温度
/sys/class/power_supply/battery/technology //电池技术
代码框架:
battery_common.c
在Battery驱动模块中,battery_probe函数中会创建一些设备节点,并且运行一个线程bat_thread_kthread获取电池相关的数据信息
battery_kthread_hrtimer_init();//检测电池插入/拔出
kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread");
在bat_thread_kthread线程中
- int bat_thread_kthread(voidvoid *x)
- {
- ktime_t ktime = ktime_set(3, 0);
-
- #ifdef BATTERY_CDP_WORKAROUND
- if (is_usb_rdy() == KAL_FALSE) {
- battery_log(BAT_LOG_CRTI, "CDP, block\n");
- wait_event(bat_thread_wq, (is_usb_rdy() == KAL_TRUE));
- battery_log(BAT_LOG_CRTI, "CDP, free\n");
- } else{
- battery_log(BAT_LOG_CRTI, "CDP, PASS\n");
- }
- #endif
-
-
- while (1) {
- mutex_lock(&bat_mutex);
-
- if (((chargin_hw_init_done == KAL_TRUE) && (battery_suspended == KAL_FALSE)) || ((chargin_hw_init_done == KAL_TRUE) && (fg_wake_up_bat == KAL_TRUE)))
- BAT_thread();
-
- mutex_unlock(&bat_mutex);
-
- #ifdef FG_BAT_INT
- if(fg_wake_up_bat==KAL_TRUE)
- {
- wake_unlock(&battery_fg_lock);
- fg_wake_up_bat=KAL_FALSE;
- battery_log(BAT_LOG_CRTI, "unlock battery_fg_lock \n");
- }
- #endif //#ifdef FG_BAT_INT
-
- battery_log(BAT_LOG_FULL, "wait event\n");
-
- wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));
-
- bat_thread_timeout = KAL_FALSE;
- hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);
- ktime = ktime_set(BAT_TASK_PERIOD, 0);
- if (chr_wake_up_bat == KAL_TRUE && g_smartbook_update != 1)
- {
- #if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
- if (DISO_data.chr_get_diso_state) {
- DISO_data.chr_get_diso_state = KAL_FALSE;
- battery_charging_control(CHARGING_CMD_GET_DISO_STATE, &DISO_data);
- }
- #endif
-
- g_smartbook_update = 0;
- #if defined(CUST_CAPACITY_OCV2CV_TRANSFORM)
- battery_meter_set_reset_soc(KAL_FALSE);
- #endif
- battery_meter_reset();
- chr_wake_up_bat = KAL_FALSE;
-
- battery_log(BAT_LOG_CRTI,
- "[BATTERY] Charger plug in/out, Call battery_meter_reset. (%d)\n",
- BMT_status.UI_SOC);
- }
-
- }
-
- return 0;
在这个线程中,每隔10s会去调用函数BAT_Thread去获取电池数据
BAT_Thread
- void BAT_thread(void)
- {
- static kal_bool battery_meter_initilized = KAL_FALSE;
- if (battery_meter_initilized == KAL_FALSE) {
- battery_meter_initial();
- BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();
- battery_meter_initilized = KAL_TRUE;
- }
-
- mt_battery_charger_detect_check();
- mt_battery_GetBatteryData();
- if (BMT_status.charger_exist == KAL_TRUE) {
- check_battery_exist();
- }
- mt_battery_thermal_check();
- mt_battery_notify_check();
-
- if (BMT_status.charger_exist == KAL_TRUE) {
- mt_battery_CheckBatteryStatus();
- mt_battery_charging_algorithm();
- }
-
- mt_battery_update_status();
- mt_kpoc_power_off_check();
- }
mt_battery_GetBatteryData:
- void mt_battery_GetBatteryData(void)
- {
- kal_uint32 bat_vol, charger_vol, Vsense, ZCV;
- kal_int32 ICharging, temperature, temperatureR, temperatureV, SOC;
- static kal_int32 bat_sum, icharging_sum, temperature_sum;
- static kal_int32 batteryVoltageBuffer[BATTERY_AVERAGE_SIZE];
- static kal_int32 batteryCurrentBuffer[BATTERY_AVERAGE_SIZE];
- static kal_int32 batteryTempBuffer[BATTERY_AVERAGE_SIZE];
- static kal_uint8 batteryIndex = 0;
- static kal_int32 previous_SOC = -1;
-
- bat_vol = battery_meter_get_battery_voltage(KAL_TRUE);
- Vsense = battery_meter_get_VSense();
- if( upmu_is_chr_det() == KAL_TRUE ) {
- ICharging = battery_meter_get_charging_current();
- } else {
- ICharging = 0;
- }
-
- charger_vol = battery_meter_get_charger_voltage();
- temperature = battery_meter_get_battery_temperature();
- temperatureV = battery_meter_get_tempV();
- temperatureR = battery_meter_get_tempR(temperatureV);
-
- if (bat_meter_timeout == KAL_TRUE || bat_spm_timeout == TRUE || fg_wake_up_bat== KAL_TRUE)
- {
- SOC = battery_meter_get_battery_percentage();
-
-
-
- bat_meter_timeout = KAL_FALSE;
- bat_spm_timeout = FALSE;
- } else {
- if (previous_SOC == -1)
- SOC = battery_meter_get_battery_percentage();
- else
- SOC = previous_SOC;
- }
-
- ZCV = battery_meter_get_battery_zcv();
-
- BMT_status.ICharging =
- mt_battery_average_method(BATTERY_AVG_CURRENT, &batteryCurrentBuffer[0], ICharging, &icharging_sum,
- batteryIndex);
-
-
- if (previous_SOC == -1 && bat_vol <= batt_cust_data.v_0percent_tracking) {
- battery_log(BAT_LOG_CRTI,
- "battery voltage too low, use ZCV to init average data.\n");
- BMT_status.bat_vol =
- mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], ZCV, &bat_sum,
- batteryIndex);
- } else {
- BMT_status.bat_vol =
- mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], bat_vol, &bat_sum,
- batteryIndex);
- }
-
-
- if (battery_cmd_thermal_test_mode == 1)
- {
- battery_log(BAT_LOG_CRTI,
- "test mode , battery temperature is fixed.\n");
- }
- else
- {
- BMT_status.temperature =
- mt_battery_average_method(BATTERY_AVG_TEMP, &batteryTempBuffer[0], temperature, &temperature_sum,
- batteryIndex);
- }
-
-
- BMT_status.Vsense = Vsense;
- BMT_status.charger_vol = charger_vol;
- BMT_status.temperatureV = temperatureV;
- BMT_status.temperatureR = temperatureR;
- BMT_status.SOC = SOC;
- BMT_status.ZCV = ZCV;
-
- #if !defined(CUST_CAPACITY_OCV2CV_TRANSFORM)
- if (BMT_status.charger_exist == KAL_FALSE) {
- if (BMT_status.SOC > previous_SOC && previous_SOC >= 0)
- BMT_status.SOC = previous_SOC;
- }
- #endif
-
- previous_SOC = BMT_status.SOC;
-
- batteryIndex++;
- if (batteryIndex >= BATTERY_AVERAGE_SIZE)
- batteryIndex = 0;
-
-
- if (g_battery_soc_ready == KAL_FALSE)
- g_battery_soc_ready = KAL_TRUE;
-
- battery_log(BAT_LOG_CRTI,
- "AvgVbat=(%d),bat_vol=(%d),AvgI=(%d),I=(%d),VChr=(%d),AvgT=(%d),T=(%d),pre_SOC=(%d),SOC=(%d),ZCV=(%d)\n",
- BMT_status.bat_vol, bat_vol, BMT_status.ICharging, ICharging,
- BMT_status.charger_vol, BMT_status.temperature, temperature,
- previous_SOC, BMT_status.SOC, BMT_status.ZCV);
-
-
- }
battery_meter_get_battery_percentage:
- kal_int32 battery_meter_get_battery_percentage(void)
- {
-
- if (bat_is_charger_exist() == KAL_FALSE)
- fg_qmax_update_for_aging_flag = 1;
-
-
- oam_run();
-
- return (100 - oam_d_5);
-
- }
oam_run:
- void oam_run(void)
- {
- int vol_bat = 0;
-
-
- int charging_current = 0;
- int ret = 0;
-
- struct timespec now_time;
- kal_int32 delta_time = 0;
-
-
- get_monotonic_boottime(&now_time);
-
-
- delta_time = now_time.tv_sec - last_oam_run_time.tv_sec;
-
-
- last_oam_run_time = now_time;
-
-
- fgauge_construct_table_by_temp();
-
-
- vol_bat = 15;
- ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &vol_bat);
-
- oam_i_1 = (((oam_v_ocv_1 - vol_bat) * 1000) * 10) / oam_r_1;
- oam_i_2 = (((oam_v_ocv_2 - vol_bat) * 1000) * 10) / oam_r_2;
-
- oam_car_1 = (oam_i_1 * delta_time / 3600) + oam_car_1;
- oam_car_2 = (oam_i_2 * delta_time / 3600) + oam_car_2;
-
- oam_d_1 = oam_d0 + (oam_car_1 * 100 / 10) / gFG_BATT_CAPACITY_aging;
-
- if (oam_d_1 < 0)
- oam_d_1 = 0;
- if (oam_d_1 > 100)
- oam_d_1 = 100;
-
- oam_d_2 = oam_d0 + (oam_car_2 * 100 / 10) / gFG_BATT_CAPACITY_aging;
- if (oam_d_2 < 0)
- oam_d_2 = 0;
- if (oam_d_2 > 100)
- oam_d_2 = 100;
-
- oam_v_ocv_1 = vol_bat + mtk_imp_tracking(vol_bat, oam_i_2, 5);
-
- oam_d_3 = fgauge_read_d_by_v(oam_v_ocv_1);
- if (oam_d_3 < 0)
- oam_d_3 = 0;
- if (oam_d_3 > 100)
- oam_d_3 = 100;
-
- oam_r_1 = fgauge_read_r_bat_by_v(oam_v_ocv_1);
-
- oam_v_ocv_2 = fgauge_read_v_by_d(oam_d_2);
- oam_r_2 = fgauge_read_r_bat_by_v(oam_v_ocv_2);
-
-
- oam_d_4 = oam_d_3;
-
- gFG_columb = oam_car_2 / 10;
-
- if ((oam_i_1 < 0) || (oam_i_2 < 0))
- gFG_Is_Charging = KAL_TRUE;
- else
- gFG_Is_Charging = KAL_FALSE;
-
-
- d5_count_time = 60;
-
- d5_count = d5_count + delta_time;
- if (d5_count >= d5_count_time) {
- if (gFG_Is_Charging == KAL_FALSE) {
- if (oam_d_3 > oam_d_5) {
- oam_d_5 = oam_d_5 + 1;
- } else {
- if (oam_d_4 > oam_d_5) {
- oam_d_5 = oam_d_5 + 1;
- }
- }
- } else {
- if (oam_d_5 > oam_d_3) {
-
- oam_d_5 = oam_d_5 - 1;
- } else {
- if (oam_d_4 < oam_d_5) {
- oam_d_5 = oam_d_5 - 1;
- }
- }
- }
- d5_count = 0;
- oam_d_3_pre = oam_d_3;
- oam_d_4_pre = oam_d_4;
- }
-
- }
oam_run的整个的一个流程如下图所示:
MTK采用的Fuel方案获取剩余电池电量
首先通过adc读取电池 Vbat脚的电压值,然后通过这个闭路电压值查找 R—Table (cust_battery_meter_table.h )获得当前电压和温度下的电池内阻值,然后通过递归回溯的方法得到开路电压 OCV,然后通过这个OCV电压值查找 放电深度表获取当前的放电深度,从而算出剩余的电池电量。
调试驱动时应注意的一些关键点
1、电池曲线
2、充电电流的一些设置(AC_CHARGER_CURRENT,NON_STD_AC_CHARGER_CURRENT,USB_CHARGER_CURRENT等),是否是高压电池HIGH_BATTERY_VOLTAGE_SUPPORT
最高温度: MAX_CHARGE_TEMPERATURE
最高电压: V_CHARGER_MAX
截止满充电流大小:CHARGING_FULL_CURRENT
充关机最大电池差异:CUST_POWERON_DELTA_CAPACITY_TOLRANCE(若小于这个值,则下一次开机用RTC里面存储的剩余电池电量值)
关机电压:SYSTEM_OFF_VOLTAGE
UI电量同步时间:SYNC_TO_REAL_TRACKING_TIME
电池充电驱动流程分析(battery_common.c):
/* Integrate with NVRAM */
ret = alloc_chrdev_region(&adc_cali_devno, 0, 1, ADC_CALI_DEVNAME);
//字符设备的注册,
register_chrdev_region(dev_t first,unsigned int count,char *name)
First :要分配的设备编号范围的初始值(次设备号常设为0);
Count:连续编号范围.
Name:编号相关联的设备名称. (/proc/devices);
动态分配:
Int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
Firstminor : 通常为0;
*dev:存放返回的设备号;
Count:连续编号范围.
Name:编号相关联的设备名称. (/proc/devices);
adc_cali_cdev = cdev_alloc();
动态申请一个字符设备的内存
adc_cali_cdev->owner = THIS_MODULE;
adc_cali_cdev->ops = &adc_cali_fops;
ret = cdev_add(adc_cali_cdev, adc_cali_devno, 1)//adc_cali_devno:设备号,前20位是主设备好,后12位此设备号 adc_cali_cdev:设备的结构体
adc_cali_major = MAJOR(adc_cali_devno); //获取主设备号
adc_cali_class = class_create(THIS_MODULE, ADC_CALI_DEVNAME);, 1);
class_dev = (struct class_device *)device_create(adc_cali_class,
NULL,
adc_cali_devno, NULL, ADC_CALI_DEVNAME);
get_charging_control();
battery_charging_control = chr_control_interface;
status = charging_func[cmd](data);
static kal_uint32 (* const charging_func[CHARGING_CMD_NUMBER])(void *data)=
{
charging_hw_init
,charging_dump_register
,charging_enable
,charging_set_cv_voltage
,charging_get_current
,charging_set_current
......
}
/* Integrate with Android Battery Service */
ret = power_supply_register(&(dev->dev), &ac_main.psy);
BMT_status.bat_charging_state = CHR_PRE;
BMT_status.bat_in_recharging_state = KAL_FALSE;
BMT_status.bat_full = KAL_FALSE;
BMT_status.nPercent_ZCV = 0; 初始化状态
battery_kthread_hrtimer_init(); 定时器初始化
kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread"); 创建并让线程一直运行起来
/*LOG System Set */
init_proc_log();
bat_thread_kthread:
{
wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));
}
void BAT_thread(void)
{
static kal_bool battery_meter_initilized = KAL_FALSE;
if (battery_meter_initilized == KAL_FALSE) {
battery_meter_initial();/* move from battery_probe() to decrease booting time */
BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();
battery_meter_initilized = KAL_TRUE;
}
mt_battery_charger_detect_check();
mt_battery_GetBatteryData();
if (BMT_status.charger_exist == KAL_TRUE) {
check_battery_exist();
}
mt_battery_thermal_check();
mt_battery_notify_check();
if (BMT_status.charger_exist == KAL_TRUE) {
mt_battery_CheckBatteryStatus(); //检查充电状态,选择CC_PRE开始,或其他非正常状态,
mt_battery_charging_algorithm(); //真正的充电开始,如果一直在CC_PRE状态,则会反复判断是否达到
进入CC状态的条件,以此类推,状态这样切换
}
mt_battery_update_status();
mt_kpoc_power_off_check();
}