static void low_comp_work_handler(struct work_struct *work) { struct battery_data *battery = container_of(work, struct battery_data, low_comp_work.work); int fg_soc; int fg_vcell; int fg_current; int i, comp_result; fg_soc = battery->info.level; for (i = 0 ; i<10 ; i++) { fg_vcell = get_fuelgauge_value(FG_VOLTAGE); fg_current = get_fuelgauge_value(FG_CURRENT); pr_info("%s : running", __func__); comp_result = p3_low_batt_compensation(fg_soc, fg_vcell, fg_current); if (comp_result == 2) { pr_info("%s : soc(%d), vcell(%d), current(%d), count(%d), pre_count(%d), pre_condition(%d)\n", __func__, fg_soc, fg_vcell, fg_current, i, max17042_chip_data->pre_cond_ok, max17042_chip_data->low_comp_pre_cond); break; } else if (comp_result == 1) { pr_info("%s : low compensation occurred!, vcell(%d), current(%d)\n", __func__, fg_vcell, fg_current); wake_lock(&battery->work_wake_lock); schedule_work(&battery->battery_work); break; } msleep(2000); } wake_unlock(&battery->low_comp_wake_lock); }
static bool check_UV_charging_case(void) { int fg_vcell = get_fuelgauge_value(FG_VOLTAGE); int fg_current = get_fuelgauge_value(FG_CURRENT); int threshold = 0; if (get_fuelgauge_value(FG_BATTERY_TYPE) == SDI_BATTERY_TYPE) threshold = 3300 + ((fg_current * 17) / 100); else if (get_fuelgauge_value(FG_BATTERY_TYPE) == ATL_BATTERY_TYPE) threshold = 3300 + ((fg_current * 13) / 100); if (fg_vcell <= threshold) return 1; else return 0; }
static void fuelgauge_work_handler(struct work_struct *work) { struct battery_data *battery = container_of(work, struct battery_data, fuelgauge_work.work); pr_info("low battery alert!"); if (get_fuelgauge_value(FG_CHECK_STATUS)) _low_battery_alarm_(battery); }
static void full_comp_work_handler(struct work_struct *work) { struct battery_data *battery = container_of(work, struct battery_data, full_comp_work.work); int avg_current = get_fuelgauge_value(FG_CURRENT_AVG); if (avg_current >= 25) { cancel_delayed_work(&battery->full_comp_work); schedule_delayed_work(&battery->full_comp_work, 100); } else { pr_info("%s: full charge compensation start (avg_current %d)\n", __func__, avg_current); fg_fullcharged_compensation( battery->full_charge_comp_recharge_info, 0); } }
static ssize_t p3_bat_show_property(struct device *dev, struct device_attribute *attr, char *buf) { int i = 0; #ifdef CONFIG_MACH_SAMSUNG_P5 s32 temp = 0; #endif u8 batt_str[5]; const ptrdiff_t off = attr - p3_battery_attrs; switch (off) { case BATT_VOL: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", get_fuelgauge_value(FG_VOLTAGE)); break; case BATT_TEMP: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", test_batterydata->info.batt_temp); break; #ifdef CONFIG_MACH_SAMSUNG_P5 case BATT_TEMP_CELS: temp = ((test_batterydata->info.batt_temp) / 10); i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", temp); break; #endif case BATT_CHARGING_SOURCE: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", test_batterydata->info.charging_source); break; case BATT_FG_SOC: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", get_fuelgauge_value(FG_LEVEL)); break; case BATT_BATT_TYPE: if (get_fuelgauge_value(FG_BATTERY_TYPE) == SDI_BATTERY_TYPE) sprintf(batt_str, "SDI"); else if (get_fuelgauge_value(FG_BATTERY_TYPE) == ATL_BATTERY_TYPE) sprintf(batt_str, "ATL"); i += scnprintf(buf + i, PAGE_SIZE - i, "%s_%s\n", batt_str, batt_str); break; case BATT_TEMP_CHECK: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", test_batterydata->info.batt_health); break; case BATT_FULL_CHECK: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", test_batterydata->info.batt_is_full); break; #ifdef CONFIG_SAMSUNG_LPM_MODE case CHARGING_MODE_BOOTING: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", test_batterydata->charging_mode_booting); break; case VOLTAGE_NOW: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", get_fuelgauge_value(FG_VOLTAGE)); break; #endif default: i = -EINVAL; } return i; }
static int p3_get_bat_temp(struct power_supply *bat_ps) { struct battery_data *battery = container_of(bat_ps, struct battery_data, psy_battery); int health = battery->info.batt_health; int update = 0; int battery_temp; int temp_high_threshold; int temp_high_recovery; int temp_low_threshold; int temp_low_recovery; #ifdef CONFIG_MACH_SAMSUNG_P4LTE extern int charging_mode_from_boot; #endif battery_temp = get_fuelgauge_value(FG_TEMPERATURE); temp_high_threshold = battery->pdata->temp_high_threshold; temp_high_recovery = battery->pdata->temp_high_recovery; temp_low_threshold = battery->pdata->temp_low_threshold; temp_low_recovery = battery->pdata->temp_low_recovery; #ifdef CONFIG_MACH_SAMSUNG_P4LTE if (charging_mode_from_boot) { temp_high_threshold = battery->pdata->temp_high_threshold_lpm; temp_high_recovery = battery->pdata->temp_high_recovery_lpm; temp_low_threshold = battery->pdata->temp_low_threshold_lpm; temp_low_recovery = battery->pdata->temp_low_recovery_lpm; } #endif #ifdef __TEST_DEVICE_DRIVER__ switch (bat_temp_force_state) { case 0: break; case 1: battery_temp = temp_high_threshold + 1; break; case 2: battery_temp = temp_low_threshold - 1; break; default: break; } #endif /* __TEST_DEVICE_DRIVER__ */ if (battery_temp >= temp_high_threshold) { if (health != POWER_SUPPLY_HEALTH_OVERHEAT && health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) { p3_temp_control(battery, POWER_SUPPLY_HEALTH_OVERHEAT); update = 1; } } else if (battery_temp <= temp_high_recovery && battery_temp >= temp_low_recovery) { if (health == POWER_SUPPLY_HEALTH_OVERHEAT || health == POWER_SUPPLY_HEALTH_COLD) { p3_temp_control(battery, POWER_SUPPLY_HEALTH_GOOD); update = 1; } } else if (battery_temp <= temp_low_threshold) { if (health != POWER_SUPPLY_HEALTH_COLD && health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) { p3_temp_control(battery, POWER_SUPPLY_HEALTH_COLD); update = 1; } } if (update) pr_info("p3_get_bat_temp = %d.", battery_temp); return battery_temp/100; }
static int p3_get_bat_level(struct power_supply *bat_ps) { struct battery_data *battery = container_of(bat_ps, struct battery_data, psy_battery); int fg_soc; int fg_vfsoc; int fg_vcell; int fg_current; int avg_current; int recover_flag = 0; recover_flag = fg_check_cap_corruption(); /* check VFcapacity every five minutes */ if (!(battery->fg_chk_cnt++ % 10)) { fg_check_vf_fullcap_range(); battery->fg_chk_cnt = 1; } fg_soc = get_fuelgauge_value(FG_LEVEL); if (fg_soc < 0) { pr_info("Can't read soc!!!"); fg_soc = battery->info.level; } if (!check_jig_on() && !max17042_chip_data->info.low_batt_comp_flag) { if (((fg_soc+5) < max17042_chip_data->info.previous_repsoc) || (fg_soc > (max17042_chip_data->info.previous_repsoc+5))) battery->fg_skip = 1; } /* skip one time (maximum 30 seconds) because of corruption. */ if (battery->fg_skip) { pr_info("%s: skip update until corruption check " "is done (fg_skip_cnt:%d)\n", __func__, ++battery->fg_skip_cnt); fg_soc = battery->info.level; if (recover_flag || battery->fg_skip_cnt > 10) { battery->fg_skip = 0; battery->fg_skip_cnt = 0; } } if (battery->low_batt_boot_flag) { fg_soc = 0; if (check_ta_conn(battery) && !check_UV_charging_case()) { fg_adjust_capacity(); battery->low_batt_boot_flag = 0; } if (!check_ta_conn(battery)) battery->low_batt_boot_flag = 0; } fg_vcell = get_fuelgauge_value(FG_VOLTAGE); if (fg_vcell < 0) { pr_info("Can't read vcell!!!"); fg_vcell = battery->info.batt_vol; } else battery->info.batt_vol = fg_vcell; fg_current = get_fuelgauge_value(FG_CURRENT); avg_current = get_fuelgauge_value(FG_CURRENT_AVG); fg_vfsoc = get_fuelgauge_value(FG_VF_SOC); // Algorithm for reducing time to fully charged (from MAXIM) if(battery->info.charging_enabled && // Charging is enabled !battery->info.batt_is_recharging && // Not Recharging battery->info.charging_source == CHARGER_AC && // Only AC (Not USB cable) !battery->is_first_check && // Skip when first check after boot up (fg_vfsoc>70 && (fg_current>20 && fg_current<250) && (avg_current>20 && avg_current<260))) { if(battery->full_check_flag == 2) { pr_info("%s: force fully charged SOC !! (%d)", __func__, battery->full_check_flag); fg_set_full_charged(); fg_soc = get_fuelgauge_value(FG_LEVEL); } else if(battery->full_check_flag < 2) pr_info("%s: full_check_flag (%d)", __func__, battery->full_check_flag); if(battery->full_check_flag++ > 10000) // prevent overflow battery->full_check_flag = 3; } else battery->full_check_flag = 0; if (battery->info.charging_source == CHARGER_AC && battery->info.batt_improper_ta == 0) { if (is_over_abs_time(battery)) { fg_soc = 100; battery->info.batt_is_full = 1; pr_info("%s: charging time is over", __func__); pr_info("%s: fg_vcell = %d, fg_soc = %d," " is_full = %d\n", __func__, fg_vcell, fg_soc, battery->info.batt_is_full); p3_set_chg_en(battery, 0); goto __end__; } } if (fg_vcell <= battery->pdata->recharge_voltage) { if (battery->info.batt_is_full && !battery->info.charging_enabled) { if (++battery->recharging_cnt > 1) { pr_info("recharging(under full)"); battery->info.batt_is_recharging = 1; p3_set_chg_en(battery, 1); battery->recharging_cnt = 0; pr_info("%s: fg_vcell = %d, fg_soc = %d," " is_recharging = %d\n", __func__, fg_vcell, fg_soc, battery->info.batt_is_recharging); } } else battery->recharging_cnt = 0; } else battery->recharging_cnt = 0; if (fg_soc > 100) fg_soc = 100; /* Checks vcell level and tries to compensate SOC if needed.*/ /* If jig cable is connected, then skip low batt compensation check. */ if (!check_jig_on() && !battery->info.charging_enabled) fg_soc = p3_low_batt_compensation(fg_soc, fg_vcell, fg_current); __end__: pr_debug("fg_vcell = %d, fg_soc = %d, is_full = %d", fg_vcell, fg_soc, battery->info.batt_is_full); if(battery->is_first_check) battery->is_first_check = false; if (battery->info.batt_is_full && (battery->info.charging_source != CHARGER_USB)) fg_soc = 100; #if 0 // not used else { if (fg_soc >= 100) fg_soc = 99; } #endif return fg_soc; }