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

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

power: qpnp-fg-gen3: Improve the accuracy of charge_counter



Currently, charge_counter is based off CC_SOC_SW which is based
off coulomb counter. However, there could be some accumulation
of error due to inaccuracy in ADC over time. This can potentially
affect the accuracy of charge_counter. To overcome this, prime
CC_SOC_SW during discharging based off battery SOC and to a full
value during charge termination.

While at it, expose the charge_counter_shadow property based off
battery SOC for comparison.

CRs-Fixed: 2109421
Change-Id: I50de44afbdbd747db95946416a09062df205fd6c
Signed-off-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
parent d475978a
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -412,6 +412,7 @@ struct fg_chip {
	int			batt_id_ohms;
	int			batt_id_ohms;
	int			ki_coeff_full_soc;
	int			ki_coeff_full_soc;
	int			charge_status;
	int			charge_status;
	int			prev_charge_status;
	int			charge_done;
	int			charge_done;
	int			charge_type;
	int			charge_type;
	int			online_status;
	int			online_status;
+68 −11
Original line number Original line Diff line number Diff line
@@ -562,6 +562,21 @@ static int fg_get_charge_raw(struct fg_chip *chip, int *val)
	return 0;
	return 0;
}
}


#define BATT_SOC_32BIT	GENMASK(31, 0)
static int fg_get_charge_counter_shadow(struct fg_chip *chip, int *val)
{
	int rc, batt_soc;

	rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
	if (rc < 0) {
		pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
		return rc;
	}

	*val = div_u64((u32)batt_soc * chip->cl.learned_cc_uah, BATT_SOC_32BIT);
	return 0;
}

static int fg_get_charge_counter(struct fg_chip *chip, int *val)
static int fg_get_charge_counter(struct fg_chip *chip, int *val)
{
{
	int rc, cc_soc;
	int rc, cc_soc;
@@ -1249,6 +1264,21 @@ static bool is_parallel_charger_available(struct fg_chip *chip)
	return true;
	return true;
}
}


static int fg_prime_cc_soc_sw(struct fg_chip *chip, int cc_soc_sw)
{
	int rc;

	rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
		chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
		chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
	if (rc < 0)
		pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
	else
		fg_dbg(chip, FG_STATUS, "cc_soc_sw: %x\n", cc_soc_sw);

	return rc;
}

static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
static int fg_save_learned_cap_to_sram(struct fg_chip *chip)
{
{
	int16_t cc_mah;
	int16_t cc_mah;
@@ -1434,7 +1464,6 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip)
	return 0;
	return 0;
}
}


#define BATT_SOC_32BIT	GENMASK(31, 0)
static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
{
{
	int rc, cc_soc_sw, batt_soc_msb;
	int rc, cc_soc_sw, batt_soc_msb;
@@ -1453,16 +1482,13 @@ static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
	/* Prime cc_soc_sw with battery SOC when capacity learning begins */
	/* Prime cc_soc_sw with battery SOC when capacity learning begins */
	cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
	cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
				BATT_SOC_32BIT);
				BATT_SOC_32BIT);
	rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
	rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
		chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
		chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
		pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
		goto out;
		goto out;
	}
	}


	chip->cl.init_cc_soc_sw = cc_soc_sw;
	chip->cl.init_cc_soc_sw = cc_soc_sw;
	chip->cl.active = true;
	fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n",
	fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n",
		batt_soc_msb, chip->cl.init_cc_soc_sw);
		batt_soc_msb, chip->cl.init_cc_soc_sw);
out:
out:
@@ -1482,9 +1508,7 @@ static int fg_cap_learning_done(struct fg_chip *chip)


	/* Write a FULL value to cc_soc_sw */
	/* Write a FULL value to cc_soc_sw */
	cc_soc_sw = CC_SOC_30BIT;
	cc_soc_sw = CC_SOC_30BIT;
	rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
	rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
		chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
		chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
		pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
		goto out;
		goto out;
@@ -1497,8 +1521,9 @@ out:


static void fg_cap_learning_update(struct fg_chip *chip)
static void fg_cap_learning_update(struct fg_chip *chip)
{
{
	int rc, batt_soc, batt_soc_msb;
	int rc, batt_soc, batt_soc_msb, cc_soc_sw;
	bool input_present = is_input_present(chip);
	bool input_present = is_input_present(chip);
	bool prime_cc = false;


	mutex_lock(&chip->cl.lock);
	mutex_lock(&chip->cl.lock);


@@ -1511,6 +1536,9 @@ static void fg_cap_learning_update(struct fg_chip *chip)
		goto out;
		goto out;
	}
	}


	if (chip->charge_status == chip->prev_charge_status)
		goto out;

	rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
	rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
		pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
