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

Commit 5198db55 authored by Harry Yang's avatar Harry Yang Committed by Subbaraman Narayanamurthy
Browse files

power: smb5: Add support for selecting secondary chargers



SM8150 platforms can be configured with SMB1355 and/or SMB1390 as
secondary charger(s). The main charger can enable secondary charger
via SMB_EN pin. The precedence of choosing secondary charger per
different power sources is as follows:

If HVDCP3 and PPS chargers are connected, SMB1390 (if present) is
preferred over SMB1355. For all other chargers (e.g. PD, HVDCP2,
DCP, OCP) SMB1355 is selected (if present).

Change-Id: I63c3cd54f934d1042b2191bf60add07c3442a76e
Signed-off-by: default avatarHarry Yang <harryy@codeaurora.org>
parent 18ebfe22
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -27,6 +27,16 @@ Charger specific properties:
  Definition: Should specify the phandle of PMI's revid module. This is used to
		identify the PMI subtype.

- qcom,sec-charger-config
  Usage:      optional
  Value type: <u32>
  Definition: Specify how the secondary chargers are configured.
		0 - No secondary charger.
		1 - Charge Pump SMB1390.
		2 - SMB1355 parallel charger.
		3 - Both Charge Pump and SMB1355.
		If the value is not present, 0 is used as default.

- io-channels
- io-channel-names
  Usage:      optional
@@ -236,6 +246,8 @@ pm8150b_charger: qcom,qpnp-smb5 {

	dpdm-supply = <&qusb_phy0>;

	qcom,sec-charger-config = <1>;

	io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>,
	              <&pm8150b_vadc ADC_USB_IN_I>,
	              <&pm8150b_vadc ADC_CHG_TEMP>;
+10 −0
Original line number Diff line number Diff line
@@ -173,6 +173,7 @@ struct smb_dt_props {
	int			chg_inhibit_thr_mv;
	bool			no_battery;
	bool			hvdcp_disable;
	int			sec_charger_config;
	int			auto_recharge_soc;
	int			auto_recharge_vbat_mv;
	int			wd_bark_time;
@@ -278,6 +279,9 @@ static int smb5_parse_dt(struct smb5 *chip)
		return -EINVAL;
	}

	of_property_read_u32(node, "qcom,sec-charger-config",
					&chip->dt.sec_charger_config);

	chg->step_chg_enabled = of_property_read_bool(node,
				"qcom,step-charging-enable");

@@ -1444,6 +1448,12 @@ static int smb5_init_hw(struct smb5 *chip)
	smblib_get_charge_param(chg, &chg->param.usb_icl,
				&chg->default_icl_ua);

	chg->sec_cp_present = chip->dt.sec_charger_config == SEC_CHG_CP_ONLY
			|| chip->dt.sec_charger_config == SEC_CHG_CP_AND_PL;

	chg->sec_pl_present = chip->dt.sec_charger_config == SEC_CHG_PL_ONLY
			|| chip->dt.sec_charger_config == SEC_CHG_CP_AND_PL;

	/* Use SW based VBUS control, disable HW autonomous mode */
	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
		HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
+107 −19
Original line number Diff line number Diff line
@@ -117,19 +117,63 @@ int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
	return 0;
}

int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
static int smblib_select_sec_charger(struct smb_charger *chg,
					enum sec_charger_type sec_chg)
{
	int rc = 0;
	int rc;

	if (sec_chg == chg->sec_chg_selected)
		return 0;

	/* override  = 1, SW STAT override; override = 0, HW auto mode */
	rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
				SMB_EN_OVERRIDE_BIT,
				override ? SMB_EN_OVERRIDE_BIT : 0);
	switch (sec_chg) {
	case SEC_CHG_CP:
		/* select Charge Pump instead of slave charger */
		rc = smblib_masked_write(chg, MISC_SMB_CFG_REG,
					SMB_EN_SEL_BIT, SMB_EN_SEL_BIT);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't select SMB charger rc=%d\n",
				rc);
			return rc;
		}
		/* Enable Charge Pump, under HW control */
		rc = smblib_write(chg, MISC_SMB_EN_CMD_REG,  EN_CP_CMD_BIT);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't enable SMB charger rc=%d\n",
						rc);
			return rc;
		}
		break;
	case SEC_CHG_PL:
		/* select slave charger instead of Charge Pump */
		rc = smblib_masked_write(chg, MISC_SMB_CFG_REG,
					SMB_EN_SEL_BIT, 0);
		if (rc < 0) {
		dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
			dev_err(chg->dev, "Couldn't select SMB charger rc=%d\n",
				rc);
			return rc;
		}
		/* Enable slave charger, under HW control */
		rc = smblib_write(chg, MISC_SMB_EN_CMD_REG,  EN_STAT_CMD_BIT);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't enable SMB charger rc=%d\n",
						rc);
			return rc;
		}
		break;
	case SEC_CHG_NONE:
	default:
		/* SW override, disabling secondary charger(s) */
		rc = smblib_write(chg, MISC_SMB_EN_CMD_REG,
						SMB_EN_OVERRIDE_BIT);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't disable charging rc=%d\n",
						rc);
			return rc;
		}
		break;
	}

	chg->sec_chg_selected = sec_chg;

	return rc;
}
@@ -602,7 +646,8 @@ static int smblib_notifier_call(struct notifier_block *nb,
			schedule_work(&chg->jeita_update_work);
	}

	if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
	if (chg->sec_pl_present && !chg->pl.psy
		&& !strcmp(psy->desc->name, "parallel")) {
		chg->pl.psy = psy;
		schedule_work(&chg->pl_update_work);
	}
