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

Commit 1a09f3e8 authored by Harry Yang's avatar Harry Yang Committed by Guru Das Srinagesh
Browse files

power: smb5: Fix ICL setting on Type-C/PD compliance failure



A Type-C/PD compliance case fails in that after PD contract at 100mA
is estabished, ~400 mA is drawn from VBUS which is over the requested
value.

Currently, PD can start its session as early as before/while APSD
is running. Before APSD is done, the 100mA (requested through USB51
mode) ICL request could be overridden by other settings, in this
case, which happens to be higher than 100mA.

Fix it by using ICL_OVERRIDE_BIT, which enforces the requested ICL
to be effective throughout the whole APSD process.

Also remove some power supply properties as they're not supposed to
be visible for any clients.

Change-Id: I1f06371d775a512c99a40550c20abd65bc99b676
Signed-off-by: default avatarHarry Yang <harryy@codeaurora.org>
parent 79579ba5
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -547,7 +547,6 @@ static enum power_supply_property smb5_usb_props[] = {
	POWER_SUPPLY_PROP_TYPEC_MODE,
	POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
	POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
	POWER_SUPPLY_PROP_TYPEC_SRC_RP,
	POWER_SUPPLY_PROP_LOW_POWER,
	POWER_SUPPLY_PROP_PD_ACTIVE,
	POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
@@ -557,10 +556,8 @@ static enum power_supply_property smb5_usb_props[] = {
	POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
	POWER_SUPPLY_PROP_HW_CURRENT_MAX,
	POWER_SUPPLY_PROP_REAL_TYPE,
	POWER_SUPPLY_PROP_PR_SWAP,
	POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
	POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
	POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
	POWER_SUPPLY_PROP_VOLTAGE_MAX,
@@ -1891,8 +1888,8 @@ static int smb5_init_hw(struct smb5 *chip)
		smblib_rerun_apsd_if_required(chg);
	}

	/* clear the ICL override if it is set */
	rc = smblib_icl_override(chg, false);
	/* Use ICL results from HW */
	rc = smblib_icl_override(chg, HW_AUTO_MODE);
	if (rc < 0) {
		pr_err("Couldn't disable ICL override rc=%d\n", rc);
		return rc;
+58 −83
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@
	|| typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH)	\
	&& !chg->typec_legacy)

static void update_sw_icl_max(struct smb_charger *chg, int pst);

int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
{
	unsigned int value;
@@ -156,15 +158,50 @@ int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
	return 0;
}

int smblib_icl_override(struct smb_charger *chg, bool override)
int smblib_icl_override(struct smb_charger *chg, enum icl_override_mode  mode)
{
	int rc;
	u8 usb51_mode, icl_override, apsd_override;

	rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
				ICL_OVERRIDE_AFTER_APSD_BIT,
				override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
	if (rc < 0)
	switch (mode) {
	case SW_OVERRIDE_USB51_MODE:
		usb51_mode = 0;
		icl_override = ICL_OVERRIDE_BIT;
		apsd_override = 0;
		break;
	case SW_OVERRIDE_HC_MODE:
		usb51_mode = USBIN_MODE_CHG_BIT;
		icl_override = 0;
		apsd_override = ICL_OVERRIDE_AFTER_APSD_BIT;
		break;
	case HW_AUTO_MODE:
	default:
		usb51_mode = USBIN_MODE_CHG_BIT;
		icl_override = 0;
		apsd_override = 0;
		break;
	}

	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
				USBIN_MODE_CHG_BIT, usb51_mode);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set USBIN_ICL_OPTIONS rc=%d\n", rc);
		return rc;
	}

	rc = smblib_masked_write(chg, CMD_ICL_OVERRIDE_REG,
				ICL_OVERRIDE_BIT, icl_override);
	if (rc < 0) {
		smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
		return rc;
	}

	rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
				ICL_OVERRIDE_AFTER_APSD_BIT, apsd_override);
	if (rc < 0) {
		smblib_err(chg, "Couldn't override ICL_AFTER_APSD rc=%d\n", rc);
		return rc;
	}

	return rc;
}
@@ -1166,42 +1203,25 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua)
	}

	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
		CFG_USB3P0_SEL_BIT | USB51_MODE_BIT | USBIN_MODE_CHG_BIT,
		icl_options);
			CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
		return rc;
	}

	return rc;
}

static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
{
	int rc;
	u8 icl_options;
	bool usb3 = false;

	rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
	rc = smblib_icl_override(chg, SW_OVERRIDE_USB51_MODE);
	if (rc < 0) {
		smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
		smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
		return rc;
	}

	usb3 = (icl_options & CFG_USB3P0_SEL_BIT);

	if (icl_options & USB51_MODE_BIT)
		*icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
	else
		*icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;

	return rc;
}

