Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8667822 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: qpnp-fg-gen4: Add support for SW based SOC scaling"

parents d7cbdcff d8342857
Loading
Loading
Loading
Loading
+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__
@@ -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,
@@ -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,
+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>
@@ -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)
{
+421 −33
Original line number Diff line number Diff line
@@ -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
@@ -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];
@@ -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];
@@ -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;
@@ -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 {
@@ -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),
@@ -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,
@@ -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,
@@ -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;
}
@@ -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)
@@ -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)
@@ -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)
@@ -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);
		}
	}

@@ -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);

@@ -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,
@@ -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:
@@ -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;
@@ -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;
@@ -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,
@@ -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 = {
@@ -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;
@@ -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,
@@ -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)
@@ -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;
}

@@ -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)
{
@@ -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",
@@ -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);
@@ -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);
@@ -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);
@@ -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",
@@ -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)