750 lines
26 KiB
C
Executable File
750 lines
26 KiB
C
Executable File
/*
|
|
* 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 "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_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_charging_status = -1;
|
|
#if defined(CONFIG_DIRECT_CHARGING)
|
|
battery->dc_float_voltage_set = false;
|
|
#endif
|
|
}
|
|
|
|
void sec_bat_exit_step_charging(struct sec_battery_info *battery)
|
|
{
|
|
sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, true,
|
|
battery->pdata->step_charging_current[battery->step_charging_step-1]);
|
|
if ((battery->step_charging_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) &&
|
|
(battery->swelling_mode == SWELLING_MODE_NONE)) {
|
|
union power_supply_propval val;
|
|
|
|
pr_info("%s : float voltage = %d \n", __func__,
|
|
battery->pdata->step_charging_float_voltage[battery->step_charging_step-1]);
|
|
val.intval = battery->pdata->step_charging_float_voltage[battery->step_charging_step-1];
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
}
|
|
sec_bat_reset_step_charging(battery);
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
static int curr_cnt = 0;
|
|
|
|
#if defined(CONFIG_SEC_FACTORY)
|
|
return false;
|
|
#endif
|
|
|
|
#if defined(CONFIG_ENG_BATTERY_CONCEPT)
|
|
if(battery->test_charge_current)
|
|
return false;
|
|
if(battery->test_step_condition <= 100)
|
|
battery->pdata->step_charging_condition[0] = battery->test_step_condition;
|
|
#endif
|
|
|
|
if (!battery->step_charging_type)
|
|
return false;
|
|
|
|
if (battery->step_charging_type & STEP_CHARGING_CONDITION_ONLINE) {
|
|
#if defined(CONFIG_DIRECT_CHARGING)
|
|
if (is_pd_apdo_wire_type(battery->cable_type) &&
|
|
!((battery->current_event & SEC_BAT_CURRENT_EVENT_DC_ERR) &&
|
|
(battery->ta_alert_mode == OCP_NONE)))
|
|
return false;
|
|
|
|
if ((is_pd_apdo_wire_type(battery->cable_type) || is_pd_apdo_wire_type(battery->wire_status)) &&
|
|
(battery->pdic_info.sink_status.rp_currentlvl == RP_CURRENT_LEVEL3)) {
|
|
pr_info("%s: This cable type should be checked in dc step check\n", __func__);
|
|
return false;
|
|
}
|
|
#endif
|
|
#if defined(CONFIG_CCIC_NOTIFIER)
|
|
if (!is_hv_wire_type(battery->cable_type) && !(battery->cable_type == SEC_BATTERY_CABLE_PDIC) &&
|
|
!(battery->pdic_info.sink_status.rp_currentlvl == RP_CURRENT_LEVEL3))
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
pr_info("%s\n", __func__);
|
|
|
|
if (battery->step_charging_type & STEP_CHARGING_CONDITION_CHARGE_POWER) {
|
|
if (battery->max_charge_power < battery->step_charging_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_status < 0)
|
|
i = 0;
|
|
else
|
|
i = battery->step_charging_status;
|
|
|
|
step_condition = battery->pdata->step_charging_condition[i];
|
|
|
|
if (battery->step_charging_type & STEP_CHARGING_CONDITION_VOLTAGE) {
|
|
value = battery->voltage_avg;
|
|
} else if (battery->step_charging_type & STEP_CHARGING_CONDITION_SOC) {
|
|
value = battery->capacity;
|
|
if (battery->siop_level < 100 || battery->lcd_status) {
|
|
step_condition = battery->pdata->step_charging_condition[i] + 15;
|
|
curr_cnt = 0;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
while(i < battery->step_charging_step - 1) {
|
|
if (value < step_condition) {
|
|
break;
|
|
}
|
|
i++;
|
|
if ((battery->step_charging_type & STEP_CHARGING_CONDITION_SOC) &&
|
|
(battery->siop_level < 100 || battery->lcd_status))
|
|
step_condition = battery->pdata->step_charging_condition[i] + 15;
|
|
else
|
|
step_condition = battery->pdata->step_charging_condition[i];
|
|
if(battery->step_charging_status != -1)
|
|
break;
|
|
}
|
|
|
|
if (i != battery->step_charging_status) {
|
|
/* this is only for no consuming current */
|
|
if ((battery->step_charging_type & STEP_CHARGING_CONDITION_CURRENT_NOW) &&
|
|
(battery->siop_level >= 100 && !battery->lcd_status) &&
|
|
battery->step_charging_status >= 0) {
|
|
int condition_curr;
|
|
condition_curr = max(battery->current_avg, battery->current_now);
|
|
if(condition_curr < battery->pdata->step_charging_condition_curr[battery->step_charging_status]) {
|
|
curr_cnt++;
|
|
pr_info("%s : cnt = %d, current avg(%d)mA < current condition(%d)mA\n", __func__,
|
|
curr_cnt, condition_curr, battery->pdata->step_charging_condition_curr[battery->step_charging_status]);
|
|
if(curr_cnt < 3)
|
|
return false;
|
|
} else {
|
|
pr_info("%s : clear count, current avg(%d)mA >= current condition(%d)mA or"
|
|
" < 0mA this log is for debug\n", __func__,
|
|
condition_curr, battery->pdata->step_charging_condition_curr[battery->step_charging_status]);
|
|
curr_cnt = 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
pr_info("%s : prev=%d, new=%d, value=%d, current=%d, curr_cnt=%d\n", __func__,
|
|
battery->step_charging_status, i, value, battery->pdata->step_charging_current[i], curr_cnt);
|
|
sec_vote(battery->fcc_vote, VOTER_STEP_CHARGE, true, battery->pdata->step_charging_current[i]);
|
|
battery->step_charging_status = i;
|
|
|
|
if ((battery->step_charging_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) &&
|
|
(battery->swelling_mode == SWELLING_MODE_NONE)) {
|
|
union power_supply_propval val;
|
|
|
|
pr_info("%s : float voltage = %d \n", __func__, battery->pdata->step_charging_float_voltage[i]);
|
|
val.intval = battery->pdata->step_charging_float_voltage[i];
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_PROP_VOLTAGE_MAX, val);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#if defined(CONFIG_DIRECT_CHARGING)
|
|
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;
|
|
bool force_change_step = false;
|
|
union power_supply_propval val;
|
|
|
|
if (!battery->dc_step_chg_type)
|
|
return false;
|
|
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_CHARGE_POWER)
|
|
if (battery->charge_power < battery->dc_step_chg_charge_power)
|
|
return false;
|
|
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_ONLINE) {
|
|
if (!is_pd_apdo_wire_type(battery->cable_type))
|
|
return false;
|
|
}
|
|
|
|
if (battery->current_event & SEC_BAT_CURRENT_EVENT_SWELLING_MODE ||
|
|
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) {
|
|
if (battery->step_charging_status >= 0)
|
|
sec_bat_reset_step_charging(battery);
|
|
return false;
|
|
}
|
|
|
|
if (battery->step_charging_status < 0)
|
|
i = 0;
|
|
else
|
|
i = battery->step_charging_status;
|
|
|
|
if (!(battery->dc_step_chg_type & STEP_CHARGING_CONDITION_DC_INIT)) {
|
|
pr_info("%s : cond_vol and cond_soc are both empty\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
/* this is only for step enter condition and do not use STEP_CHARGING_CONDITION_SOC at the same time */
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_SOC_INIT_ONLY) {
|
|
if (battery->step_charging_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[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 (battery->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[step_soc];
|
|
if (battery->step_charging_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_charging_status >= 0)
|
|
break;
|
|
}
|
|
|
|
if ((step_soc < step) || (step < 0))
|
|
step = step_soc;
|
|
|
|
if (battery->step_charging_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 (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_VOLTAGE) {
|
|
step_vol = i;
|
|
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE)
|
|
value = battery->voltage_now + DIRECT_CHARGING_FLOAT_VOLTAGE_MARGIN;
|
|
else
|
|
value = battery->voltage_avg;
|
|
|
|
while(step_vol < battery->dc_step_chg_step - 1) {
|
|
if (value < battery->pdata->dc_step_chg_cond_vol[step_vol])
|
|
break;
|
|
step_vol++;
|
|
if (battery->step_charging_status >= 0)
|
|
break;
|
|
}
|
|
if ((step_vol < step) || (step < 0))
|
|
step = step_vol;
|
|
|
|
if (battery->step_charging_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 (battery->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_charging_status >= 0) {
|
|
battery->dc_step_chg_iin_cnt++;
|
|
break;
|
|
} else {
|
|
battery->dc_step_chg_iin_cnt = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((step_input < step) || (step < 0))
|
|
step = step_input;
|
|
} else
|
|
step_input = battery->dc_step_chg_step - 1;
|
|
|
|
check_dc_step_change:
|
|
pr_info("%s : curr_step(%d), step_vol(%d), step_soc(%d), step_input(%d), curr_cnt(%d/%d)\n",
|
|
__func__, step, step_vol, step_soc, step_input,
|
|
battery->dc_step_chg_iin_cnt, battery->pdata->dc_step_chg_iin_check_cnt);
|
|
|
|
if (battery->step_charging_status < 0 ||
|
|
(step != battery->step_charging_status && step == min(min(step_vol, step_soc), step_input))) {
|
|
if ((battery->dc_step_chg_type & STEP_CHARGING_CONDITION_INPUT_CURRENT) &&
|
|
(battery->step_charging_status >= 0)) {
|
|
if (battery->dc_step_chg_iin_cnt < battery->pdata->dc_step_chg_iin_check_cnt) {
|
|
pr_info("%s : keep step(%d), curr_cnt(%d/%d)\n",
|
|
__func__, battery->step_charging_status,
|
|
battery->dc_step_chg_iin_cnt, battery->pdata->dc_step_chg_iin_check_cnt);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
pr_info("%s : cable(%d), step changed(%d->%d), current(%dmA)\n",
|
|
__func__, battery->cable_type,
|
|
battery->step_charging_status, step, battery->pdata->dc_step_chg_val_iout[step]);
|
|
battery->pdata->charging_current[battery->cable_type].fast_charging_current = battery->pdata->dc_step_chg_val_iout[step];
|
|
|
|
if ((battery->dc_step_chg_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE) &&
|
|
(battery->swelling_mode == SWELLING_MODE_NONE)) {
|
|
if (battery->step_charging_status < 0) {
|
|
pr_info("%s : step float voltage = %d \n", __func__, battery->pdata->dc_step_chg_val_vfloat[step]);
|
|
val.intval = battery->pdata->dc_step_chg_val_vfloat[step];
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_DIRECT_VOLTAGE_MAX, val);
|
|
}
|
|
battery->dc_float_voltage_set = true;
|
|
}
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_INPUT_CURRENT) {
|
|
if (battery->step_charging_status < 0) {
|
|
pr_info("%s : step input current = %d \n", __func__, battery->pdata->dc_step_chg_val_iout[step] / 2);
|
|
val.intval = battery->pdata->dc_step_chg_val_iout[step] / 2;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_DIRECT_CURRENT_MAX, val);
|
|
}
|
|
}
|
|
|
|
sec_vote(battery->fcc_vote, VOTER_CABLE, true, battery->pdata->dc_step_chg_val_iout[step]);
|
|
sec_vote_refresh(battery->fcc_vote);
|
|
|
|
battery->step_charging_status = step;
|
|
battery->dc_step_chg_iin_cnt = 0;
|
|
|
|
return true;
|
|
} else {
|
|
battery->dc_step_chg_iin_cnt = 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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, dc_step_chg_type = 0;
|
|
const u32 *p;
|
|
char str[128] = {0,};
|
|
|
|
ret = of_property_read_u32(np, "battery,dc_step_chg_type",
|
|
&battery->dc_step_chg_type);
|
|
pr_err("%s: dc_step_chg_type 0x%x\n", __func__, battery->dc_step_chg_type);
|
|
if (ret) {
|
|
pr_err("%s: dc_step_chg_type is Empty\n", __func__);
|
|
battery->dc_step_chg_type = 0;
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
dc_step_chg_type = battery->dc_step_chg_type;
|
|
|
|
if (battery->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__, battery->dc_step_chg_type,
|
|
battery->dc_step_chg_type & ~STEP_CHARGING_CONDITION_VOLTAGE);
|
|
battery->dc_step_chg_type &= ~STEP_CHARGING_CONDITION_VOLTAGE;
|
|
} 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_vol is not matched, len(%d/%d)\n",
|
|
__func__, len, battery->dc_step_chg_step);
|
|
}
|
|
|
|
pdata->dc_step_chg_cond_vol = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_vol",
|
|
pdata->dc_step_chg_cond_vol, len);
|
|
if (ret) {
|
|
pr_info("%s : dc_step_chg_cond_vol read fail\n", __func__);
|
|
battery->dc_step_chg_type &= ~STEP_CHARGING_CONDITION_VOLTAGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_SOC ||
|
|
battery->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__, battery->dc_step_chg_type,
|
|
battery->dc_step_chg_type & ~(STEP_CHARGING_CONDITION_SOC | STEP_CHARGING_CONDITION_SOC_INIT_ONLY));
|
|
battery->dc_step_chg_type &= ~(STEP_CHARGING_CONDITION_SOC | STEP_CHARGING_CONDITION_SOC_INIT_ONLY);
|
|
} 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_charging_cond_soc is not matched, len(%d/%d)\n",
|
|
__func__, len, battery->dc_step_chg_step);
|
|
}
|
|
|
|
pdata->dc_step_chg_cond_soc = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,dc_step_chg_cond_soc",
|
|
pdata->dc_step_chg_cond_soc, len);
|
|
if (ret) {
|
|
pr_info("%s : dc_step_chg_cond_soc read fail\n", __func__);
|
|
battery->dc_step_chg_type &= ~STEP_CHARGING_CONDITION_SOC;
|
|
}
|
|
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_SOC &&
|
|
battery->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__);
|
|
battery->dc_step_chg_type &= ~STEP_CHARGING_CONDITION_SOC;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_INPUT_CURRENT) {
|
|
p = of_get_property(np, "battery,dc_step_chg_cond_iin", &len);
|
|
if (!p) {
|
|
pr_err("%s: dc_step_chg_cond_iin is Empty, type(0x%X->0x%x)\n",
|
|
__func__, battery->dc_step_chg_type,
|
|
battery->dc_step_chg_type & ~STEP_CHARGING_CONDITION_INPUT_CURRENT);
|
|
battery->dc_step_chg_type &= ~STEP_CHARGING_CONDITION_INPUT_CURRENT;
|
|
} 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 = kzalloc(sizeof(u32) * len, 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__);
|
|
battery->dc_step_chg_type &= ~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);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (battery->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__, battery->dc_step_chg_type,
|
|
battery->dc_step_chg_type & ~STEP_CHARGING_CONDITION_FLOAT_VOLTAGE);
|
|
battery->dc_step_chg_type &= ~STEP_CHARGING_CONDITION_FLOAT_VOLTAGE;
|
|
} 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_val_vfloat is not matched, len(%d/%d)\n",
|
|
__func__, len, battery->dc_step_chg_step);
|
|
}
|
|
|
|
pdata->dc_step_chg_val_vfloat = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,dc_step_chg_val_vfloat",
|
|
pdata->dc_step_chg_val_vfloat, len);
|
|
if (ret) {
|
|
pr_info("%s : dc_step_chg_val_vfloat read fail\n", __func__);
|
|
battery->dc_step_chg_type &= ~STEP_CHARGING_CONDITION_FLOAT_VOLTAGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
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__);
|
|
battery->dc_step_chg_type = 0;
|
|
return -1;
|
|
} 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_val_iout is not matched, len(%d/%d)\n",
|
|
__func__, len, battery->dc_step_chg_step);
|
|
}
|
|
|
|
pdata->dc_step_chg_val_iout = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,dc_step_chg_val_iout",
|
|
pdata->dc_step_chg_val_iout, len);
|
|
if (ret) {
|
|
pr_info("%s : dc_step_chg_val_iout read fail\n", __func__);
|
|
}
|
|
}
|
|
|
|
if (battery->dc_step_chg_type != dc_step_chg_type)
|
|
pr_err("%s : dc_step_chg_type is changed, type(0x%X->0x%x)\n",
|
|
__func__, dc_step_chg_type, battery->dc_step_chg_type);
|
|
|
|
// 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 & STEP_CHARGING_CONDITION_VOLTAGE)
|
|
sprintf(str + strlen(str), "cond_vol: %dmV, ", pdata->dc_step_chg_cond_vol[i]);
|
|
if (battery->dc_step_chg_type & STEP_CHARGING_CONDITION_SOC)
|
|
sprintf(str + strlen(str), "cond_soc: %d%%, ", pdata->dc_step_chg_cond_soc[i]);
|
|
if (battery->dc_step_chg_type & 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 & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE)
|
|
sprintf(str + strlen(str), "vfloat: %dmV, ", pdata->dc_step_chg_val_vfloat[i]);
|
|
|
|
sprintf(str + strlen(str), "iout: %dmA,", pdata->dc_step_chg_val_iout[i]);
|
|
pr_info("%s : step [%d] %s\n", __func__, i, str);
|
|
}
|
|
|
|
return 0;
|
|
|
|
dc_step_charging_dt_error:
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_BATTERY_AGE_FORECAST)
|
|
void sec_bat_set_aging_info_step_charging(struct sec_battery_info *battery)
|
|
{
|
|
#if defined(CONFIG_DIRECT_CHARGING)
|
|
union power_supply_propval val;
|
|
int i = 0;
|
|
#endif
|
|
|
|
if (battery->step_charging_type) {
|
|
if (battery->step_charging_type & STEP_CHARGING_CONDITION_FLOAT_VOLTAGE)
|
|
battery->pdata->step_charging_float_voltage[battery->step_charging_step-1] = battery->pdata->chg_float_voltage;
|
|
|
|
dev_info(battery->dev, "%s: float_v(%d), step_condition(%d)\n",
|
|
__func__, battery->pdata->step_charging_float_voltage[battery->step_charging_step-1],
|
|
battery->pdata->step_charging_condition[0]);
|
|
}
|
|
#if defined(CONFIG_DIRECT_CHARGING)
|
|
for (i = 0; i < battery->dc_step_chg_step; i++) {
|
|
if (battery->pdata->dc_step_chg_val_vfloat[i] > battery->pdata->chg_float_voltage)
|
|
battery->pdata->dc_step_chg_val_vfloat[i] = battery->pdata->chg_float_voltage;
|
|
if (battery->pdata->dc_step_chg_cond_vol[i] > battery->pdata->chg_float_voltage)
|
|
battery->pdata->dc_step_chg_cond_vol[i] = battery->pdata->chg_float_voltage;
|
|
}
|
|
for (i = 0; i < battery->dc_step_chg_step; i++)
|
|
dev_info(battery->dev, "%s: cond_vol: %dmV, vfloat: %dmV\n", __func__,
|
|
battery->pdata->dc_step_chg_cond_vol[i], battery->pdata->dc_step_chg_val_vfloat[i]);
|
|
val.intval = battery->pdata->dc_step_chg_val_vfloat[battery->dc_step_chg_step-1];
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_DIRECT_FLOAT_MAX, val);
|
|
|
|
if (battery->step_charging_status >= 0 && !battery->dc_float_voltage_set) {
|
|
int float_max = battery->pdata->dc_step_chg_val_vfloat[battery->dc_step_chg_step-1];
|
|
|
|
val.intval = 0;
|
|
psy_do_property(battery->pdata->charger_name, get,
|
|
POWER_SUPPLY_EXT_PROP_DIRECT_VOLTAGE_MAX, val);
|
|
|
|
if (val.intval > float_max) {
|
|
val.intval = float_max;
|
|
psy_do_property(battery->pdata->charger_name, set,
|
|
POWER_SUPPLY_EXT_PROP_DIRECT_VOLTAGE_MAX, val);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void sec_step_charging_init(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;
|
|
const u32 *p;
|
|
|
|
ret = of_property_read_u32(np, "battery,step_charging_type",
|
|
&battery->step_charging_type);
|
|
pr_err("%s: step_charging_type 0x%x\n", __func__, battery->step_charging_type);
|
|
if (ret) {
|
|
pr_err("%s: step_charging_type is Empty\n", __func__);
|
|
battery->step_charging_type = 0;
|
|
}
|
|
|
|
if (battery->step_charging_type) {
|
|
ret = of_property_read_u32(np, "battery,step_charging_step",
|
|
&battery->step_charging_step);
|
|
if (ret) {
|
|
pr_err("%s: step_charging_step is Empty\n", __func__);
|
|
battery->step_charging_step = 0;
|
|
} else {
|
|
pr_err("%s: step_charging_step is %d\n",
|
|
__func__, battery->step_charging_step);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "battery,step_charging_charge_power",
|
|
&battery->step_charging_charge_power);
|
|
if (ret) {
|
|
pr_err("%s: step_charging_charge_power is Empty\n", __func__);
|
|
battery->step_charging_charge_power = 20000;
|
|
}
|
|
|
|
p = of_get_property(np, "battery,step_charging_condition", &len);
|
|
if (!p) {
|
|
battery->step_charging_step = 0;
|
|
} else {
|
|
len = len / sizeof(u32);
|
|
battery->step_charging_step = len;
|
|
pdata->step_charging_condition = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,step_charging_condition",
|
|
pdata->step_charging_condition, len);
|
|
if (ret) {
|
|
pr_info("%s : step_charging_condition read fail\n", __func__);
|
|
battery->step_charging_step = 0;
|
|
}
|
|
|
|
p = of_get_property(np, "battery,step_charging_condition_curr", &len);
|
|
if (!p) {
|
|
pr_err("%s: step_charging_condition_curr is Empty\n", __func__);
|
|
} else {
|
|
len = len / sizeof(u32);
|
|
pdata->step_charging_condition_curr = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,step_charging_condition_curr",
|
|
pdata->step_charging_condition_curr, len);
|
|
if (ret) {
|
|
pr_info("%s : step_charging_condition_curr read fail\n", __func__);
|
|
battery->step_charging_step = 0;
|
|
}
|
|
}
|
|
|
|
p = of_get_property(np, "battery,step_charging_float_voltage", &len);
|
|
if (!p) {
|
|
pr_err("%s: step_charging_float_voltage is Empty\n", __func__);
|
|
} else {
|
|
len = len / sizeof(u32);
|
|
pdata->step_charging_float_voltage = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,step_charging_float_voltage",
|
|
pdata->step_charging_float_voltage, len);
|
|
if (ret) {
|
|
pr_info("%s : step_charging_float_voltage read fail\n", __func__);
|
|
} else {
|
|
for (i = 0; i < len; i++) {
|
|
pr_info("%s : step condition(%d), float voltage(%d)\n",
|
|
__func__, pdata->step_charging_condition[i],
|
|
pdata->step_charging_float_voltage[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
p = of_get_property(np, "battery,step_charging_current", &len);
|
|
if (!p) {
|
|
pr_err("%s: step_charging_current is Empty\n", __func__);
|
|
} else {
|
|
len = len / sizeof(u32);
|
|
pdata->step_charging_current = kzalloc(sizeof(u32) * len, GFP_KERNEL);
|
|
ret = of_property_read_u32_array(np, "battery,step_charging_current",
|
|
pdata->step_charging_current, len);
|
|
if (ret) {
|
|
pr_info("%s : step_charging_current read fail\n", __func__);
|
|
battery->step_charging_step = 0;
|
|
} else {
|
|
battery->step_charging_status = -1;
|
|
for (i = 0; i < len; i++) {
|
|
pr_info("%s : step condition(%d), current(%d)\n",
|
|
__func__, pdata->step_charging_condition[i],
|
|
pdata->step_charging_current[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#if defined(CONFIG_DIRECT_CHARGING)
|
|
sec_dc_step_charging_dt(battery, dev);
|
|
#endif
|
|
}
|