From e55198f9ef9edd829cf879c7828f5f743a23ee89 Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Thu, 6 Jul 2017 14:53:46 -0700 Subject: 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 Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/fg-core.h | 22 +- drivers/power/supply/qcom/qpnp-fg-gen3.c | 430 ++++++++++++++++++++----------- 2 files changed, 294 insertions(+), 158 deletions(-) diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 719f09a7c372..dea107c602c3 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -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 */ diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 00bbb09b5748..eefadd9412b2 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -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) - return; + int rc; + int delay_ms; + union power_supply_propval prop = {0, }; + int online = 0; - cancel_delayed_work_sync(&chip->batt_avg_work); - fg_circ_buf_clr(&chip->ibatt_circ_buf); - fg_circ_buf_clr(&chip->vbatt_circ_buf); + 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; + } - 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)); + 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; + + 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; + + 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); + /* 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_median(&chip->ttf.ibatt, &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; - } + pr_err("failed to get IBATT AVG rc=%d\n", rc); + return rc; } - rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg); + rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_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 VBATT AVG rc=%d\n", rc); + return rc; } - mutex_unlock(&chip->batt_avg_lock); - fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg); + ibatt_avg = -ibatt_avg / MILLI_UNIT; + vbatt_avg /= MILLI_UNIT; - /* clamp ibatt_avg to -150mA */ - if (ibatt_avg > -150000) - ibatt_avg = -150000; - fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg); + /* clamp ibatt_avg to iterm */ + if (ibatt_avg < abs(chip->dt.sys_term_curr_ma)) + ibatt_avg = abs(chip->dt.sys_term_curr_ma); - /* 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, "ibatt_avg=%d\n", ibatt_avg); + 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; - - /* 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); + goto cv_estimate; - 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); - else - ln_val = i_cc2cv / (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 (msoc < 95) - centi_tau_scale = 100; + if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER) + tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm); else - centi_tau_scale = 20 * (100 - msoc); - - 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 = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm); + + 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; + } + + /* 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,31 +2998,36 @@ 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; + 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) { + pr_err("Error in getting capacity, rc=%d\n", rc); + return rc; + } - 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("Error in getting ACT_BATT_CAP, rc=%d\n", rc); return rc; } - act_cap_uah *= MILLI_UNIT; - rc = fg_get_prop_capacity(chip, &msoc); + rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc); if (rc < 0) { - pr_err("Error in getting capacity, rc=%d\n", rc); + 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; - 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); - - *val = t_predicted; + 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)); -- cgit v1.2.3 From 811a8bd2ef12b0ca589714823ea6d85381d250b6 Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Wed, 21 Jun 2017 11:10:40 -0700 Subject: power: qpnp-fg-gen3: optimize TTF for QNOVO QNOVO provides a table of expected charge current settings across the charge cycle. Use this table to calculate the time it will take to charge in each step. The sum of these steps is the total time it will take to fully charge a battery. Change-Id: I0ed48a2a63886531e761e7ce1d175a600060eaf8 Signed-off-by: Nicholas Troast Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/fg-core.h | 1 + drivers/power/supply/qcom/qpnp-fg-gen3.c | 45 +++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index dea107c602c3..a49d96463dbf 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -233,6 +233,7 @@ enum esr_timer_config { enum ttf_mode { TTF_MODE_NORMAL = 0, + TTF_MODE_QNOVO, }; /* DT parameters for FG device */ diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index eefadd9412b2..cce03d3b1432 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -2822,7 +2822,9 @@ module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644); static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) { int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah, - i_cc2cv, soc_cc2cv, tau, divisor, iterm, + i_cc2cv, soc_cc2cv, tau, divisor, iterm, ttf_mode, + i, soc_per_step, msoc_this_step, msoc_next_step, + ibatt_this_step, t_predicted_this_step, t_predicted_cv, t_predicted = 0; if (chip->bp.float_volt_uv <= 0) { @@ -2848,6 +2850,18 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) return 0; } + if (is_qnovo_en(chip)) + ttf_mode = TTF_MODE_QNOVO; + else + ttf_mode = TTF_MODE_NORMAL; + + /* when switching TTF algorithms the TTF needs to be reset */ + if (chip->ttf.mode != ttf_mode) { + fg_circ_buf_clr(&chip->ttf.ibatt); + fg_circ_buf_clr(&chip->ttf.vbatt); + chip->ttf.mode = ttf_mode; + } + /* at least 10 samples are required to produce a stable IBATT */ if (chip->ttf.ibatt.size < 10) { *val = -1; @@ -2907,6 +2921,12 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) i_cc2cv = ibatt_avg * vbatt_avg / max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT); break; + case TTF_MODE_QNOVO: + i_cc2cv = min( + chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT, + 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; @@ -2931,6 +2951,29 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) * HOURS_TO_SECONDS, divisor); break; + case TTF_MODE_QNOVO: + soc_per_step = 100 / MAX_CC_STEPS; + for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) { + msoc_next_step = (i + 1) * soc_per_step; + if (i == msoc / soc_per_step) + msoc_this_step = msoc; + else + msoc_this_step = i * soc_per_step; + + /* scale ibatt by 85% to account for discharge pulses */ + ibatt_this_step = min( + chip->ttf.cc_step.arr[i] / MILLI_UNIT, + ibatt_avg) * 85 / 100; + divisor = max(100, ibatt_this_step * 100); + t_predicted_this_step = div_s64((s64)act_cap_mah * + (msoc_next_step - msoc_this_step) * + HOURS_TO_SECONDS, divisor); + t_predicted += t_predicted_this_step; + fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n", + msoc_this_step, msoc_next_step, + ibatt_this_step, t_predicted_this_step); + } + break; default: pr_err("TTF mode %d is not supported\n", chip->ttf.mode); break; -- cgit v1.2.3 From 96168e19d4062adfcfa3e524a6b19bb1b9791675 Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Mon, 10 Jul 2017 13:14:28 -0700 Subject: power: qpnp-fg-gen3: make TTF monotonic by limiting slope Currently if there is a spike in system load or a thermal event which causes the battery current to change dramatically then the TTF can jump. While a battery is charging the TTF should be monotonically decreasing. Track the TTF starting with the first estimate and set hard bounds of -2 and -0.1 on the slope. The negative slope ensures the TTF is monotonically decreasing and the hard bounds on the slope smooth out significant changes in the TTF. Change-Id: I68a934599ff25bc5a9eb67b372b28a723532a540 Signed-off-by: Nicholas Troast Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/fg-core.h | 2 ++ drivers/power/supply/qcom/qpnp-fg-gen3.c | 41 ++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index a49d96463dbf..1a036c6edcd1 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -338,6 +338,8 @@ struct ttf { struct fg_cc_step_data cc_step; struct mutex lock; int mode; + int last_ttf; + s64 last_ms; }; static const struct fg_pt fg_ln_table[] = { diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index cce03d3b1432..ecb8af32e5ed 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -2225,6 +2225,8 @@ static void fg_ttf_update(struct fg_chip *chip) mutex_lock(&chip->ttf.lock); fg_circ_buf_clr(&chip->ttf.ibatt); fg_circ_buf_clr(&chip->ttf.vbatt); + chip->ttf.last_ttf = 0; + chip->ttf.last_ms = 0; mutex_unlock(&chip->ttf.lock); schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms)); } @@ -2824,8 +2826,9 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah, i_cc2cv, soc_cc2cv, tau, divisor, iterm, ttf_mode, i, soc_per_step, msoc_this_step, msoc_next_step, - ibatt_this_step, t_predicted_this_step, + ibatt_this_step, t_predicted_this_step, ttf_slope, t_predicted_cv, t_predicted = 0; + s64 delta_ms; if (chip->bp.float_volt_uv <= 0) { pr_err("battery profile is not loaded\n"); @@ -2859,6 +2862,8 @@ static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val) if (chip->ttf.mode != ttf_mode) { fg_circ_buf_clr(&chip->ttf.ibatt); fg_circ_buf_clr(&chip->ttf.vbatt); + chip->ttf.last_ttf = 0; + chip->ttf.last_ms = 0; chip->ttf.mode = ttf_mode; } @@ -3006,11 +3011,33 @@ cv_estimate: fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv); t_predicted += t_predicted_cv; + fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted); + if (chip->ttf.last_ms != 0) { + delta_ms = ktime_ms_delta(ktime_get_boottime(), + ms_to_ktime(chip->ttf.last_ms)); + if (delta_ms > 10000) { + ttf_slope = div64_s64( + (s64)(t_predicted - chip->ttf.last_ttf) * + MICRO_UNIT, delta_ms); + if (ttf_slope > -100) + ttf_slope = -100; + else if (ttf_slope < -2000) + ttf_slope = -2000; + + t_predicted = div_s64( + (s64)ttf_slope * delta_ms, MICRO_UNIT) + + chip->ttf.last_ttf; + fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope); + } else { + t_predicted = chip->ttf.last_ttf; + } + } + /* clamp the ttf to 0 */ if (t_predicted < 0) t_predicted = 0; - fg_dbg(chip, FG_TTF, "t_predicted=%d\n", t_predicted); + fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted); *val = t_predicted; return 0; } @@ -3238,6 +3265,7 @@ 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; + ktime_t ktime_now; mutex_lock(&chip->ttf.lock); if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING && @@ -3274,6 +3302,15 @@ static void ttf_work(struct work_struct *work) mutex_unlock(&chip->ttf.lock); return; } + + /* update the TTF reference point every minute */ + ktime_now = ktime_get_boottime(); + if (ktime_ms_delta(ktime_now, + ms_to_ktime(chip->ttf.last_ms)) > 60000 || + chip->ttf.last_ms == 0) { + chip->ttf.last_ttf = ttf; + chip->ttf.last_ms = ktime_to_ms(ktime_now); + } } /* recurse every 10 seconds */ -- cgit v1.2.3 From 183bc63f12f505b69b4fd69175e702f4243c2cc1 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 9 Jun 2017 15:09:11 -0700 Subject: power: qpnp-fg-gen3: improve cycle counter algorithm Currently, when the charging status transitions to a state other than charging, cycle counter algorithm stores the cycle count for all the buckets for which the counting had started. This is fine with respect to the algorithm. However with qnovo enabled charging, this can cause issues when charging status can go to not charging intermittently causing the cycle count to be stored multiple times for a bucket. Modify the logic to check for the charge termination or the presence of input to go through all the buckets for storing the count. Also, increment and store the counter only if battery SOC had increased more than 2 LSBs for that SOC bucket. While at it, run cycle_counter algorithm as a function instead of a work. Also, keep the usage of cycle counter feature enable flag inside the cycle counter APIs. Change-Id: I62a92964ccbc6b965af09696deddc6fa8366a841 Signed-off-by: Subbaraman Narayanamurthy Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/fg-core.h | 2 - drivers/power/supply/qcom/qpnp-fg-gen3.c | 222 ++++++++++++++----------------- 2 files changed, 103 insertions(+), 121 deletions(-) diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 1a036c6edcd1..d3932ca1f338 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -49,7 +49,6 @@ #define SRAM_READ "fg_sram_read" #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 */ @@ -438,7 +437,6 @@ struct fg_chip { struct completion soc_ready; struct delayed_work profile_load_work; struct work_struct status_change_work; - struct work_struct cycle_count_work; struct delayed_work ttf_work; struct delayed_work sram_dump_work; }; diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index ecb8af32e5ed..9b427a1b52c5 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -2231,94 +2231,14 @@ static void fg_ttf_update(struct fg_chip *chip) schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms)); } -static void status_change_work(struct work_struct *work) -{ - struct fg_chip *chip = container_of(work, - struct fg_chip, status_change_work); - union power_supply_propval prop = {0, }; - int rc, batt_temp; - - if (!batt_psy_initialized(chip)) { - fg_dbg(chip, FG_STATUS, "Charger not available?!\n"); - goto out; - } - - rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, - &prop); - if (rc < 0) { - pr_err("Error in getting charging status, rc=%d\n", rc); - goto out; - } - - chip->prev_charge_status = chip->charge_status; - chip->charge_status = prop.intval; - rc = power_supply_get_property(chip->batt_psy, - POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); - if (rc < 0) { - pr_err("Error in getting charge type, rc=%d\n", rc); - goto out; - } - - chip->charge_type = prop.intval; - rc = power_supply_get_property(chip->batt_psy, - POWER_SUPPLY_PROP_CHARGE_DONE, &prop); - if (rc < 0) { - pr_err("Error in getting charge_done, rc=%d\n", rc); - goto out; - } - - chip->charge_done = prop.intval; - if (chip->cyc_ctr.en) - schedule_work(&chip->cycle_count_work); - - fg_cap_learning_update(chip); - - rc = fg_charge_full_update(chip); - if (rc < 0) - pr_err("Error in charge_full_update, rc=%d\n", rc); - - rc = fg_adjust_recharge_soc(chip); - if (rc < 0) - pr_err("Error in adjusting recharge_soc, rc=%d\n", rc); - - rc = fg_adjust_ki_coeff_dischg(chip); - if (rc < 0) - pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc); - - rc = fg_esr_fcc_config(chip); - if (rc < 0) - pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); - - rc = fg_esr_timer_config(chip, false); - if (rc < 0) - pr_err("Error in configuring ESR timer, rc=%d\n", rc); - - rc = fg_get_battery_temp(chip, &batt_temp); - if (!rc) { - rc = fg_slope_limit_config(chip, batt_temp); - if (rc < 0) - pr_err("Error in configuring slope limiter rc:%d\n", - rc); - - rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp); - if (rc < 0) - pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", - rc); - } - - fg_ttf_update(chip); - -out: - fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n", - chip->charge_status, chip->charge_type, chip->charge_done); - pm_relax(chip->dev); -} - static void restore_cycle_counter(struct fg_chip *chip) { int rc = 0, i; u8 data[2]; + if (!chip->cyc_ctr.en) + return; + mutex_lock(&chip->cyc_ctr.lock); for (i = 0; i < BUCKET_COUNT; i++) { rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2), @@ -2372,20 +2292,25 @@ static int fg_inc_store_cycle_ctr(struct fg_chip *chip, int bucket) rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2), CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2, FG_IMA_DEFAULT); - if (rc < 0) + if (rc < 0) { pr_err("failed to write BATT_CYCLE[%d] rc=%d\n", bucket, rc); - else - chip->cyc_ctr.count[bucket] = cyc_count; + return rc; + } + + chip->cyc_ctr.count[bucket] = cyc_count; + fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count, + bucket); + return rc; } -static void cycle_count_work(struct work_struct *work) +static void fg_cycle_counter_update(struct fg_chip *chip) { int rc = 0, bucket, i, batt_soc; - struct fg_chip *chip = container_of(work, - struct fg_chip, - cycle_count_work); + + if (!chip->cyc_ctr.en) + return; mutex_lock(&chip->cyc_ctr.lock); rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc); @@ -2397,45 +2322,30 @@ static void cycle_count_work(struct work_struct *work) /* We need only the most significant byte here */ batt_soc = (u32)batt_soc >> 24; - if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { - /* Find out which bucket the SOC falls in */ - bucket = batt_soc / BUCKET_SOC_PCT; - pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket); + /* Find out which bucket the SOC falls in */ + bucket = batt_soc / BUCKET_SOC_PCT; - /* - * If we've started counting for the previous bucket, - * then store the counter for that bucket if the - * counter for current bucket is getting started. - */ - if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] && - !chip->cyc_ctr.started[bucket]) { - rc = fg_inc_store_cycle_ctr(chip, bucket - 1); - if (rc < 0) { - pr_err("Error in storing cycle_ctr rc: %d\n", - rc); - goto out; - } else { - chip->cyc_ctr.started[bucket - 1] = false; - chip->cyc_ctr.last_soc[bucket - 1] = 0; - } - } + if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) { if (!chip->cyc_ctr.started[bucket]) { chip->cyc_ctr.started[bucket] = true; chip->cyc_ctr.last_soc[bucket] = batt_soc; } - } else { + } else if (chip->charge_done || !is_input_present(chip)) { for (i = 0; i < BUCKET_COUNT; i++) { if (chip->cyc_ctr.started[i] && - batt_soc > chip->cyc_ctr.last_soc[i]) { + batt_soc > chip->cyc_ctr.last_soc[i] + 2) { rc = fg_inc_store_cycle_ctr(chip, i); if (rc < 0) pr_err("Error in storing cycle_ctr rc: %d\n", rc); chip->cyc_ctr.last_soc[i] = 0; + chip->cyc_ctr.started[i] = false; } - chip->cyc_ctr.started[i] = false; } } + + fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n", + batt_soc, bucket, chip->charge_status); out: mutex_unlock(&chip->cyc_ctr.lock); } @@ -2456,6 +2366,83 @@ static int fg_get_cycle_count(struct fg_chip *chip) return count; } +static void status_change_work(struct work_struct *work) +{ + struct fg_chip *chip = container_of(work, + struct fg_chip, status_change_work); + union power_supply_propval prop = {0, }; + int rc, batt_temp; + + if (!batt_psy_initialized(chip)) { + fg_dbg(chip, FG_STATUS, "Charger not available?!\n"); + goto out; + } + + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, + &prop); + if (rc < 0) { + pr_err("Error in getting charging status, rc=%d\n", rc); + goto out; + } + + chip->prev_charge_status = chip->charge_status; + chip->charge_status = prop.intval; + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &prop); + if (rc < 0) { + pr_err("Error in getting charge type, rc=%d\n", rc); + goto out; + } + + chip->charge_type = prop.intval; + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_DONE, &prop); + if (rc < 0) { + pr_err("Error in getting charge_done, rc=%d\n", rc); + goto out; + } + + chip->charge_done = prop.intval; + fg_cycle_counter_update(chip); + fg_cap_learning_update(chip); + + rc = fg_charge_full_update(chip); + if (rc < 0) + pr_err("Error in charge_full_update, rc=%d\n", rc); + + rc = fg_adjust_recharge_soc(chip); + if (rc < 0) + pr_err("Error in adjusting recharge_soc, rc=%d\n", rc); + + rc = fg_adjust_ki_coeff_dischg(chip); + if (rc < 0) + pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc); + + rc = fg_esr_fcc_config(chip); + if (rc < 0) + pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc); + + rc = fg_get_battery_temp(chip, &batt_temp); + if (!rc) { + rc = fg_slope_limit_config(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring slope limiter rc:%d\n", + rc); + + rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp); + if (rc < 0) + pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", + rc); + } + + fg_ttf_update(chip); + +out: + fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n", + chip->charge_status, chip->charge_type, chip->charge_done); + pm_relax(chip->dev); +} + static int fg_bp_params_config(struct fg_chip *chip) { int rc = 0; @@ -3755,8 +3742,7 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } - if (chip->cyc_ctr.en) - restore_cycle_counter(chip); + restore_cycle_counter(chip); if (chip->dt.jeita_hyst_temp >= 0) { val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT; @@ -4030,8 +4016,7 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) int rc; fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq); - if (chip->cyc_ctr.en) - schedule_work(&chip->cycle_count_work); + fg_cycle_counter_update(chip); if (chip->cl.active) fg_cap_learning_update(chip); @@ -4801,7 +4786,6 @@ static int fg_gen3_probe(struct platform_device *pdev) 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->ttf_work, ttf_work); INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work); -- cgit v1.2.3