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

Commit 784bd5bb authored by Subbaraman Narayanamurthy's avatar Subbaraman Narayanamurthy
Browse files

qpnp-fg-gen3: configure ESR timers dynamically based on charge termination



With ESR discharge timer retry, max having same value, ESR pulse
can fire frequently when battery FET is open past charge
termination. This frequent ESR pulses increase power consumption
when the device is idle.

Upon charge termination, change the ESR discharging timer retry
to 0 so that ESR pulse can fire less frequently saving power.

Add support for this through fg_esr_timer_config() based on end
of charge and sleep conditions.

Currently, retry/max for ESR charging and discharging timers are
configured with the same value specified through device tree.
Extend the device tree property to take in different retry/max
values for those timers.

Change-Id: Ib30b8ae7d893b5cab00ed83dd7318b53e3b63ac1
Signed-off-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
parent 6a9b4102
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -145,22 +145,30 @@ First Level Node - FG Gen3 device

- qcom,fg-esr-timer-charging
	Usage:      optional
	Value type: <u32>
	Value type: <prop-encoded-array>
	Definition: Number of cycles between ESR pulses while the battery is
		    charging.
		    charging. Array of 2 elements if specified.
		    Element 0 - Retry value for timer
		    Element 1 - Maximum value for timer

- qcom,fg-esr-timer-awake
	Usage:      optional
	Value type: <u32>
	Value type: <prop-encoded-array>
	Definition: Number of cycles between ESR pulses while the system is
		    awake and the battery is discharging.
		    awake and the battery is discharging. Array of 2 elements
		    if specified.
		    Element 0 - Retry value for timer
		    Element 1 - Maximum value for timer

- qcom,fg-esr-timer-asleep
	Usage:      optional
	Value type: <u32>
	Value type: <prop-encoded-array>
	Definition: Number of cycles between ESR pulses while the system is
		    asleep and the battery is discharging. This option requires
		    qcom,fg-esr-timer-awake to be defined.
		    qcom,fg-esr-timer-awake to be defined. Array of 2 elements
		    if specified.
		    Element 0 - Retry value for timer
		    Element 1 - Maximum value for timer

- qcom,fg-esr-pulse-thresh-ma
	Usage:      optional
+3 −2
Original line number Diff line number Diff line
@@ -270,8 +270,9 @@
			io-channels = <&pmi8998_rradc 0>;
			io-channel-names = "rradc_batt_id";
			qcom,rradc-base = <0x4500>;
			qcom,fg-esr-timer-awake = <96>;
			qcom,fg-esr-timer-asleep = <256>;
			qcom,fg-esr-timer-awake = <96 96>;
			qcom,fg-esr-timer-asleep = <256 256>;
			qcom,fg-esr-timer-charging = <0 96>;
			qcom,cycle-counter-en;
			status = "okay";

+10 −3
Original line number Diff line number Diff line
@@ -219,6 +219,12 @@ enum slope_limit_status {
	SLOPE_LIMIT_NUM_COEFFS,
};

enum esr_timer_config {
	TIMER_RETRY = 0,
	TIMER_MAX,
	NUM_ESR_TIMERS,
};

/* DT parameters for FG device */
struct fg_dt_props {
	bool	force_load_profile;
@@ -234,9 +240,9 @@ struct fg_dt_props {
	int	recharge_soc_thr;
	int	recharge_volt_thr_mv;
	int	rsense_sel;
	int	esr_timer_charging;
	int	esr_timer_awake;
	int	esr_timer_asleep;
	int	esr_timer_charging[NUM_ESR_TIMERS];
	int	esr_timer_awake[NUM_ESR_TIMERS];
	int	esr_timer_asleep[NUM_ESR_TIMERS];
	int	rconn_mohms;
	int	esr_clamp_mohms;
	int	cl_start_soc;
@@ -385,6 +391,7 @@ struct fg_chip {
	int			maint_soc;
	int			delta_soc;
	int			last_msoc;
	int			esr_timer_charging_default[NUM_ESR_TIMERS];
	enum slope_limit_status	slope_limit_sts;
	bool			profile_available;
	bool			profile_loaded;
+142 −94
Original line number Diff line number Diff line
@@ -1025,12 +1025,15 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val)
	*val <<= ESR_PULL_DOWN_IVAL_SHIFT;
}

static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
				int flags)
