Loading drivers/power/supply/qcom/fg-core.h +5 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef __FG_CORE_H__ Loading Loading @@ -167,6 +167,8 @@ enum fg_sram_param_id { FG_SRAM_MONOTONIC_SOC, FG_SRAM_VOLTAGE_PRED, FG_SRAM_OCV, FG_SRAM_VBAT_FLT, FG_SRAM_VBAT_TAU, FG_SRAM_VBAT_FINAL, FG_SRAM_IBAT_FINAL, FG_SRAM_ESR, Loading Loading @@ -485,6 +487,8 @@ struct fg_dbgfs { u32 addr; }; extern int fg_decode_voltage_24b(struct fg_sram_param *sp, enum fg_sram_param_id id, int val); extern int fg_decode_voltage_15b(struct fg_sram_param *sp, enum fg_sram_param_id id, int val); extern int fg_decode_current_16b(struct fg_sram_param *sp, Loading drivers/power/supply/qcom/fg-util.c +18 −2 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. */ #include <linux/of.h> Loading @@ -18,9 +18,25 @@ #define MAX_LINE_LENGTH (ADDR_LEN + (ITEMS_PER_LINE * \ CHARS_PER_ITEM) + 1) \ #define VOLTAGE_15BIT_MASK GENMASK(14, 0) #define MAX_READ_TRIES 5 #define VOLTAGE_24BIT_MSB_MASK GENMASK(27, 16) #define VOLTAGE_24BIT_LSB_MASK GENMASK(11, 0) int fg_decode_voltage_24b(struct fg_sram_param *sp, enum fg_sram_param_id id, int value) { int msb, lsb, val; msb = value & VOLTAGE_24BIT_MSB_MASK; lsb = value & VOLTAGE_24BIT_LSB_MASK; val = (msb >> 4) | lsb; sp[id].value = div_s64((s64)val * sp[id].denmtr, sp[id].numrtr); pr_debug("id: %d raw value: %x decoded value: %x\n", id, value, sp[id].value); return sp[id].value; } #define VOLTAGE_15BIT_MASK GENMASK(14, 0) int fg_decode_voltage_15b(struct fg_sram_param *sp, enum fg_sram_param_id id, int value) { Loading drivers/power/supply/qcom/qpnp-fg-gen4.c +421 −33 Original line number Diff line number Diff line Loading @@ -160,12 +160,16 @@ #define MONOTONIC_SOC_OFFSET 0 /* v2 SRAM address and offset in ascending order */ #define LOW_PASS_VBATT_WORD 3 #define LOW_PASS_VBATT_OFFSET 0 #define RSLOW_SCALE_FN_DISCHG_V2_WORD 281 #define RSLOW_SCALE_FN_DISCHG_V2_OFFSET 0 #define RSLOW_SCALE_FN_CHG_V2_WORD 285 #define RSLOW_SCALE_FN_CHG_V2_OFFSET 0 #define ACT_BATT_CAP_v2_WORD 287 #define ACT_BATT_CAP_v2_OFFSET 0 #define VBAT_FLT_WORD 326 #define VBAT_FLT_OFFSET 0 #define RSLOW_v2_WORD 371 #define RSLOW_v2_OFFSET 0 #define OCV_v2_WORD 425 Loading Loading @@ -197,12 +201,15 @@ struct fg_dt_props { bool multi_profile_load; bool esr_calib_dischg; bool soc_hi_res; bool soc_scale_mode; int cutoff_volt_mv; int empty_volt_mv; int sys_min_volt_mv; int cutoff_curr_ma; int sys_term_curr_ma; int delta_soc_thr; int vbatt_scale_thr_mv; int scale_timer_ms; int esr_timer_chg_fast[NUM_ESR_TIMERS]; int esr_timer_chg_slow[NUM_ESR_TIMERS]; int esr_timer_dischg_fast[NUM_ESR_TIMERS]; Loading Loading @@ -245,10 +252,13 @@ struct fg_gen4_chip { struct votable *parallel_current_en_votable; struct votable *mem_attn_irq_en_votable; struct work_struct esr_calib_work; struct work_struct soc_scale_work; struct alarm esr_fast_cal_timer; struct alarm soc_scale_alarm_timer; struct delayed_work pl_enable_work; struct work_struct pl_current_en_work; struct completion mem_attn; struct mutex soc_scale_lock; char batt_profile[PROFILE_LEN]; enum slope_limit_status slope_limit_sts; int ki_coeff_full_soc[2]; Loading @@ -260,6 +270,14 @@ struct fg_gen4_chip { int esr_soh_cycle_count; int batt_age_level; int last_batt_age_level; int soc_scale_msoc; int prev_soc_scale_msoc; int soc_scale_slope; int vbatt_avg; int vbatt_now; int vbatt_res; int scale_timer; int current_now; bool first_profile_load; bool ki_coeff_dischg_en; bool slope_limit_en; Loading @@ -273,6 +291,7 @@ struct fg_gen4_chip { bool rapid_soc_dec_en; bool vbatt_low; bool chg_term_good; bool soc_scale_mode; }; struct bias_config { Loading Loading @@ -329,6 +348,8 @@ static int fg_restart_mp; static bool fg_sram_dump; static bool fg_esr_fast_cal_en; static int fg_gen4_validate_soc_scale_mode(struct fg_gen4_chip *chip); static struct fg_sram_param pm8150b_v1_sram_params[] = { PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL, fg_decode_default), Loading Loading @@ -422,6 +443,8 @@ static struct fg_sram_param pm8150b_v1_sram_params[] = { }; static struct fg_sram_param pm8150b_v2_sram_params[] = { PARAM(VBAT_TAU, LOW_PASS_VBATT_WORD, LOW_PASS_VBATT_OFFSET, 1, 1, 1, 0, NULL, NULL), PARAM(BATT_SOC, BATT_SOC_v2_WORD, BATT_SOC_v2_OFFSET, 4, 1, 1, 0, NULL, fg_decode_default), PARAM(FULL_SOC, FULL_SOC_v2_WORD, FULL_SOC_v2_OFFSET, 2, 1, 1, 0, Loading @@ -432,6 +455,8 @@ static struct fg_sram_param pm8150b_v2_sram_params[] = { 1000, 244141, 0, NULL, fg_decode_voltage_15b), PARAM(OCV, OCV_v2_WORD, OCV_v2_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_voltage_15b), PARAM(VBAT_FLT, VBAT_FLT_WORD, VBAT_FLT_OFFSET, 4, 10000, 19073, 0, NULL, fg_decode_voltage_24b), PARAM(VBAT_FINAL, VBAT_FINAL_WORD, VBAT_FINAL_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_voltage_15b), PARAM(IBAT_FINAL, IBAT_FINAL_WORD, IBAT_FINAL_OFFSET, 2, 1000, 488282, Loading Loading @@ -859,14 +884,19 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) return 0; } if (chip->soc_scale_mode) { mutex_lock(&chip->soc_scale_lock); *val = chip->soc_scale_msoc; mutex_unlock(&chip->soc_scale_lock); } else { rc = fg_get_msoc(fg, &msoc); if (rc < 0) return rc; if (chip->dt.linearize_soc && fg->delta_soc > 0) *val = fg->maint_soc; else *val = msoc; } return 0; } Loading Loading @@ -960,6 +990,39 @@ static int fg_gen4_get_power(struct fg_gen4_chip *chip, int *val, bool average) return 0; } static int fg_gen4_get_prop_soc_scale(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; rc = fg_get_sram_prop(fg, FG_SRAM_VBAT_FLT, &chip->vbatt_avg); if (rc < 0) { pr_err("Failed to get filtered battery voltage, rc = %d\n", rc); return rc; } rc = fg_get_battery_voltage(fg, &chip->vbatt_now); if (rc < 0) { pr_err("Failed to get battery voltage, rc =%d\n", rc); return rc; } rc = fg_get_battery_current(fg, &chip->current_now); if (rc < 0) { pr_err("Failed to get battery current rc=%d\n", rc); return rc; } chip->vbatt_now = DIV_ROUND_CLOSEST(chip->vbatt_now, 1000); chip->vbatt_avg = DIV_ROUND_CLOSEST(chip->vbatt_avg, 1000); chip->vbatt_res = chip->vbatt_avg - chip->dt.cutoff_volt_mv; pr_debug("FVSS: Vbatt now=%d Vbatt avg=%d Vbatt res=%d\n", chip->vbatt_now, chip->vbatt_avg, chip->vbatt_res); return rc; } /* ALG callback functions below */ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) Loading Loading @@ -2231,6 +2294,10 @@ static void profile_load_work(struct work_struct *work) pm_stay_awake(fg->dev); schedule_work(&fg->status_change_work); } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); } static void get_batt_psy_props(struct fg_dev *fg) Loading Loading @@ -2870,6 +2937,193 @@ static int fg_gen4_esr_fast_calib_config(struct fg_gen4_chip *chip, bool en) return 0; } #define IBATT_TAU_MASK GENMASK(3, 0) static int fg_gen4_set_vbatt_tau(struct fg_gen4_chip *chip, u8 vbatt_tau) { struct fg_dev *fg = &chip->fg; int rc; u8 buf; rc = fg_sram_read(fg, fg->sp[FG_SRAM_VBAT_TAU].addr_word, fg->sp[FG_SRAM_VBAT_TAU].addr_byte, &buf, fg->sp[FG_SRAM_VBAT_TAU].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading Vbatt_tau, rc=%d\n", rc); return rc; } buf &= IBATT_TAU_MASK; buf |= vbatt_tau << 4; rc = fg_sram_write(fg, fg->sp[FG_SRAM_VBAT_TAU].addr_word, fg->sp[FG_SRAM_VBAT_TAU].addr_byte, &buf, fg->sp[FG_SRAM_VBAT_TAU].len, FG_IMA_DEFAULT); if (rc < 0) pr_err("Error in writing Vbatt_tau, rc=%d\n", rc); return rc; } static int fg_gen4_enter_soc_scale(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, soc; rc = fg_gen4_get_prop_capacity(fg, &soc); if (rc < 0) { pr_err("Failed to get capacity, rc =%d\n", rc); return rc; } /* Set entry FVS SOC equal to current H/W reported SOC */ chip->soc_scale_msoc = chip->prev_soc_scale_msoc = soc; chip->scale_timer = chip->dt.scale_timer_ms; /* * Calculate the FVS slope to linearly calculate SOC * based on filtered battery voltage. */ chip->soc_scale_slope = DIV_ROUND_CLOSEST(chip->vbatt_res, chip->soc_scale_msoc); if (chip->soc_scale_slope <= 0) { pr_err("Error in slope calculated = %d\n", chip->soc_scale_slope); return -EINVAL; } chip->soc_scale_mode = true; pr_debug("FVSS: Enter FVSS mode, SOC=%d slope=%d timer=%d\n", soc, chip->soc_scale_slope, chip->scale_timer); alarm_start_relative(&chip->soc_scale_alarm_timer, ms_to_ktime(chip->scale_timer)); return 0; } static void fg_gen4_write_scale_msoc(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int soc_raw, rc; if (!fg->charge_full) { soc_raw = DIV_ROUND_CLOSEST(chip->soc_scale_msoc * 0xFFFF, 100); rc = fg_sram_write(fg, fg->sp[FG_SRAM_MONOTONIC_SOC].addr_word, fg->sp[FG_SRAM_MONOTONIC_SOC].addr_byte, (u8 *)&soc_raw, fg->sp[FG_SRAM_MONOTONIC_SOC].len, FG_IMA_ATOMIC); if (rc < 0) { pr_err("failed to write monotonic_soc rc=%d\n", rc); chip->soc_scale_mode = false; } } } static void fg_gen4_exit_soc_scale(struct fg_gen4_chip *chip) { if (chip->soc_scale_mode) { alarm_cancel(&chip->soc_scale_alarm_timer); cancel_work_sync(&chip->soc_scale_work); /* While exiting soc_scale_mode, Update MSOC register */ fg_gen4_write_scale_msoc(chip); } chip->soc_scale_mode = false; pr_debug("FVSS: Exit FVSS mode\n"); } static int fg_gen4_validate_soc_scale_mode(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, msoc_actual; if (!chip->dt.soc_scale_mode) return 0; rc = fg_gen4_get_prop_soc_scale(chip); if (rc < 0) { pr_err("Failed to get soc scale props\n"); goto fail_soc_scale; } rc = fg_get_msoc(fg, &msoc_actual); if (rc < 0) { pr_err("Failed to get msoc rc=%d\n", rc); goto fail_soc_scale; } if (!chip->soc_scale_mode && fg->charge_status == POWER_SUPPLY_STATUS_DISCHARGING && chip->vbatt_avg < chip->dt.vbatt_scale_thr_mv) { rc = fg_gen4_enter_soc_scale(chip); if (rc < 0) { pr_err("Failed to enter SOC scale mode\n"); goto fail_soc_scale; } } else if (chip->soc_scale_mode && chip->current_now < 0) { /* * Stay in SOC scale mode till H/W SOC catch scaled SOC * while charging. */ if (msoc_actual >= chip->soc_scale_msoc) fg_gen4_exit_soc_scale(chip); } return 0; fail_soc_scale: fg_gen4_exit_soc_scale(chip); return rc; } static int fg_gen4_set_vbatt_low(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, vbatt_flt; if (chip->soc_scale_mode) { rc = fg_get_sram_prop(fg, FG_SRAM_VBAT_FLT, &vbatt_flt); if (rc < 0) { pr_err("failed to get filtered battery voltage, rc=%d\n", rc); /* * If we fail here, exit FVSS mode * and set Vbatt low flag true to report * 0 SOC */ fg_gen4_exit_soc_scale(chip); chip->vbatt_low = true; return 0; } vbatt_flt /= 1000; if (vbatt_flt < chip->dt.empty_volt_mv || vbatt_flt > (fg->bp.float_volt_uv/1000)) { pr_err("Filtered Vbatt is not in range %d\n", vbatt_flt); /* * If we fail here, exit FVSS mode * and set Vbatt low flag true to report * 0 SOC */ fg_gen4_exit_soc_scale(chip); chip->vbatt_low = true; return 0; } if (vbatt_flt <= chip->dt.cutoff_volt_mv) chip->vbatt_low = true; } else { /* Set the flag to show 0% */ chip->vbatt_low = true; } return 0; } /* All irq handlers below this */ static irqreturn_t fg_mem_attn_irq_handler(int irq, void *data) Loading Loading @@ -2964,8 +3218,7 @@ static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) pr_err("Error in configuring for rapid SOC reduction rc:%d\n", rc); } else { /* Set the flag to show 0% */ chip->vbatt_low = true; fg_gen4_set_vbatt_low(chip); } } Loading Loading @@ -3169,6 +3422,10 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) chip->esr_fast_calib_retry = true; } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); Loading Loading @@ -3437,6 +3694,79 @@ static void esr_calib_work(struct work_struct *work) vote(fg->awake_votable, ESR_CALIB, false, 0); } static enum alarmtimer_restart fg_soc_scale_timer(struct alarm *alarm, ktime_t time) { struct fg_gen4_chip *chip = container_of(alarm, struct fg_gen4_chip, soc_scale_alarm_timer); schedule_work(&chip->soc_scale_work); return ALARMTIMER_NORESTART; } static void soc_scale_work(struct work_struct *work) { struct fg_gen4_chip *chip = container_of(work, struct fg_gen4_chip, soc_scale_work); struct fg_dev *fg = &chip->fg; int soc, soc_thr_percent, rc; if (!chip->soc_scale_mode) return; soc_thr_percent = chip->dt.delta_soc_thr / 10; if (soc_thr_percent == 0) { /* Set minimum SOC change that can be reported = 1% */ soc_thr_percent = 1; } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); if (chip->vbatt_res <= 0) chip->vbatt_res = 0; mutex_lock(&chip->soc_scale_lock); soc = DIV_ROUND_CLOSEST(chip->vbatt_res, chip->soc_scale_slope); /* If calculated SOC is higher than current SOC, report current SOC */ if (soc > chip->prev_soc_scale_msoc) { chip->soc_scale_msoc = chip->prev_soc_scale_msoc; chip->scale_timer = chip->dt.scale_timer_ms; } else if ((chip->prev_soc_scale_msoc - soc) > soc_thr_percent) { /* * If difference b/w current SOC and calculated SOC * is higher than SOC threshold then handle this by * showing current SOC - SOC threshold and decrease * timer resolution to catch up the rate of decrement * of SOC. */ chip->soc_scale_msoc = chip->prev_soc_scale_msoc - soc_thr_percent; chip->scale_timer = chip->dt.scale_timer_ms / (chip->prev_soc_scale_msoc - soc); } else { chip->soc_scale_msoc = soc; chip->scale_timer = chip->dt.scale_timer_ms; } if (chip->soc_scale_msoc < 0) chip->soc_scale_msoc = 0; mutex_unlock(&chip->soc_scale_lock); if (chip->prev_soc_scale_msoc != chip->soc_scale_msoc) { if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); } chip->prev_soc_scale_msoc = chip->soc_scale_msoc; pr_debug("FVSS: Calculated SOC=%d SOC reported=%d timer resolution=%d\n", soc, chip->soc_scale_msoc, chip->scale_timer); alarm_start_relative(&chip->soc_scale_alarm_timer, ms_to_ktime(chip->scale_timer)); } static void pl_current_en_work(struct work_struct *work) { struct fg_gen4_chip *chip = container_of(work, Loading Loading @@ -3549,6 +3879,10 @@ static void status_change_work(struct work_struct *work) schedule_work(&chip->pl_current_en_work); } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); ttf_update(chip->ttf, input_present); fg->prev_charge_status = fg->charge_status; out: Loading Loading @@ -3797,6 +4131,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_OCV: rc = fg_get_sram_prop(fg, FG_SRAM_OCV, &pval->intval); break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: rc = fg_get_sram_prop(fg, FG_SRAM_VBAT_FLT, &pval->intval); break; case POWER_SUPPLY_PROP_RESISTANCE_ID: pval->intval = fg->batt_id_ohms; break; Loading Loading @@ -3874,6 +4211,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: pval->intval = chip->batt_age_level; break; case POWER_SUPPLY_PROP_SCALE_MODE_EN: pval->intval = chip->soc_scale_mode; break; case POWER_SUPPLY_PROP_POWER_NOW: rc = fg_gen4_get_power(chip, &pval->intval, false); break; Loading Loading @@ -4003,6 +4343,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_VOLTAGE_AVG, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_RESISTANCE_ID, POWER_SUPPLY_PROP_RESISTANCE, Loading @@ -4029,6 +4370,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_BATT_AGE_LEVEL, POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_SCALE_MODE_EN, }; static const struct power_supply_desc fg_psy_desc = { Loading Loading @@ -4465,6 +4807,7 @@ static int fg_gen4_batt_temp_config(struct fg_gen4_chip *chip) return rc; } #define VBATT_TAU_DEFAULT 3 static int fg_gen4_hw_init(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; Loading Loading @@ -4520,7 +4863,6 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } } if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 125) { fg_encode(fg->sp, FG_SRAM_DELTA_MSOC_THR, chip->dt.delta_soc_thr, buf); rc = fg_sram_write(fg, Loading @@ -4544,7 +4886,6 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc); return rc; } } rc = fg_gen4_batt_temp_config(chip); if (rc < 0) Loading Loading @@ -4661,6 +5002,15 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) if (!rc) chip->batt_age_level = chip->last_batt_age_level = val; } if (chip->dt.soc_scale_mode) { rc = fg_gen4_set_vbatt_tau(chip, VBATT_TAU_DEFAULT); if (rc < 0) { fg_gen4_exit_soc_scale(chip); return rc; } } return 0; } Loading Loading @@ -5075,6 +5425,8 @@ static int fg_gen4_parse_child_nodes_dt(struct fg_gen4_chip *chip) #define DEFAULT_DELTA_SOC_THR 5 /* 0.5 % */ #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 #define DEFAULT_SCALE_VBATT_THR_MV 3400 #define DEFAULT_SCALE_ALARM_TIMER_MS 10000 static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) { Loading Loading @@ -5121,6 +5473,12 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) of_property_read_u32(node, "qcom,fg-delta-soc-thr", &chip->dt.delta_soc_thr); if (chip->dt.delta_soc_thr < 0 || chip->dt.delta_soc_thr >= 125) { pr_err("Invalid delta SOC threshold=%d\n", chip->dt.delta_soc_thr); return -EINVAL; } chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-chg-fast", Loading Loading @@ -5163,6 +5521,17 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) chip->dt.linearize_soc = of_property_read_bool(node, "qcom,linearize-soc"); chip->dt.soc_scale_mode = of_property_read_bool(node, "qcom,soc-scale-mode-en"); if (chip->dt.soc_scale_mode) { chip->dt.vbatt_scale_thr_mv = DEFAULT_SCALE_VBATT_THR_MV; of_property_read_u32(node, "qcom,soc-scale-vbatt-mv", &chip->dt.vbatt_scale_thr_mv); chip->dt.scale_timer_ms = DEFAULT_SCALE_ALARM_TIMER_MS; of_property_read_u32(node, "qcom,soc-scale-time-ms", &chip->dt.scale_timer_ms); } rc = fg_parse_ki_coefficients(fg); if (rc < 0) pr_err("Error in parsing Ki coefficients, rc=%d\n", rc); Loading Loading @@ -5216,6 +5585,9 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip) fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); cancel_work_sync(&fg->status_change_work); if (chip->soc_scale_mode) fg_gen4_exit_soc_scale(chip); cancel_delayed_work_sync(&fg->profile_load_work); cancel_delayed_work_sync(&fg->sram_dump_work); cancel_work_sync(&chip->pl_current_en_work); Loading Loading @@ -5273,11 +5645,13 @@ static int fg_gen4_probe(struct platform_device *pdev) mutex_init(&fg->bus_lock); mutex_init(&fg->sram_rw_lock); mutex_init(&fg->charge_full_lock); mutex_init(&chip->soc_scale_lock); init_completion(&fg->soc_update); init_completion(&fg->soc_ready); init_completion(&chip->mem_attn); INIT_WORK(&fg->status_change_work, status_change_work); INIT_WORK(&chip->esr_calib_work, esr_calib_work); INIT_WORK(&chip->soc_scale_work, soc_scale_work); INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); Loading Loading @@ -5353,6 +5727,17 @@ static int fg_gen4_probe(struct platform_device *pdev) } } if (chip->dt.soc_scale_mode) { if (alarmtimer_get_rtcdev()) { alarm_init(&chip->soc_scale_alarm_timer, ALARM_BOOTTIME, fg_soc_scale_timer); } else { dev_err(fg->dev, "Failed to initialize SOC scale timer\n"); rc = -EPROBE_DEFER; goto exit; } } rc = fg_memif_init(fg); if (rc < 0) { dev_err(fg->dev, "Error in initializing FG_MEMIF, rc:%d\n", Loading Loading @@ -5475,6 +5860,9 @@ static void fg_gen4_shutdown(struct platform_device *pdev) fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); if (chip->soc_scale_mode) fg_gen4_exit_soc_scale(chip); if (chip->rapid_soc_dec_en) { rc = fg_gen4_rapid_soc_config(chip, false); if (rc < 0) Loading Loading
drivers/power/supply/qcom/fg-core.h +5 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #ifndef __FG_CORE_H__ Loading Loading @@ -167,6 +167,8 @@ enum fg_sram_param_id { FG_SRAM_MONOTONIC_SOC, FG_SRAM_VOLTAGE_PRED, FG_SRAM_OCV, FG_SRAM_VBAT_FLT, FG_SRAM_VBAT_TAU, FG_SRAM_VBAT_FINAL, FG_SRAM_IBAT_FINAL, FG_SRAM_ESR, Loading Loading @@ -485,6 +487,8 @@ struct fg_dbgfs { u32 addr; }; extern int fg_decode_voltage_24b(struct fg_sram_param *sp, enum fg_sram_param_id id, int val); extern int fg_decode_voltage_15b(struct fg_sram_param *sp, enum fg_sram_param_id id, int val); extern int fg_decode_current_16b(struct fg_sram_param *sp, Loading
drivers/power/supply/qcom/fg-util.c +18 −2 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. */ #include <linux/of.h> Loading @@ -18,9 +18,25 @@ #define MAX_LINE_LENGTH (ADDR_LEN + (ITEMS_PER_LINE * \ CHARS_PER_ITEM) + 1) \ #define VOLTAGE_15BIT_MASK GENMASK(14, 0) #define MAX_READ_TRIES 5 #define VOLTAGE_24BIT_MSB_MASK GENMASK(27, 16) #define VOLTAGE_24BIT_LSB_MASK GENMASK(11, 0) int fg_decode_voltage_24b(struct fg_sram_param *sp, enum fg_sram_param_id id, int value) { int msb, lsb, val; msb = value & VOLTAGE_24BIT_MSB_MASK; lsb = value & VOLTAGE_24BIT_LSB_MASK; val = (msb >> 4) | lsb; sp[id].value = div_s64((s64)val * sp[id].denmtr, sp[id].numrtr); pr_debug("id: %d raw value: %x decoded value: %x\n", id, value, sp[id].value); return sp[id].value; } #define VOLTAGE_15BIT_MASK GENMASK(14, 0) int fg_decode_voltage_15b(struct fg_sram_param *sp, enum fg_sram_param_id id, int value) { Loading
drivers/power/supply/qcom/qpnp-fg-gen4.c +421 −33 Original line number Diff line number Diff line Loading @@ -160,12 +160,16 @@ #define MONOTONIC_SOC_OFFSET 0 /* v2 SRAM address and offset in ascending order */ #define LOW_PASS_VBATT_WORD 3 #define LOW_PASS_VBATT_OFFSET 0 #define RSLOW_SCALE_FN_DISCHG_V2_WORD 281 #define RSLOW_SCALE_FN_DISCHG_V2_OFFSET 0 #define RSLOW_SCALE_FN_CHG_V2_WORD 285 #define RSLOW_SCALE_FN_CHG_V2_OFFSET 0 #define ACT_BATT_CAP_v2_WORD 287 #define ACT_BATT_CAP_v2_OFFSET 0 #define VBAT_FLT_WORD 326 #define VBAT_FLT_OFFSET 0 #define RSLOW_v2_WORD 371 #define RSLOW_v2_OFFSET 0 #define OCV_v2_WORD 425 Loading Loading @@ -197,12 +201,15 @@ struct fg_dt_props { bool multi_profile_load; bool esr_calib_dischg; bool soc_hi_res; bool soc_scale_mode; int cutoff_volt_mv; int empty_volt_mv; int sys_min_volt_mv; int cutoff_curr_ma; int sys_term_curr_ma; int delta_soc_thr; int vbatt_scale_thr_mv; int scale_timer_ms; int esr_timer_chg_fast[NUM_ESR_TIMERS]; int esr_timer_chg_slow[NUM_ESR_TIMERS]; int esr_timer_dischg_fast[NUM_ESR_TIMERS]; Loading Loading @@ -245,10 +252,13 @@ struct fg_gen4_chip { struct votable *parallel_current_en_votable; struct votable *mem_attn_irq_en_votable; struct work_struct esr_calib_work; struct work_struct soc_scale_work; struct alarm esr_fast_cal_timer; struct alarm soc_scale_alarm_timer; struct delayed_work pl_enable_work; struct work_struct pl_current_en_work; struct completion mem_attn; struct mutex soc_scale_lock; char batt_profile[PROFILE_LEN]; enum slope_limit_status slope_limit_sts; int ki_coeff_full_soc[2]; Loading @@ -260,6 +270,14 @@ struct fg_gen4_chip { int esr_soh_cycle_count; int batt_age_level; int last_batt_age_level; int soc_scale_msoc; int prev_soc_scale_msoc; int soc_scale_slope; int vbatt_avg; int vbatt_now; int vbatt_res; int scale_timer; int current_now; bool first_profile_load; bool ki_coeff_dischg_en; bool slope_limit_en; Loading @@ -273,6 +291,7 @@ struct fg_gen4_chip { bool rapid_soc_dec_en; bool vbatt_low; bool chg_term_good; bool soc_scale_mode; }; struct bias_config { Loading Loading @@ -329,6 +348,8 @@ static int fg_restart_mp; static bool fg_sram_dump; static bool fg_esr_fast_cal_en; static int fg_gen4_validate_soc_scale_mode(struct fg_gen4_chip *chip); static struct fg_sram_param pm8150b_v1_sram_params[] = { PARAM(BATT_SOC, BATT_SOC_WORD, BATT_SOC_OFFSET, 4, 1, 1, 0, NULL, fg_decode_default), Loading Loading @@ -422,6 +443,8 @@ static struct fg_sram_param pm8150b_v1_sram_params[] = { }; static struct fg_sram_param pm8150b_v2_sram_params[] = { PARAM(VBAT_TAU, LOW_PASS_VBATT_WORD, LOW_PASS_VBATT_OFFSET, 1, 1, 1, 0, NULL, NULL), PARAM(BATT_SOC, BATT_SOC_v2_WORD, BATT_SOC_v2_OFFSET, 4, 1, 1, 0, NULL, fg_decode_default), PARAM(FULL_SOC, FULL_SOC_v2_WORD, FULL_SOC_v2_OFFSET, 2, 1, 1, 0, Loading @@ -432,6 +455,8 @@ static struct fg_sram_param pm8150b_v2_sram_params[] = { 1000, 244141, 0, NULL, fg_decode_voltage_15b), PARAM(OCV, OCV_v2_WORD, OCV_v2_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_voltage_15b), PARAM(VBAT_FLT, VBAT_FLT_WORD, VBAT_FLT_OFFSET, 4, 10000, 19073, 0, NULL, fg_decode_voltage_24b), PARAM(VBAT_FINAL, VBAT_FINAL_WORD, VBAT_FINAL_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_voltage_15b), PARAM(IBAT_FINAL, IBAT_FINAL_WORD, IBAT_FINAL_OFFSET, 2, 1000, 488282, Loading Loading @@ -859,14 +884,19 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) return 0; } if (chip->soc_scale_mode) { mutex_lock(&chip->soc_scale_lock); *val = chip->soc_scale_msoc; mutex_unlock(&chip->soc_scale_lock); } else { rc = fg_get_msoc(fg, &msoc); if (rc < 0) return rc; if (chip->dt.linearize_soc && fg->delta_soc > 0) *val = fg->maint_soc; else *val = msoc; } return 0; } Loading Loading @@ -960,6 +990,39 @@ static int fg_gen4_get_power(struct fg_gen4_chip *chip, int *val, bool average) return 0; } static int fg_gen4_get_prop_soc_scale(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc; rc = fg_get_sram_prop(fg, FG_SRAM_VBAT_FLT, &chip->vbatt_avg); if (rc < 0) { pr_err("Failed to get filtered battery voltage, rc = %d\n", rc); return rc; } rc = fg_get_battery_voltage(fg, &chip->vbatt_now); if (rc < 0) { pr_err("Failed to get battery voltage, rc =%d\n", rc); return rc; } rc = fg_get_battery_current(fg, &chip->current_now); if (rc < 0) { pr_err("Failed to get battery current rc=%d\n", rc); return rc; } chip->vbatt_now = DIV_ROUND_CLOSEST(chip->vbatt_now, 1000); chip->vbatt_avg = DIV_ROUND_CLOSEST(chip->vbatt_avg, 1000); chip->vbatt_res = chip->vbatt_avg - chip->dt.cutoff_volt_mv; pr_debug("FVSS: Vbatt now=%d Vbatt avg=%d Vbatt res=%d\n", chip->vbatt_now, chip->vbatt_avg, chip->vbatt_res); return rc; } /* ALG callback functions below */ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) Loading Loading @@ -2231,6 +2294,10 @@ static void profile_load_work(struct work_struct *work) pm_stay_awake(fg->dev); schedule_work(&fg->status_change_work); } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); } static void get_batt_psy_props(struct fg_dev *fg) Loading Loading @@ -2870,6 +2937,193 @@ static int fg_gen4_esr_fast_calib_config(struct fg_gen4_chip *chip, bool en) return 0; } #define IBATT_TAU_MASK GENMASK(3, 0) static int fg_gen4_set_vbatt_tau(struct fg_gen4_chip *chip, u8 vbatt_tau) { struct fg_dev *fg = &chip->fg; int rc; u8 buf; rc = fg_sram_read(fg, fg->sp[FG_SRAM_VBAT_TAU].addr_word, fg->sp[FG_SRAM_VBAT_TAU].addr_byte, &buf, fg->sp[FG_SRAM_VBAT_TAU].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading Vbatt_tau, rc=%d\n", rc); return rc; } buf &= IBATT_TAU_MASK; buf |= vbatt_tau << 4; rc = fg_sram_write(fg, fg->sp[FG_SRAM_VBAT_TAU].addr_word, fg->sp[FG_SRAM_VBAT_TAU].addr_byte, &buf, fg->sp[FG_SRAM_VBAT_TAU].len, FG_IMA_DEFAULT); if (rc < 0) pr_err("Error in writing Vbatt_tau, rc=%d\n", rc); return rc; } static int fg_gen4_enter_soc_scale(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, soc; rc = fg_gen4_get_prop_capacity(fg, &soc); if (rc < 0) { pr_err("Failed to get capacity, rc =%d\n", rc); return rc; } /* Set entry FVS SOC equal to current H/W reported SOC */ chip->soc_scale_msoc = chip->prev_soc_scale_msoc = soc; chip->scale_timer = chip->dt.scale_timer_ms; /* * Calculate the FVS slope to linearly calculate SOC * based on filtered battery voltage. */ chip->soc_scale_slope = DIV_ROUND_CLOSEST(chip->vbatt_res, chip->soc_scale_msoc); if (chip->soc_scale_slope <= 0) { pr_err("Error in slope calculated = %d\n", chip->soc_scale_slope); return -EINVAL; } chip->soc_scale_mode = true; pr_debug("FVSS: Enter FVSS mode, SOC=%d slope=%d timer=%d\n", soc, chip->soc_scale_slope, chip->scale_timer); alarm_start_relative(&chip->soc_scale_alarm_timer, ms_to_ktime(chip->scale_timer)); return 0; } static void fg_gen4_write_scale_msoc(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int soc_raw, rc; if (!fg->charge_full) { soc_raw = DIV_ROUND_CLOSEST(chip->soc_scale_msoc * 0xFFFF, 100); rc = fg_sram_write(fg, fg->sp[FG_SRAM_MONOTONIC_SOC].addr_word, fg->sp[FG_SRAM_MONOTONIC_SOC].addr_byte, (u8 *)&soc_raw, fg->sp[FG_SRAM_MONOTONIC_SOC].len, FG_IMA_ATOMIC); if (rc < 0) { pr_err("failed to write monotonic_soc rc=%d\n", rc); chip->soc_scale_mode = false; } } } static void fg_gen4_exit_soc_scale(struct fg_gen4_chip *chip) { if (chip->soc_scale_mode) { alarm_cancel(&chip->soc_scale_alarm_timer); cancel_work_sync(&chip->soc_scale_work); /* While exiting soc_scale_mode, Update MSOC register */ fg_gen4_write_scale_msoc(chip); } chip->soc_scale_mode = false; pr_debug("FVSS: Exit FVSS mode\n"); } static int fg_gen4_validate_soc_scale_mode(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, msoc_actual; if (!chip->dt.soc_scale_mode) return 0; rc = fg_gen4_get_prop_soc_scale(chip); if (rc < 0) { pr_err("Failed to get soc scale props\n"); goto fail_soc_scale; } rc = fg_get_msoc(fg, &msoc_actual); if (rc < 0) { pr_err("Failed to get msoc rc=%d\n", rc); goto fail_soc_scale; } if (!chip->soc_scale_mode && fg->charge_status == POWER_SUPPLY_STATUS_DISCHARGING && chip->vbatt_avg < chip->dt.vbatt_scale_thr_mv) { rc = fg_gen4_enter_soc_scale(chip); if (rc < 0) { pr_err("Failed to enter SOC scale mode\n"); goto fail_soc_scale; } } else if (chip->soc_scale_mode && chip->current_now < 0) { /* * Stay in SOC scale mode till H/W SOC catch scaled SOC * while charging. */ if (msoc_actual >= chip->soc_scale_msoc) fg_gen4_exit_soc_scale(chip); } return 0; fail_soc_scale: fg_gen4_exit_soc_scale(chip); return rc; } static int fg_gen4_set_vbatt_low(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; int rc, vbatt_flt; if (chip->soc_scale_mode) { rc = fg_get_sram_prop(fg, FG_SRAM_VBAT_FLT, &vbatt_flt); if (rc < 0) { pr_err("failed to get filtered battery voltage, rc=%d\n", rc); /* * If we fail here, exit FVSS mode * and set Vbatt low flag true to report * 0 SOC */ fg_gen4_exit_soc_scale(chip); chip->vbatt_low = true; return 0; } vbatt_flt /= 1000; if (vbatt_flt < chip->dt.empty_volt_mv || vbatt_flt > (fg->bp.float_volt_uv/1000)) { pr_err("Filtered Vbatt is not in range %d\n", vbatt_flt); /* * If we fail here, exit FVSS mode * and set Vbatt low flag true to report * 0 SOC */ fg_gen4_exit_soc_scale(chip); chip->vbatt_low = true; return 0; } if (vbatt_flt <= chip->dt.cutoff_volt_mv) chip->vbatt_low = true; } else { /* Set the flag to show 0% */ chip->vbatt_low = true; } return 0; } /* All irq handlers below this */ static irqreturn_t fg_mem_attn_irq_handler(int irq, void *data) Loading Loading @@ -2964,8 +3218,7 @@ static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) pr_err("Error in configuring for rapid SOC reduction rc:%d\n", rc); } else { /* Set the flag to show 0% */ chip->vbatt_low = true; fg_gen4_set_vbatt_low(chip); } } Loading Loading @@ -3169,6 +3422,10 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) chip->esr_fast_calib_retry = true; } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); Loading Loading @@ -3437,6 +3694,79 @@ static void esr_calib_work(struct work_struct *work) vote(fg->awake_votable, ESR_CALIB, false, 0); } static enum alarmtimer_restart fg_soc_scale_timer(struct alarm *alarm, ktime_t time) { struct fg_gen4_chip *chip = container_of(alarm, struct fg_gen4_chip, soc_scale_alarm_timer); schedule_work(&chip->soc_scale_work); return ALARMTIMER_NORESTART; } static void soc_scale_work(struct work_struct *work) { struct fg_gen4_chip *chip = container_of(work, struct fg_gen4_chip, soc_scale_work); struct fg_dev *fg = &chip->fg; int soc, soc_thr_percent, rc; if (!chip->soc_scale_mode) return; soc_thr_percent = chip->dt.delta_soc_thr / 10; if (soc_thr_percent == 0) { /* Set minimum SOC change that can be reported = 1% */ soc_thr_percent = 1; } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); if (chip->vbatt_res <= 0) chip->vbatt_res = 0; mutex_lock(&chip->soc_scale_lock); soc = DIV_ROUND_CLOSEST(chip->vbatt_res, chip->soc_scale_slope); /* If calculated SOC is higher than current SOC, report current SOC */ if (soc > chip->prev_soc_scale_msoc) { chip->soc_scale_msoc = chip->prev_soc_scale_msoc; chip->scale_timer = chip->dt.scale_timer_ms; } else if ((chip->prev_soc_scale_msoc - soc) > soc_thr_percent) { /* * If difference b/w current SOC and calculated SOC * is higher than SOC threshold then handle this by * showing current SOC - SOC threshold and decrease * timer resolution to catch up the rate of decrement * of SOC. */ chip->soc_scale_msoc = chip->prev_soc_scale_msoc - soc_thr_percent; chip->scale_timer = chip->dt.scale_timer_ms / (chip->prev_soc_scale_msoc - soc); } else { chip->soc_scale_msoc = soc; chip->scale_timer = chip->dt.scale_timer_ms; } if (chip->soc_scale_msoc < 0) chip->soc_scale_msoc = 0; mutex_unlock(&chip->soc_scale_lock); if (chip->prev_soc_scale_msoc != chip->soc_scale_msoc) { if (batt_psy_initialized(fg)) power_supply_changed(fg->batt_psy); } chip->prev_soc_scale_msoc = chip->soc_scale_msoc; pr_debug("FVSS: Calculated SOC=%d SOC reported=%d timer resolution=%d\n", soc, chip->soc_scale_msoc, chip->scale_timer); alarm_start_relative(&chip->soc_scale_alarm_timer, ms_to_ktime(chip->scale_timer)); } static void pl_current_en_work(struct work_struct *work) { struct fg_gen4_chip *chip = container_of(work, Loading Loading @@ -3549,6 +3879,10 @@ static void status_change_work(struct work_struct *work) schedule_work(&chip->pl_current_en_work); } rc = fg_gen4_validate_soc_scale_mode(chip); if (rc < 0) pr_err("Failed to validate SOC scale mode, rc=%d\n", rc); ttf_update(chip->ttf, input_present); fg->prev_charge_status = fg->charge_status; out: Loading Loading @@ -3797,6 +4131,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_OCV: rc = fg_get_sram_prop(fg, FG_SRAM_OCV, &pval->intval); break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: rc = fg_get_sram_prop(fg, FG_SRAM_VBAT_FLT, &pval->intval); break; case POWER_SUPPLY_PROP_RESISTANCE_ID: pval->intval = fg->batt_id_ohms; break; Loading Loading @@ -3874,6 +4211,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: pval->intval = chip->batt_age_level; break; case POWER_SUPPLY_PROP_SCALE_MODE_EN: pval->intval = chip->soc_scale_mode; break; case POWER_SUPPLY_PROP_POWER_NOW: rc = fg_gen4_get_power(chip, &pval->intval, false); break; Loading Loading @@ -4003,6 +4343,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_VOLTAGE_AVG, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_RESISTANCE_ID, POWER_SUPPLY_PROP_RESISTANCE, Loading @@ -4029,6 +4370,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_BATT_AGE_LEVEL, POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_SCALE_MODE_EN, }; static const struct power_supply_desc fg_psy_desc = { Loading Loading @@ -4465,6 +4807,7 @@ static int fg_gen4_batt_temp_config(struct fg_gen4_chip *chip) return rc; } #define VBATT_TAU_DEFAULT 3 static int fg_gen4_hw_init(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; Loading Loading @@ -4520,7 +4863,6 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } } if (chip->dt.delta_soc_thr > 0 && chip->dt.delta_soc_thr < 125) { fg_encode(fg->sp, FG_SRAM_DELTA_MSOC_THR, chip->dt.delta_soc_thr, buf); rc = fg_sram_write(fg, Loading @@ -4544,7 +4886,6 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) pr_err("Error in writing delta_bsoc_thr, rc=%d\n", rc); return rc; } } rc = fg_gen4_batt_temp_config(chip); if (rc < 0) Loading Loading @@ -4661,6 +5002,15 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) if (!rc) chip->batt_age_level = chip->last_batt_age_level = val; } if (chip->dt.soc_scale_mode) { rc = fg_gen4_set_vbatt_tau(chip, VBATT_TAU_DEFAULT); if (rc < 0) { fg_gen4_exit_soc_scale(chip); return rc; } } return 0; } Loading Loading @@ -5075,6 +5425,8 @@ static int fg_gen4_parse_child_nodes_dt(struct fg_gen4_chip *chip) #define DEFAULT_DELTA_SOC_THR 5 /* 0.5 % */ #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 #define DEFAULT_SCALE_VBATT_THR_MV 3400 #define DEFAULT_SCALE_ALARM_TIMER_MS 10000 static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) { Loading Loading @@ -5121,6 +5473,12 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) of_property_read_u32(node, "qcom,fg-delta-soc-thr", &chip->dt.delta_soc_thr); if (chip->dt.delta_soc_thr < 0 || chip->dt.delta_soc_thr >= 125) { pr_err("Invalid delta SOC threshold=%d\n", chip->dt.delta_soc_thr); return -EINVAL; } chip->dt.esr_timer_chg_fast[TIMER_RETRY] = -EINVAL; chip->dt.esr_timer_chg_fast[TIMER_MAX] = -EINVAL; rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-chg-fast", Loading Loading @@ -5163,6 +5521,17 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) chip->dt.linearize_soc = of_property_read_bool(node, "qcom,linearize-soc"); chip->dt.soc_scale_mode = of_property_read_bool(node, "qcom,soc-scale-mode-en"); if (chip->dt.soc_scale_mode) { chip->dt.vbatt_scale_thr_mv = DEFAULT_SCALE_VBATT_THR_MV; of_property_read_u32(node, "qcom,soc-scale-vbatt-mv", &chip->dt.vbatt_scale_thr_mv); chip->dt.scale_timer_ms = DEFAULT_SCALE_ALARM_TIMER_MS; of_property_read_u32(node, "qcom,soc-scale-time-ms", &chip->dt.scale_timer_ms); } rc = fg_parse_ki_coefficients(fg); if (rc < 0) pr_err("Error in parsing Ki coefficients, rc=%d\n", rc); Loading Loading @@ -5216,6 +5585,9 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip) fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); cancel_work_sync(&fg->status_change_work); if (chip->soc_scale_mode) fg_gen4_exit_soc_scale(chip); cancel_delayed_work_sync(&fg->profile_load_work); cancel_delayed_work_sync(&fg->sram_dump_work); cancel_work_sync(&chip->pl_current_en_work); Loading Loading @@ -5273,11 +5645,13 @@ static int fg_gen4_probe(struct platform_device *pdev) mutex_init(&fg->bus_lock); mutex_init(&fg->sram_rw_lock); mutex_init(&fg->charge_full_lock); mutex_init(&chip->soc_scale_lock); init_completion(&fg->soc_update); init_completion(&fg->soc_ready); init_completion(&chip->mem_attn); INIT_WORK(&fg->status_change_work, status_change_work); INIT_WORK(&chip->esr_calib_work, esr_calib_work); INIT_WORK(&chip->soc_scale_work, soc_scale_work); INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); Loading Loading @@ -5353,6 +5727,17 @@ static int fg_gen4_probe(struct platform_device *pdev) } } if (chip->dt.soc_scale_mode) { if (alarmtimer_get_rtcdev()) { alarm_init(&chip->soc_scale_alarm_timer, ALARM_BOOTTIME, fg_soc_scale_timer); } else { dev_err(fg->dev, "Failed to initialize SOC scale timer\n"); rc = -EPROBE_DEFER; goto exit; } } rc = fg_memif_init(fg); if (rc < 0) { dev_err(fg->dev, "Error in initializing FG_MEMIF, rc:%d\n", Loading Loading @@ -5475,6 +5860,9 @@ static void fg_gen4_shutdown(struct platform_device *pdev) fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); if (chip->soc_scale_mode) fg_gen4_exit_soc_scale(chip); if (chip->rapid_soc_dec_en) { rc = fg_gen4_rapid_soc_config(chip, false); if (rc < 0) Loading