/* * sec_step_charging.c * Samsung Mobile Battery Driver * * Copyright (C) 2018 Samsung Electronics * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include "sec_battery.h" #define STEP_CHARGING_CONDITION_VOLTAGE 0x01 #define STEP_CHARGING_CONDITION_SOC 0x02 #define STEP_CHARGING_CONDITION_CHARGE_POWER 0x04 #define STEP_CHARGING_CONDITION_ONLINE 0x08 #define STEP_CHARGING_CONDITION_CURRENT_NOW 0x10 #define STEP_CHARGING_CONDITION_FLOAT_VOLTAGE 0x20 #define STEP_CHARGING_CONDITION_INPUT_CURRENT 0x40 #define STEP_CHARGING_CONDITION_SOC_INIT_ONLY 0x80 /* use this to consider SOC to decide starting step only */ #define STEP_CHARGING_CONDITION_FORCE_SOC 0x100 #define STEP_CHARGING_CONDITION_FG_CURRENT 0x200 #define STEP_CHARGING_CONDITION_DC_INIT (STEP_CHARGING_CONDITION_VOLTAGE | STEP_CHARGING_CONDITION_SOC | STEP_CHARGING_CONDITION_SOC_INIT_ONLY) #define DIRECT_CHARGING_FLOAT_VOLTAGE_MARGIN 20 #define DIRECT_CHARGING_FORCE_SOC_MARGIN 10 void sec_bat_reset_step_charging(struct sec_battery_info *battery) { pr_info("%s\n", __func__); battery->step_chg_status = -1; #if IS_ENABLED(CONFIG_DIRECT_CHARGING) battery->dc_float_voltage_set = false; #endif } EXPORT_SYMBOL(sec_bat_reset_step_charging); void sec_bat_exit_step_charging(struct sec_battery_info *battery) { sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, false, 0); if (battery->step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) sec_vote(battery->fv_vote, VOTER_STEP_CHARGE, false, 0); sec_bat_reset_step_charging(battery); } EXPORT_SYMBOL(sec_bat_exit_step_charging); void sec_bat_exit_wpc_step_charging(struct sec_battery_info *battery) { sec_vote(battery->fcc_vote, VOTER_WPC_STEP_CHARGE, false, 0); if (battery->step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) sec_vote(battery->fv_vote, VOTER_WPC_STEP_CHARGE, false, 0); sec_bat_reset_step_charging(battery); } EXPORT_SYMBOL(sec_bat_exit_wpc_step_charging); /* * true: step is changed * false: not changed */ bool sec_bat_check_step_charging(struct sec_battery_info *battery) { int i = 0, value = 0, step_condition = 0, lcd_status = 0; #if IS_ENABLED(CONFIG_DUAL_BATTERY) int value_sub = 0, step_condition_sub = 0; #endif static int curr_cnt; static bool skip_lcd_on_changed; int age_step = battery->pdata->age_step; union power_supply_propval val = {0, }; int fpdo_sc = 0; #if defined(CONFIG_SEC_FACTORY) if (!battery->step_chg_en_in_factory) return false; #endif if (!battery->step_chg_type) return false; #if defined(CONFIG_ENG_BATTERY_CONCEPT) if (battery->test_charge_current) return false; if (battery->test_step_condition <= 4500) battery->pdata->step_chg_cond[0][0] = battery->test_step_condition; #endif if (battery->siop_level < 100 || battery->lcd_status) lcd_status = 1; else lcd_status = 0; if (battery->cable_type == SEC_BATTERY_CABLE_FPDO_DC) { psy_do_property(battery->pdata->charger_name, get, POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC, val); fpdo_sc = val.intval; pr_info("%s: SC for FPDO_DC(%d)", __func__, fpdo_sc); if (!fpdo_sc && battery->step_chg_status >= 0) sec_bat_reset_step_charging(battery); } if (battery->step_chg_type & STEP_CHARGING_CONDITION_ONLINE) { #if IS_ENABLED(CONFIG_DIRECT_CHARGING) if ((is_pd_apdo_wire_type(battery->cable_type) && !fpdo_sc) && !((battery->current_event & SEC_BAT_CURRENT_EVENT_DC_ERR) && (battery->ta_alert_mode == OCP_NONE))) { sec_vote(battery->fv_vote, VOTER_STEP_CHARGE, false, 0); sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, false, 0); return false; } if (((is_pd_apdo_wire_type(battery->cable_type) || is_pd_apdo_wire_type(battery->wire_status)) && !fpdo_sc) && (battery->sink_status.rp_currentlvl == RP_CURRENT_LEVEL3)) { pr_info("%s: This cable type should be checked in dc step check\n", __func__); sec_vote(battery->fv_vote, VOTER_STEP_CHARGE, false, 0); sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, false, 0); return false; } #endif if (!is_hv_wire_type(battery->cable_type) && !is_pd_wire_type(battery->cable_type) && (battery->sink_status.rp_currentlvl != RP_CURRENT_LEVEL3)) { sec_vote(battery->fv_vote, VOTER_STEP_CHARGE, false, 0); sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, false, 0); return false; } } pr_info("%s\n", __func__); if (battery->step_chg_type & STEP_CHARGING_CONDITION_CHARGE_POWER) { if (battery->max_charge_power < battery->step_chg_charge_power) { /* In case of max_charge_power falling by AICL during step-charging ongoing */ sec_bat_exit_step_charging(battery); return false; } } if (battery->step_charging_skip_lcd_on && lcd_status) { if (!skip_lcd_on_changed) { if (battery->step_chg_status != (battery->step_chg_step - 1)) { sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, true, battery->pdata->step_chg_curr[age_step][battery->step_chg_step - 1]); if (battery->step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) { pr_info("%s : float voltage = %d\n", __func__, battery->pdata->step_chg_vfloat[age_step][battery->step_chg_step - 1]); sec_vote(battery->fv_vote, VOTER_STEP_CHARGE, true, battery->pdata->step_chg_vfloat[age_step][battery->step_chg_step - 1]); } pr_info("%s : skip step charging because lcd on\n", __func__); skip_lcd_on_changed = true; return true; } } return false; } if (battery->step_chg_status < 0) { i = 0; /* this is only for step enter condition and do not use STEP_CHARGING_CONDITION_SOC at the same time */ if (battery->step_chg_type & STEP_CHARGING_CONDITION_SOC_INIT_ONLY) { int soc_condition; value = battery->capacity; while (i < battery->step_chg_step - 1) { soc_condition = battery->pdata->step_chg_cond_soc[age_step][i]; if (value < soc_condition) break; i++; } pr_info("%s : set initial step(%d) by soc\n", __func__, i); goto check_step_change; } } else i = battery->step_chg_status; step_condition = battery->pdata->step_chg_cond[age_step][i]; if (battery->step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) { #if IS_ENABLED(CONFIG_DUAL_BATTERY) step_condition_sub = battery->pdata->step_chg_cond_sub[age_step][i]; value = battery->voltage_pack_main; value_sub = battery->voltage_pack_sub; #else value = battery->voltage_avg; #endif } else if (battery->step_chg_type & STEP_CHARGING_CONDITION_SOC) { value = battery->capacity; if (lcd_status) { step_condition = battery->pdata->step_chg_cond[age_step][i] + 15; curr_cnt = 0; } } else { return false; } while (i < battery->step_chg_step - 1) { #if IS_ENABLED(CONFIG_DUAL_BATTERY) if (battery->step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) { if ((value < step_condition) && (value_sub < step_condition_sub)) break; } else { if (value < step_condition) break; } #else if (value < step_condition) break; #endif i++; if ((battery->step_chg_type & STEP_CHARGING_CONDITION_SOC) && lcd_status) step_condition = battery->pdata->step_chg_cond[age_step][i] + 15; else { step_condition = battery->pdata->step_chg_cond[age_step][i]; #if IS_ENABLED(CONFIG_DUAL_BATTERY) if (battery->step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) step_condition_sub = battery->pdata->step_chg_cond_sub[age_step][i]; #endif } if (battery->step_chg_status != -1) break; } check_step_change: if ((i != battery->step_chg_status) || skip_lcd_on_changed) { /* this is only for no consuming current */ if ((battery->step_chg_type & STEP_CHARGING_CONDITION_CURRENT_NOW) && !lcd_status && battery->step_chg_status >= 0) { int condition_curr; condition_curr = max(battery->current_avg, battery->current_now); if (condition_curr < battery->pdata->step_chg_cond_curr[battery->step_chg_status]) { curr_cnt++; pr_info("%s : cnt = %d, curr(%d)mA < curr cond(%d)mA\n", __func__, curr_cnt, condition_curr, battery->pdata->step_chg_cond_curr[battery->step_chg_status]); if (curr_cnt < 3) return false; } else { pr_info("%s : clear cnt, curr(%d)mA >= curr cond(%d)mA or < 0mA\n", __func__, condition_curr, battery->pdata->step_chg_cond_curr[battery->step_chg_status]); curr_cnt = 0; return false; } } pr_info("%s : prev=%d, new=%d, value=%d, current=%d, curr_cnt=%d\n", __func__, battery->step_chg_status, i, value, battery->pdata->step_chg_curr[age_step][i], curr_cnt); battery->step_chg_status = i; skip_lcd_on_changed = false; sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, true, battery->pdata->step_chg_curr[age_step][i]); if (battery->step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) { pr_info("%s : float voltage = %d\n", __func__, battery->pdata->step_chg_vfloat[age_step][i]); sec_vote(battery->fv_vote, VOTER_STEP_CHARGE, true, battery->pdata->step_chg_vfloat[age_step][i]); } return true; } return false; } EXPORT_SYMBOL(sec_bat_check_step_charging); #if IS_ENABLED(CONFIG_WIRELESS_CHARGING) bool sec_bat_check_wpc_step_charging(struct sec_battery_info *battery) { int i = 0, value = 0, step_condition = 0, lcd_status = 0; static int curr_cnt; static bool skip_lcd_on_changed; int age_step = battery->pdata->age_step; #if defined(CONFIG_SEC_FACTORY) if (!battery->step_chg_en_in_factory) return false; #endif if (!battery->wpc_step_chg_type) return false; if (is_not_wireless_type(battery->cable_type)) { sec_vote(battery->fv_vote, VOTER_WPC_STEP_CHARGE, false, 0); sec_vote(battery->fcc_vote, VOTER_WPC_STEP_CHARGE, false, 0); return false; } #if defined(CONFIG_ENG_BATTERY_CONCEPT) if (battery->test_charge_current) return false; if (battery->test_step_condition <= 4500) battery->pdata->wpc_step_chg_cond[0][0] = battery->test_step_condition; #endif if (battery->siop_level < 100 || battery->lcd_status) lcd_status = 1; else lcd_status = 0; pr_info("%s\n", __func__); if (battery->wpc_step_chg_type & STEP_CHARGING_CONDITION_CHARGE_POWER) { if (battery->max_charge_power < battery->wpc_step_chg_charge_power) { /* In case of max_charge_power falling by AICL during step-charging ongoing */ sec_bat_exit_wpc_step_charging(battery); return false; } } if (battery->step_charging_skip_lcd_on && lcd_status) { if (!skip_lcd_on_changed) { if (battery->step_chg_status != (battery->wpc_step_chg_step - 1)) { sec_vote(battery->fcc_vote, VOTER_WPC_STEP_CHARGE, true, battery->pdata->wpc_step_chg_curr[age_step][battery->wpc_step_chg_step - 1]); if (battery->wpc_step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) { pr_info("%s : float voltage = %d\n", __func__, battery->pdata->wpc_step_chg_vfloat[age_step][battery->wpc_step_chg_step - 1]); sec_vote(battery->fv_vote, VOTER_WPC_STEP_CHARGE, true, battery->pdata->wpc_step_chg_vfloat[age_step][battery->wpc_step_chg_step - 1]); } pr_info("%s : skip step charging because lcd on\n", __func__); skip_lcd_on_changed = true; return true; } } return false; } if (battery->step_chg_status < 0) i = 0; else i = battery->step_chg_status; step_condition = battery->pdata->wpc_step_chg_cond[age_step][i]; if (battery->wpc_step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) { value = battery->voltage_avg; } else if (battery->wpc_step_chg_type & STEP_CHARGING_CONDITION_SOC) { value = battery->capacity; if (lcd_status) { step_condition = battery->pdata->wpc_step_chg_cond[age_step][i] + 15; curr_cnt = 0; } } else { return false; } while (i < battery->wpc_step_chg_step - 1) { if (value < step_condition) break; i++; if ((battery->wpc_step_chg_type & STEP_CHARGING_CONDITION_SOC) && lcd_status) step_condition = battery->pdata->wpc_step_chg_cond[age_step][i] + 15; else { step_condition = battery->pdata->wpc_step_chg_cond[age_step][i]; } if (battery->step_chg_status != -1) break; } if ((i != battery->step_chg_status) || skip_lcd_on_changed) { /* this is only for no consuming current */ if ((battery->wpc_step_chg_type & STEP_CHARGING_CONDITION_CURRENT_NOW) && !lcd_status && battery->step_chg_status >= 0) { int condition_curr; condition_curr = max(battery->current_avg, battery->current_now); if (condition_curr < battery->pdata->wpc_step_chg_cond_curr[battery->step_chg_status]) { curr_cnt++; pr_info("%s : cnt = %d, curr(%d)mA < curr cond(%d)mA\n", __func__, curr_cnt, condition_curr, battery->pdata->wpc_step_chg_cond_curr[battery->step_chg_status]); if (curr_cnt < 3) return false; } else { pr_info("%s : clear cnt, curr(%d)mA >= curr cond(%d)mA or < 0mA\n", __func__, condition_curr, battery->pdata->wpc_step_chg_cond_curr[battery->step_chg_status]); curr_cnt = 0; return false; } } pr_info("%s : prev=%d, new=%d, value=%d, current=%d, curr_cnt=%d\n", __func__, battery->step_chg_status, i, value, battery->pdata->wpc_step_chg_curr[age_step][i], curr_cnt); battery->step_chg_status = i; skip_lcd_on_changed = false; sec_vote(battery->fcc_vote, VOTER_WPC_STEP_CHARGE, true, battery->pdata->wpc_step_chg_curr[age_step][i]); if (battery->wpc_step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) { pr_info("%s : float voltage = %d\n", __func__, battery->pdata->wpc_step_chg_vfloat[age_step][i]); sec_vote(battery->fv_vote, VOTER_WPC_STEP_CHARGE, true, battery->pdata->wpc_step_chg_vfloat[age_step][i]); } return true; } return false; } EXPORT_SYMBOL(sec_bat_check_wpc_step_charging); #endif #if IS_ENABLED(CONFIG_DIRECT_CHARGING) bool skip_check_dc_step(struct sec_battery_info *battery) { if (battery->dchg_dc_in_swelling) { if (battery->current_event & SEC_BAT_CURRENT_EVENT_LOW_TEMP_MODE) return true; } else { if (battery->current_event & SEC_BAT_CURRENT_EVENT_SWELLING_MODE) return true; } if (battery->current_event & SEC_BAT_CURRENT_EVENT_HV_DISABLE || ((battery->current_event & SEC_BAT_CURRENT_EVENT_DC_ERR) && (battery->ta_alert_mode == OCP_NONE)) || battery->current_event & SEC_BAT_CURRENT_EVENT_SIOP_LIMIT || battery->wc_tx_enable || battery->uno_en || battery->mix_limit || battery->lrp_chg_src == SEC_CHARGING_SOURCE_SWITCHING) return true; else return false; } bool sec_bat_check_dc_step_charging(struct sec_battery_info *battery) { int i, value; int step = -1, step_vol = -1, step_input = -1, step_soc = -1, soc_condition = 0; int force_step_soc = 0, step_fg_current = -1; bool force_change_step = false; union power_supply_propval val = {0, }; int age_step = battery->pdata->age_step; unsigned int dc_step_chg_type; if (battery->cable_type == SEC_BATTERY_CABLE_FPDO_DC) { sec_vote(battery->dc_fv_vote, VOTER_DC_STEP_CHARGE, false, 0); sec_vote(battery->fcc_vote, VOTER_CABLE, true, battery->pdata->charging_current[SEC_BATTERY_CABLE_FPDO_DC].fast_charging_current); sec_vote_refresh(battery->fcc_vote); return false; } i = (battery->step_chg_status < 0 ? 0 : battery->step_chg_status); dc_step_chg_type = battery->dc_step_chg_type[i]; if (!dc_step_chg_type) { sec_vote(battery->dc_fv_vote, VOTER_DC_STEP_CHARGE, false, 0); return false; } if (dc_step_chg_type & STEP_CHARGING_CONDITION_CHARGE_POWER) if (battery->charge_power < battery->dc_step_chg_charge_power) { sec_vote(battery->dc_fv_vote, VOTER_DC_STEP_CHARGE, false, 0); return false; } if (dc_step_chg_type & STEP_CHARGING_CONDITION_ONLINE) { if (!is_pd_apdo_wire_type(battery->cable_type)) { sec_vote(battery->dc_fv_vote, VOTER_DC_STEP_CHARGE, false, 0); return false; } } if (skip_check_dc_step(battery)) { if (battery->step_chg_status >= 0) sec_bat_reset_step_charging(battery); sec_vote(battery->dc_fv_vote, VOTER_DC_STEP_CHARGE, false, 0); return false; } if (!(dc_step_chg_type & STEP_CHARGING_CONDITION_DC_INIT)) { pr_info("%s : cond_vol and cond_soc are both empty\n", __func__); sec_vote(battery->dc_fv_vote, VOTER_DC_STEP_CHARGE, false, 0); return false; } /* this is only for step enter condition and do not use STEP_CHARGING_CONDITION_SOC at the same time */ if (dc_step_chg_type & STEP_CHARGING_CONDITION_SOC_INIT_ONLY) { if (battery->step_chg_status < 0) { step_soc = i; value = battery->capacity; while (step_soc < battery->dc_step_chg_step - 1) { soc_condition = battery->pdata->dc_step_chg_cond_soc[age_step][step_soc]; if (value < soc_condition) break; step_soc++; } if ((step_soc < step) || (step < 0)) step = step_soc; pr_info("%s : set initial step(%d) by soc\n", __func__, step_soc); goto check_dc_step_change; } else step_soc = battery->dc_step_chg_step - 1; } if (dc_step_chg_type & STEP_CHARGING_CONDITION_SOC) { step_soc = i; value = battery->capacity; while (step_soc < battery->dc_step_chg_step - 1) { soc_condition = battery->pdata->dc_step_chg_cond_soc[age_step][step_soc]; if (battery->step_chg_status >= 0 && (battery->siop_level < 100 || battery->lcd_status)) { soc_condition += DIRECT_CHARGING_FORCE_SOC_MARGIN; force_change_step = true; } if (value < soc_condition) break; step_soc++; if (battery->step_chg_status >= 0) break; } if ((step_soc < step) || (step < 0)) step = step_soc; if (battery->step_chg_status < 0) { pr_info("%s : set initial step(%d) by soc\n", __func__, step_soc); goto check_dc_step_change; } if (force_change_step) { pr_info("%s : force check step(%d) by soc\n", __func__, step_soc); step_vol = step_input = step_soc; battery->dc_step_chg_iin_cnt = battery->pdata->dc_step_chg_iin_check_cnt; goto check_dc_step_change; } } else step_soc = battery->dc_step_chg_step - 1; if (dc_step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) { step_vol = i; #if IS_ENABLED(CONFIG_DUAL_BATTERY) value = max((battery->voltage_pack_main - battery->pdata->dc_step_cond_v_margin_main), (battery->voltage_pack_sub - battery->pdata->dc_step_cond_v_margin_sub)); /* (charging current)step down when main or sub voltage condition meets */ while (step_vol < battery->dc_step_chg_step - 1) { if (battery->voltage_pack_main < battery->pdata->dc_step_chg_cond_vol[age_step][step_vol] && battery->voltage_pack_sub < battery->pdata->dc_step_chg_cond_vol_sub[age_step][step_vol]) break; step_vol++; if (battery->step_chg_status >= 0) break; } #else if (dc_step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) value = battery->voltage_now + battery->pdata->dc_step_chg_cond_v_margin; else value = battery->voltage_avg; while (step_vol < battery->dc_step_chg_step - 1) { if (value < battery->pdata->dc_step_chg_cond_vol[age_step][step_vol]) break; step_vol++; if (battery->step_chg_status >= 0) break; } #endif if ((step_vol < step) || (step < 0)) step = step_vol; if (battery->step_chg_status < 0) { pr_info("%s : set initial step(%d) by vol\n", __func__, step_vol); goto check_dc_step_change; } } else step_vol = battery->dc_step_chg_step - 1; if (dc_step_chg_type & STEP_CHARGING_CONDITION_INPUT_CURRENT) { step_input = i; psy_do_property(battery->pdata->charger_name, get, POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_MODE, val); if (val.intval != SEC_DIRECT_CHG_MODE_DIRECT_ON) { pr_info("%s : dc no charging status = %d\n", __func__, val.intval); battery->dc_step_chg_iin_cnt = 0; return false; } else if (battery->siop_level >= 100 && !battery->lcd_status) { val.intval = SEC_BATTERY_IIN_MA; psy_do_property(battery->pdata->charger_name, get, POWER_SUPPLY_EXT_PROP_MEASURE_INPUT, val); value = val.intval; while (step_input < battery->dc_step_chg_step - 1) { if (value > battery->pdata->dc_step_chg_cond_iin[step_input]) break; step_input++; if (battery->step_chg_status >= 0) { battery->dc_step_chg_iin_cnt++; break; } else { battery->dc_step_chg_iin_cnt = 0; } } } else { /* * Do not check input current when lcd is on or siop is not 100 * since there might be quite big system current */ step_input = battery->dc_step_chg_step - 1; } if ((step_input < step) || (step < 0)) step = step_input; } else step_input = battery->dc_step_chg_step - 1; if (dc_step_chg_type & STEP_CHARGING_CONDITION_FG_CURRENT) { step_fg_current = i; psy_do_property(battery->pdata->charger_name, get, POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_MODE, val); if (val.intval != SEC_DIRECT_CHG_MODE_DIRECT_ON) { pr_info("%s : dc no charging status = %d\n", __func__, val.intval); battery->dc_step_chg_iin_cnt = 0; return false; } else if (battery->siop_level >= 100 && !battery->lcd_status) { int current_now, current_avg; val.intval = SEC_BATTERY_CURRENT_MA; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_CURRENT_NOW, val); current_now = val.intval; val.intval = SEC_BATTERY_CURRENT_MA; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_CURRENT_AVG, val); current_avg = val.intval; value = max(current_now, current_avg) / 2; while (step_fg_current < battery->dc_step_chg_step - 1) { if (value > battery->pdata->dc_step_chg_cond_iin[step_fg_current]) break; step_fg_current++; if (battery->step_chg_status >= 0) { battery->dc_step_chg_iin_cnt++; break; } battery->dc_step_chg_iin_cnt = 0; } } else { /* * Do not check input current when lcd is on or siop is not 100 * since there might be quite big system current */ step_fg_current = battery->dc_step_chg_step - 1; } if ((step_fg_current < step) || (step < 0)) step = step_fg_current; } else step_fg_current = battery->dc_step_chg_step - 1; if (dc_step_chg_type & STEP_CHARGING_CONDITION_FORCE_SOC) { force_step_soc = i; if (battery->capacity >= battery->pdata->dc_step_chg_cond_soc[age_step][i]) { if (++force_step_soc > step) step = force_step_soc; pr_info("%s : SOC(%d) cond_soc(%d) step(%d) force_step_soc(%d)\n", __func__, battery->capacity, battery->pdata->dc_step_chg_cond_soc[age_step][i], step, force_step_soc); } else force_step_soc = 0; } else force_step_soc = 0; check_dc_step_change: pr_info("%s : curr_step(%d), step_vol(%d), step_soc(%d), step_input(%d, %d), curr_cnt(%d/%d) force_step_soc(%d)\n", __func__, step, step_vol, step_soc, step_input, step_fg_current, battery->dc_step_chg_iin_cnt, battery->pdata->dc_step_chg_iin_check_cnt, force_step_soc); if (battery->step_chg_status < 0 || force_step_soc || (step != battery->step_chg_status && step == min(min(step_vol, step_soc), min(step_input, step_fg_current)))) { if ((dc_step_chg_type & (STEP_CHARGING_CONDITION_INPUT_CURRENT | STEP_CHARGING_CONDITION_FG_CURRENT)) && (battery->step_chg_status >= 0)) { if ((battery->dc_step_chg_iin_cnt < battery->pdata->dc_step_chg_iin_check_cnt) && (battery->siop_level >= 100 && !battery->lcd_status) && !force_step_soc) { pr_info("%s : keep step(%d), curr_cnt(%d/%d)\n", __func__, battery->step_chg_status, battery->dc_step_chg_iin_cnt, battery->pdata->dc_step_chg_iin_check_cnt); return false; } } pr_info("%s : cable(%d), soc(%d), step changed(%d->%d), current(%dmA) force_step_soc(%d)\n", __func__, battery->cable_type, battery->capacity, battery->step_chg_status, step, battery->pdata->dc_step_chg_val_iout[age_step][step], force_step_soc); /* set charging current */ battery->pdata->charging_current[battery->cable_type].fast_charging_current = battery->pdata->dc_step_chg_val_iout[age_step][step]; if (dc_step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) { if (battery->step_chg_status < 0) { pr_info("%s : step float voltage = %d\n", __func__, battery->pdata->dc_step_chg_val_vfloat[age_step][step]); sec_vote(battery->dc_fv_vote, VOTER_DC_STEP_CHARGE, true, battery->pdata->dc_step_chg_val_vfloat[age_step][step]); } battery->dc_float_voltage_set = true; } if (battery->step_chg_status < 0) { pr_info("%s : step input current = %d\n", __func__, battery->pdata->dc_step_chg_val_iout[age_step][step] / 2); val.intval = battery->pdata->dc_step_chg_val_iout[age_step][step] / 2; psy_do_property(battery->pdata->charger_name, set, POWER_SUPPLY_EXT_PROP_DIRECT_CURRENT_MAX, val); } battery->step_chg_status = step; battery->dc_step_chg_iin_cnt = 0; sec_vote(battery->fcc_vote, VOTER_CABLE, true, battery->pdata->dc_step_chg_val_iout[age_step][step]); sec_vote_refresh(battery->fcc_vote); return true; } else { battery->dc_step_chg_iin_cnt = 0; } return false; } EXPORT_SYMBOL(sec_bat_check_dc_step_charging); int sec_dc_step_charging_dt(struct sec_battery_info *battery, struct device *dev) { struct device_node *np = dev->of_node; int ret = 0, len = 0; sec_battery_platform_data_t *pdata = battery->pdata; unsigned int i = 0, j = 0, dc_step_chg_type = 0; const u32 *p; char str[128] = {0,}; u32 *soc_cond_temp, *vol_cond_temp, *vfloat_temp, *iout_temp; int age_step = battery->pdata->age_step; int num_age_step = battery->pdata->num_age_step; battery->dchg_dc_in_swelling = of_property_read_bool(np, "battery,dchg_dc_in_swelling"); pr_info("%s: dchg_dc_in_swelling(%d)\n", __func__, battery->dchg_dc_in_swelling); ret = of_property_read_u32(np, "battery,dc_step_chg_step", &battery->dc_step_chg_step); if (ret) { pr_err("%s: dc_step_chg_step is Empty\n", __func__); battery->dc_step_chg_step = 0; goto dc_step_charging_dt_error; } else { pr_err("%s: dc_step_chg_step is %d\n", __func__, battery->dc_step_chg_step); } battery->dc_step_chg_type = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); p = of_get_property(np, "battery,dc_step_chg_type", &len); if (!p) { pr_info("%s: dc_step_chg_type is Empty\n", __func__); return -1; } len = len / sizeof(u32); ret = of_property_read_u32_array(np, "battery,dc_step_chg_type", battery->dc_step_chg_type, len); if (len != battery->dc_step_chg_step) { pr_err("%s not match size of dc_step_chg_type: %d\n", __func__, len); for (i = 1; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] = battery->dc_step_chg_type[0]; dc_step_chg_type = battery->dc_step_chg_type[0]; } else { for (i = 0; i < battery->dc_step_chg_step; i++) dc_step_chg_type |= battery->dc_step_chg_type[i]; } memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "dc_step_chg_type arr :"); for (i = 0; i < battery->dc_step_chg_step; i++) sprintf(str + strlen(str), " 0x%x", battery->dc_step_chg_type[i]); pr_info("%s: %s 0x%x\n", __func__, str, dc_step_chg_type); ret = of_property_read_u32(np, "battery,dc_step_chg_charge_power", &battery->dc_step_chg_charge_power); if (ret) { pr_err("%s: dc_step_chg_charge_power is Empty\n", __func__); battery->dc_step_chg_charge_power = 20000; } if (dc_step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) { p = of_get_property(np, "battery,dc_step_chg_cond_vol", &len); if (!p) { pr_err("%s: dc_step_chg_cond_vol is Empty, type(0x%X->0x%X)\n", __func__, dc_step_chg_type, dc_step_chg_type & ~STEP_CHARGING_CONDITION_VOLTAGE); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~STEP_CHARGING_CONDITION_VOLTAGE; } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), dc_step_chg_cond_vol len(%d)\n", __func__, battery->dc_step_chg_step, num_age_step, len); vol_cond_temp = kcalloc(battery->dc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_vol", vol_cond_temp, battery->dc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->dc_step_chg_cond_vol = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->dc_step_chg_cond_vol[i] = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_cond_vol[i][j] = vol_cond_temp[i*battery->dc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->dc_step_chg_step * num_age_step != len) { pr_err("%s: len of dc_step_chg_cond_vol is not matched\n", __func__); ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_vol", *pdata->dc_step_chg_cond_vol, battery->dc_step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_cond_vol[i][j] = pdata->dc_step_chg_cond_vol[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "vol arr[%d]:", i); for (j = 0; j < battery->dc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->dc_step_chg_cond_vol[i][j]); pr_info("%s: %s\n", __func__, str); } #if IS_ENABLED(CONFIG_DUAL_BATTERY) len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), dc_step_chg_cond_vol_sub len(%d)\n", __func__, battery->dc_step_chg_step, num_age_step, len); vol_cond_temp = kcalloc(battery->dc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_vol_sub", vol_cond_temp, battery->dc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->dc_step_chg_cond_vol_sub = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->dc_step_chg_cond_vol_sub[i] = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_cond_vol_sub[i][j] = vol_cond_temp[i*battery->dc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->dc_step_chg_step * num_age_step != len) { pr_err("%s: len of dc_step_chg_cond_vol_sub is not matched\n", __func__); ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_vol_sub", *pdata->dc_step_chg_cond_vol_sub, battery->dc_step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_cond_vol_sub[i][j] = pdata->dc_step_chg_cond_vol_sub[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "vol_sub arr[%d]:", i); for (j = 0; j < battery->dc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->dc_step_chg_cond_vol_sub[i][j]); pr_info("%s: %s\n", __func__, str); } #endif if (ret) { pr_info("%s : dc_step_chg_cond_vol read fail\n", __func__); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~STEP_CHARGING_CONDITION_VOLTAGE; } kfree(vol_cond_temp); #if IS_ENABLED(CONFIG_DUAL_BATTERY) ret = of_property_read_u32(np, "battery,dc_step_cond_v_margin_main", &battery->pdata->dc_step_cond_v_margin_main); if (ret) battery->pdata->dc_step_cond_v_margin_main = 0; ret = of_property_read_u32(np, "battery,dc_step_cond_v_margin_sub", &battery->pdata->dc_step_cond_v_margin_sub); if (ret) battery->pdata->dc_step_cond_v_margin_sub = 0; ret = of_property_read_u32(np, "battery,sc_vbat_thresh_main", &battery->pdata->sc_vbat_thresh_main); if (ret) battery->pdata->sc_vbat_thresh_main = 4420; ret = of_property_read_u32(np, "battery,sc_vbat_thresh_sub", &battery->pdata->sc_vbat_thresh_sub); if (ret) battery->pdata->sc_vbat_thresh_sub = battery->pdata->sc_vbat_thresh_main; #endif } } if (dc_step_chg_type & STEP_CHARGING_CONDITION_SOC || dc_step_chg_type & STEP_CHARGING_CONDITION_SOC_INIT_ONLY) { p = of_get_property(np, "battery,dc_step_chg_cond_soc", &len); if (!p) { pr_err("%s: dc_step_chg_cond_soc is Empty, type(0x%X->0x%x)\n", __func__, dc_step_chg_type, dc_step_chg_type & ~(STEP_CHARGING_CONDITION_SOC | STEP_CHARGING_CONDITION_SOC_INIT_ONLY)); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~(STEP_CHARGING_CONDITION_SOC | STEP_CHARGING_CONDITION_SOC_INIT_ONLY); } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), dc_step_chg_cond_soc len(%d)\n", __func__, battery->dc_step_chg_step, num_age_step, len); /* get dt to buff */ soc_cond_temp = kcalloc(battery->dc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_soc", soc_cond_temp, battery->dc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->dc_step_chg_cond_soc = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->dc_step_chg_cond_soc[i] = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_cond_soc[i][j] = soc_cond_temp[i*battery->dc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->dc_step_chg_step * num_age_step != len) { pr_err("%s: len of dc_step_chg_cond_soc is not matched\n", __func__); ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_soc", *pdata->dc_step_chg_cond_soc, battery->dc_step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_cond_soc[i][j] = pdata->dc_step_chg_cond_soc[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "soc arr[%d]:", i); for (j = 0; j < battery->dc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->dc_step_chg_cond_soc[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) { pr_info("%s : dc_step_chg_cond_soc read fail\n", __func__); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~STEP_CHARGING_CONDITION_SOC; } kfree(soc_cond_temp); if (dc_step_chg_type & STEP_CHARGING_CONDITION_SOC && dc_step_chg_type & STEP_CHARGING_CONDITION_SOC_INIT_ONLY) { pr_info("%s : do not set SOC and SOC_INIT_ONLY at the same time\n", __func__); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~STEP_CHARGING_CONDITION_SOC; } } } if (dc_step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) { p = of_get_property(np, "battery,dc_step_chg_val_vfloat", &len); if (!p) { pr_err("%s: dc_step_chg_val_vfloat is Empty, type(0x%X->0x%x)\n", __func__, dc_step_chg_type, dc_step_chg_type & ~STEP_CHARGING_CONDITION_FLOAT_VOLTAGE); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~STEP_CHARGING_CONDITION_FLOAT_VOLTAGE; } else { ret = of_property_read_u32(np, "battery,dc_step_chg_cond_v_margin", &battery->pdata->dc_step_chg_cond_v_margin); if (ret) battery->pdata->dc_step_chg_cond_v_margin = DIRECT_CHARGING_FLOAT_VOLTAGE_MARGIN; pr_err("%s: dc_step_chg_cond_v_margin is %d\n", __func__, battery->pdata->dc_step_chg_cond_v_margin); len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), dc_step_chg_val_vfloat len(%d)\n", __func__, battery->dc_step_chg_step, num_age_step, len); vfloat_temp = kcalloc(battery->dc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,dc_step_chg_val_vfloat", vfloat_temp, battery->dc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->dc_step_chg_val_vfloat = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->dc_step_chg_val_vfloat[i] = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_val_vfloat[i][j] = vfloat_temp[i*battery->dc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->dc_step_chg_step * num_age_step != len) { pr_err("%s: len of dc_step_chg_val_vfloat is not matched\n", __func__); ret = of_property_read_u32_array(np, "battery,dc_step_chg_val_vfloat", *pdata->dc_step_chg_val_vfloat, battery->dc_step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_val_vfloat[i][j] = pdata->dc_step_chg_val_vfloat[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "vfloat arr[%d]:", i); for (j = 0; j < battery->dc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->dc_step_chg_val_vfloat[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) { pr_info("%s : dc_step_chg_val_vfloat read fail\n", __func__); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~STEP_CHARGING_CONDITION_FLOAT_VOLTAGE; } kfree(vfloat_temp); pdata->dc_step_chg_vol_offset = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,dc_step_chg_vol_offset", pdata->dc_step_chg_vol_offset, battery->dc_step_chg_step); if (ret) { pr_info("%s: dc_step_chg_vol_offset is empty\n", __func__); /* Fill-up use one-dimensional offset table */ for (j = 0; j < battery->dc_step_chg_step; j++) if (pdata->dc_step_chg_val_vfloat[0][j] > battery->pdata->chg_float_voltage) pdata->dc_step_chg_vol_offset[j] = pdata->dc_step_chg_val_vfloat[0][j] - battery->pdata->chg_float_voltage; } memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "dc_step_chg_vol_offset arr :"); for (i = 0; i < battery->dc_step_chg_step; i++) sprintf(str + strlen(str), " %d", pdata->dc_step_chg_vol_offset[i]); pr_info("%s: %s\n", __func__, str); } } p = of_get_property(np, "battery,dc_step_chg_val_iout", &len); if (!p) { pr_err("%s: dc_step_chg_val_iout is Empty\n", __func__); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] = 0; return -1; } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), dc_step_chg_val_iout len(%d)\n", __func__, battery->dc_step_chg_step, num_age_step, len); iout_temp = kcalloc(battery->dc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,dc_step_chg_val_iout", iout_temp, battery->dc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->dc_step_chg_val_iout = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->dc_step_chg_val_iout[i] = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_val_iout[i][j] = iout_temp[i*battery->dc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->dc_step_chg_step * num_age_step != len) { pr_err("%s: len of dc_step_chg_val_iout is not matched\n", __func__); ret = of_property_read_u32_array(np, "battery,dc_step_chg_val_iout", *pdata->dc_step_chg_val_iout, battery->dc_step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->dc_step_chg_step; j++) pdata->dc_step_chg_val_iout[i][j] = pdata->dc_step_chg_val_iout[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "iout arr[%d]:", i); for (j = 0; j < battery->dc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->dc_step_chg_val_iout[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) { pr_info("%s : dc_step_chg_val_iout read fail\n", __func__); } kfree(iout_temp); } if ((dc_step_chg_type & STEP_CHARGING_CONDITION_INPUT_CURRENT) || (dc_step_chg_type & STEP_CHARGING_CONDITION_FG_CURRENT)) { p = of_get_property(np, "battery,dc_step_chg_cond_iin", &len); if (!p) { pr_info("%s: dc_step_chg_cond_iin is Empty, set default (Iout / 2)\n", __func__); pdata->dc_step_chg_cond_iin = kcalloc(battery->dc_step_chg_step, sizeof(u32), GFP_KERNEL); for (i = 0; i < (battery->dc_step_chg_step - 1); i++) { pdata->dc_step_chg_cond_iin[i] = pdata->dc_step_chg_val_iout[age_step][i+1] / 2; pr_info("%s: Condition Iin [step %d] %dmA", __func__, i, pdata->dc_step_chg_cond_iin[i]); } pdata->dc_step_chg_cond_iin[i] = 0; } else { len = len / sizeof(u32); if (len != battery->dc_step_chg_step) { /* [dchg] TODO: do some error handling */ pr_err("%s: len of dc_step_chg_cond_iin is not matched, len(%d/%d)\n", __func__, len, battery->dc_step_chg_step); } pdata->dc_step_chg_cond_iin = kcalloc(len, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_iin", pdata->dc_step_chg_cond_iin, len); if (ret) { pr_info("%s : dc_step_chg_cond_iin read fail\n", __func__); for (i = 0; i < battery->dc_step_chg_step; i++) battery->dc_step_chg_type[i] &= ~STEP_CHARGING_CONDITION_INPUT_CURRENT; } } ret = of_property_read_u32(np, "battery,dc_step_chg_iin_check_cnt", &battery->pdata->dc_step_chg_iin_check_cnt); if (ret) { pr_err("%s: dc_step_chg_iin_check_cnt is Empty\n", __func__); battery->pdata->dc_step_chg_iin_check_cnt = 2; } else { pr_err("%s: dc_step_chg_iin_check_cnt is %d\n", __func__, battery->pdata->dc_step_chg_iin_check_cnt); } } // print dc step charging information for (i = 0; i < battery->dc_step_chg_step; i++) { memset(str, 0x0, sizeof(str)); if (battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_VOLTAGE) sprintf(str + strlen(str), "cond_vol: %dmV, ", pdata->dc_step_chg_cond_vol[age_step][i]); if (battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_SOC) sprintf(str + strlen(str), "cond_soc: %d%%, ", pdata->dc_step_chg_cond_soc[age_step][i]); if (battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_INPUT_CURRENT) sprintf(str + strlen(str), "cond_iin: %dmA, ", pdata->dc_step_chg_cond_iin[i]); if (battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) sprintf(str + strlen(str), "vfloat: %dmV, ", pdata->dc_step_chg_val_vfloat[age_step][i]); sprintf(str + strlen(str), "iout: %dmA,", pdata->dc_step_chg_val_iout[age_step][i]); pr_info("%s : step [%d] %s\n", __func__, i, str); } return 0; dc_step_charging_dt_error: return -1; } /* sec_dc_step_charging_dt */ #endif void sec_bat_set_aging_info_step_charging(struct sec_battery_info *battery) { #if IS_ENABLED(CONFIG_DIRECT_CHARGING) union power_supply_propval val; int i = 0; unsigned int max_fv = 0; int float_volt; #endif int age_step = battery->pdata->age_step; #if IS_ENABLED(CONFIG_DIRECT_CHARGING) i = (battery->step_chg_status < 0 ? 0 : battery->step_chg_status); if (!battery->dc_step_chg_type[i]) { pr_info("%s : invalid dc step chg type\n", __func__); return; } #endif if (battery->step_chg_type) { if (battery->step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) battery->pdata->step_chg_vfloat[age_step][battery->step_chg_step-1] = battery->pdata->chg_float_voltage; dev_info(battery->dev, "%s: float_v(%d)\n", __func__, battery->pdata->step_chg_vfloat[age_step][battery->step_chg_step-1]); } #if IS_ENABLED(CONFIG_DIRECT_CHARGING) for (i = 0; i < battery->dc_step_chg_step; i++) { float_volt = battery->pdata->dc_step_chg_vol_offset[i] + battery->pdata->chg_float_voltage; if (battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) if (battery->pdata->dc_step_chg_val_vfloat[age_step][i] > float_volt) battery->pdata->dc_step_chg_val_vfloat[age_step][i] = float_volt; max_fv = max(max_fv, battery->pdata->dc_step_chg_val_vfloat[age_step][i]); if (battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_VOLTAGE) if (battery->pdata->dc_step_chg_cond_vol[age_step][i] > float_volt) battery->pdata->dc_step_chg_cond_vol[age_step][i] = float_volt; } for (i = 0; i < battery->dc_step_chg_step; i++) { dev_info(battery->dev, "%s: cond_vol: %dmV, vfloat: %dmV, cond_iin: %dmA, iout: %dmA\n", __func__, battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_VOLTAGE ? battery->pdata->dc_step_chg_cond_vol[age_step][i] : 0, battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE ? battery->pdata->dc_step_chg_val_vfloat[age_step][i] : 0, battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_INPUT_CURRENT ? battery->pdata->dc_step_chg_cond_iin[i] : 0, battery->pdata->dc_step_chg_val_iout[age_step][i]); } i = (battery->step_chg_status < 0 ? 0 : battery->step_chg_status); if (battery->dc_step_chg_type[i] & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) { val.intval = battery->pdata->dc_step_chg_val_vfloat[age_step][battery->dc_step_chg_step-1]; psy_do_property(battery->pdata->charger_name, set, POWER_SUPPLY_EXT_PROP_DIRECT_CONSTANT_CHARGE_VOLTAGE_MAX, val); } sec_vote(battery->dc_fv_vote, VOTER_AGING_STEP, true, max_fv); sec_bat_reset_step_charging(battery); sec_bat_check_dc_step_charging(battery); #endif } EXPORT_SYMBOL(sec_bat_set_aging_info_step_charging); void sec_step_charging_dt(struct sec_battery_info *battery, struct device *dev) { struct device_node *np = dev->of_node; int ret, len; sec_battery_platform_data_t *pdata = battery->pdata; unsigned int i = 0, j = 0; const u32 *p; char str[128] = {0,}; u32 *soc_cond_temp, *vfloat_temp, *curr_temp; int num_age_step = battery->pdata->num_age_step; battery->step_charging_skip_lcd_on = of_property_read_bool(np, "battery,step_charging_skip_lcd_on"); battery->step_chg_en_in_factory = of_property_read_bool(np, "battery,step_chg_en_in_factory"); ret = of_property_read_u32(np, "battery,step_chg_step", &battery->step_chg_step); if (ret) { pr_err("%s: step_chg_step is Empty\n", __func__); battery->step_chg_step = 0; } else { pr_err("%s: step_chg_step is %d\n", __func__, battery->step_chg_step); } ret = of_property_read_u32(np, "battery,step_chg_charge_power", &battery->step_chg_charge_power); if (ret) { pr_err("%s: step_chg_charge_power is Empty\n", __func__); battery->step_chg_charge_power = 20000; } p = of_get_property(np, "battery,step_chg_cond", &len); if (!p) { battery->step_chg_step = 0; } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), step_chg_cond len(%d)\n", __func__, battery->step_chg_step, num_age_step, len); /* get dt to buff */ soc_cond_temp = kcalloc(battery->step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,step_chg_cond", soc_cond_temp, battery->step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->step_chg_cond = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->step_chg_cond[i] = kcalloc(battery->step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_cond[i][j] = soc_cond_temp[i*battery->step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->step_chg_step * num_age_step != len) { ret = of_property_read_u32_array(np, "battery,step_chg_cond", *pdata->step_chg_cond, battery->step_chg_step); for (i = 0; i < num_age_step; i++) { for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_cond[i][j] = pdata->step_chg_cond[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "step_chg_cond arr[%d]:", i); for (j = 0; j < battery->step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->step_chg_cond[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) { pr_info("%s : step_chg_cond read fail\n", __func__); battery->step_chg_step = 0; } kfree(soc_cond_temp); #if IS_ENABLED(CONFIG_DUAL_BATTERY) if (battery->step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) { /* get dt to buff */ soc_cond_temp = kcalloc(battery->step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,step_chg_cond_sub", soc_cond_temp, battery->step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->step_chg_cond_sub = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->step_chg_cond_sub[i] = kcalloc(battery->step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_cond_sub[i][j] = soc_cond_temp[i*battery->step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->step_chg_step * num_age_step != len) { ret = of_property_read_u32_array(np, "battery,step_chg_cond", *pdata->step_chg_cond_sub, battery->step_chg_step); for (i = 0; i < num_age_step; i++) { for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_cond_sub[i][j] = pdata->step_chg_cond[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "step_chg_cond_sub arr[%d]:", i); for (j = 0; j < battery->step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->step_chg_cond_sub[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) pr_info("%s : step_chg_cond_sub read fail\n", __func__); kfree(soc_cond_temp); } #endif p = of_get_property(np, "battery,step_chg_cond_curr", &len); if (!p) { pr_err("%s: step_chg_cond_curr is Empty\n", __func__); } else { len = len / sizeof(u32); pdata->step_chg_cond_curr = kcalloc(len, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,step_chg_cond_curr", pdata->step_chg_cond_curr, len); if (ret) { pr_info("%s : step_chg_cond_curr read fail\n", __func__); battery->step_chg_step = 0; } } p = of_get_property(np, "battery,step_chg_vfloat", &len); if (!p) { pr_err("%s: step_chg_vfloat is Empty\n", __func__); } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), step_chg_vfloat len(%d)\n", __func__, battery->step_chg_step, num_age_step, len); vfloat_temp = kcalloc(battery->step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,step_chg_vfloat", vfloat_temp, battery->step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->step_chg_vfloat = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->step_chg_vfloat[i] = kcalloc(battery->step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_vfloat[i][j] = vfloat_temp[i*battery->step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->step_chg_step * num_age_step != len) { ret = of_property_read_u32_array(np, "battery,step_chg_vfloat", *pdata->step_chg_vfloat, battery->step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_vfloat[i][j] = pdata->step_chg_vfloat[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "step_chg_vfloat arr[%d]:", i); for (j = 0; j < battery->step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->step_chg_vfloat[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) pr_info("%s : step_chg_vfloat read fail\n", __func__); kfree(vfloat_temp); } p = of_get_property(np, "battery,step_chg_curr", &len); if (!p) { pr_err("%s: step_chg_curr is Empty\n", __func__); } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), step_chg_curr len(%d)\n", __func__, battery->step_chg_step, num_age_step, len); curr_temp = kcalloc(battery->step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,step_chg_curr", curr_temp, battery->step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->step_chg_curr = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->step_chg_curr[i] = kcalloc(battery->step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_curr[i][j] = curr_temp[i*battery->step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->step_chg_step * num_age_step != len) { ret = of_property_read_u32_array(np, "battery,step_chg_curr", *pdata->step_chg_curr, battery->step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_curr[i][j] = pdata->step_chg_curr[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "step_chg_curr arr[%d]:", i); for (j = 0; j < battery->step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->step_chg_curr[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) pr_info("%s : step_chg_curr read fail\n", __func__); kfree(curr_temp); } p = of_get_property(np, "battery,step_chg_cond_soc", &len); if (!p) { pr_err("%s: step_chg_cond_soc is Empty\n", __func__); battery->step_chg_type = (battery->step_chg_type) & (~STEP_CHARGING_CONDITION_SOC_INIT_ONLY); } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), step_chg_soc len(%d)\n", __func__, battery->step_chg_step, num_age_step, len); if (battery->step_chg_step * num_age_step != len) { pr_err("%s: mis-match len!!\n", __func__); battery->step_chg_type = (battery->step_chg_type) & (~STEP_CHARGING_CONDITION_SOC_INIT_ONLY); goto err_soc; } curr_temp = kcalloc(battery->step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); if (!curr_temp) goto err_soc; ret = of_property_read_u32_array(np, "battery,step_chg_cond_soc", curr_temp, battery->step_chg_step * num_age_step); if (ret) { pr_err("%s: failed to read chg_cond_soc(ret = %d)\n", __func__, ret); kfree(curr_temp); battery->step_chg_type = (battery->step_chg_type) & (~STEP_CHARGING_CONDITION_SOC_INIT_ONLY); goto err_soc; } pdata->step_chg_cond_soc = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->step_chg_cond_soc[i] = kcalloc(battery->step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->step_chg_step; j++) pdata->step_chg_cond_soc[i][j] = curr_temp[i*battery->step_chg_step + j]; } for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "step_chg_cond_soc arr[%d]:", i); for (j = 0; j < battery->step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->step_chg_cond_soc[i][j]); pr_info("%s: %s\n", __func__, str); } err_soc: pr_info("%s: step_chg_soc end\n", __func__); } } } #if IS_ENABLED(CONFIG_WIRELESS_CHARGING) void sec_wpc_step_charging_dt(struct sec_battery_info *battery, struct device *dev) { struct device_node *np = dev->of_node; int ret, len; sec_battery_platform_data_t *pdata = battery->pdata; unsigned int i = 0, j = 0; const u32 *p; char str[128] = {0,}; u32 *soc_cond_temp, *vfloat_temp, *curr_temp; int num_age_step = battery->pdata->num_age_step; ret = of_property_read_u32(np, "battery,wpc_step_chg_step", &battery->wpc_step_chg_step); if (ret) { pr_err("%s: wpc_step_chg_step is Empty\n", __func__); battery->wpc_step_chg_step = 0; } else { pr_err("%s: wpc_step_chg_step is %d\n", __func__, battery->wpc_step_chg_step); } ret = of_property_read_u32(np, "battery,wpc_step_chg_charge_power", &battery->wpc_step_chg_charge_power); if (ret) { pr_err("%s: wpc_step_chg_charge_power is Empty\n", __func__); battery->wpc_step_chg_charge_power = 7500; } p = of_get_property(np, "battery,wpc_step_chg_cond", &len); if (!p) { battery->wpc_step_chg_step = 0; } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), step_chg_cond len(%d)\n", __func__, battery->wpc_step_chg_step, num_age_step, len); /* get dt to buff */ soc_cond_temp = kcalloc(battery->wpc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,wpc_step_chg_cond", soc_cond_temp, battery->wpc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->wpc_step_chg_cond = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->wpc_step_chg_cond[i] = kcalloc(battery->wpc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->wpc_step_chg_step; j++) pdata->wpc_step_chg_cond[i][j] = soc_cond_temp[i*battery->wpc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->wpc_step_chg_step * num_age_step != len) { ret = of_property_read_u32_array(np, "battery,wpc_step_chg_cond", *pdata->wpc_step_chg_cond, battery->wpc_step_chg_step); for (i = 0; i < num_age_step; i++) { for (j = 0; j < battery->wpc_step_chg_step; j++) pdata->wpc_step_chg_cond[i][j] = pdata->wpc_step_chg_cond[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "wpc_step_chg_cond arr[%d]:", i); for (j = 0; j < battery->wpc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->wpc_step_chg_cond[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) { pr_info("%s : wpc_step_chg_cond read fail\n", __func__); battery->wpc_step_chg_step = 0; } kfree(soc_cond_temp); p = of_get_property(np, "battery,wpc_step_chg_cond_curr", &len); if (!p) { pr_err("%s: wpc_step_chg_cond_curr is Empty\n", __func__); } else { len = len / sizeof(u32); pdata->wpc_step_chg_cond_curr = kcalloc(len, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,wpc_step_chg_cond_curr", pdata->wpc_step_chg_cond_curr, len); if (ret) { pr_info("%s : wpc_step_chg_cond_curr read fail\n", __func__); battery->wpc_step_chg_step = 0; } } p = of_get_property(np, "battery,wpc_step_chg_vfloat", &len); if (!p) { pr_err("%s: wpc_step_chg_vfloat is Empty\n", __func__); } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), wpc_step_chg_vfloat len(%d)\n", __func__, battery->wpc_step_chg_step, num_age_step, len); vfloat_temp = kcalloc(battery->wpc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,wpc_step_chg_vfloat", vfloat_temp, battery->wpc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->wpc_step_chg_vfloat = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->wpc_step_chg_vfloat[i] = kcalloc(battery->wpc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->wpc_step_chg_step; j++) pdata->wpc_step_chg_vfloat[i][j] = vfloat_temp[i*battery->wpc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->wpc_step_chg_step * num_age_step != len) { ret = of_property_read_u32_array(np, "battery,wpc_step_chg_vfloat", *pdata->wpc_step_chg_vfloat, battery->wpc_step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->wpc_step_chg_step; j++) pdata->wpc_step_chg_vfloat[i][j] = pdata->wpc_step_chg_vfloat[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "wpc_step_chg_vfloat arr[%d]:", i); for (j = 0; j < battery->wpc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->wpc_step_chg_vfloat[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) pr_info("%s : wpc_step_chg_vfloat read fail\n", __func__); kfree(vfloat_temp); } p = of_get_property(np, "battery,wpc_step_chg_curr", &len); if (!p) { pr_err("%s: wpc_step_chg_curr is Empty\n", __func__); } else { len = len / sizeof(u32); pr_info("%s: step(%d) * age_step(%d), wpc_step_chg_curr len(%d)\n", __func__, battery->wpc_step_chg_step, num_age_step, len); curr_temp = kcalloc(battery->wpc_step_chg_step * num_age_step, sizeof(u32), GFP_KERNEL); ret = of_property_read_u32_array(np, "battery,wpc_step_chg_curr", curr_temp, battery->wpc_step_chg_step * num_age_step); /* copy buff to 2d arr */ pdata->wpc_step_chg_curr = kcalloc(num_age_step, sizeof(u32 *), GFP_KERNEL); for (i = 0; i < num_age_step; i++) { pdata->wpc_step_chg_curr[i] = kcalloc(battery->wpc_step_chg_step, sizeof(u32), GFP_KERNEL); for (j = 0; j < battery->wpc_step_chg_step; j++) pdata->wpc_step_chg_curr[i][j] = curr_temp[i*battery->wpc_step_chg_step + j]; } /* if there are only 1 dimentional array of value, get the same value */ if (battery->wpc_step_chg_step * num_age_step != len) { ret = of_property_read_u32_array(np, "battery,wpc_step_chg_curr", *pdata->wpc_step_chg_curr, battery->wpc_step_chg_step); for (i = 1; i < num_age_step; i++) { for (j = 0; j < battery->wpc_step_chg_step; j++) pdata->wpc_step_chg_curr[i][j] = pdata->wpc_step_chg_curr[0][j]; } } /* debug log */ for (i = 0; i < num_age_step; i++) { memset(str, 0x0, sizeof(str)); sprintf(str + strlen(str), "wpc_step_chg_curr arr[%d]:", i); for (j = 0; j < battery->wpc_step_chg_step; j++) sprintf(str + strlen(str), " %d", pdata->wpc_step_chg_curr[i][j]); pr_info("%s: %s\n", __func__, str); } if (ret) pr_info("%s : wpc_step_chg_curr read fail\n", __func__); kfree(curr_temp); } } } #endif void sec_step_charging_init(struct sec_battery_info *battery, struct device *dev) { struct device_node *np = dev->of_node; int ret; battery->step_chg_status = -1; ret = of_property_read_u32(np, "battery,step_chg_type", &battery->step_chg_type); pr_err("%s: step_chg_type 0x%x\n", __func__, battery->step_chg_type); if (ret) { pr_err("%s: step_chg_type is Empty\n", __func__); battery->step_chg_type = 0; } if (battery->step_chg_type) sec_step_charging_dt(battery, dev); #if IS_ENABLED(CONFIG_WIRELESS_CHARGING) ret = of_property_read_u32(np, "battery,wpc_step_chg_type", &battery->wpc_step_chg_type); pr_err("%s: wpc_step_chg_type 0x%x\n", __func__, battery->wpc_step_chg_type); if (ret) { pr_err("%s: wpc_step_chg_type is Empty\n", __func__); battery->wpc_step_chg_type = 0; } if (battery->wpc_step_chg_type) sec_wpc_step_charging_dt(battery, dev); #endif #if IS_ENABLED(CONFIG_DIRECT_CHARGING) sec_dc_step_charging_dt(battery, dev); #endif } EXPORT_SYMBOL(sec_step_charging_init);