static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init,
				int cycles_max, bool charging, int flags)
{
	u8 buf[2];
	int rc, timer_max, timer_init;

	if (cycles_init < 0 || cycles_max < 0)
		return 0;

	if (charging) {
		timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
		timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
@@ -1039,7 +1042,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
		timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
	}

	fg_encode(chip->sp, timer_max, cycles, buf);
	fg_encode(chip->sp, timer_max, cycles_max, buf);
	rc = fg_sram_write(chip,
			chip->sp[timer_max].addr_word,
			chip->sp[timer_max].addr_byte, buf,
@@ -1050,7 +1053,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
		return rc;
	}

	fg_encode(chip->sp, timer_init, cycles, buf);
	fg_encode(chip->sp, timer_init, cycles_init, buf);
	rc = fg_sram_write(chip,
			chip->sp[timer_init].addr_word,
			chip->sp[timer_init].addr_byte, buf,
@@ -1061,6 +1064,8 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
		return rc;
	}

	fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n",
		charging ? "charging" : "discharging", cycles_init, cycles_max);
	return 0;
}

@@ -2039,6 +2044,50 @@ static int fg_esr_fcc_config(struct fg_chip *chip)
	return 0;
}

static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
{
	int rc, cycles_init, cycles_max;
	bool end_of_charge = false;

	end_of_charge = is_input_present(chip) && chip->charge_done;
	fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);

	/* ESR discharging timer configuration */
	cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
			chip->dt.esr_timer_awake[TIMER_RETRY];
	if (end_of_charge)
		cycles_init = 0;

	cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
			chip->dt.esr_timer_awake[TIMER_MAX];

	rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
		sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
	if (rc < 0) {
		pr_err("Error in setting ESR timer, rc=%d\n", rc);
		return rc;
	}

	/* ESR charging timer configuration */
	cycles_init = cycles_max = -EINVAL;
	if (end_of_charge || sleep) {
		cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
		cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
	} else if (is_input_present(chip)) {
		cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
		cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
	}

	rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
		sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
	if (rc < 0) {
		pr_err("Error in setting ESR timer, rc=%d\n", rc);
		return rc;
	}

	return 0;
}

static void fg_batt_avg_update(struct fg_chip *chip)
{
	if (chip->charge_status == chip->prev_charge_status)
@@ -2112,6 +2161,10 @@ static void status_change_work(struct work_struct *work)
	if (rc < 0)
		pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);

	rc = fg_esr_timer_config(chip, false);
	if (rc < 0)
		pr_err("Error in configuring ESR timer, rc=%d\n", rc);

	rc = fg_get_battery_temp(chip, &batt_temp);
	if (!rc) {
		rc = fg_slope_limit_config(chip, batt_temp);
@@ -3115,6 +3168,8 @@ static const struct power_supply_desc fg_psy_desc = {

/* INIT FUNCTIONS STAY HERE */

#define DEFAULT_ESR_CHG_TIMER_RETRY	8
#define DEFAULT_ESR_CHG_TIMER_MAX	16
static int fg_hw_init(struct fg_chip *chip)
{
	int rc;
@@ -3283,23 +3338,30 @@ static int fg_hw_init(struct fg_chip *chip)
		return rc;
	}

	if (chip->dt.esr_timer_charging > 0) {
		rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging, true,
				      FG_IMA_DEFAULT);
	if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
		chip->esr_timer_charging_default[TIMER_RETRY] =
			DEFAULT_ESR_CHG_TIMER_RETRY;
		chip->esr_timer_charging_default[TIMER_MAX] =
			DEFAULT_ESR_CHG_TIMER_MAX;
	} else {
		/* We don't need this for pm660 at present */
		chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
		chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
	}

	rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
		chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
	if (rc < 0) {
		pr_err("Error in setting ESR timer, rc=%d\n", rc);
		return rc;
	}
	}

	if (chip->dt.esr_timer_awake > 0) {
		rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false,
				      FG_IMA_DEFAULT);
	rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
		chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
	if (rc < 0) {
		pr_err("Error in setting ESR timer, rc=%d\n", rc);
		return rc;
	}
	}

	if (chip->cyc_ctr.en)
		restore_cycle_counter(chip);
@@ -3778,6 +3840,32 @@ static int fg_register_interrupts(struct fg_chip *chip)
	return 0;
}

static int fg_parse_dt_property_u32_array(struct device_node *node,
				const char *prop_name, int *buf, int len)
{
	int rc;

	rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
	if (rc < 0) {
		if (rc == -EINVAL)
			return 0;
		else
			return rc;
	} else if (rc != len) {
		pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
			rc);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(node, prop_name, buf, len);
	if (rc < 0) {
		pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
		return rc;
	}

	return 0;
}

