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

Commit 4d716fff authored by Subbaraman Narayanamurthy's avatar Subbaraman Narayanamurthy
Browse files

power: qpnp-fg-gen4: Adjust recharge SOC dynamically



On PM8150B, recharge SOC threshold is configured in the charger
hardware. Since FG driver needs to support maintenance charging
and recharge SOC needs to be modified dynamically based on the
early termination, it is better to have it configured at one
place, in FG driver. It is expected that recharge SOC threshold
is exposed by the charger driver through battery power supply.

Recharge SOC threshold is adjusted based on the SOC at which
charge termination happens and it is set back to the original
threshold when one of the following happens.

- Battery is out of FULL state meaning recharging had begun
- Battery is out of JEITA zone
- Charger is removed

Change-Id: Ifa08c4bdbd161b20a385c1850f7d32c932b1ffb8
Signed-off-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
parent e148e353
Loading
Loading
Loading
Loading
+114 −0
Original line number Diff line number Diff line
@@ -148,6 +148,7 @@ struct fg_gen4_chip {
	struct ttf		ttf;
	struct delayed_work	ttf_work;
	char			batt_profile[PROFILE_LEN];
	int			recharge_soc_thr;
	bool			ki_coeff_dischg_en;
	bool			slope_limit_en;
};
@@ -1046,6 +1047,7 @@ static void profile_load_work(struct work_struct *work)

static void get_batt_psy_props(struct fg_dev *fg)
{
	struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg);
	union power_supply_propval prop = {0, };
	int rc;

@@ -1084,6 +1086,21 @@ static void get_batt_psy_props(struct fg_dev *fg)
	}

	fg->health = prop.intval;

	if (!chip->recharge_soc_thr) {
		rc = power_supply_get_property(fg->batt_psy,
			POWER_SUPPLY_PROP_RECHARGE_SOC, &prop);
		if (rc < 0) {
			pr_err("Error in getting recharge SOC, rc=%d\n", rc);
			return;
		}

		if (prop.intval < 0)
			pr_debug("Recharge SOC not configured %d\n",
				prop.intval);
		else
			chip->recharge_soc_thr = prop.intval;
	}
}

static int fg_gen4_configure_full_soc(struct fg_dev *fg, int bsoc)
@@ -1113,6 +1130,99 @@ static int fg_gen4_configure_full_soc(struct fg_dev *fg, int bsoc)
	return 0;
}

static int fg_gen4_set_recharge_soc(struct fg_dev *fg, int recharge_soc)
{
	union power_supply_propval prop = {0, };
	int rc;

	if (recharge_soc < 0 || recharge_soc > FULL_CAPACITY || !fg->batt_psy)
		return 0;

	prop.intval = recharge_soc;
	rc = power_supply_set_property(fg->batt_psy,
		POWER_SUPPLY_PROP_RECHARGE_SOC, &prop);
	if (rc < 0) {
		pr_err("Error in setting recharge SOC, rc=%d\n", rc);
		return rc;
	}

	return 0;
}

static int fg_gen4_adjust_recharge_soc(struct fg_gen4_chip *chip)
{
	struct fg_dev *fg = &chip->fg;
	int rc, msoc, recharge_soc, new_recharge_soc = 0;
	bool recharge_soc_status;

	if (!chip->recharge_soc_thr)
		return 0;

	recharge_soc = chip->recharge_soc_thr;
	recharge_soc_status = fg->recharge_soc_adjusted;

	/*
	 * If the input is present and charging had been terminated, adjust
	 * the recharge SOC threshold based on the monotonic SOC at which
	 * the charge termination had happened.
	 */
	if (is_input_present(fg)) {
		if (fg->charge_done) {
			if (!fg->recharge_soc_adjusted) {
				/* Get raw monotonic SOC for calculation */
				rc = fg_get_msoc(fg, &msoc);
				if (rc < 0) {
					pr_err("Error in getting msoc, rc=%d\n",
						rc);
					return rc;
				}

				/* Adjust the recharge_soc threshold */
				new_recharge_soc = msoc - (FULL_CAPACITY -
								recharge_soc);
				fg->recharge_soc_adjusted = true;
			} else {
				/* adjusted already, do nothing */
				return 0;
			}
		} else {
			if (!fg->recharge_soc_adjusted)
				return 0;

			/*
			 * If we are here, then it means that recharge SOC
			 * had been adjusted already and it could be probably
			 * because of early termination. We shouldn't restore
			 * the original recharge SOC threshold if the health is
			 * not good, which means battery is in JEITA zone.
			 */
			if (fg->health != POWER_SUPPLY_HEALTH_GOOD)
				return 0;

			/* Restore the default value */
			new_recharge_soc = recharge_soc;
			fg->recharge_soc_adjusted = false;
		}
	} else {
		/* Restore the default value */
		new_recharge_soc = recharge_soc;
		fg->recharge_soc_adjusted = false;
	}

	if (recharge_soc_status == fg->recharge_soc_adjusted)
		return 0;

	rc = fg_gen4_set_recharge_soc(fg, new_recharge_soc);
	if (rc < 0) {
		fg->recharge_soc_adjusted = recharge_soc_status;
		pr_err("Couldn't set recharge SOC, rc=%d\n", rc);
		return rc;
	}

	fg_dbg(fg, FG_STATUS, "recharge soc set to %d\n", new_recharge_soc);
	return 0;
}

static int fg_gen4_charge_full_update(struct fg_dev *fg)
{
	struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg);
@@ -1676,6 +1786,10 @@ static void status_change_work(struct work_struct *work)
	if (rc < 0)
		pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);

	rc = fg_gen4_adjust_recharge_soc(chip);
	if (rc < 0)
		pr_err("Error in adjusting recharge SOC, rc=%d\n", rc);

	fg_ttf_update(fg);
	fg->prev_charge_status = fg->charge_status;
out: