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

Commit f7b89907 authored by Harry Yang's avatar Harry Yang Committed by Ashay Jaiswal
Browse files

power: smb5: Rearrange USB ICL SW configuration



SW configures USB ICL by updating ICL_MAX to override APSD results.
As APSD/PD flow has been re-organized by running APSD after PD, SW
ICL configuration process has to be updated accordingly.

Following is the order of power source precedence along with ICL_MAX
set by SW.

 1. USB PD: set by USB PD driver
 2. HVDCP (Quick Charge 2.0/3.0): 3A
 3. USB Type-C Rp-high: 3A; Rp-medium: 1.5A
 4. USB Legacy/Type-C Rp-std: follow USB BC 1.2

CRs-Fixed: 2215965
Change-Id: Ibd1cd3d531c3132f3cfadad68f6bb10453c702f2
Signed-off-by: default avatarHarry Yang <harryy@codeaurora.org>
parent 6afaea25
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -52,6 +52,13 @@ static struct smb_params smb5_pmi632_params = {
		.max_u  = 3000000,
		.step_u = 50000,
	},
	.icl_max_stat		= {
		.name   = "dcdc icl max status",
		.reg    = ICL_MAX_STATUS_REG,
		.min_u  = 0,
		.max_u  = 3000000,
		.step_u = 50000,
	},
	.icl_stat		= {
		.name   = "input current limit status",
		.reg    = AICL_ICL_STATUS_REG,
@@ -90,7 +97,7 @@ static struct smb_params smb5_pmi632_params = {
	},
};

static struct smb_params smb5_pmi855_params = {
static struct smb_params smb5_pm855b_params = {
	.fcc			= {
		.name   = "fast charge current",
		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
@@ -112,8 +119,15 @@ static struct smb_params smb5_pmi855_params = {
		.max_u  = 5000000,
		.step_u = 50000,
	},
	.icl_max_stat		= {
		.name   = "dcdc icl max status",
		.reg    = ICL_MAX_STATUS_REG,
		.min_u  = 0,
		.max_u  = 5000000,
		.step_u = 50000,
	},
	.icl_stat		= {
		.name   = "input current limit status",
		.name   = "aicl icl status",
		.reg    = AICL_ICL_STATUS_REG,
		.min_u  = 0,
		.max_u  = 5000000,
@@ -221,7 +235,7 @@ static int smb5_chg_config_init(struct smb5 *chip)
	switch (pmic_rev_id->pmic_subtype) {
	case PM855B_SUBTYPE:
		chip->chg.smb_version = PM855B_SUBTYPE;
		chg->param = smb5_pmi855_params;
		chg->param = smb5_pm855b_params;
		chg->name = "pm855b_charger";
		break;
	case PMI632_SUBTYPE:
+135 −59
Original line number Diff line number Diff line
@@ -39,6 +39,10 @@
				__func__, ##__VA_ARGS__);	\
	} while (0)

#define typec_rp_med_high(chg, typec_mode)			\
	((typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM	\
	|| typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH)	\
	&& !chg->typec_legacy)

int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
{
@@ -654,7 +658,7 @@ int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
	return 0;
}

#define USBIN_100MA	100000
#define SDP_100_MA			100000
static void smblib_uusb_removal(struct smb_charger *chg)
{
	int rc;
@@ -679,6 +683,7 @@ static void smblib_uusb_removal(struct smb_charger *chg)
	/* reset both usbin current and voltage votes */
	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
	vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);

	/* reconfigure allowed voltage for HVDCP */
@@ -701,8 +706,6 @@ static void smblib_uusb_removal(struct smb_charger *chg)
		smblib_err(chg, "Couldn't write float charger options rc=%d\n",
			rc);

	/* leave the ICL configured to 100mA for next insertion */
	vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA);
	/* clear USB ICL vote for USB_PSY_VOTER */
	rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
	if (rc < 0)
@@ -768,6 +771,7 @@ static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
}

#define USBIN_25MA	25000
#define USBIN_100MA	100000
#define USBIN_150MA	150000
#define USBIN_500MA	500000
#define USBIN_900MA	900000
@@ -881,6 +885,10 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
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;
	}

	/* unsuspend after configuring current and override */
	rc = smblib_set_usb_suspend(chg, false);
@@ -921,7 +929,8 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
			return INT_MAX;