static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
{
	struct device_node *node = chip->dev->of_node;
@@ -3788,17 +3876,10 @@ static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
	if (rc < 0)
		return 0;

	rc = of_property_count_elems_of_size(node, "qcom,slope-limit-coeffs",
			sizeof(u32));
	if (rc != SLOPE_LIMIT_NUM_COEFFS)
		return -EINVAL;

	rc = of_property_read_u32_array(node, "qcom,slope-limit-coeffs",
	rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
		chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
	if (rc < 0) {
		pr_err("Error in reading qcom,slope-limit-coeffs, rc=%d\n", rc);
	if (rc < 0)
		return rc;
	}

	for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
		if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
@@ -3817,44 +3898,20 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip)
	struct device_node *node = chip->dev->of_node;
	int rc, i;

	rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-soc-dischg",
		sizeof(u32));
	if (rc != KI_COEFF_SOC_LEVELS)
		return 0;

	rc = of_property_read_u32_array(node, "qcom,ki-coeff-soc-dischg",
	rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
		chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
	if (rc < 0) {
		pr_err("Error in reading ki-coeff-soc-dischg, rc=%d\n",
			rc);
	if (rc < 0)
		return rc;
	}

	rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-med-dischg",
		sizeof(u32));
	if (rc != KI_COEFF_SOC_LEVELS)
		return 0;

	rc = of_property_read_u32_array(node, "qcom,ki-coeff-med-dischg",
	rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
		chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
	if (rc < 0) {
		pr_err("Error in reading ki-coeff-med-dischg, rc=%d\n",
			rc);
	if (rc < 0)
		return rc;
	}

	rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-hi-dischg",
		sizeof(u32));
	if (rc != KI_COEFF_SOC_LEVELS)
		return 0;

	rc = of_property_read_u32_array(node, "qcom,ki-coeff-hi-dischg",
	rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
		chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
	if (rc < 0) {
		pr_err("Error in reading ki-coeff-hi-dischg, rc=%d\n",
			rc);
	if (rc < 0)
		return rc;
	}

	for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
		if (chip->dt.ki_coeff_soc[i] < 0 ||
@@ -4099,23 +4156,26 @@ static int fg_parse_dt(struct fg_chip *chip)
				rc);
	}

	rc = of_property_read_u32(node, "qcom,fg-esr-timer-charging", &temp);
	if (rc < 0)
		chip->dt.esr_timer_charging = -EINVAL;
	else
		chip->dt.esr_timer_charging = temp;
	rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
		chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
	if (rc < 0) {
		chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
		chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
	}

	rc = of_property_read_u32(node, "qcom,fg-esr-timer-awake", &temp);
	if (rc < 0)
		chip->dt.esr_timer_awake = -EINVAL;
	else
		chip->dt.esr_timer_awake = temp;
	rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
		chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
	if (rc < 0) {
		chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
		chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
	}

	rc = of_property_read_u32(node, "qcom,fg-esr-timer-asleep", &temp);
	if (rc < 0)
		chip->dt.esr_timer_asleep = -EINVAL;
	else
		chip->dt.esr_timer_asleep = temp;
	rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
		chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
	if (rc < 0) {
		chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
		chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
	}

	chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
	if (chip->cyc_ctr.en)
@@ -4453,15 +4513,9 @@ static int fg_gen3_suspend(struct device *dev)
	struct fg_chip *chip = dev_get_drvdata(dev);
	int rc;

	if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) {
		rc = fg_set_esr_timer(chip, chip->dt.esr_timer_asleep, false,
				      FG_IMA_NO_WLOCK);
		if (rc < 0) {
			pr_err("Error in setting ESR timer during suspend, rc=%d\n",
			       rc);
			return rc;
		}
	}
	rc = fg_esr_timer_config(chip, true);
	if (rc < 0)
		pr_err("Error in configuring ESR timer, rc=%d\n", rc);

	cancel_delayed_work_sync(&chip->batt_avg_work);
	if (fg_sram_dump)
@@ -4474,15 +4528,9 @@ static int fg_gen3_resume(struct device *dev)
	struct fg_chip *chip = dev_get_drvdata(dev);
	int rc;

	if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) {
		rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false,
				      FG_IMA_DEFAULT);
		if (rc < 0) {
			pr_err("Error in setting ESR timer during resume, rc=%d\n",
			       rc);
			return rc;
		}
	}
	rc = fg_esr_timer_config(chip, false);
	if (rc < 0)
		pr_err("Error in configuring ESR timer, rc=%d\n", rc);

	fg_circ_buf_clr(&chip->ibatt_circ_buf);
	fg_circ_buf_clr(&chip->vbatt_circ_buf);