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

Commit eabd2e60 authored by Anirudh Ghayal's avatar Anirudh Ghayal
Browse files

power: fg-alg: Use batt_soc centi-percentage for CL calculations



The CL calculations currently use a 0-255 value of battery-SOC.
This adds to some inaccuracy in the learned capacity. Fix this
by using the centi-percentage value of battery SOC.

Change-Id: I9b07e5fb32f4bfc814337224bf41d44043603744
Signed-off-by: default avatarAnirudh Ghayal <aghayal@codeaurora.org>
parent 69208a86
Loading
Loading
Loading
Loading
+47 −40
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

#define FULL_SOC_RAW		255
#define CAPACITY_DELTA_DECIPCT	500
#define CENTI_FULL_SOC		10000

#define CENTI_ICORRECT_C0	105
#define CENTI_ICORRECT_C1	20
@@ -366,7 +367,7 @@ static void cap_learning_post_process(struct cap_learning *cl)
 * cap_wt_learning_process_full_data -
 * @cl: Capacity learning object
 * @delta_batt_soc_pct: percentage change in battery State of Charge
 * @batt_soc_msb: MSB of battery State of Charge
 * @batt_soc_cp: Battery State of Charge in centi-percentage
 *
 * Calculates the final learnt capacity when
 * weighted capacity learning is enabled.
@@ -374,11 +375,11 @@ static void cap_learning_post_process(struct cap_learning *cl)
 */