		/* override is set */
		rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
		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;
@@ -2103,24 +2112,40 @@ static int smblib_handle_usb_current(struct smb_charger *chg,

	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
		if (usb_current == -ETIMEDOUT) {
			if ((chg->float_cfg & FLOAT_OPTIONS_MASK)
						== FORCE_FLOAT_SDP_CFG_BIT) {
				/*
			 * Valid FLOAT charger, report the current based
			 * of Rp
				 * Confiugure USB500 mode if Float charger is
				 * configured for SDP.
				 */
				rc = set_sdp_current(chg, USBIN_500MA);
				if (rc < 0)
					smblib_err(chg,
						"Couldn't set SDP ICL rc=%d\n",
						rc);

				return rc;
			}

			if (chg->connector_type ==
					POWER_SUPPLY_CONNECTOR_TYPEC) {
				/*
				 * Valid FLOAT charger, report the current
				 * based of Rp.
				 */
				typec_mode = smblib_get_prop_typec_mode(chg);
				rp_ua = get_rp_based_dcp_current(chg,
								typec_mode);
				rc = vote(chg->usb_icl_votable,
						DYNAMIC_RP_VOTER, true, rp_ua);
				if (rc < 0) {
					pr_err("Couldn't vote ICL DYNAMIC_RP_VOTER rc=%d\n",
							rc);
					SW_ICL_MAX_VOTER, true, rp_ua);
				if (rc < 0)
					return rc;
			} else {
				rc = vote(chg->usb_icl_votable,
					SW_ICL_MAX_VOTER, true, DCP_CURRENT_UA);
				if (rc < 0)
					return rc;
			}
			}
			/* No specific handling required for micro-USB */
		} else {
			/*
			 * FLOAT charger detected as SDP by USB driver,
@@ -2130,11 +2155,12 @@ static int smblib_handle_usb_current(struct smb_charger *chg,
			chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
			rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
						true, usb_current);
			if (rc < 0) {
				pr_err("Couldn't vote ICL USB_PSY_VOTER rc=%d\n",
						rc);
			if (rc < 0)
				return rc;
			rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER,
							false, 0);
			if (rc < 0)
				return rc;
			}
		}
	} else {
		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
@@ -2144,14 +2170,14 @@ static int smblib_handle_usb_current(struct smb_charger *chg,
			return rc;
		}

	}

	rc = vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
		rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
		if (rc < 0) {
		pr_err("Couldn't unvote ICL DEFAULT_100MA_VOTER rc=%d\n", rc);
			pr_err("Couldn't remove SW_ICL_MAX vote rc=%d\n", rc);
			return rc;
		}

	}

	return 0;
}

@@ -2285,7 +2311,9 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
		 * pd_current_max
		 */
		vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
	} 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);

@@ -2828,18 +2856,17 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
{
	if (rising) {

		if (qc_charger) {
			/* enable HDC and ICL irq for QC2/3 charger */
		if (qc_charger)
			vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
		else
		/*
		 * HVDCP detection timeout done
		 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
		 * enforce DCP ICL if specified
		 */
			vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
				HVDCP_CURRENT_UA);
		} else {
			/* A plain DCP, enforce DCP ICL if specified */
			vote(chg->usb_icl_votable, DCP_VOTER,
				chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
		}
	}

	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
		   rising ? "rising" : "falling");
@@ -2853,6 +2880,69 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
		   rising ? "rising" : "falling");
}

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

	/* while PD is active it should have complete ICL control */
	if (chg->pd_active)
		return;

	/*
	 * HVDCP 2/3, handled separately
	 * For UNKNOWN(input not present) return without updating ICL
	 */
	if (pst == POWER_SUPPLY_TYPE_USB_HVDCP
			|| pst == POWER_SUPPLY_TYPE_USB_HVDCP_3
			|| pst == POWER_SUPPLY_TYPE_UNKNOWN)
		return;

	/* TypeC rp med or high, use rp value */
	typec_mode = smblib_get_prop_typec_mode(chg);
	if (typec_rp_med_high(chg, typec_mode)) {
		rp_ua = get_rp_based_dcp_current(chg, typec_mode);
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua);
		return;
	}

	/* rp-std or legacy, USB BC 1.2 */
	switch (pst) {
	case POWER_SUPPLY_TYPE_USB:
		/*
		 * USB_PSY will vote to increase the current to 500/900mA once
		 * enumeration is done.
		 */
		if (!is_client_vote_enabled(chg->usb_icl_votable,
								USB_PSY_VOTER))
			vote(chg->usb_icl_votable, USB_PSY_VOTER, true,
					SDP_100_MA);
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
		break;
	case POWER_SUPPLY_TYPE_USB_CDP:
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
					CDP_CURRENT_UA);
		break;
	case POWER_SUPPLY_TYPE_USB_DCP:
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
					DCP_CURRENT_UA);
		break;
	case POWER_SUPPLY_TYPE_USB_FLOAT:
		/*
		 * limit ICL to 100mA, the USB driver will enumerate to check
		 * if this is a SDP and appropriately set the current
		 */
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
					SDP_100_MA);
		break;
	default:
		smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
		vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
					SDP_CURRENT_UA);
		break;
	}
}

