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

Commit 4afec022 authored by Sahil Chandna's avatar Sahil Chandna
Browse files

power: battery: smb1390-charger-psy: Handle CP(s) disable conditions



Add support to disable charge pump(s) when FCC or ILIM falls below its
specified threshold.
Once slave charge pump is disabled, redistribute the ILIM to master charge
pump.

Change-Id: I3f23933185e518fa5d66df4eb37b49715d453737
Signed-off-by: default avatarSahil Chandna <chandna@codeaurora.org>
parent 8c6a3243
Loading
Loading
Loading
Loading
+60 −17
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ struct pl_data {
	struct votable		*cp_ilim_votable;
	struct votable		*cp_disable_votable;
	struct votable		*fcc_main_votable;
	struct votable		*cp_slave_disable_votable;
	struct delayed_work	status_change_work;
	struct work_struct	pl_disable_forever_work;
	struct work_struct	pl_taper_work;
@@ -74,6 +75,7 @@ struct pl_data {
	struct power_supply	*usb_psy;
	struct power_supply	*dc_psy;
	struct power_supply	*cp_master_psy;
	struct power_supply	*cp_slave_psy;
	int			charge_type;
	int			total_settled_ua;
	int			pl_settled_ua;
@@ -803,7 +805,9 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
{
	struct pl_data *chip = data;
	int master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
	int main_fcc_ua = 0, cp_fcc_ua = 0, fcc_thr_ua = 0, rc;
	union power_supply_propval pval = {0, };
	bool is_cc_mode = false;

	if (total_fcc_ua < 0)
		return 0;
@@ -814,22 +818,65 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
	if (!chip->cp_disable_votable)
		chip->cp_disable_votable = find_votable("CP_DISABLE");

	if (chip->cp_disable_votable) {
		if (cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE)
					== POWER_SUPPLY_PL_OUTPUT_VPH) {
			power_supply_get_property(chip->cp_master_psy,
	if (!chip->cp_master_psy)
		chip->cp_master_psy =
			power_supply_get_by_name("charge_pump_master");

	if (!chip->cp_slave_psy)
		chip->cp_slave_psy = power_supply_get_by_name("cp_slave");

	if (!chip->cp_slave_disable_votable)
		chip->cp_slave_disable_votable =
			find_votable("CP_SLAVE_DISABLE");

	if (!chip->usb_psy)
		chip->usb_psy = power_supply_get_by_name("usb");

	if (chip->usb_psy) {
		rc = power_supply_get_property(chip->usb_psy,
					POWER_SUPPLY_PROP_ADAPTER_CC_MODE,
					&pval);
		if (rc < 0)
			pr_err("Couldn't get PPS CC mode status rc=%d\n", rc);
		else
			is_cc_mode = pval.intval;
	}

	if (chip->cp_master_psy) {
		rc = power_supply_get_property(chip->cp_master_psy,
					POWER_SUPPLY_PROP_MIN_ICL, &pval);
		if (rc < 0)
			pr_err("Couldn't get MIN ICL threshold rc=%d\n", rc);
		else
			fcc_thr_ua = is_cc_mode ? (3 * pval.intval) :
							(4 * pval.intval);
	}

	if (chip->fcc_main_votable)
		main_fcc_ua =
			get_effective_result_locked(chip->fcc_main_votable);

	if (main_fcc_ua < 0)
		main_fcc_ua = 0;

	cp_fcc_ua = total_fcc_ua - main_fcc_ua;
	if (cp_fcc_ua > 0) {
		if (chip->cp_slave_psy && chip->cp_slave_disable_votable) {
			/*
			 * With VPH output configuration ILIM is configured
			 * independent of battery FCC, disable CP here if FCC/2
			 * falls below MIN_ICL supported by CP.
			 * Disable Slave CP if FCC share
			 * falls below threshold.
			 */
			vote(chip->cp_slave_disable_votable, FCC_VOTER,
				(cp_fcc_ua < fcc_thr_ua), 0);
		}

		if (chip->cp_disable_votable) {
			/*
			 * Disable Master CP if FCC share
			 * falls below 2 * min ICL threshold.
			 */
			if ((total_fcc_ua / 2) < pval.intval)
				vote(chip->cp_disable_votable, FCC_VOTER,
						true, 0);
			else
			vote(chip->cp_disable_votable, FCC_VOTER,
						false, 0);
			     (cp_fcc_ua < (2 * pval.intval)), 0);
		}
	}

@@ -848,10 +895,6 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,

	rerun_election(chip->pl_disable_votable);
	/* When FCC changes, trigger psy changed event for CC mode */
	if (!chip->cp_master_psy)
		chip->cp_master_psy =
			power_supply_get_by_name("charge_pump_master");

	if (chip->cp_master_psy)
		power_supply_changed(chip->cp_master_psy);

+56 −7
Original line number Diff line number Diff line
@@ -180,6 +180,7 @@ struct smb1390 {
	struct votable		*cp_awake_votable;
	struct votable		*slave_disable_votable;
	struct votable		*usb_icl_votable;
	struct votable		*fcc_main_votable;

	/* power supplies */
	struct power_supply	*cps_psy;
@@ -876,13 +877,38 @@ static int smb1390_slave_disable_vote_cb(struct votable *votable, void *data,
			      int disable, const char *client)
{
	struct smb1390 *chip = data;
	int rc;
	int rc = 0, ilim_ua = 0;

	rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SL_BIT,
					disable ? 0 : CMD_EN_SL_BIT);
	if (rc < 0)
	if (rc < 0) {
		pr_err("Couldn't %s slave rc=%d\n",
				disable ? "disable" : "enable", rc);
		return rc;
	}

	/* Re-distribute ILIM to Master CP when Slave is disabled */
	if (disable && (chip->ilim_votable)) {
		ilim_ua = get_effective_result_locked(chip->ilim_votable);
		if (ilim_ua > MAX_ILIM_UA)
			ilim_ua = MAX_ILIM_UA;

		if (ilim_ua < 500000) {
			smb1390_dbg(chip, PR_INFO, "ILIM too low, not re-distributing, ilim=%duA\n",
								ilim_ua);
			return 0;
		}

		rc = smb1390_set_ilim(chip,
		      DIV_ROUND_CLOSEST(ilim_ua - 500000, 100000));
		if (rc < 0) {
			pr_err("Failed to set ILIM, rc=%d\n", rc);
			return rc;
		}

		smb1390_dbg(chip, PR_INFO, "Master ILIM set to %duA\n",
								ilim_ua);
	}

	return rc;
}
@@ -893,6 +919,7 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data,
	struct smb1390 *chip = data;
	union power_supply_propval pval = {0, };
	int rc = 0;
	bool slave_enabled = false;

	if (!is_psy_voter_available(chip) || chip->suspended)
		return -EAGAIN;
@@ -911,7 +938,17 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data,
			ilim_uA);
		vote(chip->disable_votable, ILIM_VOTER, true, 0);
	} else {
		/* Disable Slave CP if ILIM is < 2 * min ILIM */
		if (is_cps_available(chip)) {
			vote(chip->slave_disable_votable, ILIM_VOTER,
				(ilim_uA < (2 * chip->min_ilim_ua)), 0);

			if (get_effective_result(chip->slave_disable_votable)
									== 0)
				slave_enabled = true;
		}

		if (slave_enabled) {
			ilim_uA /= 2;
			pval.intval = DIV_ROUND_CLOSEST(ilim_uA - 500000,
					100000);
@@ -930,7 +967,8 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data,
			return rc;
		}

		smb1390_dbg(chip, PR_INFO, "ILIM set to %duA\n", ilim_uA);
		smb1390_dbg(chip, PR_INFO, "ILIM set to %duA slave_enabled%d\n",
						ilim_uA, slave_enabled);
		vote(chip->disable_votable, ILIM_VOTER, false, 0);
	}

@@ -1167,11 +1205,20 @@ static void smb1390_taper_work(struct work_struct *work)
{
	struct smb1390 *chip = container_of(work, struct smb1390, taper_work);
	union power_supply_propval pval = {0, };
	int rc, fcc_uA, delta_fcc_uA;
	int rc, fcc_uA, delta_fcc_uA, main_fcc_ua = 0;

	if (!is_psy_voter_available(chip))
		goto out;

	if (!chip->fcc_main_votable)
		chip->fcc_main_votable = find_votable("FCC_MAIN");

	if (chip->fcc_main_votable)
		main_fcc_ua = get_effective_result(chip->fcc_main_votable);

	if (main_fcc_ua < 0)
		main_fcc_ua = 0;

	chip->taper_entry_fv = get_effective_result(chip->fv_votable);
	while (true) {
		rc = power_supply_get_property(chip->batt_psy,
@@ -1200,14 +1247,15 @@ static void smb1390_taper_work(struct work_struct *work)
			smb1390_dbg(chip, PR_INFO, "taper work reducing FCC to %duA\n",
				fcc_uA);
			vote(chip->fcc_votable, CP_VOTER, true, fcc_uA);
			rc = smb1390_validate_slave_chg_taper(chip, fcc_uA);
			rc = smb1390_validate_slave_chg_taper(chip, (fcc_uA -
							      main_fcc_ua));
			if (rc < 0) {
				pr_err("Couldn't Disable slave in Taper, rc=%d\n",
				       rc);
				goto out;
			}

			if (fcc_uA < (chip->min_ilim_ua * 2)) {
			if ((fcc_uA - main_fcc_ua) < (chip->min_ilim_ua * 2)) {
				vote(chip->disable_votable, TAPER_END_VOTER,
								true, 0);
				/*
@@ -1482,7 +1530,8 @@ static int smb1390_parse_dt(struct smb1390 *chip)
	of_property_read_u32(chip->dev->of_node, "qcom,parallel-input-mode",
			&chip->pl_input_mode);

	chip->cp_slave_thr_taper_ua = chip->min_ilim_ua * 3;
	chip->cp_slave_thr_taper_ua = smb1390_is_adapter_cc_mode(chip) ?
			(3 * chip->min_ilim_ua) : (4 * chip->min_ilim_ua);
	of_property_read_u32(chip->dev->of_node, "qcom,cp-slave-thr-taper-ua",
			      &chip->cp_slave_thr_taper_ua);