static int cap_wt_learning_process_full_data(struct cap_learning *cl,
					int delta_batt_soc_pct,
					int batt_soc_msb)
					int batt_soc_cp)
{
	int64_t del_cap_uah, total_cap_uah,
		res_cap_uah, wt_learnt_cap_uah;
	int delta_batt_soc_msb, res_batt_soc_msb;
	int delta_batt_soc_cp, res_batt_soc_cp;

	/* If the delta is < 10%, then skip processing full data */
	if (delta_batt_soc_pct < cl->dt.min_delta_batt_soc) {
@@ -386,11 +387,11 @@ static int cap_wt_learning_process_full_data(struct cap_learning *cl,
		return -ERANGE;
	}

	delta_batt_soc_msb = batt_soc_msb - cl->init_batt_soc_msb;
	res_batt_soc_msb = FULL_SOC_RAW - batt_soc_msb;
	/* Learnt Capacity from end Battery SOC MSB to FULL_SOC_RAW */
	delta_batt_soc_cp = batt_soc_cp - cl->init_batt_soc_cp;
	res_batt_soc_cp = CENTI_FULL_SOC - batt_soc_cp;
	/* Learnt Capacity from end Battery SOC to CENTI_FULL_SOC */
	res_cap_uah = div64_s64(cl->learned_cap_uah *
				res_batt_soc_msb, FULL_SOC_RAW);
				res_batt_soc_cp, CENTI_FULL_SOC);
	total_cap_uah = cl->init_cap_uah + cl->delta_cap_uah + res_cap_uah;
	/*
	 * difference in capacity learnt in this
@@ -398,8 +399,8 @@ static int cap_wt_learning_process_full_data(struct cap_learning *cl,
	 */
	del_cap_uah = total_cap_uah - cl->learned_cap_uah;
	/* Applying weight based on change in battery SOC MSB */
	wt_learnt_cap_uah = div64_s64(del_cap_uah * delta_batt_soc_msb,
					FULL_SOC_RAW);
	wt_learnt_cap_uah = div64_s64(del_cap_uah * delta_batt_soc_cp,
					CENTI_FULL_SOC);
	cl->final_cap_uah = cl->learned_cap_uah + wt_learnt_cap_uah;

	pr_debug("wt_learnt_cap_uah=%lld, del_cap_uah=%lld\n",
@@ -413,14 +414,14 @@ static int cap_wt_learning_process_full_data(struct cap_learning *cl,
/**
 * cap_learning_process_full_data -
 * @cl: Capacity learning object
 * @batt_soc_msb: Most significant byte of Battery State of Charge
 * @batt_soc_cp: Battery State of Charge in centi-percentage
 *
 * Processes the coulomb counter during charge termination and calculates the
 * delta w.r.to the coulomb counter obtained earlier when the learning begun.
 *
 */
static int cap_learning_process_full_data(struct cap_learning *cl,
					int batt_soc_msb)
					int batt_soc_cp)
{
	int rc, cc_soc_sw, cc_soc_delta_pct, delta_batt_soc_pct, batt_soc_pct,
		cc_soc_fraction;
@@ -432,7 +433,7 @@ static int cap_learning_process_full_data(struct cap_learning *cl,
		return rc;
	}

	batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW);
	batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_cp, 100);
	delta_batt_soc_pct = batt_soc_pct - cl->init_batt_soc;
	cc_soc_delta_pct =
		div_s64_rem((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 100,
@@ -446,7 +447,7 @@ static int cap_learning_process_full_data(struct cap_learning *cl,

	if (cl->dt.cl_wt_enable) {
		rc = cap_wt_learning_process_full_data(cl, delta_batt_soc_pct,
							batt_soc_msb);
							batt_soc_cp);
		return rc;
	}

@@ -465,24 +466,25 @@ static int cap_learning_process_full_data(struct cap_learning *cl,
/**
 * cap_learning_begin -
 * @cl: Capacity learning object
 * @batt_soc: Battery State of Charge (SOC)
 * @batt_soc_cp: Battery State of Charge in centi-percentage
 *
 * Gets the coulomb counter from FG/QG when the conditions are suitable for
 * beginning capacity learning. Also, primes the coulomb counter based on
 * battery SOC if required.
 *
 */
static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc)
#define BATT_SOC_32BIT	GENMASK(31, 0)
static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc_cp)
{
	int rc, cc_soc_sw, batt_soc_msb, batt_soc_pct;
	int rc, cc_soc_sw, batt_soc_pct;
	u32 batt_soc_prime;

	if (cl->ok_to_begin && !cl->ok_to_begin(cl->data)) {
		pr_debug("Not OK to begin\n");
		return -EINVAL;
	}

	batt_soc_msb = batt_soc >> 24;
	batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW);
	batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_cp, 100);

	if (!cl->dt.cl_wt_enable) {
		if (batt_soc_pct > cl->dt.max_start_soc ||
@@ -493,15 +495,18 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc)
		}
	}

	cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_msb,
					FULL_SOC_RAW);
	cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_cp,
					CENTI_FULL_SOC);

	if (cl->prime_cc_soc) {
		/*
		 * Prime cc_soc_sw with battery SOC when capacity learning
		 * begins.
		 */
		rc = cl->prime_cc_soc(cl->data, batt_soc);
		batt_soc_prime = div64_u64(
				(uint64_t)batt_soc_cp * BATT_SOC_32BIT,
							CENTI_FULL_SOC);
		rc = cl->prime_cc_soc(cl->data, batt_soc_prime);
		if (rc < 0) {
			pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
			goto out;
@@ -516,9 +521,9 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc)

	cl->init_cc_soc_sw = cc_soc_sw;
	cl->init_batt_soc = batt_soc_pct;
	cl->init_batt_soc_msb = batt_soc_msb;
	cl->init_batt_soc_cp = batt_soc_cp;
	pr_debug("Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n",
		batt_soc_msb, cl->init_cc_soc_sw);
		batt_soc_cp, cl->init_cc_soc_sw);
out:
	return rc;
}
@@ -526,17 +531,17 @@ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc)
/**
 * cap_learning_done -
 * @cl: Capacity learning object
 * @batt_soc_msb: Most significant byte of battery State of Charge
 * @batt_soc_cp: Battery State of Charge in centi-percentage
 *
 * Top level function for getting coulomb counter and post processing the
 * data once the capacity learning is complete after charge termination.
 *
 */