static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
{
	const struct apsd_result *apsd_result;
@@ -2862,6 +2952,8 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)

	apsd_result = smblib_update_usb_type(chg);

	update_sw_icl_max(chg, apsd_result->pst);

	switch (apsd_result->bit) {
	case SDP_CHARGER_BIT:
	case CDP_CHARGER_BIT:
@@ -2872,7 +2964,6 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
		break;
	case OCP_CHARGER_BIT:
	case DCP_CHARGER_BIT:
		vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
		break;
	default:
		break;
@@ -3028,7 +3119,7 @@ static void typec_src_removal(struct smb_charger *chg)
	cancel_delayed_work_sync(&chg->pl_enable_work);

	/* reset input current limit voters */
	vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA);
	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_icl_votable, USB_PSY_VOTER, false, 0);
	vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
@@ -3036,7 +3127,6 @@ static void typec_src_removal(struct smb_charger *chg)
	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
	vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
	vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
	vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0);

	/* reset usb irq voters */
	vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
@@ -3081,41 +3171,27 @@ static void typec_src_removal(struct smb_charger *chg)

static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
{
	int rp_ua;
	const struct apsd_result *apsd = smblib_get_apsd_result(chg);

	if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
		&& (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
		return;

	/*
	 * if APSD indicates FLOAT and the USB stack had detected SDP,
	 * do not respond to Rp changes as we do not confirm that its
	 * a legacy cable
	 */
	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
		return;
	/*
	 * We want the ICL vote @ 100mA for a FLOAT charger
	 * until the detection by the USB stack is complete.
	 * Ignore the Rp changes unless there is a
	 * pre-existing valid vote.
	 * pre-existing valid vote or FLOAT is configured for
	 * SDP current.
	 */
	if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
		(get_client_vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER)
					<= USBIN_100MA))
	if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
		if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER)
					<= USBIN_100MA
			|| (chg->float_cfg & FLOAT_OPTIONS_MASK)
					== FORCE_FLOAT_SDP_CFG_BIT)
		return;
	}

	update_sw_icl_max(chg, apsd->pst);

	/*
	 * handle Rp change for DCP/FLOAT/OCP.
	 * Update the current only if the Rp is different from
	 * the last Rp value.
	 */
	smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
						chg->typec_mode, typec_mode);

	rp_ua = get_rp_based_dcp_current(chg, typec_mode);
	vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua);
}

irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
+2 −2
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ enum print_reason {
#define CTM_VOTER			"CTM_VOTER"
#define SW_QC3_VOTER			"SW_QC3_VOTER"
#define AICL_RERUN_VOTER		"AICL_RERUN_VOTER"
#define SW_ICL_MAX_VOTER		"SW_ICL_MAX_VOTER"
#define QNOVO_VOTER			"QNOVO_VOTER"
#define BATT_PROFILE_VOTER		"BATT_PROFILE_VOTER"
#define OTG_DELAY_VOTER			"OTG_DELAY_VOTER"
@@ -65,8 +66,6 @@ enum print_reason {
#define PL_FCC_LOW_VOTER		"PL_FCC_LOW_VOTER"
#define WBC_VOTER			"WBC_VOTER"
#define HW_LIMIT_VOTER			"HW_LIMIT_VOTER"
#define DYNAMIC_RP_VOTER		"DYNAMIC_RP_VOTER"
#define DEFAULT_100MA_VOTER		"DEFAULT_100MA_VOTER"
#define FORCE_RECHARGE_VOTER		"FORCE_RECHARGE_VOTER"

#define BOOST_BACK_STORM_COUNT	3
@@ -234,6 +233,7 @@ struct smb_params {
	struct smb_chg_param	fcc;
	struct smb_chg_param	fv;
	struct smb_chg_param	usb_icl;
	struct smb_chg_param	icl_max_stat;
	struct smb_chg_param	icl_stat;
	struct smb_chg_param	otg_cl;
	struct smb_chg_param	jeita_cc_comp_hot;
+2 −0
Original line number Diff line number Diff line
@@ -105,6 +105,8 @@ enum {
/********************************
 *  DCDC Peripheral Registers  *
 ********************************/
#define ICL_MAX_STATUS_REG			(DCDC_BASE + 0x06)

#define AICL_ICL_STATUS_REG			(DCDC_BASE + 0x08)

#define AICL_STATUS_REG				(DCDC_BASE + 0x0A)