Loading Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +28 −2 Original line number Diff line number Diff line Loading @@ -366,7 +366,7 @@ First Level Node - FG Gen3 device Value type: <u32> Definition: Value in micro percentage for low temperature ESR tight filter. If this is not specified, then a default value of 48829 (4.88 %) will be used. Lowest possible value is 1954 30000 (3 %) will be used. Lowest possible value is 1954 (0.19 %). - qcom,fg-esr-broad-lt-filter-micro-pct Loading @@ -374,9 +374,35 @@ First Level Node - FG Gen3 device Value type: <u32> Definition: Value in micro percentage for low temperature ESR broad filter. If this is not specified, then a default value of 148438 (14.84 %) will be used. Lowest possible value is 30000 (3 %) will be used. Lowest possible value is 1954 (0.19 %). - qcom,fg-esr-rt-filter-switch-temp Usage: optional Value type: <u32> Definition: Battery temperature threshold below which ESR relax filter coefficients will be applied after a certain number of delta battery temperature interrupts firing in an interval of time. This will be applied only when Qnovo is enabled. If this is not specified, then the default value used will be -100. Unit is in decidegC. - qcom,fg-esr-tight-rt-filter-micro-pct Usage: optional Value type: <u32> Definition: Value in micro percentage for relax temperature ESR tight filter. If this is not specified, then a default value of 5860 will be used. Lowest possible value is 1954 (0.19 %). This will be applied only if Qnovo is enabled. - qcom,fg-esr-broad-rt-filter-micro-pct Usage: optional Value type: <u32> Definition: Value in micro percentage for relax temperature ESR broad filter. If this is not specified, then a default value of 156250 will be used. Lowest possible value is 1954 (0.19 %). This will be applied only if Qnovo is enabled. - qcom,fg-auto-recharge-soc Usage: optional Value type: <empty> Loading drivers/power/supply/qcom/fg-core.h +15 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #ifndef __FG_CORE_H__ #define __FG_CORE_H__ #include <linux/alarmtimer.h> #include <linux/atomic.h> #include <linux/bitops.h> #include <linux/debugfs.h> Loading Loading @@ -299,6 +300,12 @@ enum slope_limit_status { SLOPE_LIMIT_NUM_COEFFS, }; enum esr_filter_status { ROOM_TEMP = 1, LOW_TEMP, RELAX_TEMP, }; enum esr_timer_config { TIMER_RETRY = 0, TIMER_MAX, Loading Loading @@ -329,7 +336,7 @@ struct fg_cyc_ctr_data { bool started[BUCKET_COUNT]; u16 count[BUCKET_COUNT]; u8 last_soc[BUCKET_COUNT]; int id; char counter[BUCKET_COUNT * 8]; struct mutex lock; }; Loading Loading @@ -438,6 +445,7 @@ struct fg_dev { struct mutex sram_rw_lock; struct mutex charge_full_lock; struct mutex qnovo_esr_ctrl_lock; spinlock_t suspend_lock; u32 batt_soc_base; u32 batt_info_base; u32 mem_if_base; Loading @@ -456,6 +464,8 @@ struct fg_dev { int delta_soc; int last_msoc; int last_recharge_volt_mv; int delta_temp_irq_count; enum esr_filter_status esr_flt_sts; bool profile_available; enum prof_load_status profile_load_status; bool battery_missing; Loading @@ -467,11 +477,15 @@ struct fg_dev { bool use_dma; bool qnovo_enable; enum fg_version version; bool suspended; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; struct work_struct status_change_work; struct delayed_work sram_dump_work; struct work_struct esr_filter_work; struct alarm esr_filter_alarm; ktime_t last_delta_temp_time; }; /* Debugfs data structures are below */ Loading drivers/power/supply/qcom/qpnp-fg-gen3.c +254 −74 Original line number Diff line number Diff line /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -192,6 +192,9 @@ struct fg_dt_props { int esr_broad_flt_upct; int esr_tight_lt_flt_upct; int esr_broad_lt_flt_upct; int esr_flt_rt_switch_temp; int esr_tight_rt_flt_upct; int esr_broad_rt_flt_upct; int slope_limit_temp; int esr_pulse_thresh_ma; int esr_meas_curr_ma; Loading Loading @@ -1036,16 +1039,16 @@ static void fg_cap_learning_post_process(struct fg_dev *fg) QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah); chip->cl.final_cc_uah = chip->cl.final_cc_uah * (1000 + QNOVO_CL_SKEW_DECIPCT); do_div(chip->cl.final_cc_uah, 1000); chip->cl.final_cc_uah = div64_u64(chip->cl.final_cc_uah, 1000); } max_inc_val = chip->cl.learned_cc_uah * (1000 + chip->dt.cl_max_cap_inc); do_div(max_inc_val, 1000); max_inc_val = div64_u64(max_inc_val, 1000); min_dec_val = chip->cl.learned_cc_uah * (1000 - chip->dt.cl_max_cap_dec); do_div(min_dec_val, 1000); min_dec_val = div64_u64(min_dec_val, 1000); old_cap = chip->cl.learned_cc_uah; if (chip->cl.final_cc_uah > max_inc_val) Loading @@ -1059,7 +1062,7 @@ static void fg_cap_learning_post_process(struct fg_dev *fg) if (chip->dt.cl_max_cap_limit) { max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 + chip->dt.cl_max_cap_limit); do_div(max_inc_val, 1000); max_inc_val = div64_u64(max_inc_val, 1000); if (chip->cl.final_cc_uah > max_inc_val) { fg_dbg(fg, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n", chip->cl.final_cc_uah, max_inc_val); Loading @@ -1070,7 +1073,7 @@ static void fg_cap_learning_post_process(struct fg_dev *fg) if (chip->dt.cl_min_cap_limit) { min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 - chip->dt.cl_min_cap_limit); do_div(min_dec_val, 1000); min_dec_val = div64_u64(min_dec_val, 1000); if (chip->cl.final_cc_uah < min_dec_val) { fg_dbg(fg, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n", chip->cl.final_cc_uah, min_dec_val); Loading Loading @@ -1582,7 +1585,7 @@ static int fg_rconn_config(struct fg_dev *fg) } val *= scaling_factor; do_div(val, 1000); val = div64_u64(val, 1000); rc = fg_sram_write(fg, ESR_RSLOW_CHG_WORD, ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT); if (rc < 0) { Loading @@ -1599,7 +1602,7 @@ static int fg_rconn_config(struct fg_dev *fg) } val *= scaling_factor; do_div(val, 1000); val = div64_u64(val, 1000); rc = fg_sram_write(fg, ESR_RSLOW_DISCHG_WORD, ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT); if (rc < 0) { Loading Loading @@ -1826,12 +1829,69 @@ static int fg_slope_limit_config(struct fg_dev *fg, int batt_temp) return 0; } static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp) static int __fg_esr_filter_config(struct fg_dev *fg, enum esr_filter_status esr_flt_sts) { u8 esr_tight_flt, esr_broad_flt; int esr_tight_flt_upct, esr_broad_flt_upct; int rc; struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); u8 esr_tight_lt_flt, esr_broad_lt_flt; bool cold_temp = false; if (esr_flt_sts == fg->esr_flt_sts) return 0; if (esr_flt_sts == ROOM_TEMP) { esr_tight_flt_upct = chip->dt.esr_tight_flt_upct; esr_broad_flt_upct = chip->dt.esr_broad_flt_upct; } else if (esr_flt_sts == LOW_TEMP) { esr_tight_flt_upct = chip->dt.esr_tight_lt_flt_upct; esr_broad_flt_upct = chip->dt.esr_broad_lt_flt_upct; } else if (esr_flt_sts == RELAX_TEMP) { esr_tight_flt_upct = chip->dt.esr_tight_rt_flt_upct; esr_broad_flt_upct = chip->dt.esr_broad_rt_flt_upct; } else { pr_err("Unknown esr filter config\n"); return 0; } fg_encode(fg->sp, FG_SRAM_ESR_TIGHT_FILTER, esr_tight_flt_upct, &esr_tight_flt); rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, &esr_tight_flt, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc); return rc; } fg_encode(fg->sp, FG_SRAM_ESR_BROAD_FILTER, esr_broad_flt_upct, &esr_broad_flt); rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, &esr_broad_flt, fg->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc); return rc; } fg->esr_flt_sts = esr_flt_sts; fg_dbg(fg, FG_STATUS, "applied ESR filter %d values\n", esr_flt_sts); return 0; } #define DT_IRQ_COUNT 3 #define DELTA_TEMP_IRQ_TIME_MS 300000 #define ESR_FILTER_ALARM_TIME_MS 900000 static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp, bool override) { enum esr_filter_status esr_flt_sts = ROOM_TEMP; bool qnovo_en, input_present, count_temp_irq = false; s64 time_ms; int rc; struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); /* * If the battery temperature is lower than -20 C, then skip modifying Loading @@ -1840,6 +1900,47 @@ static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp) if (batt_temp < -210) return 0; qnovo_en = is_qnovo_en(fg); input_present = is_input_present(fg); /* * If Qnovo is enabled, after hitting a lower battery temperature of * say 6 C, count the delta battery temperature interrupts for a * certain period of time when the battery temperature increases. * Switch to relaxed filter coefficients once the temperature increase * is qualified so that ESR accuracy can be improved. */ if (qnovo_en && !override) { if (input_present) { if (fg->esr_flt_sts == RELAX_TEMP) { /* do nothing */ return 0; } count_temp_irq = true; if (fg->delta_temp_irq_count) { /* Don't count when temperature is dropping. */ if (batt_temp <= fg->last_batt_temp) count_temp_irq = false; } else { /* * Starting point for counting. Check if the * temperature is qualified. */ if (batt_temp > chip->dt.esr_flt_rt_switch_temp) count_temp_irq = false; else fg->last_delta_temp_time = ktime_get(); } } else { fg->delta_temp_irq_count = 0; rc = alarm_try_to_cancel(&fg->esr_filter_alarm); if (rc < 0) pr_err("Couldn't cancel esr_filter_alarm\n"); } } /* * If battery temperature is lesser than 10 C (default), then apply the * ESR low temperature tight and broad filter values to ESR room Loading @@ -1847,45 +1948,80 @@ static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp) * than 10 C, then apply back the room temperature ESR filter * coefficients to ESR room temperature tight and broad filters. */ if (batt_temp > chip->dt.esr_flt_switch_temp && chip->esr_flt_cold_temp_en) { fg_encode(fg->sp, FG_SRAM_ESR_TIGHT_FILTER, chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt); fg_encode(fg->sp, FG_SRAM_ESR_BROAD_FILTER, chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt); } else if (batt_temp <= chip->dt.esr_flt_switch_temp && !chip->esr_flt_cold_temp_en) { fg_encode(fg->sp, FG_SRAM_ESR_TIGHT_FILTER, chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt); fg_encode(fg->sp, FG_SRAM_ESR_BROAD_FILTER, chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt); cold_temp = true; } else { if (batt_temp > chip->dt.esr_flt_switch_temp) esr_flt_sts = ROOM_TEMP; else esr_flt_sts = LOW_TEMP; if (count_temp_irq) { time_ms = ktime_ms_delta(ktime_get(), fg->last_delta_temp_time); fg->delta_temp_irq_count++; fg_dbg(fg, FG_STATUS, "dt_irq_count: %d\n", fg->delta_temp_irq_count); if (fg->delta_temp_irq_count >= DT_IRQ_COUNT && time_ms <= DELTA_TEMP_IRQ_TIME_MS) { fg_dbg(fg, FG_STATUS, "%d interrupts in %lld ms\n", fg->delta_temp_irq_count, time_ms); esr_flt_sts = RELAX_TEMP; } } rc = __fg_esr_filter_config(fg, esr_flt_sts); if (rc < 0) return rc; if (esr_flt_sts == RELAX_TEMP) alarm_start_relative(&fg->esr_filter_alarm, ms_to_ktime(ESR_FILTER_ALARM_TIME_MS)); return 0; } rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, &esr_tight_lt_flt, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT); #define FG_ESR_FILTER_RESTART_MS 60000 static void esr_filter_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, struct fg_dev, status_change_work); int rc, batt_temp; rc = fg_get_battery_temp(fg, &batt_temp); if (rc < 0) { pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc); return rc; pr_err("Error in getting batt_temp\n"); alarm_start_relative(&fg->esr_filter_alarm, ms_to_ktime(FG_ESR_FILTER_RESTART_MS)); goto out; } rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, &esr_broad_lt_flt, fg->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT); rc = fg_esr_filter_config(fg, batt_temp, true); if (rc < 0) { pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc); return rc; pr_err("Error in configuring ESR filter rc:%d\n", rc); alarm_start_relative(&fg->esr_filter_alarm, ms_to_ktime(FG_ESR_FILTER_RESTART_MS)); } chip->esr_flt_cold_temp_en = cold_temp; fg_dbg(fg, FG_STATUS, "applied %s ESR filter values\n", cold_temp ? "cold" : "normal"); return 0; out: fg->delta_temp_irq_count = 0; pm_relax(fg->dev); } static enum alarmtimer_restart fg_esr_filter_alarm_cb(struct alarm *alarm, ktime_t now) { struct fg_dev *fg = container_of(alarm, struct fg_dev, esr_filter_alarm); fg_dbg(fg, FG_STATUS, "ESR filter alarm triggered %lld\n", ktime_to_ms(now)); /* * We cannot vote for awake votable here as that takes a mutex lock * and this is executed in an atomic context. */ pm_stay_awake(fg->dev); schedule_work(&fg->esr_filter_work); return ALARMTIMER_NORESTART; } static int fg_esr_fcc_config(struct fg_dev *fg) Loading Loading @@ -2191,21 +2327,30 @@ static void fg_cycle_counter_update(struct fg_dev *fg) mutex_unlock(&chip->cyc_ctr.lock); } static int fg_get_cycle_count(struct fg_dev *fg) static const char *fg_get_cycle_count(struct fg_dev *fg) { struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); int count; int i, len = 0; char *buf; if (!chip->cyc_ctr.en) return 0; if ((chip->cyc_ctr.id <= 0) || (chip->cyc_ctr.id > BUCKET_COUNT)) return -EINVAL; return NULL; buf = chip->cyc_ctr.counter; mutex_lock(&chip->cyc_ctr.lock); count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1]; for (i = 0; i < BUCKET_COUNT; i++) { if (sizeof(chip->cyc_ctr.counter) - len < 8) { pr_err("Invalid length %d\n", len); mutex_unlock(&chip->cyc_ctr.lock); return count; return NULL; } len += snprintf(buf+len, 8, "%d ", chip->cyc_ctr.count[i]); } mutex_unlock(&chip->cyc_ctr.lock); buf[len] = '\0'; return buf; } static void status_change_work(struct work_struct *work) Loading Loading @@ -3299,11 +3444,8 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: pval->intval = fg->bp.float_volt_uv; break; case POWER_SUPPLY_PROP_CYCLE_COUNT: pval->intval = fg_get_cycle_count(fg); break; case POWER_SUPPLY_PROP_CYCLE_COUNT_ID: pval->intval = chip->cyc_ctr.id; case POWER_SUPPLY_PROP_CYCLE_COUNTS: pval->strval = fg_get_cycle_count(fg); break; case POWER_SUPPLY_PROP_CHARGE_NOW_RAW: rc = fg_get_charge_raw(fg, &pval->intval); Loading Loading @@ -3370,15 +3512,6 @@ static int fg_psy_set_property(struct power_supply *psy, int rc = 0; switch (psp) { case POWER_SUPPLY_PROP_CYCLE_COUNT_ID: if ((pval->intval > 0) && (pval->intval <= BUCKET_COUNT)) { chip->cyc_ctr.id = pval->intval; } else { pr_err("rejecting invalid cycle_count_id = %d\n", pval->intval); return -EINVAL; } break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: rc = fg_set_constant_chg_voltage(fg, pval->intval); break; Loading Loading @@ -3461,7 +3594,6 @@ static int fg_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { case POWER_SUPPLY_PROP_CYCLE_COUNT_ID: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_CC_STEP: case POWER_SUPPLY_PROP_CC_STEP_SEL: Loading Loading @@ -3489,6 +3621,14 @@ static int fg_notifier_cb(struct notifier_block *nb, struct power_supply *psy = data; struct fg_dev *fg = container_of(nb, struct fg_dev, nb); spin_lock(&fg->suspend_lock); if (fg->suspended) { /* Return if we are still suspended */ spin_unlock(&fg->suspend_lock); return NOTIFY_OK; } spin_unlock(&fg->suspend_lock); if (event != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; Loading Loading @@ -3525,8 +3665,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_BATTERY_TYPE, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CYCLE_COUNT_ID, POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_CHARGE_NOW_RAW, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL, Loading Loading @@ -3947,14 +4086,14 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) union power_supply_propval prop = {0, }; int rc, batt_temp; fg_dbg(fg, FG_IRQ, "irq %d triggered\n", irq); rc = fg_get_battery_temp(fg, &batt_temp); if (rc < 0) { pr_err("Error in getting batt_temp\n"); return IRQ_HANDLED; } fg_dbg(fg, FG_IRQ, "irq %d triggered bat_temp: %d\n", irq, batt_temp); rc = fg_esr_filter_config(fg, batt_temp); rc = fg_esr_filter_config(fg, batt_temp, false); if (rc < 0) pr_err("Error in configuring ESR filter rc:%d\n", rc); Loading Loading @@ -4296,8 +4435,11 @@ static int fg_parse_ki_coefficients(struct fg_dev *fg) #define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100 #define DEFAULT_ESR_TIGHT_FLT_UPCT 3907 #define DEFAULT_ESR_BROAD_FLT_UPCT 99610 #define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829 #define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438 #define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 30000 #define DEFAULT_ESR_BROAD_LT_FLT_UPCT 30000 #define DEFAULT_ESR_FLT_RT_DECIDEGC 60 #define DEFAULT_ESR_TIGHT_RT_FLT_UPCT 5860 #define DEFAULT_ESR_BROAD_RT_FLT_UPCT 156250 #define DEFAULT_ESR_CLAMP_MOHMS 20 #define DEFAULT_ESR_PULSE_THRESH_MA 110 #define DEFAULT_ESR_MEAS_CURR_MA 120 Loading Loading @@ -4525,8 +4667,6 @@ static int fg_parse_dt(struct fg_gen3_chip *chip) } chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en"); if (chip->cyc_ctr.en) chip->cyc_ctr.id = 1; chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); Loading Loading @@ -4634,6 +4774,27 @@ static int fg_parse_dt(struct fg_gen3_chip *chip) else chip->dt.esr_broad_lt_flt_upct = temp; rc = of_property_read_u32(node, "qcom,fg-esr-rt-filter-switch-temp", &temp); if (rc < 0) chip->dt.esr_flt_rt_switch_temp = DEFAULT_ESR_FLT_RT_DECIDEGC; else chip->dt.esr_flt_rt_switch_temp = temp; rc = of_property_read_u32(node, "qcom,fg-esr-tight-rt-filter-micro-pct", &temp); if (rc < 0) chip->dt.esr_tight_rt_flt_upct = DEFAULT_ESR_TIGHT_RT_FLT_UPCT; else chip->dt.esr_tight_rt_flt_upct = temp; rc = of_property_read_u32(node, "qcom,fg-esr-broad-rt-filter-micro-pct", &temp); if (rc < 0) chip->dt.esr_broad_rt_flt_upct = DEFAULT_ESR_BROAD_RT_FLT_UPCT; else chip->dt.esr_broad_rt_flt_upct = temp; rc = fg_parse_slope_limit_coefficients(fg); if (rc < 0) pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc); Loading Loading @@ -4675,6 +4836,7 @@ static void fg_cleanup(struct fg_gen3_chip *chip) struct fg_dev *fg = &chip->fg; fg_unregister_interrupts(fg, chip, FG_GEN3_IRQ_MAX); alarm_try_to_cancel(&fg->esr_filter_alarm); power_supply_unreg_notifier(&fg->nb); debugfs_remove_recursive(fg->dfs_root); if (fg->awake_votable) Loading Loading @@ -4789,6 +4951,7 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->cl.lock); mutex_init(&chip->ttf.lock); mutex_init(&fg->qnovo_esr_ctrl_lock); spin_lock_init(&fg->suspend_lock); init_completion(&fg->soc_update); init_completion(&fg->soc_ready); INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); Loading @@ -4796,6 +4959,9 @@ static int fg_gen3_probe(struct platform_device *pdev) INIT_WORK(&fg->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->ttf_work, ttf_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); INIT_WORK(&fg->esr_filter_work, esr_filter_work); alarm_init(&fg->esr_filter_alarm, ALARM_BOOTTIME, fg_esr_filter_alarm_cb); rc = fg_memif_init(fg); if (rc < 0) { Loading Loading @@ -4867,7 +5033,7 @@ static int fg_gen3_probe(struct platform_device *pdev) if (!rc) { pr_info("battery SOC:%d voltage: %duV temp: %d\n", msoc, volt_uv, batt_temp); rc = fg_esr_filter_config(fg, batt_temp); rc = fg_esr_filter_config(fg, batt_temp, false); if (rc < 0) pr_err("Error in configuring ESR filter rc:%d\n", rc); } Loading @@ -4888,6 +5054,10 @@ static int fg_gen3_suspend(struct device *dev) struct fg_dev *fg = &chip->fg; int rc; spin_lock(&fg->suspend_lock); fg->suspended = true; spin_unlock(&fg->suspend_lock); rc = fg_esr_timer_config(fg, true); if (rc < 0) pr_err("Error in configuring ESR timer, rc=%d\n", rc); Loading @@ -4912,6 +5082,16 @@ static int fg_gen3_resume(struct device *dev) if (fg_sram_dump) schedule_delayed_work(&fg->sram_dump_work, msecs_to_jiffies(fg_sram_dump_period_ms)); if (!work_pending(&fg->status_change_work)) { pm_stay_awake(fg->dev); schedule_work(&fg->status_change_work); } spin_lock(&fg->suspend_lock); fg->suspended = false; spin_unlock(&fg->suspend_lock); return 0; } Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +28 −2 Original line number Diff line number Diff line Loading @@ -366,7 +366,7 @@ First Level Node - FG Gen3 device Value type: <u32> Definition: Value in micro percentage for low temperature ESR tight filter. If this is not specified, then a default value of 48829 (4.88 %) will be used. Lowest possible value is 1954 30000 (3 %) will be used. Lowest possible value is 1954 (0.19 %). - qcom,fg-esr-broad-lt-filter-micro-pct Loading @@ -374,9 +374,35 @@ First Level Node - FG Gen3 device Value type: <u32> Definition: Value in micro percentage for low temperature ESR broad filter. If this is not specified, then a default value of 148438 (14.84 %) will be used. Lowest possible value is 30000 (3 %) will be used. Lowest possible value is 1954 (0.19 %). - qcom,fg-esr-rt-filter-switch-temp Usage: optional Value type: <u32> Definition: Battery temperature threshold below which ESR relax filter coefficients will be applied after a certain number of delta battery temperature interrupts firing in an interval of time. This will be applied only when Qnovo is enabled. If this is not specified, then the default value used will be -100. Unit is in decidegC. - qcom,fg-esr-tight-rt-filter-micro-pct Usage: optional Value type: <u32> Definition: Value in micro percentage for relax temperature ESR tight filter. If this is not specified, then a default value of 5860 will be used. Lowest possible value is 1954 (0.19 %). This will be applied only if Qnovo is enabled. - qcom,fg-esr-broad-rt-filter-micro-pct Usage: optional Value type: <u32> Definition: Value in micro percentage for relax temperature ESR broad filter. If this is not specified, then a default value of 156250 will be used. Lowest possible value is 1954 (0.19 %). This will be applied only if Qnovo is enabled. - qcom,fg-auto-recharge-soc Usage: optional Value type: <empty> Loading
drivers/power/supply/qcom/fg-core.h +15 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #ifndef __FG_CORE_H__ #define __FG_CORE_H__ #include <linux/alarmtimer.h> #include <linux/atomic.h> #include <linux/bitops.h> #include <linux/debugfs.h> Loading Loading @@ -299,6 +300,12 @@ enum slope_limit_status { SLOPE_LIMIT_NUM_COEFFS, }; enum esr_filter_status { ROOM_TEMP = 1, LOW_TEMP, RELAX_TEMP, }; enum esr_timer_config { TIMER_RETRY = 0, TIMER_MAX, Loading Loading @@ -329,7 +336,7 @@ struct fg_cyc_ctr_data { bool started[BUCKET_COUNT]; u16 count[BUCKET_COUNT]; u8 last_soc[BUCKET_COUNT]; int id; char counter[BUCKET_COUNT * 8]; struct mutex lock; }; Loading Loading @@ -438,6 +445,7 @@ struct fg_dev { struct mutex sram_rw_lock; struct mutex charge_full_lock; struct mutex qnovo_esr_ctrl_lock; spinlock_t suspend_lock; u32 batt_soc_base; u32 batt_info_base; u32 mem_if_base; Loading @@ -456,6 +464,8 @@ struct fg_dev { int delta_soc; int last_msoc; int last_recharge_volt_mv; int delta_temp_irq_count; enum esr_filter_status esr_flt_sts; bool profile_available; enum prof_load_status profile_load_status; bool battery_missing; Loading @@ -467,11 +477,15 @@ struct fg_dev { bool use_dma; bool qnovo_enable; enum fg_version version; bool suspended; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; struct work_struct status_change_work; struct delayed_work sram_dump_work; struct work_struct esr_filter_work; struct alarm esr_filter_alarm; ktime_t last_delta_temp_time; }; /* Debugfs data structures are below */ Loading
drivers/power/supply/qcom/qpnp-fg-gen3.c +254 −74 Original line number Diff line number Diff line /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -192,6 +192,9 @@ struct fg_dt_props { int esr_broad_flt_upct; int esr_tight_lt_flt_upct; int esr_broad_lt_flt_upct; int esr_flt_rt_switch_temp; int esr_tight_rt_flt_upct; int esr_broad_rt_flt_upct; int slope_limit_temp; int esr_pulse_thresh_ma; int esr_meas_curr_ma; Loading Loading @@ -1036,16 +1039,16 @@ static void fg_cap_learning_post_process(struct fg_dev *fg) QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah); chip->cl.final_cc_uah = chip->cl.final_cc_uah * (1000 + QNOVO_CL_SKEW_DECIPCT); do_div(chip->cl.final_cc_uah, 1000); chip->cl.final_cc_uah = div64_u64(chip->cl.final_cc_uah, 1000); } max_inc_val = chip->cl.learned_cc_uah * (1000 + chip->dt.cl_max_cap_inc); do_div(max_inc_val, 1000); max_inc_val = div64_u64(max_inc_val, 1000); min_dec_val = chip->cl.learned_cc_uah * (1000 - chip->dt.cl_max_cap_dec); do_div(min_dec_val, 1000); min_dec_val = div64_u64(min_dec_val, 1000); old_cap = chip->cl.learned_cc_uah; if (chip->cl.final_cc_uah > max_inc_val) Loading @@ -1059,7 +1062,7 @@ static void fg_cap_learning_post_process(struct fg_dev *fg) if (chip->dt.cl_max_cap_limit) { max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 + chip->dt.cl_max_cap_limit); do_div(max_inc_val, 1000); max_inc_val = div64_u64(max_inc_val, 1000); if (chip->cl.final_cc_uah > max_inc_val) { fg_dbg(fg, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n", chip->cl.final_cc_uah, max_inc_val); Loading @@ -1070,7 +1073,7 @@ static void fg_cap_learning_post_process(struct fg_dev *fg) if (chip->dt.cl_min_cap_limit) { min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 - chip->dt.cl_min_cap_limit); do_div(min_dec_val, 1000); min_dec_val = div64_u64(min_dec_val, 1000); if (chip->cl.final_cc_uah < min_dec_val) { fg_dbg(fg, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n", chip->cl.final_cc_uah, min_dec_val); Loading Loading @@ -1582,7 +1585,7 @@ static int fg_rconn_config(struct fg_dev *fg) } val *= scaling_factor; do_div(val, 1000); val = div64_u64(val, 1000); rc = fg_sram_write(fg, ESR_RSLOW_CHG_WORD, ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT); if (rc < 0) { Loading @@ -1599,7 +1602,7 @@ static int fg_rconn_config(struct fg_dev *fg) } val *= scaling_factor; do_div(val, 1000); val = div64_u64(val, 1000); rc = fg_sram_write(fg, ESR_RSLOW_DISCHG_WORD, ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT); if (rc < 0) { Loading Loading @@ -1826,12 +1829,69 @@ static int fg_slope_limit_config(struct fg_dev *fg, int batt_temp) return 0; } static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp) static int __fg_esr_filter_config(struct fg_dev *fg, enum esr_filter_status esr_flt_sts) { u8 esr_tight_flt, esr_broad_flt; int esr_tight_flt_upct, esr_broad_flt_upct; int rc; struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); u8 esr_tight_lt_flt, esr_broad_lt_flt; bool cold_temp = false; if (esr_flt_sts == fg->esr_flt_sts) return 0; if (esr_flt_sts == ROOM_TEMP) { esr_tight_flt_upct = chip->dt.esr_tight_flt_upct; esr_broad_flt_upct = chip->dt.esr_broad_flt_upct; } else if (esr_flt_sts == LOW_TEMP) { esr_tight_flt_upct = chip->dt.esr_tight_lt_flt_upct; esr_broad_flt_upct = chip->dt.esr_broad_lt_flt_upct; } else if (esr_flt_sts == RELAX_TEMP) { esr_tight_flt_upct = chip->dt.esr_tight_rt_flt_upct; esr_broad_flt_upct = chip->dt.esr_broad_rt_flt_upct; } else { pr_err("Unknown esr filter config\n"); return 0; } fg_encode(fg->sp, FG_SRAM_ESR_TIGHT_FILTER, esr_tight_flt_upct, &esr_tight_flt); rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, &esr_tight_flt, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc); return rc; } fg_encode(fg->sp, FG_SRAM_ESR_BROAD_FILTER, esr_broad_flt_upct, &esr_broad_flt); rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, &esr_broad_flt, fg->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc); return rc; } fg->esr_flt_sts = esr_flt_sts; fg_dbg(fg, FG_STATUS, "applied ESR filter %d values\n", esr_flt_sts); return 0; } #define DT_IRQ_COUNT 3 #define DELTA_TEMP_IRQ_TIME_MS 300000 #define ESR_FILTER_ALARM_TIME_MS 900000 static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp, bool override) { enum esr_filter_status esr_flt_sts = ROOM_TEMP; bool qnovo_en, input_present, count_temp_irq = false; s64 time_ms; int rc; struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); /* * If the battery temperature is lower than -20 C, then skip modifying Loading @@ -1840,6 +1900,47 @@ static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp) if (batt_temp < -210) return 0; qnovo_en = is_qnovo_en(fg); input_present = is_input_present(fg); /* * If Qnovo is enabled, after hitting a lower battery temperature of * say 6 C, count the delta battery temperature interrupts for a * certain period of time when the battery temperature increases. * Switch to relaxed filter coefficients once the temperature increase * is qualified so that ESR accuracy can be improved. */ if (qnovo_en && !override) { if (input_present) { if (fg->esr_flt_sts == RELAX_TEMP) { /* do nothing */ return 0; } count_temp_irq = true; if (fg->delta_temp_irq_count) { /* Don't count when temperature is dropping. */ if (batt_temp <= fg->last_batt_temp) count_temp_irq = false; } else { /* * Starting point for counting. Check if the * temperature is qualified. */ if (batt_temp > chip->dt.esr_flt_rt_switch_temp) count_temp_irq = false; else fg->last_delta_temp_time = ktime_get(); } } else { fg->delta_temp_irq_count = 0; rc = alarm_try_to_cancel(&fg->esr_filter_alarm); if (rc < 0) pr_err("Couldn't cancel esr_filter_alarm\n"); } } /* * If battery temperature is lesser than 10 C (default), then apply the * ESR low temperature tight and broad filter values to ESR room Loading @@ -1847,45 +1948,80 @@ static int fg_esr_filter_config(struct fg_dev *fg, int batt_temp) * than 10 C, then apply back the room temperature ESR filter * coefficients to ESR room temperature tight and broad filters. */ if (batt_temp > chip->dt.esr_flt_switch_temp && chip->esr_flt_cold_temp_en) { fg_encode(fg->sp, FG_SRAM_ESR_TIGHT_FILTER, chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt); fg_encode(fg->sp, FG_SRAM_ESR_BROAD_FILTER, chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt); } else if (batt_temp <= chip->dt.esr_flt_switch_temp && !chip->esr_flt_cold_temp_en) { fg_encode(fg->sp, FG_SRAM_ESR_TIGHT_FILTER, chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt); fg_encode(fg->sp, FG_SRAM_ESR_BROAD_FILTER, chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt); cold_temp = true; } else { if (batt_temp > chip->dt.esr_flt_switch_temp) esr_flt_sts = ROOM_TEMP; else esr_flt_sts = LOW_TEMP; if (count_temp_irq) { time_ms = ktime_ms_delta(ktime_get(), fg->last_delta_temp_time); fg->delta_temp_irq_count++; fg_dbg(fg, FG_STATUS, "dt_irq_count: %d\n", fg->delta_temp_irq_count); if (fg->delta_temp_irq_count >= DT_IRQ_COUNT && time_ms <= DELTA_TEMP_IRQ_TIME_MS) { fg_dbg(fg, FG_STATUS, "%d interrupts in %lld ms\n", fg->delta_temp_irq_count, time_ms); esr_flt_sts = RELAX_TEMP; } } rc = __fg_esr_filter_config(fg, esr_flt_sts); if (rc < 0) return rc; if (esr_flt_sts == RELAX_TEMP) alarm_start_relative(&fg->esr_filter_alarm, ms_to_ktime(ESR_FILTER_ALARM_TIME_MS)); return 0; } rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, &esr_tight_lt_flt, fg->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT); #define FG_ESR_FILTER_RESTART_MS 60000 static void esr_filter_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, struct fg_dev, status_change_work); int rc, batt_temp; rc = fg_get_battery_temp(fg, &batt_temp); if (rc < 0) { pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc); return rc; pr_err("Error in getting batt_temp\n"); alarm_start_relative(&fg->esr_filter_alarm, ms_to_ktime(FG_ESR_FILTER_RESTART_MS)); goto out; } rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word, fg->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, &esr_broad_lt_flt, fg->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT); rc = fg_esr_filter_config(fg, batt_temp, true); if (rc < 0) { pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc); return rc; pr_err("Error in configuring ESR filter rc:%d\n", rc); alarm_start_relative(&fg->esr_filter_alarm, ms_to_ktime(FG_ESR_FILTER_RESTART_MS)); } chip->esr_flt_cold_temp_en = cold_temp; fg_dbg(fg, FG_STATUS, "applied %s ESR filter values\n", cold_temp ? "cold" : "normal"); return 0; out: fg->delta_temp_irq_count = 0; pm_relax(fg->dev); } static enum alarmtimer_restart fg_esr_filter_alarm_cb(struct alarm *alarm, ktime_t now) { struct fg_dev *fg = container_of(alarm, struct fg_dev, esr_filter_alarm); fg_dbg(fg, FG_STATUS, "ESR filter alarm triggered %lld\n", ktime_to_ms(now)); /* * We cannot vote for awake votable here as that takes a mutex lock * and this is executed in an atomic context. */ pm_stay_awake(fg->dev); schedule_work(&fg->esr_filter_work); return ALARMTIMER_NORESTART; } static int fg_esr_fcc_config(struct fg_dev *fg) Loading Loading @@ -2191,21 +2327,30 @@ static void fg_cycle_counter_update(struct fg_dev *fg) mutex_unlock(&chip->cyc_ctr.lock); } static int fg_get_cycle_count(struct fg_dev *fg) static const char *fg_get_cycle_count(struct fg_dev *fg) { struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); int count; int i, len = 0; char *buf; if (!chip->cyc_ctr.en) return 0; if ((chip->cyc_ctr.id <= 0) || (chip->cyc_ctr.id > BUCKET_COUNT)) return -EINVAL; return NULL; buf = chip->cyc_ctr.counter; mutex_lock(&chip->cyc_ctr.lock); count = chip->cyc_ctr.count[chip->cyc_ctr.id - 1]; for (i = 0; i < BUCKET_COUNT; i++) { if (sizeof(chip->cyc_ctr.counter) - len < 8) { pr_err("Invalid length %d\n", len); mutex_unlock(&chip->cyc_ctr.lock); return count; return NULL; } len += snprintf(buf+len, 8, "%d ", chip->cyc_ctr.count[i]); } mutex_unlock(&chip->cyc_ctr.lock); buf[len] = '\0'; return buf; } static void status_change_work(struct work_struct *work) Loading Loading @@ -3299,11 +3444,8 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: pval->intval = fg->bp.float_volt_uv; break; case POWER_SUPPLY_PROP_CYCLE_COUNT: pval->intval = fg_get_cycle_count(fg); break; case POWER_SUPPLY_PROP_CYCLE_COUNT_ID: pval->intval = chip->cyc_ctr.id; case POWER_SUPPLY_PROP_CYCLE_COUNTS: pval->strval = fg_get_cycle_count(fg); break; case POWER_SUPPLY_PROP_CHARGE_NOW_RAW: rc = fg_get_charge_raw(fg, &pval->intval); Loading Loading @@ -3370,15 +3512,6 @@ static int fg_psy_set_property(struct power_supply *psy, int rc = 0; switch (psp) { case POWER_SUPPLY_PROP_CYCLE_COUNT_ID: if ((pval->intval > 0) && (pval->intval <= BUCKET_COUNT)) { chip->cyc_ctr.id = pval->intval; } else { pr_err("rejecting invalid cycle_count_id = %d\n", pval->intval); return -EINVAL; } break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: rc = fg_set_constant_chg_voltage(fg, pval->intval); break; Loading Loading @@ -3461,7 +3594,6 @@ static int fg_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { case POWER_SUPPLY_PROP_CYCLE_COUNT_ID: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_CC_STEP: case POWER_SUPPLY_PROP_CC_STEP_SEL: Loading Loading @@ -3489,6 +3621,14 @@ static int fg_notifier_cb(struct notifier_block *nb, struct power_supply *psy = data; struct fg_dev *fg = container_of(nb, struct fg_dev, nb); spin_lock(&fg->suspend_lock); if (fg->suspended) { /* Return if we are still suspended */ spin_unlock(&fg->suspend_lock); return NOTIFY_OK; } spin_unlock(&fg->suspend_lock); if (event != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; Loading Loading @@ -3525,8 +3665,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_BATTERY_TYPE, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CYCLE_COUNT_ID, POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_CHARGE_NOW_RAW, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL, Loading Loading @@ -3947,14 +4086,14 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data) union power_supply_propval prop = {0, }; int rc, batt_temp; fg_dbg(fg, FG_IRQ, "irq %d triggered\n", irq); rc = fg_get_battery_temp(fg, &batt_temp); if (rc < 0) { pr_err("Error in getting batt_temp\n"); return IRQ_HANDLED; } fg_dbg(fg, FG_IRQ, "irq %d triggered bat_temp: %d\n", irq, batt_temp); rc = fg_esr_filter_config(fg, batt_temp); rc = fg_esr_filter_config(fg, batt_temp, false); if (rc < 0) pr_err("Error in configuring ESR filter rc:%d\n", rc); Loading Loading @@ -4296,8 +4435,11 @@ static int fg_parse_ki_coefficients(struct fg_dev *fg) #define DEFAULT_ESR_FLT_TEMP_DECIDEGC 100 #define DEFAULT_ESR_TIGHT_FLT_UPCT 3907 #define DEFAULT_ESR_BROAD_FLT_UPCT 99610 #define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829 #define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438 #define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 30000 #define DEFAULT_ESR_BROAD_LT_FLT_UPCT 30000 #define DEFAULT_ESR_FLT_RT_DECIDEGC 60 #define DEFAULT_ESR_TIGHT_RT_FLT_UPCT 5860 #define DEFAULT_ESR_BROAD_RT_FLT_UPCT 156250 #define DEFAULT_ESR_CLAMP_MOHMS 20 #define DEFAULT_ESR_PULSE_THRESH_MA 110 #define DEFAULT_ESR_MEAS_CURR_MA 120 Loading Loading @@ -4525,8 +4667,6 @@ static int fg_parse_dt(struct fg_gen3_chip *chip) } chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en"); if (chip->cyc_ctr.en) chip->cyc_ctr.id = 1; chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); Loading Loading @@ -4634,6 +4774,27 @@ static int fg_parse_dt(struct fg_gen3_chip *chip) else chip->dt.esr_broad_lt_flt_upct = temp; rc = of_property_read_u32(node, "qcom,fg-esr-rt-filter-switch-temp", &temp); if (rc < 0) chip->dt.esr_flt_rt_switch_temp = DEFAULT_ESR_FLT_RT_DECIDEGC; else chip->dt.esr_flt_rt_switch_temp = temp; rc = of_property_read_u32(node, "qcom,fg-esr-tight-rt-filter-micro-pct", &temp); if (rc < 0) chip->dt.esr_tight_rt_flt_upct = DEFAULT_ESR_TIGHT_RT_FLT_UPCT; else chip->dt.esr_tight_rt_flt_upct = temp; rc = of_property_read_u32(node, "qcom,fg-esr-broad-rt-filter-micro-pct", &temp); if (rc < 0) chip->dt.esr_broad_rt_flt_upct = DEFAULT_ESR_BROAD_RT_FLT_UPCT; else chip->dt.esr_broad_rt_flt_upct = temp; rc = fg_parse_slope_limit_coefficients(fg); if (rc < 0) pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc); Loading Loading @@ -4675,6 +4836,7 @@ static void fg_cleanup(struct fg_gen3_chip *chip) struct fg_dev *fg = &chip->fg; fg_unregister_interrupts(fg, chip, FG_GEN3_IRQ_MAX); alarm_try_to_cancel(&fg->esr_filter_alarm); power_supply_unreg_notifier(&fg->nb); debugfs_remove_recursive(fg->dfs_root); if (fg->awake_votable) Loading Loading @@ -4789,6 +4951,7 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->cl.lock); mutex_init(&chip->ttf.lock); mutex_init(&fg->qnovo_esr_ctrl_lock); spin_lock_init(&fg->suspend_lock); init_completion(&fg->soc_update); init_completion(&fg->soc_ready); INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); Loading @@ -4796,6 +4959,9 @@ static int fg_gen3_probe(struct platform_device *pdev) INIT_WORK(&fg->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->ttf_work, ttf_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); INIT_WORK(&fg->esr_filter_work, esr_filter_work); alarm_init(&fg->esr_filter_alarm, ALARM_BOOTTIME, fg_esr_filter_alarm_cb); rc = fg_memif_init(fg); if (rc < 0) { Loading Loading @@ -4867,7 +5033,7 @@ static int fg_gen3_probe(struct platform_device *pdev) if (!rc) { pr_info("battery SOC:%d voltage: %duV temp: %d\n", msoc, volt_uv, batt_temp); rc = fg_esr_filter_config(fg, batt_temp); rc = fg_esr_filter_config(fg, batt_temp, false); if (rc < 0) pr_err("Error in configuring ESR filter rc:%d\n", rc); } Loading @@ -4888,6 +5054,10 @@ static int fg_gen3_suspend(struct device *dev) struct fg_dev *fg = &chip->fg; int rc; spin_lock(&fg->suspend_lock); fg->suspended = true; spin_unlock(&fg->suspend_lock); rc = fg_esr_timer_config(fg, true); if (rc < 0) pr_err("Error in configuring ESR timer, rc=%d\n", rc); Loading @@ -4912,6 +5082,16 @@ static int fg_gen3_resume(struct device *dev) if (fg_sram_dump) schedule_delayed_work(&fg->sram_dump_work, msecs_to_jiffies(fg_sram_dump_period_ms)); if (!work_pending(&fg->status_change_work)) { pm_stay_awake(fg->dev); schedule_work(&fg->status_change_work); } spin_lock(&fg->suspend_lock); fg->suspended = false; spin_unlock(&fg->suspend_lock); return 0; } Loading