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

Commit 6793aa21 authored by Xiaozhe Shi's avatar Xiaozhe Shi
Browse files

power: qpnp-fg: reload profile if vbat differs from predicted



Sometimes, the saved fuel gauge SOC will not match the actual battery
SOC due to temperature and charge escaping over time. In this case the
fuel gauge driver should redo the first SOC estimate in order to get a
better starting point.

Reload the profile in order to get a better SOC estimate if the
vbat_current_predicted differs from the actual vbat by more than a set
threshold.

CRs-Fixed: 771347
Change-Id: I6604a762a8811a600260f9b37e5389ce30e0c52c
Signed-off-by: default avatarXiaozhe Shi <xiaozhes@codeaurora.org>
parent d330d0af
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -71,6 +71,12 @@ Parent node optional properties:
					the fuel gauge will try to count SoC so
					that the battery SoC will be 0 when it
					is 3400mV.
- qcom,fg-vbat-estimate-diff-mv:	If the estimated voltage based on SoC
					and battery current/resistance differs
					from the actual voltage by more than
					this amount, the fuel gauge will
					redo the first SoC estimate when the
					driver probes.

qcom,fg-soc node required properties:
- reg : offset and length of the PMIC peripheral register map.
+36 −14
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ enum fg_mem_setting_index {
	FG_MEM_TERM_CURRENT,
	FG_MEM_IRQ_VOLT_EMPTY,
	FG_MEM_CUTOFF_VOLTAGE,
	FG_MEM_VBAT_EST_DIFF,
	FG_MEM_SETTING_MAX,
};

