/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 2010 High Tech Computer Corporation Module Name: ds2784_param.c Abstract: This module implements the battery formula based on power spec, including below concepts: 1. adc converter 2. voltage mapping to capacity 3. over temperature algorithm 4. id range algorithm 5. ACR maintainance Add from TPE PMA: 1. temperature index 2. pd_m_coef_boot 3. preserved_capacity_by_temp Remove from TAO PMA: 1. pd_temp To adapt different PMA/projects, we need to modify below tables: 1. ID_RANGE: which battery is used in the project? 2. FL_25: the full capacity in temp 25C. 3. pd_m_bias_mA: the discharge current threshold to calculating pd_m 4. M_PARAMTER_TABLE: the voltage-capacity mapping table 5. TEMP_RANGE: how many temp condition we need to consider 6. PD_M_COEF_TABLE(BOOT)/PD_M_RESL_TABLE(BOOT): voltage compensation based on current 7. PD_T_COEF: voltage compensation based on temp 8. CAPACITY_DEDUCTION_01p: the capacity deduction due to low temperature Original Auther: Andy.ys Wang June-01-2010 ---------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include /*======================================================================================== build flags ========================================================================================*/ #define HTC_ENABLE_POWER_DEBUG 0 #define HTC_ENABLE_DUMMY_BATTERY 0 /*======================================================================================== battery common parameter defines (independent on battery id yet...) ========================================================================================*/ #define BATTERY_VOLTAGE_MIN 2000 #define BATTERY_VOLTAGE_MAX 20000 /*======================================================================================== battery parameter helper functions ========================================================================================*/ static INT32 get_id_index(struct battery_type *battery) { int i; for (i = 0; i < BATTERY_ID_NUM - 1; i++) { /* minus 1, unknown battery is not in ID_RANGE [min, max)*/ UINT32 resister_min = ID_RANGE[i*2]; UINT32 resister_max = ID_RANGE[i*2 + 1]; if (resister_min <= battery->id_ohm && resister_max > battery->id_ohm) { return i + 1; } } return BATTERY_ID_UNKNOWN; } static INT32 get_temp_index(struct battery_type *battery) { int i; for (i = 0; i < 255; i++) { /* the table size shall not be greater then 255, to ensure no infinite looping [min, max)*/ INT32 temp = TEMP_RANGE[i]; if (battery->temp_01c >= temp) return i; } printk(DRIVER_ZONE " invalid batt_temp (%d) or temp range mapping.\n", battery->temp_01c); return -1; } /*======================================================================================== temperature formula definitions ========================================================================================*/ static INT32 get_temp_01c(struct battery_type *battery) { int current_index = battery->temp_check_index; int search_direction = 0; if (battery->last_temp_adc > battery->temp_adc) { search_direction = -1; } else { search_direction = 1; } while (current_index >= 0 && current_index < TEMP_NUM-1) { UINT32 temp_min = TEMP_MAP[current_index]; UINT32 temp_max = TEMP_MAP[current_index + 1]; if (temp_max > battery->temp_adc && temp_min <= battery->temp_adc) { battery->temp_check_index = current_index; battery->last_temp_adc = battery->temp_adc; return (TEMP_MAX-current_index)*10; } current_index += search_direction; } return (TEMP_MIN-1)*10; } /*======================================================================================== over temperature protection ========================================================================================*/ static BOOL is_over_temp(struct battery_type *battery) { /* stop charging*/ if (battery->temp_01c < over_low_temp_lock_01c || battery->temp_01c >= over_high_temp_lock_01c) { return TRUE; } return FALSE; } static BOOL is_not_over_temp(struct battery_type *battery) { /* start charging*/ if (battery->temp_01c >= over_low_temp_release_01c && battery->temp_01c < over_high_temp_release_01c) { return TRUE; } return FALSE; } static void __protect_flags_update(struct battery_type *battery, struct protect_flags_type *flags) { /* Flags: is_charging_enable_available - Over temperature, need to stop charging is_charging_high_current_avaialble - Temperature is too high so that we have to slow charge*/ if (is_over_temp(battery)) { /* Ex: T<0 or T>45 */ flags->is_charging_enable_available = FALSE; flags->is_charging_high_current_avaialble = FALSE; #if 0 flags->is_battery_overtemp = TRUE; #endif } else if (is_not_over_temp(battery)) { /* Ex: T<42 or T>3*/ flags->is_charging_enable_available = TRUE; flags->is_charging_high_current_avaialble = TRUE; #if 0 flags->is_battery_overtemp = FALSE; #endif } /* Flags: is_battery_dead - If battery is dead, show special indicator for it*/ if (battery->voltage_mV < BATTERY_DEAD_VOLTAGE_LEVEL) { flags->is_battery_dead = TRUE; } else if (battery->voltage_mV > BATTERY_DEAD_VOLTAGE_RELEASE) { flags->is_battery_dead = FALSE; } } /*======================================================================================== Voltage-Percentage mapping ========================================================================================*/ /*------------------------------------------------------------------------ Example: p0 = (4200, 10000); 4.2V for 100% p1 = (3900, 8000); 3.9V for 80% p2 = (3700, 2000); 3.7V for 20% p3 = (3300, 0); 3.3V for 0% if V = 4000, (3900<4000<4200) P = (4000-3900) * (10000-8000)/(4200-3900) + 8000 = 8666*/ #define NUM_SAMPLED_POINTS_MAX 12 struct sampled_point_type { DWORD voltage; DWORD capacity; }; struct voltage_curve_translator { DWORD voltage_min; DWORD voltage_max; DWORD capacity_min; DWORD capacity_max; int sampled_point_count; struct sampled_point_type sampled_points[NUM_SAMPLED_POINTS_MAX]; }; static void voltage_curve_translator_init(struct voltage_curve_translator *t) { memset(t, 0, sizeof(*t)); } static void voltage_curve_translator_add(struct voltage_curve_translator *t, DWORD voltage, DWORD capacity) { struct sampled_point_type *pt; if (t->sampled_point_count >= NUM_SAMPLED_POINTS_MAX) { return; } t->sampled_points[t->sampled_point_count].voltage = voltage; t->sampled_points[t->sampled_point_count].capacity = capacity; pt = &t->sampled_points[t->sampled_point_count]; t->sampled_point_count++; if (pt->voltage > t->voltage_max) t->voltage_max = pt->voltage; if (pt->voltage < t->voltage_min) t->voltage_min = pt->voltage; if (pt->capacity > t->capacity_max) t->capacity_max = pt->capacity; if (pt->capacity < t->capacity_min) t->capacity_min = pt->capacity; #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " kadc t: capacity=%d voltage=%d\n", capacity, voltage); #endif /* HTC_ENABLE_POWER_DEBUG*/ } static INT32 voltage_curve_translator_get(struct voltage_curve_translator *t, DWORD voltage) { struct sampled_point_type *p0, *p1; INT32 capacity; int i; if (voltage > t->voltage_max) voltage = t->voltage_max; if (voltage < t->voltage_min) voltage = t->voltage_min; p0 = &t->sampled_points[0]; p1 = p0 + 1; for (i = 0; i < t->sampled_point_count - 1 && voltage < p1->voltage; i++) { p0++; p1++; } /* DIV ZERO check*/ if (p0->voltage - p1->voltage == 0) { return 0; } /* INT32 overflow check: mv(4200) * capacity(10000), shall be no problem at all...*/ capacity = (voltage - p1->voltage) * (p0->capacity - p1->capacity) / (p0->voltage - p1->voltage) + p1->capacity; if (capacity > t->capacity_max) { capacity = t->capacity_max; } if (capacity < t->capacity_min) { capacity = t->capacity_min; } return capacity; } /*======================================================================================== KADC mapping functions ========================================================================================*/ static struct voltage_curve_translator __get_kadc_t; static INT32 get_kadc_001p(struct battery_type *battery) { INT32 pd_m = 0; INT32 pd_temp = 0; INT32 temp_01c = battery->temp_01c; INT32 current_mA = battery->current_mA; UINT32 *m_paramtable; INT32 pd_m_coef; INT32 pd_m_resl; INT32 capacity_deduction_01p = CAPACITY_DEDUCTION_01p[battery->temp_index]; INT32 capacity_predict_001p; /* 1. INT32 overflow check: assert abs(iChgCurrent_ma) <= 3000, iBattTemp_01c>-250, pd_t_coef <= 1000 when calculating pd_temp: 0x7FFFFFFF / (500 * 3000 * 1000) =:= 1.4*/ if (battery->current_mA > 3000) current_mA = 3000; else if (battery->current_mA < -3000) current_mA = -3000; if (battery->temp_01c <= -250) temp_01c = -250; /* 2. calculate pd_m and pd_temp*/ if (battery->is_power_on_reset) { pd_m_coef = PD_M_COEF_TABLE_BOOT[battery->temp_index][battery->id_index]; pd_m_resl = PD_M_RESL_TABLE_BOOT[battery->temp_index][battery->id_index]; } else{ pd_m_coef = PD_M_COEF_TABLE[battery->temp_index][battery->id_index]; pd_m_resl = PD_M_RESL_TABLE[battery->temp_index][battery->id_index]; } if (battery->current_mA < -pd_m_bias_mA) { /* ex: -150mA < -130mA*/ pd_m = (abs(battery->current_mA) - pd_m_bias_mA) * pd_m_coef /pd_m_resl; } if (battery->temp_01c < 250) { pd_temp = ((250 - battery->temp_01c) * (abs(battery->current_mA) * PD_T_COEF[battery->id_index])) / (10 * 10000); } battery->pd_m = pd_m; /* 3. calculate KADC using M_PARAMTER_TABLE*/ m_paramtable = M_PARAMTER_TABLE[battery->id_index]; if (m_paramtable) { int i = 0; /* assume that m_paramtable has at least 2 items...the last capacity item must be 0 to end the loop...*/ voltage_curve_translator_init(&__get_kadc_t); while (1) { INT32 capacity = m_paramtable[i]; INT32 voltage = m_paramtable[i + 1]; if (capacity == 10000) { /* full capacity, no need to fix voltage level*/ voltage_curve_translator_add(&__get_kadc_t, voltage, capacity); } else { voltage_curve_translator_add(&__get_kadc_t, voltage - pd_temp, capacity); } if (capacity == 0) break; i += 2; } #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " pd_m=%d, pd_temp=%d\n", pd_m, pd_temp); #endif /* HTC_ENABLE_POWER_DEBUG*/ capacity_predict_001p = voltage_curve_translator_get(&__get_kadc_t, battery->voltage_mV + pd_m); } else{ capacity_predict_001p = (battery->voltage_mV - 3400) * 10000 / (4200 - 3400); } return (capacity_predict_001p - capacity_deduction_01p * 10) * 10000 / (10000 - capacity_deduction_01p * 10); } /*======================================================================================== coulomb counter+curve tracer ========================================================================================*/ static INT32 get_software_acr_revise(struct battery_type *battery, UINT32 ms) { INT32 kadc_01p = battery->KADC_01p; INT32 ccbi_01p = battery->RARC_01p; INT32 delta_01p = kadc_01p - ccbi_01p; DWORD C = 5; /* KADC = 15%~100%*/ if (kadc_01p <= 150) { C = 5; } /* KADC = 0%~15%*/ if (delta_01p < 0) { /* if KADC is less than RARC, p shall be lower*/ return -(INT32) (C * ms * delta_01p * delta_01p) / 1000; } else{ /* if KADC is larger than RARC, p shall be higher*/ return (INT32) (C * ms * delta_01p * delta_01p) / 1000; } } /*======================================================================================== ds2746 gauge ic functions, to access ds2746 registers and convert ADC to battery param ========================================================================================*/ static void __ds2746_clear_porf(void) { UINT8 reg_data; if (!ds2746_i2c_read_u8(®_data, 0x01)) { printk(DRIVER_ZONE " clear porf error in read.\n"); return; } if (!ds2746_i2c_write_u8((reg_data & (~DS2746_STATUS_PORF)), 0x01)) { printk(DRIVER_ZONE " clear porf error in write.\n"); return; } } static void __ds2746_acr_update(struct battery_type *battery, int capacity_01p) { printk(DRIVER_ZONE " acr update: P=%d, C=%d.\n", capacity_01p, battery->charge_counter_adc); ds2746_i2c_write_u8((battery->charge_counter_adc & 0xFF00) >> 8, 0x10); ds2746_i2c_write_u8((battery->charge_counter_adc & 0x00FF), 0x11); if (battery->is_power_on_reset) { __ds2746_clear_porf(); } } static void __ds2746_init_config(struct battery_type *battery) { UINT8 reg_data; if (!ds2746_i2c_read_u8(®_data, 0x01)) { printk(DRIVER_ZONE " init config error in read.\n"); return; } /* Erase SMOD and NBEN value in DS2746 status/config register*/ reg_data &= ~(DS2746_STATUS_SMOD | DS2746_STATUS_NBEN); if (!ds2746_i2c_write_u8(reg_data, 0x01)) { printk(DRIVER_ZONE " init config error in write.\n"); return; } } static BOOL __ds2746_get_reg_data(UINT8 *reg) { memset(reg, 0, 12); if (!ds2746_i2c_read_u8(®[0], 0x01)) return FALSE; if (!ds2746_i2c_read_u8(®[2], 0x08)) return FALSE; if (!ds2746_i2c_read_u8(®[3], 0x09)) return FALSE; if (!ds2746_i2c_read_u8(®[4], 0x0a)) return FALSE; if (!ds2746_i2c_read_u8(®[5], 0x0b)) return FALSE; if (!ds2746_i2c_read_u8(®[6], 0x0c)) return FALSE; if (!ds2746_i2c_read_u8(®[7], 0x0d)) return FALSE; if (!ds2746_i2c_read_u8(®[8], 0x0e)) return FALSE; if (!ds2746_i2c_read_u8(®[9], 0x0f)) return FALSE; if (!ds2746_i2c_read_u8(®[10], 0x10)) return FALSE; if (!ds2746_i2c_read_u8(®[11], 0x11)) return FALSE; return TRUE; } static BOOL __ds2746_battery_adc_udpate(struct battery_type *battery) { UINT8 reg[12]; if (!__ds2746_get_reg_data((UINT8 *) ®)) { printk(DRIVER_ZONE " get ds2746 data failed...\n"); return FALSE; } #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " [x0]%x [x8]%x %x %x %x %x %x %x %x %x %x\n", reg[0], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7], reg[8], reg[9], reg[10], reg[11]); #endif if (!(reg[0] & DS2746_STATUS_AIN0) || !(reg[0] & DS2746_STATUS_AIN1)) { printk(DRIVER_ZONE " AIN not ready...\n"); return FALSE; } if (reg[0] & DS2746_STATUS_PORF) { battery->is_power_on_reset = TRUE; } else{ battery->is_power_on_reset = FALSE; } /* adc register value*/ battery->voltage_adc = MAKEWORD(reg[7], reg[6]) >> 4; battery->current_adc = MAKEWORD(reg[9], reg[8]); if (battery->current_adc & 0x8000) { battery->current_adc = -(0x10000 - battery->current_adc); } battery->current_adc /= 4; battery->charge_counter_adc = MAKEWORD(reg[11], reg[10]); if (battery->charge_counter_adc & 0x8000) { battery->charge_counter_adc = -(0x10000 - battery->charge_counter_adc); } battery->id_adc = MAKEWORD(reg[5], reg[4]) >> 4; battery->temp_adc = MAKEWORD(reg[3], reg[2]) >> 4; if (support_ds2746_gauge_ic) { /* we preserve 500mAh for capacity lower than 0%, however the 500mAh is still drained out...we need to do predict for correct ACR*/ if ((battery->charge_counter_adc & 0xFFFF) >= 0xF000){ printk(DRIVER_ZONE " ACR out of range (x%x)...\n", battery->charge_counter_adc); battery->is_power_on_reset = TRUE; } } return TRUE; } /*======================================================================================== softwar acr functions, to accumulate ACR by software and revise by battery parameter ========================================================================================*/ static void __software_charge_counter_update(struct battery_type *battery, UINT32 ms) { /* if the charge counter is maintained by sw, batt_alg shall use this routine to update charge counter and related parameters*/ INT32 capacity_deduction_01p = CAPACITY_DEDUCTION_01p[battery->temp_index]; /* AEL(mAh): A low temp unusable battery capacity, calculated in runtime*/ INT32 ael_mAh = capacity_deduction_01p *battery->charge_full_real_mAh / 1000; #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE "chgctr update: I=%d ms=%d.\n", battery->current_mA, ms); #endif /* HTC_ENABLE_POWER_DEBUG*/ /* ACRt(mAh): The total capacity battery owns, stored in battery->charge_counter_mAh*/ battery->software_charge_counter_mAms += (INT32) (battery->current_mA * ms); battery->charge_counter_mAh += (battery->software_charge_counter_mAms / 3600000); battery->software_charge_counter_mAms -= (battery->software_charge_counter_mAms / 3600000) * 3600000; /* CCBI(0.1%): A software RARC*/ battery->RARC_01p = (battery->charge_counter_mAh - ael_mAh) * 1000 / (battery->charge_full_real_mAh - ael_mAh); /* store back the battery->charge_counter_mAh to battery->charge_counter_adc*/ battery->charge_counter_adc = (battery->charge_counter_mAh + charge_counter_zero_base_mAh) * acr_adc_to_mv_coef / acr_adc_to_mv_resl; } static void __software_charge_counter_revise(struct battery_type *battery, UINT32 ms) { if (battery->current_mA < 0) { #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE "chgctr revise: delta=%d.\n", get_software_acr_revise(battery, ms)); #endif /* HTC_ENABLE_POWER_DEBUG*/ /* revise software charge counter by coulomb counter+curve tracer*/ battery->software_charge_counter_mAms += get_software_acr_revise(battery, ms); battery->charge_counter_mAh += (battery->software_charge_counter_mAms / 3600000); battery->software_charge_counter_mAms -= (battery->software_charge_counter_mAms / 3600000) * 3600000; /* store back the battery->charge_counter_mAh to battery->charge_counter_adc*/ battery->charge_counter_adc = (battery->charge_counter_mAh + charge_counter_zero_base_mAh) * acr_adc_to_mv_coef / acr_adc_to_mv_resl; } } static void __software_acr_update(struct battery_type *battery) { static BOOL s_bFirstEntry = TRUE; static DWORD last_time_ms; DWORD now_time_ms = BAHW_MyGetMSecs(); if (s_bFirstEntry) { s_bFirstEntry = FALSE; last_time_ms = now_time_ms; } #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE "+acr update: adc=%d C=%d mams=%d.\n", battery->charge_counter_adc, battery->charge_counter_mAh, battery->software_charge_counter_mAms); #endif /* HTC_ENABLE_POWER_DEBUG*/ __software_charge_counter_update(battery, now_time_ms - last_time_ms); __software_charge_counter_revise(battery, now_time_ms - last_time_ms); #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE "-acr update: adc=%d C=%d mams=%d.\n", battery->charge_counter_adc, battery->charge_counter_mAh, battery->software_charge_counter_mAms); #endif /* HTC_ENABLE_POWER_DEBUG*/ last_time_ms = now_time_ms; } /*======================================================================================== battery param update, the coef are referenced from power spec ========================================================================================*/ static BOOL __battery_param_udpate(struct battery_type *battery) { static int batt_id_stable_counter = 0; INT32 batt_id_index; INT32 temp_01c; if (support_ds2746_gauge_ic) { /* adc register value are read from __ds2746_battery_adc_udpate()*/ if (!__ds2746_battery_adc_udpate(battery)) return FALSE; } else{ /* adc register value are read from BAHW_get_batt_info_all() if ( !BAHW_get_batt_info_all(battery) ) return FALSE;*/ } /*real physical value*/ battery->voltage_mV = (battery->voltage_adc * voltage_adc_to_mv_coef / voltage_adc_to_mv_resl); battery->current_mA = (battery->current_adc * current_adc_to_mv_coef / current_adc_to_mv_resl); battery->discharge_mA = (battery->discharge_adc * discharge_adc_to_mv_coef / discharge_adc_to_mv_resl); battery->charge_counter_mAh = (battery->charge_counter_adc * acr_adc_to_mv_coef / acr_adc_to_mv_resl) - charge_counter_zero_base_mAh; battery->current_mA = battery->current_mA - battery->discharge_mA; #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " battery.id_adc pre clip: %d\n", battery->id_adc); printk(DRIVER_ZONE " battery.temp_adc pre clip: %d\n", battery->temp_adc); #endif /* prevent from adc out of range*/ if (battery->id_adc >= id_adc_resl) { battery->id_adc = id_adc_resl - 1; } if (battery->id_adc <= 0) { battery->id_adc = 1; } if (battery->temp_adc >= temp_adc_resl) { battery->temp_adc = temp_adc_resl - 1; } if (battery->temp_adc <= 0) { battery->temp_adc = 1; } /* battery ID shall be ready first for temp/kadc calculation*/ // if ( id_conversion ) battery->id_ohm = ((float)id_R_kohm / ((float)id_adc_resl/battery->id_adc - 1)) * 1000; // kohm -> ohm // else battery->id_ohm = battery->id_adc; battery->id_ohm = battery->temp_adc; #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " battery.id_ohm pre calibrate: %d\n", battery->id_ohm); #endif /* HTC_ENABLE_POWER_DEBUG*/ //calibrate_id_ohm(battery); #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " battery.id_ohm post calibrate: %d\n", battery->id_ohm); #endif /* HTC_ENABLE_POWER_DEBUG*/ batt_id_index = get_id_index(battery); #if HTC_ENABLE_POWER_DEBUG printk(DRIVER_ZONE " batt_id: %d\n", batt_id_index); #endif /* HTC_ENABLE_POWER_DEBUG*/ if (is_allow_batt_id_change) { /*! TODO: batt_id changes immediately; may need to modify in future*/ if (batt_id_stable_counter >= 3 && batt_id_index != battery->id_index){ /* if batt_id is stable but is different from previous one*/ batt_id_stable_counter = 0; /* reset stable counter and set batt_id to new one*/ } } if (batt_id_stable_counter < 3) { if (batt_id_stable_counter == 0) { /* first time to get the batt id*/ battery->id_index = batt_id_index; battery->charge_full_design_mAh = FL_25[battery->id_index]; battery->charge_full_real_mAh = battery->charge_full_design_mAh; batt_id_stable_counter = 1; } else{ /* 2nd and further time to get the batt id*/ if (batt_id_index == battery->id_index) batt_id_stable_counter++; else batt_id_stable_counter = 0; } } temp_01c = get_temp_01c(battery); if (batt_id_index == 5) { //battery->temp_adc = battery->temp_adc * 7; temp_01c = 650 - battery->temp_adc*10; } /* calculate temperature*/ // battery->temp_01c = get_temp_c((float)temp_R_kohm / ((float)temp_adc_resl/battery->temp_adc - 1))*10; if(temp_01c == 700) { FL_25[battery->id_index] = 2300; battery->charge_full_real_mAh = FL_25[battery->id_index]; battery->charge_full_design_mAh = battery->charge_full_real_mAh; temp_01c = 650 - battery->temp_adc*10; } if (temp_01c >= TEMP_MIN*10) battery->temp_01c = temp_01c; else printk(DRIVER_ZONE " get temp_01c(%d) failed...\n", temp_01c); battery->temp_index = get_temp_index(battery); /* calculate KADC and RARC*/ battery->KADC_01p = CEILING(get_kadc_001p(battery), 10); battery->RARC_01p = CEILING(10000 * battery->charge_counter_mAh / battery->charge_full_real_mAh, 10); if (!support_ds2746_gauge_ic) { __software_acr_update(battery); } if (battery->voltage_mV voltage_mV> BATTERY_VOLTAGE_MAX) { printk(DRIVER_ZONE " invalid V(%d).\n", battery->voltage_mV); return FALSE; } /*! star_lee 20100426 - minimum RARC is 0%*/ if (battery->RARC_01p <= 0) { battery->RARC_01p = 0; } printk(DRIVER_ZONE " V=%d(%x) I=%d(%x) C=%d.%d/%d(%x) id=%d(%x) T=%d(%x) KADC=%d\n", battery->voltage_mV, battery->voltage_adc, battery->current_mA, battery->current_adc, battery->charge_counter_mAh, battery->software_charge_counter_mAms, battery->charge_full_real_mAh, battery->charge_counter_adc, battery->id_index, battery->id_adc, battery->temp_01c, battery->temp_adc, battery->KADC_01p); return TRUE; } /*======================================================================================== time functions ========================================================================================*/ DWORD BAHW_MyGetMSecs(void) { struct timespec now; getnstimeofday(&now); /*struct timespec t; t.tv_sec = t.tv_nsec = 0; clock_gettime(CLOCK_MONOTONIC, &t);*/ return now.tv_sec * 1000 + now.tv_nsec / 1000000; } /*======================================================================================== battery param public function ========================================================================================*/ void battery_capacity_update(struct battery_type *battery, int capacity_01p) { /* ACR 500~500+FULL mapping to capacity 0~FULL*/ battery->charge_counter_mAh = capacity_01p * battery->charge_full_real_mAh / 1000; battery->charge_counter_adc = (battery->charge_counter_mAh + charge_counter_zero_base_mAh) * acr_adc_to_mv_resl / acr_adc_to_mv_coef; battery->RARC_01p = capacity_01p; if (support_ds2746_gauge_ic) { __ds2746_acr_update(battery, capacity_01p); } printk(DRIVER_ZONE "new RARC=%d C=%dmAh adc=%d.\n", battery->RARC_01p, battery->charge_counter_mAh, battery->charge_counter_adc); battery->is_power_on_reset = FALSE; } BOOL battery_param_update(struct battery_type *battery, struct protect_flags_type *flags) { if (!__battery_param_udpate(battery)) { return FALSE; } if (flags->is_fake_room_temp) { battery->temp_01c = 250; printk(DRIVER_ZONE "fake temp=%d(%x)\n", battery->temp_01c, battery->temp_adc); } __protect_flags_update(battery, flags); #if ! HTC_ENABLE_DUMMY_BATTERY if (battery->id_index == BATTERY_ID_UNKNOWN) { flags->is_charging_enable_available = FALSE; } #else /* HTC_ENABLE_DUMMY_BATTERY*/ /* do not disable charging for debug stage*/ flags->is_charging_enable_available = TRUE; #endif /* HTC_ENABLE_DUMMY_BATTERY*/ return TRUE; } void battery_param_init(struct battery_type *battery) { /* set battery id to unknown to get battery id and related characters*/ battery->id_index = BATTERY_ID_UNKNOWN; /* default to 25C unless we can get valid battery temp from adc*/ battery->temp_01c = 250; battery->last_temp_01c = battery->temp_01c; battery->temp_check_index = 0; battery->last_temp_adc = 0; battery->voltage_mV = 3800; /* this is used when accumulate current by software; initial it as 0mAs*/ battery->software_charge_counter_mAms = 0; /* set POR at first by software; gauge ic will has correct value*/ battery->is_power_on_reset = TRUE; if (support_ds2746_gauge_ic) { __ds2746_init_config(battery); } if (battery->thermal_id == THERMAL_1000) { TEMP_MAP = TEMP_MAP_1000K; printk(DRIVER_ZONE "Use 1000 Kohm thermal resistance"); } else if (battery->thermal_id == THERMAL_600) { TEMP_MAP = TEMP_MAP_600K; printk(DRIVER_ZONE "Use 600 Kohm thermal resistance"); } else { printk(DRIVER_ZONE "Use default(300 Kohm) thermal resistance"); } /*printk(DRIVER_ZONE "battery param inited with board name <%s>\n", HTC_BATT_BOARD_NAME);*/ }