power: qpnp-fg-gen3: prepare for QNOVO TTF

Micro resolution and 64-bit division is unnecessary; use milli
resolution instead. Measuring the IBATT and VBATT periodically during
sleep is necessary for accuracy. Don't clear the IBATT and VBATT buffers
on suspend to account for the higher charge current during suspend.
Prime the IBATT and VBATT buffers with 10 samples to get a more accurate
first estimate. Introduce a ttf mode to separate the differences in the
QNOVO version of TTF.

Change-Id: Ibc591dd5d38d4bbb712d8906755040d59181f008
Signed-off-by: Nicholas Troast <ntroast@codeaurora.org>
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
This commit is contained in:
Nicholas Troast 2017-07-06 14:53:46 -07:00
parent 175907d3d2
commit e55198f9ef
2 changed files with 296 additions and 160 deletions

View file

@ -50,6 +50,7 @@
#define SRAM_WRITE "fg_sram_write"
#define PROFILE_LOAD "fg_profile_load"
#define DELTA_SOC "fg_delta_soc"
#define TTF_PRIMING "fg_ttf_priming"
/* Delta BSOC irq votable reasons */
#define DELTA_BSOC_IRQ_VOTER "fg_delta_bsoc_irq"
@ -230,6 +231,10 @@ enum esr_timer_config {
NUM_ESR_TIMERS,
};
enum ttf_mode {
TTF_MODE_NORMAL = 0,
};
/* DT parameters for FG device */
struct fg_dt_props {
bool force_load_profile;
@ -326,6 +331,14 @@ struct fg_pt {
s32 y;
};
struct ttf {
struct fg_circ_buf ibatt;
struct fg_circ_buf vbatt;
struct fg_cc_step_data cc_step;
struct mutex lock;
int mode;
};
static const struct fg_pt fg_ln_table[] = {
{ 1000, 0 },
{ 2000, 693 },
@ -365,6 +378,7 @@ struct fg_chip {
struct power_supply *usb_psy;
struct power_supply *dc_psy;
struct power_supply *parallel_psy;
struct power_supply *pc_port_psy;
struct iio_channel *batt_id_chan;
struct iio_channel *die_temp_chan;
struct fg_memif *sram;
@ -381,10 +395,9 @@ struct fg_chip {
struct fg_cyc_ctr_data cyc_ctr;
struct notifier_block nb;
struct fg_cap_learning cl;
struct fg_cc_step_data cc_step;
struct ttf ttf;
struct mutex bus_lock;
struct mutex sram_rw_lock;
struct mutex batt_avg_lock;
struct mutex charge_full_lock;
u32 batt_soc_base;
u32 batt_info_base;
@ -397,6 +410,7 @@ struct fg_chip {
int prev_charge_status;
int charge_done;
int charge_type;
int online_status;
int last_soc;
int last_batt_temp;
int health;
@ -422,10 +436,8 @@ struct fg_chip {
struct delayed_work profile_load_work;
struct work_struct status_change_work;
struct work_struct cycle_count_work;
struct delayed_work batt_avg_work;
struct delayed_work ttf_work;
struct delayed_work sram_dump_work;
struct fg_circ_buf ibatt_circ_buf;
struct fg_circ_buf vbatt_circ_buf;
};
/* Debugfs data structures are below */

View file

@ -1173,6 +1173,42 @@ static bool batt_psy_initialized(struct fg_chip *chip)
return true;
}
static bool usb_psy_initialized(struct fg_chip *chip)
{
if (chip->usb_psy)
return true;
chip->usb_psy = power_supply_get_by_name("usb");
if (!chip->usb_psy)
return false;
return true;
}
static bool pc_port_psy_initialized(struct fg_chip *chip)
{
if (chip->pc_port_psy)
return true;
chip->pc_port_psy = power_supply_get_by_name("pc_port");
if (!chip->pc_port_psy)
return false;
return true;
}
static bool dc_psy_initialized(struct fg_chip *chip)
{
if (chip->dc_psy)
return true;
chip->dc_psy = power_supply_get_by_name("dc");
if (!chip->dc_psy)
return false;
return true;
}
static bool is_parallel_charger_available(struct fg_chip *chip)
{
if (!chip->parallel_psy)
@ -2132,19 +2168,65 @@ static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
return 0;
}
static void fg_batt_avg_update(struct fg_chip *chip)
static void fg_ttf_update(struct fg_chip *chip)
{
if (chip->charge_status == chip->prev_charge_status)
int rc;
int delay_ms;
union power_supply_propval prop = {0, };
int online = 0;
if (usb_psy_initialized(chip)) {
rc = power_supply_get_property(chip->usb_psy,
POWER_SUPPLY_PROP_ONLINE, &prop);
if (rc < 0) {
pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
return;
}
online = online || prop.intval;
}
if (pc_port_psy_initialized(chip)) {
rc = power_supply_get_property(chip->pc_port_psy,
POWER_SUPPLY_PROP_ONLINE, &prop);
if (rc < 0) {
pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
return;
}
online = online || prop.intval;
}
if (dc_psy_initialized(chip)) {
rc = power_supply_get_property(chip->dc_psy,
POWER_SUPPLY_PROP_ONLINE, &prop);
if (rc < 0) {
pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
return;
}
online = online || prop.intval;
}
if (chip->online_status == online)
return;
cancel_delayed_work_sync(&chip->batt_avg_work);
fg_circ_buf_clr(&chip->ibatt_circ_buf);
fg_circ_buf_clr(&chip->vbatt_circ_buf);
chip->online_status = online;
if (online)
/* wait 35 seconds for the input to settle */
delay_ms = 35000;
else
/* wait 5 seconds for current to settle during discharge */
delay_ms = 5000;
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
schedule_delayed_work(&chip->batt_avg_work,
msecs_to_jiffies(2000));
vote(chip->awake_votable, TTF_PRIMING, true, 0);
cancel_delayed_work_sync(&chip->ttf_work);
mutex_lock(&chip->ttf.lock);
fg_circ_buf_clr(&chip->ttf.ibatt);
fg_circ_buf_clr(&chip->ttf.vbatt);
mutex_unlock(&chip->ttf.lock);
schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
}
static void status_change_work(struct work_struct *work)
@ -2222,7 +2304,7 @@ static void status_change_work(struct work_struct *work)
rc);
}
fg_batt_avg_update(chip);
fg_ttf_update(chip);
out:
fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
@ -2732,45 +2814,16 @@ static struct kernel_param_ops fg_restart_ops = {
module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
#define BATT_AVG_POLL_PERIOD_MS 10000
static void batt_avg_work(struct work_struct *work)
{
struct fg_chip *chip = container_of(work, struct fg_chip,
batt_avg_work.work);
int rc, ibatt_now, vbatt_now;
mutex_lock(&chip->batt_avg_lock);
rc = fg_get_battery_current(chip, &ibatt_now);
if (rc < 0) {
pr_err("failed to get battery current, rc=%d\n", rc);
goto reschedule;
}
rc = fg_get_battery_voltage(chip, &vbatt_now);
if (rc < 0) {
pr_err("failed to get battery voltage, rc=%d\n", rc);
goto reschedule;
}
fg_circ_buf_add(&chip->ibatt_circ_buf, ibatt_now);
fg_circ_buf_add(&chip->vbatt_circ_buf, vbatt_now);
reschedule:
mutex_unlock(&chip->batt_avg_lock);
schedule_delayed_work(&chip->batt_avg_work,
msecs_to_jiffies(BATT_AVG_POLL_PERIOD_MS));
}
#define HOURS_TO_SECONDS 3600
#define OCV_SLOPE_UV 10869
#define MILLI_UNIT 1000
#define MICRO_UNIT 1000000
static int fg_get_time_to_full(struct fg_chip *chip, int *val)
#define NANO_UNIT 1000000000
static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
{
int rc, ibatt_avg, vbatt_avg, rbatt, msoc, ocv_cc2cv, full_soc,
act_cap_uah;
s32 i_cc2cv, soc_cc2cv, ln_val, centi_tau_scale;
s64 t_predicted_cc = 0, t_predicted_cv = 0;
int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
i_cc2cv, soc_cc2cv, tau, divisor, iterm,
t_predicted_cv, t_predicted = 0;
if (chip->bp.float_volt_uv <= 0) {
pr_err("battery profile is not loaded\n");
@ -2789,48 +2842,39 @@ static int fg_get_time_to_full(struct fg_chip *chip, int *val)
}
fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
/* the battery is considered full if the SOC is 100% */
if (msoc >= 100) {
*val = 0;
return 0;
}
mutex_lock(&chip->batt_avg_lock);
rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
if (rc < 0) {
/* try to get instantaneous current */
rc = fg_get_battery_current(chip, &ibatt_avg);
if (rc < 0) {
mutex_unlock(&chip->batt_avg_lock);
pr_err("failed to get battery current, rc=%d\n", rc);
return rc;
}
/* at least 10 samples are required to produce a stable IBATT */
if (chip->ttf.ibatt.size < 10) {
*val = -1;
return 0;
}
rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg);
rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
if (rc < 0) {
/* try to get instantaneous voltage */
rc = fg_get_battery_voltage(chip, &vbatt_avg);
if (rc < 0) {
mutex_unlock(&chip->batt_avg_lock);
pr_err("failed to get battery voltage, rc=%d\n", rc);
return rc;
}
pr_err("failed to get IBATT AVG rc=%d\n", rc);
return rc;
}
mutex_unlock(&chip->batt_avg_lock);
fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
if (rc < 0) {
pr_err("failed to get VBATT AVG rc=%d\n", rc);
return rc;
}
ibatt_avg = -ibatt_avg / MILLI_UNIT;
vbatt_avg /= MILLI_UNIT;
/* clamp ibatt_avg to iterm */
if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
ibatt_avg = abs(chip->dt.sys_term_curr_ma);
/* clamp ibatt_avg to -150mA */
if (ibatt_avg > -150000)
ibatt_avg = -150000;
fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
/* reverse polarity to be consistent with unsigned current settings */
ibatt_avg = abs(ibatt_avg);
/* estimated battery current at the CC to CV transition */
i_cc2cv = div_s64((s64)ibatt_avg * vbatt_avg, chip->bp.float_volt_uv);
fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
rc = fg_get_battery_resistance(chip, &rbatt);
if (rc < 0) {
@ -2838,19 +2882,14 @@ static int fg_get_time_to_full(struct fg_chip *chip, int *val)
return rc;
}
/* clamp rbatt to 50mOhms */
if (rbatt < 50000)
rbatt = 50000;
rbatt /= MILLI_UNIT;
fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
if (rc < 0) {
pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
return rc;
}
act_cap_uah *= MILLI_UNIT;
fg_dbg(chip, FG_TTF, "actual_capacity_uah=%d\n", act_cap_uah);
rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
if (rc < 0) {
@ -2859,69 +2898,97 @@ static int fg_get_time_to_full(struct fg_chip *chip, int *val)
}
full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
FULL_SOC_RAW);
fg_dbg(chip, FG_TTF, "full_soc=%d\n", full_soc);
act_cap_mah = full_soc * act_cap_mah / 100;
fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
/* estimated battery current at the CC to CV transition */
switch (chip->ttf.mode) {
case TTF_MODE_NORMAL:
i_cc2cv = ibatt_avg * vbatt_avg /
max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
break;
default:
pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
break;
}
fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
/* if we are already in CV state then we can skip estimating CC */
if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
goto skip_cc_estimate;
goto cv_estimate;
/* if the charger is current limited then use power approximation */
if (ibatt_avg > chip->bp.fastchg_curr_ma * MILLI_UNIT - 50000)
ocv_cc2cv = div_s64((s64)rbatt * ibatt_avg, MICRO_UNIT);
else
ocv_cc2cv = div_s64((s64)rbatt * i_cc2cv, MICRO_UNIT);
ocv_cc2cv = chip->bp.float_volt_uv - ocv_cc2cv;
fg_dbg(chip, FG_TTF, "ocv_cc2cv=%d\n", ocv_cc2cv);
soc_cc2cv = div_s64(chip->bp.float_volt_uv - ocv_cc2cv, OCV_SLOPE_UV);
/* estimated SOC at the CC to CV transition */
soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
soc_cc2cv = 100 - soc_cc2cv;
fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
/* the esimated SOC may be lower than the current SOC */
if (soc_cc2cv - msoc <= 0)
goto skip_cc_estimate;
switch (chip->ttf.mode) {
case TTF_MODE_NORMAL:
if (soc_cc2cv - msoc <= 0)
goto cv_estimate;
t_predicted_cc = div_s64((s64)full_soc * act_cap_uah, 100);
t_predicted_cc = div_s64(t_predicted_cc * (soc_cc2cv - msoc), 100);
t_predicted_cc *= HOURS_TO_SECONDS;
t_predicted_cc = div_s64(t_predicted_cc, (ibatt_avg + i_cc2cv) / 2);
divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
HOURS_TO_SECONDS, divisor);
break;
default:
pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
break;
}
skip_cc_estimate:
fg_dbg(chip, FG_TTF, "t_predicted_cc=%lld\n", t_predicted_cc);
cv_estimate:
fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
/* CV estimate starts here */
if (chip->charge_type >= POWER_SUPPLY_CHARGE_TYPE_TAPER)
ln_val = ibatt_avg / (abs(chip->dt.sys_term_curr_ma) + 200);
iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
else
ln_val = i_cc2cv / (abs(chip->dt.sys_term_curr_ma) + 200);
tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
if (msoc < 95)
centi_tau_scale = 100;
else
centi_tau_scale = 20 * (100 - msoc);
rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
if (rc < 0) {
pr_err("failed to interpolate tau rc=%d\n", rc);
return rc;
}
fg_dbg(chip, FG_TTF, "ln_in=%d\n", ln_val);
rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), ln_val, &ln_val);
fg_dbg(chip, FG_TTF, "ln_out=%d\n", ln_val);
t_predicted_cv = div_s64((s64)act_cap_uah * rbatt, MICRO_UNIT);
t_predicted_cv = div_s64(t_predicted_cv * centi_tau_scale, 100);
t_predicted_cv = div_s64(t_predicted_cv * ln_val, MILLI_UNIT);
t_predicted_cv = div_s64(t_predicted_cv * HOURS_TO_SECONDS, MICRO_UNIT);
fg_dbg(chip, FG_TTF, "t_predicted_cv=%lld\n", t_predicted_cv);
*val = t_predicted_cc + t_predicted_cv;
/* tau is scaled linearly from 95% to 100% SOC */
if (msoc >= 95)
tau = tau * 2 * (100 - msoc) / 10;
fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
HOURS_TO_SECONDS, NANO_UNIT);
fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
t_predicted += t_predicted_cv;
/* clamp the ttf to 0 */
if (t_predicted < 0)
t_predicted = 0;
fg_dbg(chip, FG_TTF, "t_predicted=%d\n", t_predicted);
*val = t_predicted;
return 0;
}
static int fg_get_time_to_full(struct fg_chip *chip, int *val)
{
int rc;
mutex_lock(&chip->ttf.lock);
rc = fg_get_time_to_full_locked(chip, val);
mutex_unlock(&chip->ttf.lock);
return rc;
}
#define CENTI_ICORRECT_C0 105
#define CENTI_ICORRECT_C1 20
static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
{
int rc, ibatt_avg, msoc, act_cap_uah;
s32 divisor;
s64 t_predicted;
int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
if (rc < 0) {
/* try to get instantaneous current */
rc = fg_get_battery_current(chip, &ibatt_avg);
@ -2931,16 +2998,10 @@ static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
}
}
/* clamp ibatt_avg to 150mA */
if (ibatt_avg < 150000)
ibatt_avg = 150000;
rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
if (rc < 0) {
pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
return rc;
}
act_cap_uah *= MILLI_UNIT;
ibatt_avg /= MILLI_UNIT;
/* clamp ibatt_avg to 100mA */
if (ibatt_avg < 100)
ibatt_avg = 100;
rc = fg_get_prop_capacity(chip, &msoc);
if (rc < 0) {
@ -2948,14 +3009,25 @@ static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
return rc;
}
t_predicted = div_s64((s64)msoc * act_cap_uah, 100);
t_predicted *= HOURS_TO_SECONDS;
divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
divisor = div_s64((s64)divisor * ibatt_avg, 10000);
if (divisor > 0)
t_predicted = div_s64(t_predicted, divisor);
rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
if (rc < 0) {
pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
return rc;
}
*val = t_predicted;
rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
if (rc < 0) {
pr_err("failed to get full soc rc=%d\n", rc);
return rc;
}
full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
FULL_SOC_RAW);
act_cap_mah = full_soc * act_cap_mah / 100;
divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
divisor = ibatt_avg * divisor / 100;
divisor = max(100, divisor);
*val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
return 0;
}
@ -3117,6 +3189,57 @@ static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n");
return 0;
}
static void ttf_work(struct work_struct *work)
{
struct fg_chip *chip = container_of(work, struct fg_chip,
ttf_work.work);
int rc, ibatt_now, vbatt_now, ttf;
mutex_lock(&chip->ttf.lock);
if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
goto end_work;
rc = fg_get_battery_current(chip, &ibatt_now);
if (rc < 0) {
pr_err("failed to get battery current, rc=%d\n", rc);
goto end_work;
}
rc = fg_get_battery_voltage(chip, &vbatt_now);
if (rc < 0) {
pr_err("failed to get battery voltage, rc=%d\n", rc);
goto end_work;
}
fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
rc = fg_get_time_to_full_locked(chip, &ttf);
if (rc < 0) {
pr_err("failed to get ttf, rc=%d\n", rc);
goto end_work;
}
/* keep the wake lock and prime the IBATT and VBATT buffers */
if (ttf < 0) {
/* delay for one FG cycle */
schedule_delayed_work(&chip->ttf_work,
msecs_to_jiffies(1500));
mutex_unlock(&chip->ttf.lock);
return;
}
}
/* recurse every 10 seconds */
schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
end_work:
vote(chip->awake_votable, TTF_PRIMING, false, 0);
mutex_unlock(&chip->ttf.lock);
}
/* PSY CALLBACKS STAY HERE */
static int fg_psy_get_property(struct power_supply *psy,
@ -3194,17 +3317,18 @@ static int fg_psy_get_property(struct power_supply *psy,
rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
break;
case POWER_SUPPLY_PROP_CC_STEP:
if ((chip->cc_step.sel >= 0) &&
(chip->cc_step.sel < MAX_CC_STEPS)) {
pval->intval = chip->cc_step.arr[chip->cc_step.sel];
if ((chip->ttf.cc_step.sel >= 0) &&
(chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
pval->intval =
chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
} else {
pr_err("cc_step_sel is out of bounds [0, %d]\n",
chip->cc_step.sel);
chip->ttf.cc_step.sel);
return -EINVAL;
}
break;
case POWER_SUPPLY_PROP_CC_STEP_SEL:
pval->intval = chip->cc_step.sel;
pval->intval = chip->ttf.cc_step.sel;
break;
default:
pr_err("unsupported property %d\n", psp);
@ -3245,18 +3369,19 @@ static int fg_psy_set_property(struct power_supply *psy,
rc = fg_prepare_for_qnovo(chip, pval->intval);
break;
case POWER_SUPPLY_PROP_CC_STEP:
if ((chip->cc_step.sel >= 0) &&
(chip->cc_step.sel < MAX_CC_STEPS)) {
chip->cc_step.arr[chip->cc_step.sel] = pval->intval;
if ((chip->ttf.cc_step.sel >= 0) &&
(chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
pval->intval;
} else {
pr_err("cc_step_sel is out of bounds [0, %d]\n",
chip->cc_step.sel);
chip->ttf.cc_step.sel);
return -EINVAL;
}
break;
case POWER_SUPPLY_PROP_CC_STEP_SEL:
if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
chip->cc_step.sel = pval->intval;
chip->ttf.cc_step.sel = pval->intval;
} else {
pr_err("cc_step_sel is out of bounds [0, %d]\n",
pval->intval);
@ -4521,6 +4646,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
chip->charge_status = -EINVAL;
chip->prev_charge_status = -EINVAL;
chip->ki_coeff_full_soc = -EINVAL;
chip->online_status = -EINVAL;
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
if (!chip->regmap) {
dev_err(chip->dev, "Parent regmap is unavailable\n");
@ -4589,14 +4715,14 @@ static int fg_gen3_probe(struct platform_device *pdev)
mutex_init(&chip->sram_rw_lock);
mutex_init(&chip->cyc_ctr.lock);
mutex_init(&chip->cl.lock);
mutex_init(&chip->batt_avg_lock);
mutex_init(&chip->ttf.lock);
mutex_init(&chip->charge_full_lock);
init_completion(&chip->soc_update);
init_completion(&chip->soc_ready);
INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
INIT_WORK(&chip->status_change_work, status_change_work);
INIT_WORK(&chip->cycle_count_work, cycle_count_work);
INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
rc = fg_memif_init(chip);
@ -4693,7 +4819,7 @@ static int fg_gen3_suspend(struct device *dev)
if (rc < 0)
pr_err("Error in configuring ESR timer, rc=%d\n", rc);
cancel_delayed_work_sync(&chip->batt_avg_work);
cancel_delayed_work_sync(&chip->ttf_work);
if (fg_sram_dump)
cancel_delayed_work_sync(&chip->sram_dump_work);
return 0;
@ -4708,9 +4834,7 @@ static int fg_gen3_resume(struct device *dev)
if (rc < 0)
pr_err("Error in configuring ESR timer, rc=%d\n", rc);
fg_circ_buf_clr(&chip->ibatt_circ_buf);
fg_circ_buf_clr(&chip->vbatt_circ_buf);
schedule_delayed_work(&chip->batt_avg_work, 0);
schedule_delayed_work(&chip->ttf_work, 0);
if (fg_sram_dump)
schedule_delayed_work(&chip->sram_dump_work,
msecs_to_jiffies(fg_sram_dump_period_ms));