@@ -2365,11 +2410,29 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
		 */
		vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);

		/*
		 * For PPS, Charge Pump is preferred over parallel charger if
		 * present.
		 */
		if (chg->pd_active == 2 && chg->sec_cp_present) {
			rc = smblib_select_sec_charger(chg, SEC_CHG_CP);
			if (rc < 0)
				dev_err(chg->dev, "Couldn't enable secondary charger rc=%d\n",
					rc);
		}
	} else {
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
		vote(chg->usb_icl_votable, PD_VOTER, false, 0);
		vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);

		rc = smblib_select_sec_charger(chg,
			chg->sec_pl_present ? SEC_CHG_PL : SEC_CHG_NONE);
		if (rc < 0)
			dev_err(chg->dev,
				"Couldn't enable secondary charger rc=%d\n",
					rc);

		/* PD hard resets failed, rerun apsd */
		if (chg->ok_to_pd) {
			chg->ok_to_pd = false;
@@ -2891,6 +2954,7 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
					      bool rising)
{
	const struct apsd_result *apsd_result;
	int rc;

	if (!rising)
		return;
@@ -2900,6 +2964,15 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,

	/* the APSD done handler will set the USB supply type */
	apsd_result = smblib_get_apsd_result(chg);

	/* for QC3, switch to CP if present */
	if ((apsd_result->bit & QC_3P0_BIT) && chg->sec_cp_present) {
		rc = smblib_select_sec_charger(chg, SEC_CHG_CP);
		if (rc < 0)
			dev_err(chg->dev,
			"Couldn't enable secondary chargers  rc=%d\n", rc);
	}

	smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
		   apsd_result->name);
}
@@ -3148,6 +3221,12 @@ static void typec_src_removal(struct smb_charger *chg)
	struct smb_irq_data *data;
	struct storm_watch *wdata;

	rc = smblib_select_sec_charger(chg,
			chg->sec_pl_present ? SEC_CHG_PL : SEC_CHG_NONE);
	if (rc < 0)
		dev_err(chg->dev,
			"Couldn't disable secondary charger rc=%d\n", rc);

	/* disable apsd */
	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
				HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
@@ -3582,7 +3661,10 @@ static void pl_update_work(struct work_struct *work)
	struct smb_charger *chg = container_of(work, struct smb_charger,
						pl_update_work);

	smblib_stat_sw_override_cfg(chg, false);
	if (chg->sec_chg_selected == SEC_CHG_CP)
		return;

	smblib_select_sec_charger(chg, SEC_CHG_PL);
}

static void clear_hdc_work(struct work_struct *work)
@@ -3839,6 +3921,7 @@ int smblib_init(struct smb_charger *chg)
	chg->fake_batt_status = -EINVAL;
	chg->sink_src_mode = UNATTACHED_MODE;
	chg->jeita_configured = false;
	chg->sec_chg_selected = SEC_CHG_NONE;

	switch (chg->mode) {
	case PARALLEL_MASTER:
@@ -3865,15 +3948,20 @@ int smblib_init(struct smb_charger *chg)
		}

		chg->bms_psy = power_supply_get_by_name("bms");

		if (chg->sec_pl_present) {
			chg->pl.psy = power_supply_get_by_name("parallel");
		if (chg->pl.psy) {
			rc = smblib_stat_sw_override_cfg(chg, false);
			if (chg->pl.psy &&
					chg->sec_chg_selected != SEC_CHG_CP) {
				rc = smblib_select_sec_charger(chg, SEC_CHG_PL);
				if (rc < 0) {
				smblib_err(chg,
					"Couldn't config stat sw rc=%d\n", rc);
					smblib_err(chg, "Couldn't config pl charger rc=%d\n",
						rc);
					return rc;
				}
			}
		}

		rc = smblib_register_notifier(chg);
		if (rc < 0) {
			smblib_err(chg,
+18 −1
Original line number Diff line number Diff line
@@ -78,6 +78,19 @@ enum smb_mode {
	NUM_MODES,
};

enum sec_charger_config {
	MAIN_STANDALONE = 0,
	SEC_CHG_CP_ONLY,
	SEC_CHG_PL_ONLY,
	SEC_CHG_CP_AND_PL,
};

enum sec_charger_type {
	SEC_CHG_NONE = 0,
	SEC_CHG_CP,
	SEC_CHG_PL,
};

enum sink_src_mode {
	SINK_MODE,
	SRC_MODE,
@@ -313,6 +326,11 @@ struct smb_charger {
	struct delayed_work	uusb_otg_work;
	struct delayed_work	bb_removal_work;

	/* secondary charger config */
	bool			sec_pl_present;
	bool			sec_cp_present;
	int			sec_chg_selected;

	/* pd */
	int			voltage_min_uv;
	int			voltage_max_uv;
@@ -536,7 +554,6 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
				union power_supply_propval *val);
int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
				const union power_supply_propval *val);
int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override);

int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);