static int cap_learning_done(struct cap_learning *cl, int batt_soc_msb)
static int cap_learning_done(struct cap_learning *cl, int batt_soc_cp)
{
	int rc;

	rc = cap_learning_process_full_data(cl, batt_soc_msb);
	rc = cap_learning_process_full_data(cl, batt_soc_cp);
	if (rc < 0) {
		pr_debug("Error in processing cap learning full data, rc=%d\n",
			rc);
@@ -560,19 +565,19 @@ static int cap_learning_done(struct cap_learning *cl, int batt_soc_msb)
/**
 * cap_wt_learning_update -
 * @cl: Capacity learning object
 * @batt_soc_msb: Most significant byte of battery State of Charge
 * @batt_soc_cp: Battery State of Charge in centi-percentage
 * @input_present: Indicator for input presence
 *
 * Called by cap_learning_update when weighted learning is enabled
 *
 */
static void cap_wt_learning_update(struct cap_learning *cl, int batt_soc_msb,
static void cap_wt_learning_update(struct cap_learning *cl, int batt_soc_cp,
					bool input_present)
{
	int rc;

	if (!input_present) {
		rc = cap_learning_done(cl, batt_soc_msb);
		rc = cap_learning_done(cl, batt_soc_cp);
		if (rc < 0)
			pr_debug("Error in completing capacity learning, rc=%d\n",
				rc);
@@ -595,10 +600,11 @@ static void cap_wt_learning_update(struct cap_learning *cl, int batt_soc_msb,
 *
 */
void cap_learning_update(struct cap_learning *cl, int batt_temp,
			int batt_soc, int charge_status, bool charge_done,
			int batt_soc_cp, int charge_status, bool charge_done,
			bool input_present, bool qnovo_en)
{
	int rc, batt_soc_msb, batt_soc_prime;
	int rc;
	u32 batt_soc_prime;
	bool prime_cc = false;

	if (!cl)
@@ -613,18 +619,16 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp,
		goto out;
	}

	batt_soc_msb = (u32)batt_soc >> 24;
	pr_debug("Charge_status: %d active: %d batt_soc: %d\n",
		charge_status, cl->active, batt_soc_msb);
		charge_status, cl->active, batt_soc_cp);

	if (cl->active && cl->dt.cl_wt_enable)
		cap_wt_learning_update(cl, batt_soc_msb,
					input_present);
		cap_wt_learning_update(cl, batt_soc_cp, input_present);

	/* Initialize the starting point of learning capacity */
	if (!cl->active) {
		if (charge_status == POWER_SUPPLY_STATUS_CHARGING) {
			rc = cap_learning_begin(cl, batt_soc);
			rc = cap_learning_begin(cl, batt_soc_cp);
			cl->active = (rc == 0);
		} else {
			if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING ||
@@ -633,7 +637,7 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp,
		}
	} else {
		if (charge_done) {
			rc = cap_learning_done(cl, batt_soc_msb);
			rc = cap_learning_done(cl, batt_soc_cp);
			if (rc < 0)
				pr_err("Error in completing capacity learning, rc=%d\n",
					rc);
@@ -645,7 +649,7 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp,
		if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING &&
				!input_present) {
			pr_debug("Capacity learning aborted @ battery SOC %d\n",
				 batt_soc_msb);
				 batt_soc_cp);
			cl->active = false;
			cl->init_cap_uah = 0;
			prime_cc = true;
@@ -662,7 +666,7 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp,
				 */
			} else {
				pr_debug("Capacity learning aborted @ battery SOC %d\n",
					batt_soc_msb);
					batt_soc_cp);
				cl->active = false;
				cl->init_cap_uah = 0;
				prime_cc = true;
@@ -676,10 +680,13 @@ void cap_learning_update(struct cap_learning *cl, int batt_temp,
	 */

	if (prime_cc && cl->prime_cc_soc) {
		/* pass 32-bit batt_soc to the priming logic */
		if (charge_done)
			batt_soc_prime = cl->cc_soc_max;
		else
			batt_soc_prime = batt_soc;
			batt_soc_prime = div64_u64(
				(uint64_t)batt_soc_cp * BATT_SOC_32BIT,
							CENTI_FULL_SOC);

		rc = cl->prime_cc_soc(cl->data, batt_soc_prime);
		if (rc < 0)
+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ struct cap_learning {
	int			init_cc_soc_sw;
	int			cc_soc_max;
	int			init_batt_soc;
	int			init_batt_soc_msb;
	int			init_batt_soc_cp;
	int64_t			nom_cap_uah;
	int64_t			init_cap_uah;
	int64_t			final_cap_uah;
+3 −6
Original line number Diff line number Diff line
@@ -306,7 +306,7 @@ static bool maint_soc_timeout(struct qpnp_qg *chip)

static void update_msoc(struct qpnp_qg *chip)
{
	int rc = 0, sdam_soc, batt_temp = 0,  batt_soc_32bit = 0;
	int rc = 0, sdam_soc, batt_temp = 0;
	bool input_present = is_input_present(chip);

	if (chip->catch_up_soc > chip->msoc) {
@@ -345,11 +345,8 @@ static void update_msoc(struct qpnp_qg *chip)
		rc = qg_get_battery_temp(chip, &batt_temp);
		if (rc < 0) {
			pr_err("Failed to read BATT_TEMP rc=%d\n", rc);
		} else {
			batt_soc_32bit = div64_u64(
						chip->batt_soc * BATT_SOC_32BIT,
						QG_SOC_FULL);
			cap_learning_update(chip->cl, batt_temp, batt_soc_32bit,
		} else if (chip->batt_soc >= 0) {
			cap_learning_update(chip->cl, batt_temp, chip->batt_soc,
					chip->charge_status, chip->charge_done,
					input_present, false);
		}
+14 −4
Original line number Diff line number Diff line
@@ -3595,12 +3595,14 @@ static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data)
	return IRQ_HANDLED;
}

#define CENTI_FULL_SOC		10000
static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
{
	struct fg_dev *fg = data;
	struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg);
	int rc, batt_soc, batt_temp, msoc_raw;
	bool input_present = is_input_present(fg);
	u32 batt_soc_cp;

	rc = fg_get_msoc_raw(fg, &msoc_raw);
	if (!rc)
@@ -3620,10 +3622,14 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
	if (rc < 0) {
		pr_err("Failed to read battery temp rc: %d\n", rc);
	} else {
		if (chip->cl->active)
			cap_learning_update(chip->cl, batt_temp, batt_soc,
		if (chip->cl->active) {
			batt_soc_cp = div64_u64(
					(u64)(u32)batt_soc * CENTI_FULL_SOC,
					BATT_SOC_32BIT);
			cap_learning_update(chip->cl, batt_temp, batt_soc_cp,
				fg->charge_status, fg->charge_done,
				input_present, is_qnovo_en(fg));
		}

		rc = fg_gen4_slope_limit_config(chip, batt_temp);
		if (rc < 0)
@@ -4059,6 +4065,7 @@ static void status_change_work(struct work_struct *work)
	struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg);
	int rc, batt_soc, batt_temp;
	bool input_present, qnovo_en;
	u32 batt_soc_cp;

	if (fg->battery_missing) {
		pm_relax(fg->dev);
@@ -4103,10 +4110,13 @@ static void status_change_work(struct work_struct *work)
	cycle_count_update(chip->counter, (u32)batt_soc >> 24,
		fg->charge_status, fg->charge_done, input_present);

	if (fg->charge_status != fg->prev_charge_status)
		cap_learning_update(chip->cl, batt_temp, batt_soc,
	if (fg->charge_status != fg->prev_charge_status) {
		batt_soc_cp = div64_u64((u64)(u32)batt_soc * CENTI_FULL_SOC,
					BATT_SOC_32BIT);
		cap_learning_update(chip->cl, batt_temp, batt_soc_cp,
			fg->charge_status, fg->charge_done, input_present,
			qnovo_en);
	}

	rc = fg_gen4_charge_full_update(fg);
	if (rc < 0)
+3 −6
Original line number Diff line number Diff line
@@ -2553,7 +2553,7 @@ static void qg_status_change_work(struct work_struct *work)
	struct qpnp_qg *chip = container_of(work,
			struct qpnp_qg, qg_status_change_work);
	union power_supply_propval prop = {0, };
	int rc = 0, batt_temp = 0, batt_soc_32b = 0;
	int rc = 0, batt_temp = 0;
	bool input_present = false;

	if (!is_batt_available(chip)) {
@@ -2609,11 +2609,8 @@ static void qg_status_change_work(struct work_struct *work)
		rc = qg_get_battery_temp(chip, &batt_temp);
		if (rc < 0) {
			pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
		} else {
			batt_soc_32b = div64_u64(
					chip->batt_soc * BATT_SOC_32BIT,
					QG_SOC_FULL);
			cap_learning_update(chip->cl, batt_temp, batt_soc_32b,
		} else if (chip->batt_soc >= 0) {
			cap_learning_update(chip->cl, batt_temp, chip->batt_soc,
				chip->charge_status, chip->charge_done,
				input_present, false);
		}