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

Commit b174bcb2 authored by Subbaraman Narayanamurthy's avatar Subbaraman Narayanamurthy
Browse files

power: qpnp-fg: improve capacity learning algorithm



Currently, when the battery missing event happens, capacity
learning algorithm doesn't handle that scenario. This can cause
unexpected processing and storing of learned capacity. Skip this
by checking battery missing condition at every step of capacity
learning algorithm.

In addition, if a bad capacity was stored before, detect that by
validating against nominal capacity which comes from the battery
profile. If the learned capacity deviates from nominal capacity
by a certain percentage (e.g. 50%), then use the nominal capacity
instead of the learned capacity.

CRs-Fixed: 977878
Change-Id: I8f47fdf5da216789f6b6f0fccf2fb66ceb618b9b
Signed-off-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
parent b5417217
Loading
Loading
Loading
Loading
+72 −22
Original line number Diff line number Diff line
@@ -3006,11 +3006,34 @@ static int fg_get_cc_soc(struct fg_chip *chip, int *cc_soc)
	return 0;
}

#define BATT_MISSING_STS BIT(6)
static bool is_battery_missing(struct fg_chip *chip)
{
	int rc;
	u8 fg_batt_sts;

	rc = fg_read(chip, &fg_batt_sts,
				 INT_RT_STS(chip->batt_base), 1);
	if (rc) {
		pr_err("spmi read failed: addr=%03X, rc=%d\n",
				INT_RT_STS(chip->batt_base), rc);
		return false;
	}

	return (fg_batt_sts & BATT_MISSING_STS) ? true : false;
}

static int fg_cap_learning_process_full_data(struct fg_chip *chip)
{
	int cc_pc_val, rc = -EINVAL;
	unsigned int cc_soc_delta_pc;
	int64_t delta_cc_uah;
	bool batt_missing = is_battery_missing(chip);

	if (batt_missing) {
		pr_err("Battery is missing!\n");
		goto fail;
	}

	if (!chip->learning_data.active)
		goto fail;
@@ -3131,6 +3154,12 @@ static void fg_cap_learning_save_data(struct fg_chip *chip)
{
	int16_t cc_mah;
	int rc;
	bool batt_missing = is_battery_missing(chip);

	if (batt_missing) {
		pr_err("Battery is missing!\n");
		return;
	}

	cc_mah = div64_s64(chip->learning_data.learned_cc_uah, 1000);

@@ -3152,6 +3181,12 @@ static void fg_cap_learning_save_data(struct fg_chip *chip)
static void fg_cap_learning_post_process(struct fg_chip *chip)
{
	int64_t max_inc_val, min_dec_val, old_cap;
	bool batt_missing = is_battery_missing(chip);

	if (batt_missing) {
		pr_err("Battery is missing!\n");
		return;
	}

	max_inc_val = chip->learning_data.learned_cc_uah
			* (1000 + chip->learning_data.max_increment);
@@ -3229,7 +3264,7 @@ static int fg_cap_learning_check(struct fg_chip *chip)
		if (battery_soc * 100 / FULL_PERCENT_3B
				> chip->learning_data.max_start_soc) {
			if (fg_debug_mask & FG_AGING)
				pr_info("battery soc too low (%d < %d), aborting\n",
				pr_info("battery soc too high (%d > %d), aborting\n",
					battery_soc * 100 / FULL_PERCENT_3B,
					chip->learning_data.max_start_soc);
			fg_mem_release(chip);
@@ -3414,6 +3449,13 @@ static void status_change_work(struct work_struct *work)
				status_change_work);
	unsigned long current_time = 0;
	int cc_soc, rc, capacity = get_prop_capacity(chip);
	bool batt_missing = is_battery_missing(chip);

	if (batt_missing) {
		if (fg_debug_mask & FG_STATUS)
			pr_info("Battery is missing\n");
		return;
	}

	if (chip->esr_pulse_tune_en) {
		fg_stay_awake(&chip->esr_extract_wakeup_source);
@@ -3912,23 +3954,6 @@ done:
	fg_relax(&chip->gain_comp_wakeup_source);
}

#define BATT_MISSING_STS BIT(6)
static bool is_battery_missing(struct fg_chip *chip)
{
	int rc;
	u8 fg_batt_sts;

	rc = fg_read(chip, &fg_batt_sts,
				 INT_RT_STS(chip->batt_base), 1);
	if (rc) {
		pr_err("spmi read failed: addr=%03X, rc=%d\n",
				INT_RT_STS(chip->batt_base), rc);
		return false;
	}

	return (fg_batt_sts & BATT_MISSING_STS) ? true : false;
}

#define SOC_FIRST_EST_DONE	BIT(5)
static bool is_first_est_done(struct fg_chip *chip)
{
@@ -3981,6 +4006,7 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *_chip)
	bool batt_missing = is_battery_missing(chip);

	if (batt_missing) {
		fg_cap_learning_stop(chip);
		chip->battery_missing = true;
		chip->profile_loaded = false;
		chip->batt_type = default_batt_type;
@@ -4227,11 +4253,13 @@ done:
#define RSLOW_COMP_REG			0x528
#define RSLOW_COMP_C1_OFFSET		0
#define RSLOW_COMP_C2_OFFSET		2
#define CAPACITY_DELTA_DECIPCT		500
static int populate_system_data(struct fg_chip *chip)
{
	u8 buffer[24];
	int rc, i;
	int16_t cc_mah;
	int64_t delta_cc_uah, pct_nom_cap_uah;

	fg_mem_lock(chip);
	rc = fg_mem_read(chip, buffer, OCV_COEFFS_START_REG, 24, 0, 0);
@@ -4271,10 +4299,32 @@ static int populate_system_data(struct fg_chip *chip)
		chip->learning_data.learned_cc_uah = chip->nom_cap_uah;
		fg_cap_learning_save_data(chip);
	} else if (chip->learning_data.feedback_on) {
		cc_mah = div64_s64(chip->learning_data.learned_cc_uah, 1000);
		delta_cc_uah = abs(chip->learning_data.learned_cc_uah -
					chip->nom_cap_uah);
		pct_nom_cap_uah = div64_s64((int64_t)chip->nom_cap_uah *
				CAPACITY_DELTA_DECIPCT, 1000);
		/*
		 * If the learned capacity is out of range, say by 50%
		 * from the nominal capacity, then overwrite the learned
		 * capacity with the nominal capacity.
		 */
		if (chip->nom_cap_uah && delta_cc_uah > pct_nom_cap_uah) {
			if (fg_debug_mask & FG_AGING) {
				pr_info("learned_cc_uah: %lld is higher than expected\n",
					chip->learning_data.learned_cc_uah);
				pr_info("Capping it to nominal:%d\n",
					chip->nom_cap_uah);
			}
			chip->learning_data.learned_cc_uah = chip->nom_cap_uah;
			fg_cap_learning_save_data(chip);
		} else {
			cc_mah = div64_s64(chip->learning_data.learned_cc_uah,
					1000);
			rc = fg_calc_and_store_cc_soc_coeff(chip, cc_mah);
			if (rc)
			pr_err("Error in restoring cc_soc_coeff, rc:%d\n", rc);
				pr_err("Error in restoring cc_soc_coeff, rc:%d\n",
					rc);
		}
	}
	rc = fg_mem_read(chip, buffer, CUTOFF_VOLTAGE_REG, 2, 0, 0);
	if (rc) {