diff options
| -rw-r--r-- | Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt | 26 | ||||
| -rw-r--r-- | drivers/power/supply/qcom/fg-core.h | 15 | ||||
| -rw-r--r-- | drivers/power/supply/qcom/qpnp-fg-gen3.c | 230 |
3 files changed, 235 insertions, 36 deletions
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt index 0c2e365cd099..dc967edb6192 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt @@ -370,6 +370,32 @@ First Level Node - FG Gen3 device 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> diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 1935704fcf09..20191ffa5e68 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -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> @@ -224,6 +225,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, @@ -270,6 +277,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; @@ -424,8 +434,10 @@ struct fg_chip { int delta_soc; int last_msoc; int last_recharge_volt_mv; + int delta_temp_irq_count; int esr_timer_charging_default[NUM_ESR_TIMERS]; enum slope_limit_status slope_limit_sts; + enum esr_filter_status esr_flt_sts; bool profile_available; bool profile_loaded; bool battery_missing; @@ -446,6 +458,9 @@ struct fg_chip { struct work_struct status_change_work; struct delayed_work ttf_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 */ diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index f33673732d62..2f958a3438ee 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -2182,67 +2182,197 @@ static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp) return 0; } -static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp) +static int __fg_esr_filter_config(struct fg_chip *chip, + enum esr_filter_status esr_flt_sts) { - u8 esr_tight_lt_flt, esr_broad_lt_flt; - bool cold_temp = false; + u8 esr_tight_flt, esr_broad_flt; + int esr_tight_flt_upct, esr_broad_flt_upct; int rc; - /* - * If the battery temperature is lower than -20 C, then skip modifying - * ESR filter. - */ - if (batt_temp < -210) + if (esr_flt_sts == chip->esr_flt_sts) return 0; - /* - * If battery temperature is lesser than 10 C (default), then apply the - * ESR low temperature tight and broad filter values to ESR room - * temperature tight and broad filters. If battery temperature is higher - * 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(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, - chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt); - fg_encode(chip->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(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, - chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt); - fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER, - chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt); - cold_temp = true; + 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(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, esr_tight_flt_upct, + &esr_tight_flt); rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte, - &esr_tight_lt_flt, + &esr_tight_flt, chip->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(chip->sp, FG_SRAM_ESR_BROAD_FILTER, esr_broad_flt_upct, + &esr_broad_flt); rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte, - &esr_broad_lt_flt, + &esr_broad_flt, chip->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; } - chip->esr_flt_cold_temp_en = cold_temp; - fg_dbg(chip, FG_STATUS, "applied %s ESR filter values\n", - cold_temp ? "cold" : "normal"); + chip->esr_flt_sts = esr_flt_sts; + fg_dbg(chip, 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_chip *chip, 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; + + /* + * If the battery temperature is lower than -20 C, then skip modifying + * ESR filter. + */ + if (batt_temp < -210) + return 0; + + qnovo_en = is_qnovo_en(chip); + input_present = is_input_present(chip); + + /* + * 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 (chip->esr_flt_sts == RELAX_TEMP) { + /* do nothing */ + return 0; + } + + count_temp_irq = true; + if (chip->delta_temp_irq_count) { + /* Don't count when temperature is dropping. */ + if (batt_temp <= chip->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 + chip->last_delta_temp_time = + ktime_get(); + } + } else { + chip->delta_temp_irq_count = 0; + rc = alarm_try_to_cancel(&chip->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 + * temperature tight and broad filters. If battery temperature is higher + * 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) + esr_flt_sts = ROOM_TEMP; + else + esr_flt_sts = LOW_TEMP; + + if (count_temp_irq) { + time_ms = ktime_ms_delta(ktime_get(), + chip->last_delta_temp_time); + chip->delta_temp_irq_count++; + fg_dbg(chip, FG_STATUS, "dt_irq_count: %d\n", + chip->delta_temp_irq_count); + + if (chip->delta_temp_irq_count >= DT_IRQ_COUNT + && time_ms <= DELTA_TEMP_IRQ_TIME_MS) { + fg_dbg(chip, FG_STATUS, "%d interrupts in %lld ms\n", + chip->delta_temp_irq_count, time_ms); + esr_flt_sts = RELAX_TEMP; + } + } + + rc = __fg_esr_filter_config(chip, esr_flt_sts); + if (rc < 0) + return rc; + + if (esr_flt_sts == RELAX_TEMP) + alarm_start_relative(&chip->esr_filter_alarm, + ms_to_ktime(ESR_FILTER_ALARM_TIME_MS)); + return 0; } +#define FG_ESR_FILTER_RESTART_MS 60000 +static void esr_filter_work(struct work_struct *work) +{ + struct fg_chip *chip = container_of(work, + struct fg_chip, esr_filter_work); + int rc, batt_temp; + + rc = fg_get_battery_temp(chip, &batt_temp); + if (rc < 0) { + pr_err("Error in getting batt_temp\n"); + alarm_start_relative(&chip->esr_filter_alarm, + ms_to_ktime(FG_ESR_FILTER_RESTART_MS)); + } + + rc = fg_esr_filter_config(chip, batt_temp, true); + if (rc < 0) { + pr_err("Error in configuring ESR filter rc:%d\n", rc); + alarm_start_relative(&chip->esr_filter_alarm, + ms_to_ktime(FG_ESR_FILTER_RESTART_MS)); + } + + chip->delta_temp_irq_count = 0; + pm_relax(chip->dev); +} + +static enum alarmtimer_restart fg_esr_filter_alarm_cb(struct alarm *alarm, + ktime_t now) +{ + struct fg_chip *chip = container_of(alarm, struct fg_chip, + esr_filter_alarm); + + fg_dbg(chip, 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(chip->dev); + schedule_work(&chip->esr_filter_work); + + return ALARMTIMER_NORESTART; +} + static int fg_esr_fcc_config(struct fg_chip *chip) { union power_supply_propval prop = {0, }; @@ -4293,14 +4423,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(chip, FG_IRQ, "irq %d triggered\n", irq); rc = fg_get_battery_temp(chip, &batt_temp); if (rc < 0) { pr_err("Error in getting batt_temp\n"); return IRQ_HANDLED; } + fg_dbg(chip, FG_IRQ, "irq %d triggered bat_temp: %d\n", irq, batt_temp); - rc = fg_esr_filter_config(chip, batt_temp); + rc = fg_esr_filter_config(chip, batt_temp, false); if (rc < 0) pr_err("Error in configuring ESR filter rc:%d\n", rc); @@ -4691,6 +4821,9 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip) #define DEFAULT_ESR_BROAD_FLT_UPCT 99610 #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 @@ -5016,6 +5149,27 @@ static int fg_parse_dt(struct fg_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(chip); if (rc < 0) pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc); @@ -5047,6 +5201,7 @@ static int fg_parse_dt(struct fg_chip *chip) static void fg_cleanup(struct fg_chip *chip) { + alarm_try_to_cancel(&chip->esr_filter_alarm); power_supply_unreg_notifier(&chip->nb); debugfs_remove_recursive(chip->dfs_root); if (chip->awake_votable) @@ -5159,6 +5314,9 @@ static int fg_gen3_probe(struct platform_device *pdev) INIT_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->ttf_work, ttf_work); INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work); + INIT_WORK(&chip->esr_filter_work, esr_filter_work); + alarm_init(&chip->esr_filter_alarm, ALARM_BOOTTIME, + fg_esr_filter_alarm_cb); rc = fg_memif_init(chip); if (rc < 0) { @@ -5230,7 +5388,7 @@ static int fg_gen3_probe(struct platform_device *pdev) if (!rc) { pr_info("battery SOC:%d voltage: %duV temp: %d id: %dKOhms\n", msoc, volt_uv, batt_temp, chip->batt_id_ohms / 1000); - rc = fg_esr_filter_config(chip, batt_temp); + rc = fg_esr_filter_config(chip, batt_temp, false); if (rc < 0) pr_err("Error in configuring ESR filter rc:%d\n", rc); } |