int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
{
	int rc = 0;
	bool hc_mode = false, override = false;
	enum icl_override_mode icl_override = HW_AUTO_MODE;
	/* suspend if 25mA or less is requested */
	bool suspend = (icl_ua <= USBIN_25MA);

@@ -1249,25 +1269,11 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
			smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
			goto out;
		}
		hc_mode = true;

		/*
		 * Micro USB mode follows ICL register independent of override
		 * bit, configure override only for typeC mode.
		 */
		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
			override = true;
		icl_override = SW_OVERRIDE_HC_MODE;
	}

set_mode:
	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
		USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set USBIN_ICL_OPTIONS rc=%d\n", rc);
		goto out;
	}

	rc = smblib_icl_override(chg, override);
	rc = smblib_icl_override(chg, icl_override);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
		goto out;
@@ -1289,38 +1295,13 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)

int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
{
	int rc = 0;
	u8 load_cfg;
	bool override;

	if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
		|| chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
		&& (chg->usb_psy->desc->type == POWER_SUPPLY_TYPE_USB)) {
		rc = get_sdp_current(chg, icl_ua);
		if (rc < 0) {
			smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
			return rc;
		}
	} else {
		rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
		if (rc < 0) {
			smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
			return rc;
		}
		override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
		if (!override)
			return INT_MAX;
	int rc;

		/* override is set */
		rc = smblib_get_charge_param(chg, &chg->param.icl_max_stat,
					icl_ua);
		if (rc < 0) {
	rc = smblib_get_charge_param(chg, &chg->param.icl_max_stat, icl_ua);
	if (rc < 0)
		smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
			return rc;
		}
	}

	return 0;
	return rc;
}

int smblib_toggle_smb_en(struct smb_charger *chg, int toggle)
@@ -3613,6 +3594,8 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
int smblib_set_prop_pd_active(struct smb_charger *chg,
				const union power_supply_propval *val)
{
	const struct apsd_result *apsd = smblib_get_apsd_result(chg);

	int rc = 0;
	int sec_charger;

@@ -3620,6 +3603,8 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,

	smblib_apsd_enable(chg, !chg->pd_active);

	update_sw_icl_max(chg, apsd->pst);

	if (chg->pd_active) {
		vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);

@@ -3646,7 +3631,6 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
					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);

@@ -4359,10 +4343,8 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,

static void update_sw_icl_max(struct smb_charger *chg, int pst)
{
	union power_supply_propval pval;
	int typec_mode;
	int rp_ua;
	int rc;

	/* while PD is active it should have complete ICL control */
	if (chg->pd_active)
@@ -4414,15 +4396,8 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst)
		break;
	case POWER_SUPPLY_TYPE_UNKNOWN:
	default:
		rc = smblib_get_prop_usb_present(chg, &pval);
		if (rc < 0) {
			smblib_err(chg, "Couldn't get usb present rc = %d\n",
					rc);
			return;
		}

		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
				pval.intval ? SDP_CURRENT_UA : SDP_100_MA);
					SDP_100_MA);
		break;
	}
}
+10 −1
Original line number Diff line number Diff line
@@ -228,6 +228,15 @@ enum thermal_status_levels {
	TEMP_BELOW_RANGE,
};

enum icl_override_mode {
	/* APSD/Type-C/QC auto */
	HW_AUTO_MODE,
	/* 100/150/500/900mA */
	SW_OVERRIDE_USB51_MODE,
	/* ICL other than USB51 */
	SW_OVERRIDE_HC_MODE,
};

/* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */
static const u32 smblib_extcon_exclusive[] = {0x3, 0};

@@ -645,7 +654,7 @@ int smblib_get_iio_channel(struct smb_charger *chg, const char *propname,
int smblib_read_iio_channel(struct smb_charger *chg, struct iio_channel *chan,
							int div, int *data);
int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable);
int smblib_icl_override(struct smb_charger *chg, bool override);
int smblib_icl_override(struct smb_charger *chg, enum icl_override_mode mode);
enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm,
				ktime_t time);
int smblib_toggle_smb_en(struct smb_charger *chg, int toggle);
+3 −0
Original line number Diff line number Diff line
@@ -216,6 +216,9 @@ enum {
#define CMD_APSD_REG				(USBIN_BASE + 0x41)
#define APSD_RERUN_BIT				BIT(0)

#define CMD_ICL_OVERRIDE_REG			(USBIN_BASE + 0x42)
#define ICL_OVERRIDE_BIT			BIT(0)

#define CMD_HVDCP_2_REG				(USBIN_BASE + 0x43)
#define FORCE_12V_BIT				BIT(5)
#define FORCE_9V_BIT				BIT(4)