@@ -132,6 +133,8 @@ enum fg_mem_data_index {
	FG_DATA_CURRENT,
	FG_DATA_BATT_ESR,
	FG_DATA_BATT_ESR_COUNT,
	/* values below this only gets read once per profile reload */
	FG_DATA_CPRED_VOLTAGE,
	FG_DATA_BATT_ID,
	FG_DATA_BATT_ID_INFO,
	FG_DATA_MAX,
@@ -156,6 +159,7 @@ static struct fg_mem_setting settings[FG_MEM_SETTING_MAX] = {
	SETTING(TERM_CURRENT,	 0x40C,   2,      250),
	SETTING(IRQ_VOLT_EMPTY,	 0x458,   3,      3350),
	SETTING(CUTOFF_VOLTAGE,	 0x40C,   0,      3400),
	SETTING(VBAT_EST_DIFF,	 0x000,   0,      30),
};

#define DATA(_idx, _address, _offset, _length,  _value)	\
@@ -174,6 +178,7 @@ static struct fg_mem_data fg_data[FG_DATA_MAX] = {
	DATA(CURRENT,         0x5CC,   3,      2,     -EINVAL),
	DATA(BATT_ESR,        0x554,   2,      2,     -EINVAL),
	DATA(BATT_ESR_COUNT,  0x558,   2,      2,     -EINVAL),
	DATA(CPRED_VOLTAGE,   0x540,   0,      2,     -EINVAL),
	DATA(BATT_ID,         0x594,   1,      1,     -EINVAL),
	DATA(BATT_ID_INFO,    0x594,   3,      1,     -EINVAL),
};
@@ -274,6 +279,7 @@ struct fg_chip {
	struct power_supply	*batt_psy;
	struct fg_wakeup_source	memif_wakeup_source;
	struct fg_wakeup_source	profile_wakeup_source;
	bool			first_profile_loaded;
	bool			profile_loaded;
	bool			use_otp_profile;
	bool			battery_missing;
@@ -1178,6 +1184,8 @@ static void update_sram_data(struct fg_chip *chip, int *resched_ms)
	int battid_valid = fg_is_batt_id_valid(chip);

	for (i = 1; i < FG_DATA_MAX; i++) {
		if (chip->profile_loaded && i >= FG_DATA_CPRED_VOLTAGE)
			continue;
		rc = fg_mem_read(chip, reg, fg_data[i].address,
			fg_data[i].len, fg_data[i].offset,
			(i+1 == FG_DATA_MAX) ? 0 : 1);
@@ -1192,6 +1200,7 @@ static void update_sram_data(struct fg_chip *chip, int *resched_ms)
		switch (i) {
		case FG_DATA_OCV:
		case FG_DATA_VOLTAGE:
		case FG_DATA_CPRED_VOLTAGE:
			fg_data[i].value = div_u64(
					(u64)(u16)temp * LSB_16B_NUMRTR,
					LSB_16B_DENMTR);
@@ -1549,6 +1558,7 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *_chip)

	if (batt_missing) {
		chip->battery_missing = true;
		chip->profile_loaded = false;
		chip->batt_type = missing_batt_type;
	} else {
		if (!chip->use_otp_profile) {
@@ -1651,6 +1661,10 @@ do { \
				" property rc = %d\n", rc);		\
} while (0)

#define V_PREDICTED_ADDR		0x540
#define V_CURRENT_PREDICTED_OFFSET	0


#define LOW_LATENCY	BIT(6)
#define PROFILE_LOAD_TIMEOUT_MS		5000
#define BATT_PROFILE_OFFSET		0x4C0
@@ -1666,7 +1680,7 @@ static int fg_batt_profile_init(struct fg_chip *chip)
	struct device_node *node = chip->spmi->dev.of_node;
	struct device_node *batt_node, *profile_node;
	const char *data, *batt_type_str, *old_batt_type;
	bool tried_again = false;
	bool tried_again = false, vbat_in_range;
	u8 reg = 0;

wait:
@@ -1744,16 +1758,23 @@ wait:
		goto no_profile;
	}

	if ((reg & PROFILE_INTEGRITY_BIT)
	vbat_in_range = abs(fg_data[FG_DATA_VOLTAGE].value
				- fg_data[FG_DATA_CPRED_VOLTAGE].value)
				< settings[FG_MEM_VBAT_EST_DIFF].value * 1000;
	if ((reg & PROFILE_INTEGRITY_BIT) && vbat_in_range
			&& memcmp(chip->batt_profile, data, len - 4) == 0) {
		if (fg_debug_mask & FG_STATUS)
			pr_info("Battery profiles same, using default\n");
		if (fg_est_dump)
			schedule_work(&chip->dump_sram);
		goto done;
	} else {
	}
	if ((fg_debug_mask & FG_STATUS) && !vbat_in_range)
		pr_info("Vbat out of range: v_current_pred: %d, v:%d\n",
				fg_data[FG_DATA_CPRED_VOLTAGE].value,
				fg_data[FG_DATA_VOLTAGE].value);
	if (fg_debug_mask & FG_STATUS) {
			pr_info("Battery profiles differ, using new profile\n");
		pr_info("Using new profile\n");
		print_hex_dump(KERN_INFO, "FG: loaded profile: ",
				DUMP_PREFIX_NONE, 16, 1,
				chip->batt_profile, len, false);
@@ -1762,7 +1783,6 @@ wait:
	chip->batt_type = loading_batt_type;
	if (chip->power_supply_registered)
		power_supply_changed(&chip->bms_psy);
	}

	memcpy(chip->batt_profile, data, len);

@@ -1815,7 +1835,7 @@ wait:
	 * If this is not the first time a profile has been loaded, sleep for
	 * 3 seconds to make sure the NO_OTP_RELOAD is cleared in memory
	 */
	if (chip->profile_loaded)
	if (chip->first_profile_loaded)
		msleep(3000);

	mutex_lock(&chip->rw_lock);
@@ -1904,6 +1924,7 @@ done:
		chip->batt_type = fg_batt_type;
	else
		chip->batt_type = batt_type_str;
	chip->first_profile_loaded = true;
	chip->profile_loaded = true;
	chip->battery_missing = is_battery_missing(chip);
	if (chip->power_supply_registered)
@@ -2038,6 +2059,7 @@ static int fg_of_init(struct fg_chip *chip)
	}
	OF_READ_SETTING(FG_MEM_RESUME_SOC, "resume-soc", rc, 1);
	OF_READ_SETTING(FG_MEM_IRQ_VOLT_EMPTY, "irq-volt-empty-mv", rc, 1);
	OF_READ_SETTING(FG_MEM_VBAT_EST_DIFF, "vbat-estimate-diff-mv", rc, 1);

	/* Get the use-otp-profile property */
	chip->use_otp_profile = of_property_read_bool(