@@ -1526,8 +1554,12 @@ static void fg_cap_learning_update(struct fg_chip *chip)
		if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
		if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
			rc = fg_cap_learning_begin(chip, batt_soc);
			rc = fg_cap_learning_begin(chip, batt_soc);
			chip->cl.active = (rc == 0);
			chip->cl.active = (rc == 0);
		} else {
			if ((chip->charge_status ==
					POWER_SUPPLY_STATUS_DISCHARGING) ||
					chip->charge_done)
				prime_cc = true;
		}
		}

	} else {
	} else {
		if (chip->charge_done) {
		if (chip->charge_done) {
			rc = fg_cap_learning_done(chip);
			rc = fg_cap_learning_done(chip);
@@ -1545,6 +1577,7 @@ static void fg_cap_learning_update(struct fg_chip *chip)
					 batt_soc_msb);
					 batt_soc_msb);
				chip->cl.active = false;
				chip->cl.active = false;
				chip->cl.init_cc_uah = 0;
				chip->cl.init_cc_uah = 0;
				prime_cc = true;
			}
			}
		}
		}


@@ -1561,8 +1594,27 @@ static void fg_cap_learning_update(struct fg_chip *chip)
					batt_soc_msb);
					batt_soc_msb);
				chip->cl.active = false;
				chip->cl.active = false;
				chip->cl.init_cc_uah = 0;
				chip->cl.init_cc_uah = 0;
				prime_cc = true;
			}
		}
		}
	}
	}

	/*
	 * Prime CC_SOC_SW when the device is not charging or during charge
	 * termination when the capacity learning is not active.
	 */

	if (prime_cc) {
		if (chip->charge_done)
			cc_soc_sw = CC_SOC_30BIT;
		else
			cc_soc_sw = div_u64((u32)batt_soc *
					CC_SOC_30BIT, BATT_SOC_32BIT);

		rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
		if (rc < 0)
			pr_err("Error in writing cc_soc_sw, rc=%d\n",
				rc);
	}
	}


out:
out:
@@ -2564,7 +2616,7 @@ static void status_change_work(struct work_struct *work)
	}
	}


	fg_ttf_update(chip);
	fg_ttf_update(chip);

	chip->prev_charge_status = chip->charge_status;
out:
out:
	fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
	fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
		chip->charge_status, chip->charge_type, chip->charge_done);
		chip->charge_status, chip->charge_type, chip->charge_done);
@@ -3553,6 +3605,9 @@ static int fg_psy_get_property(struct power_supply *psy,
	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
		rc = fg_get_charge_counter(chip, &pval->intval);
		rc = fg_get_charge_counter(chip, &pval->intval);
		break;
		break;
	case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW:
		rc = fg_get_charge_counter_shadow(chip, &pval->intval);
		break;
	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
	case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
		rc = fg_get_time_to_full(chip, &pval->intval);
		rc = fg_get_time_to_full(chip, &pval->intval);
		break;
		break;
@@ -3762,6 +3817,7 @@ static enum power_supply_property fg_psy_props[] = {
	POWER_SUPPLY_PROP_CHARGE_NOW,
	POWER_SUPPLY_PROP_CHARGE_NOW,
	POWER_SUPPLY_PROP_CHARGE_FULL,
	POWER_SUPPLY_PROP_CHARGE_FULL,
	POWER_SUPPLY_PROP_CHARGE_COUNTER,
	POWER_SUPPLY_PROP_CHARGE_COUNTER,
	POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
	POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
	POWER_SUPPLY_PROP_SOC_REPORTING_READY,
	POWER_SUPPLY_PROP_SOC_REPORTING_READY,
@@ -4958,6 +5014,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
	chip->debug_mask = &fg_gen3_debug_mask;
	chip->debug_mask = &fg_gen3_debug_mask;
	chip->irqs = fg_irqs;
	chip->irqs = fg_irqs;
	chip->charge_status = -EINVAL;
	chip->charge_status = -EINVAL;
	chip->prev_charge_status = -EINVAL;
	chip->ki_coeff_full_soc = -EINVAL;
	chip->ki_coeff_full_soc = -EINVAL;
	chip->online_status = -EINVAL;
	chip->online_status = -EINVAL;
	chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
	chip->regmap = dev_get_regmap(chip->dev->parent, NULL);