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

Commit 552e41c2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: smb5: update USB source detection sequence" into msm-4.9

parents eeb585ca 6afaea25
Loading
Loading
Loading
Loading
+44 −41
Original line number Diff line number Diff line
@@ -177,6 +177,11 @@ module_param_named(
	debug_mask, __debug_mask, int, 0600
);

static int __pd_disabled;
module_param_named(
	pd_disabled, __pd_disabled, int, 0600
);

static int __weak_chg_icl_ua = 500000;
module_param_named(
	weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
@@ -434,7 +439,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_PD_ALLOWED,
	POWER_SUPPLY_PROP_PD_ACTIVE,
	POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
	POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
@@ -515,9 +519,6 @@ static int smb5_usb_get_prop(struct power_supply *psy,
		else
			rc = smblib_get_prop_typec_cc_orientation(chg, val);
		break;
	case POWER_SUPPLY_PROP_PD_ALLOWED:
		rc = smblib_get_prop_pd_allowed(chg, val);
		break;
	case POWER_SUPPLY_PROP_PD_ACTIVE:
		val->intval = chg->pd_active;
		break;
@@ -605,12 +606,6 @@ static int smb5_usb_set_prop(struct power_supply *psy,
	struct smb_charger *chg = &chip->chg;
	int rc = 0;

	mutex_lock(&chg->lock);
	if (!chg->typec_present) {
		rc = -EINVAL;
		goto unlock;
	}

	switch (psp) {
	case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
		rc = smblib_set_prop_pd_current_max(chg, val);
@@ -652,8 +647,6 @@ static int smb5_usb_set_prop(struct power_supply *psy,
		break;
	}

unlock:
	mutex_unlock(&chg->lock);
	return rc;
}

@@ -1425,6 +1418,15 @@ static int smb5_configure_typec(struct smb_charger *chg)
{
	int rc;

	/* disable apsd */
	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
				HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
				0);
	if (rc < 0) {
		dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
		return rc;
	}

	rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
				TYPEC_CCOUT_DETACH_INT_EN_BIT |
				TYPEC_CCOUT_ATTACH_INT_EN_BIT);
@@ -1459,14 +1461,6 @@ static int smb5_configure_micro_usb(struct smb_charger *chg)
{
	int rc;

	/* configure micro USB mode */
	rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
			EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT);
	if (rc < 0) {
		dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc);
		return rc;
	}

	rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
					MICRO_USB_STATE_CHANGE_INT_EN_BIT,
					MICRO_USB_STATE_CHANGE_INT_EN_BIT);
@@ -1500,7 +1494,6 @@ static int smb5_init_hw(struct smb5 *chip)
				&chg->default_icl_ua);

	/* Use SW based VBUS control, disable HW autonomous mode */
	/* TODO: auth can be enabled through vote based on APSD flow */
	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
		HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
		HVDCP_AUTH_ALG_EN_CFG_BIT);
@@ -1537,10 +1530,22 @@ static int smb5_init_hw(struct smb5 *chip)
		type = !!(val & EN_MICRO_USB_MODE_BIT);
	}

	chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
					: POWER_SUPPLY_CONNECTOR_TYPEC;
	pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");

	if (type) {
		chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
		smblib_rerun_apsd_if_required(chg);
		rc = smb5_configure_micro_usb(chg);
	} else {
		chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
		rc = smb5_configure_typec(chg);
	}
	if (rc < 0) {
		dev_err(chg->dev,
			"Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
		return rc;
	}

	/*
	 * PMI632 based hw init:
	 * - Initialize flash module for PMI632
@@ -1548,8 +1553,6 @@ static int smb5_init_hw(struct smb5 *chip)
	if (chg->smb_version == PMI632_SUBTYPE)
		schgm_flash_init(chg);

	smblib_rerun_apsd_if_required(chg);

	/* vote 0mA on usb_icl for non battery platforms */
	vote(chg->usb_icl_votable,
		DEFAULT_VOTER, chip->dt.no_battery, 0);
@@ -1565,12 +1568,6 @@ static int smb5_init_hw(struct smb5 *chip)
	vote(chg->fv_votable,
		BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
		chg->batt_profile_fv_uv);
	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
			true, 0);
	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
			true, 0);
	vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
		chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);

	/* Some h/w limit maximum supported ICL */
	vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
@@ -1594,16 +1591,6 @@ static int smb5_init_hw(struct smb5 *chip)
		return rc;
	}

	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
		rc = smb5_configure_micro_usb(chg);
	else
		rc = smb5_configure_typec(chg);
	if (rc < 0) {
		dev_err(chg->dev,
			"Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
		return rc;
	}

	/* configure VBUS for software control */
	rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
	if (rc < 0) {
@@ -1812,11 +1799,21 @@ static int smb5_determine_initial_status(struct smb5 *chip)
{
	struct smb_irq_data irq_data = {chip, "determine-initial-status"};
	struct smb_charger *chg = &chip->chg;
	union power_supply_propval val;
	int rc;

	rc = smblib_get_prop_usb_present(chg, &val);
	if (rc < 0) {
		pr_err("Couldn't get usb present rc=%d\n", rc);
		return rc;
	}
	chg->early_usb_attach = val.intval;

	if (chg->bms_psy)
		smblib_suspend_on_debug_battery(chg);

	usb_plugin_irq_handler(0, &irq_data);
	typec_attach_detach_irq_handler(0, &irq_data);
	typec_state_change_irq_handler(0, &irq_data);
	usb_source_change_irq_handler(0, &irq_data);
	chg_state_change_irq_handler(0, &irq_data);
@@ -2008,6 +2005,7 @@ static struct smb_irq_info smb5_irqs[] = {
	},
	[TYPEC_ATTACH_DETACH_IRQ] = {
		.name		= "typec-attach-detach",
		.handler	= typec_attach_detach_irq_handler,
	},
	[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
		.name		= "typec-legacy-cable-detect",
@@ -2303,6 +2301,7 @@ static int smb5_probe(struct platform_device *pdev)
	chg = &chip->chg;
	chg->dev = &pdev->dev;
	chg->debug_mask = &__debug_mask;
	chg->pd_disabled = &__pd_disabled;
	chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
	chg->mode = PARALLEL_MASTER;
	chg->irq_info = smb5_irqs;
@@ -2452,6 +2451,10 @@ static int smb5_remove(struct platform_device *pdev)
	struct smb5 *chip = platform_get_drvdata(pdev);
	struct smb_charger *chg = &chip->chg;

	/* force enable APSD */
	smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
				BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);

	smb5_free_interrupts(chg);
	smblib_deinit(chg);
	platform_set_drvdata(pdev, NULL);
+149 −248
Original line number Diff line number Diff line
@@ -663,10 +663,6 @@ static void smblib_uusb_removal(struct smb_charger *chg)

	cancel_delayed_work_sync(&chg->pl_enable_work);

	rc = smblib_request_dpdm(chg, false);
	if (rc < 0)
		smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);

	if (chg->wa_flags & BOOST_BACK_WA) {
		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
		if (data) {
@@ -954,18 +950,6 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
	return smblib_set_dc_suspend(chg, (bool)suspend);
}

static int smblib_pd_disallowed_votable_indirect_callback(
	struct votable *votable, void *data, int disallowed, const char *client)
{
	struct smb_charger *chg = data;
	int rc;

	rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
		!disallowed, 0);

	return rc;
}

static int smblib_awake_vote_callback(struct votable *votable, void *data,
			int awake, const char *client)
{
@@ -1989,13 +1973,6 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg,
	return rc;
}

int smblib_get_prop_pd_allowed(struct smb_charger *chg,
			       union power_supply_propval *val)
{
	val->intval = get_effective_result(chg->pd_allowed_votable);
	return 0;
}

int smblib_get_prop_input_current_settled(struct smb_charger *chg,
					  union power_supply_propval *val)
{
@@ -2039,13 +2016,7 @@ int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
int smblib_get_pe_start(struct smb_charger *chg,
			       union power_supply_propval *val)
{
	/*
	 * hvdcp timeout voter is the last one to allow pd. Use its vote
	 * to indicate start of pe engine
	 */
	val->intval
		= !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
			APSD_VOTER);
	val->intval = chg->ok_to_pd;
	return 0;
}

@@ -2298,14 +2269,14 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
	return rc;
}

static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
int smblib_set_prop_pd_active(struct smb_charger *chg,
				const union power_supply_propval *val)
{
	int rc = 0;

	chg->pd_active = pd_active;
	chg->pd_active = val->intval;

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

		/*
@@ -2313,24 +2284,24 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
		 * It is guaranteed that pd_active is set prior to
		 * pd_current_max
		 */
		rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
		if (rc < 0)
			smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
									rc);

		/* clear USB ICL vote for DCP_VOTER */
		rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
		if (rc < 0)
			smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
									rc);

		/* remove USB_PSY_VOTER */
		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
		if (rc < 0)
			smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
		vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
	} else {
		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
		vote(chg->usb_icl_votable, PD_VOTER, false, 0);
		vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);

		/* PD hard resets failed, rerun apsd */
		if (chg->ok_to_pd) {
			chg->ok_to_pd = false;
			rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
					HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
					HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT);
			if (rc < 0) {
				dev_err(chg->dev,
					"Couldn't disable APSD rc=%d\n", rc);
				return rc;
			}
			smblib_rerun_apsd(chg);
		}
	}

	smblib_update_usb_type(chg);
@@ -2338,15 +2309,6 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
	return rc;
}

int smblib_set_prop_pd_active(struct smb_charger *chg,
			      const union power_supply_propval *val)
{
	if (!get_effective_result(chg->pd_allowed_votable))
		return -EINVAL;

	return __smblib_set_prop_pd_active(chg, val->intval);
}

int smblib_set_prop_ship_mode(struct smb_charger *chg,
				const union power_supply_propval *val)
{
@@ -2657,11 +2619,7 @@ irqreturn_t icl_change_irq_handler(int irq, void *data)

static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
{
	if (vbus_rising) {
		/* use the typec flag even though its not typec */
		chg->typec_present = 1;
	} else {
		chg->typec_present = 0;
	if (!vbus_rising) {
		smblib_update_usb_type(chg);
		smblib_notify_device_mode(chg, false);
		smblib_uusb_removal(chg);
@@ -2764,12 +2722,10 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data)
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;

	mutex_lock(&chg->lock);
	if (chg->pd_hard_reset)
		smblib_usb_plugin_hard_reset_locked(chg);
	else
		smblib_usb_plugin_locked(chg);
	mutex_unlock(&chg->lock);

	return IRQ_HANDLED;
}
@@ -2858,8 +2814,6 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
	if (!rising)
		return;

	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);

	if (chg->mode == PARALLEL_MASTER)
		vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);

@@ -2872,33 +2826,19 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
					      bool rising, bool qc_charger)
{
	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);

	/* Hold off PD only until hvdcp 2.0 detection timeout */
	if (rising) {

		/* enable HDC and ICL irq for QC2/3 charger */
		if (qc_charger)
			vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
		else
			vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
							false, 0);

		/*
		 * HVDCP detection timeout done
		 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
		 * enforce DCP ICL if specified
		 */
		if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
			/* enforce DCP ICL if specified */
			vote(chg->usb_icl_votable, DCP_VOTER,
				chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);

		/*
		 * if pd is not allowed, then set pd_active = false right here,
		 * so that it starts the hvdcp engine
		 */
		if (!get_effective_result(chg->pd_allowed_votable))
			__smblib_set_prop_pd_active(chg, 0);
	}

	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
@@ -2926,19 +2866,11 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
	case SDP_CHARGER_BIT:
	case CDP_CHARGER_BIT:
	case FLOAT_CHARGER_BIT:
		/* if not DCP then no hvdcp timeout happens. Enable pd here */
		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
				false, 0);
		if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
				|| chg->use_extcon)
			smblib_notify_device_mode(chg, true);
		break;
	case OCP_CHARGER_BIT:
		vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
		/* if not DCP then no hvdcp timeout happens, Enable pd here. */
		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
				false, 0);
		break;
	case DCP_CHARGER_BIT:
		vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
		break;
@@ -2957,6 +2889,14 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data)
	int rc = 0;
	u8 stat;

	/*
	 * Prepared to run PD or PD is active. At this moment, APSD is disabled,
	 * but there still can be irq on apsd_done from previously unfinished
	 * APSD run, skip it.
	 */
	if (chg->ok_to_pd)
		return IRQ_HANDLED;

	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
@@ -3011,32 +2951,68 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data)

static void typec_sink_insertion(struct smb_charger *chg)
{
	/* when a sink is inserted we should not wait on hvdcp timeout to
	 * enable pd
	 */
	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
	vote(chg->usb_icl_votable, OTG_VOTER, true, 0);

	if (chg->use_extcon) {
		smblib_notify_usb_host(chg, true);
		chg->otg_present = true;
	}

	if (!chg->pr_swap_in_progress)
		chg->ok_to_pd = !(*chg->pd_disabled) || chg->early_usb_attach;
}

static void typec_src_insertion(struct smb_charger *chg)
{
	int rc = 0;
	u8 stat;

	if (chg->pr_swap_in_progress)
		return;

	rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
			rc);
		return;
	}

	chg->typec_legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
	chg->ok_to_pd = !(chg->typec_legacy || *chg->pd_disabled)
						|| chg->early_usb_attach;
	if (!chg->ok_to_pd) {
		rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
				HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
				HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT);
		if (rc < 0) {
			dev_err(chg->dev,
				"Couldn't disable APSD rc=%d\n", rc);
			return;
		}
		smblib_rerun_apsd(chg);
	}
}

static void typec_sink_removal(struct smb_charger *chg)
{
	smblib_set_charge_param(chg, &chg->param.freq_switcher,
			chg->chg_freq.freq_above_otg_threshold);
	chg->boost_current_ua = 0;
	vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
}

static void smblib_handle_typec_removal(struct smb_charger *chg)
static void typec_src_removal(struct smb_charger *chg)
{
	int rc;
	struct smb_irq_data *data;
	struct storm_watch *wdata;

	rc = smblib_request_dpdm(chg, false);
	/* disable apsd */
	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
				HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
				0);
	if (rc < 0)
		smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
		smblib_err(chg,
			"Couldn't disable APSD rc=%d\n", rc);

	smblib_update_usb_type(chg);

	if (chg->wa_flags & BOOST_BACK_WA) {
		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
@@ -3062,11 +3038,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
	vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
	vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0);

	/* reset power delivery voters */
	vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0);

	/* reset usb irq voters */
	vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
	vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
@@ -3078,14 +3049,10 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);

	chg->vconn_attempts = 0;
	chg->otg_attempts = 0;
	chg->pulse_cnt = 0;
	chg->usb_icl_delta_ua = 0;
	chg->voltage_min_uv = MICRO_5V;
	chg->voltage_max_uv = MICRO_5V;
	chg->pd_active = 0;
	chg->pd_hard_reset = 0;

	/* write back the default FLOAT charger configuration */
	rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
@@ -3094,12 +3061,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
		smblib_err(chg, "Couldn't write float charger options rc=%d\n",
			rc);

	/* reset back to 103mS tCC debounce */
	rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
					REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0);
	if (rc < 0)
		smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);

	/* reconfigure allowed voltage for HVDCP */
	rc = smblib_set_adapter_allowance(chg,
			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
@@ -3107,58 +3068,15 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
			rc);

	/* enable DRP */
	rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
				TYPEC_POWER_ROLE_CMD_MASK, 0);
	if (rc < 0)
		smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);

	/* HW controlled CC_OUT */
	rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
				TYPEC_CCOUT_SRC_BIT, 0);
	if (rc < 0)
		smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);

	/* clear exit sink based on cc */
	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
						EXIT_SNK_BASED_ON_CC_BIT, 0);
	if (rc < 0)
		smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
				rc);

	typec_sink_removal(chg);
	smblib_update_usb_type(chg);

	if (chg->use_extcon) {
		if (chg->otg_present)
			smblib_notify_usb_host(chg, false);
		else
			smblib_notify_device_mode(chg, false);
	}
	chg->otg_present = false;
}

static void smblib_handle_typec_insertion(struct smb_charger *chg)
{
	int rc;
	u8 stat;

	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);

	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
		return;
	}

	if (stat & SNK_SRC_MODE_BIT) {
		typec_sink_insertion(chg);
	} else {
		rc = smblib_request_dpdm(chg, true);
		if (rc < 0)
			smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
		typec_sink_removal(chg);
	}
	chg->otg_present = false;
	chg->typec_legacy = false;
}

static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
@@ -3200,98 +3118,102 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
	vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua);
}

static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
{
	u8 stat;
	int typec_mode, rc;

	if (chg->pr_swap_in_progress)
		return;

	typec_mode = smblib_get_prop_typec_mode(chg);
	if (chg->typec_present && (typec_mode != chg->typec_mode))
		smblib_handle_rp_change(chg, typec_mode);

	chg->typec_mode = typec_mode;

	if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
		chg->typec_present = true;
		smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
			smblib_typec_mode_name[chg->typec_mode]);
		smblib_handle_typec_insertion(chg);
	} else if (chg->typec_present &&
				chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
		chg->typec_present = false;
		smblib_dbg(chg, PR_MISC, "TypeC removal\n");
		smblib_handle_typec_removal(chg);
	}
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;

	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
		return;
	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
		cancel_delayed_work_sync(&chg->uusb_otg_work);
		vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
		smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
		schedule_delayed_work(&chg->uusb_otg_work,
				msecs_to_jiffies(chg->otg_delay_ms));
		return IRQ_HANDLED;
	}
	/* suspend usb if sink */
	if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present)
		vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
	else
		vote(chg->usb_icl_votable, OTG_VOTER, false, 0);

	smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
				smblib_typec_mode_name[chg->typec_mode]);
	return IRQ_HANDLED;
}

static void smblib_usb_typec_change(struct smb_charger *chg)
irqreturn_t typec_state_change_irq_handler(int irq, void *data)
{
	int rc;
	u8 stat;

	smblib_handle_typec_cc_state_change(chg);
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
	int typec_mode;

	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
		return;
	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
		smblib_dbg(chg, PR_INTERRUPT,
				"Ignoring for micro USB\n");
		return IRQ_HANDLED;
	}

	if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
		smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
	typec_mode = smblib_get_prop_typec_mode(chg);
	if (chg->sink_src_mode != UNATTACHED_MODE
			&& (typec_mode != chg->typec_mode))
		smblib_handle_rp_change(chg, typec_mode);
	chg->typec_mode = typec_mode;

	smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
				smblib_typec_mode_name[chg->typec_mode]);

	power_supply_changed(chg->usb_psy);

	return IRQ_HANDLED;
}

irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
irqreturn_t typec_attach_detach_irq_handler(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
	u8 stat;
	int rc;

	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
		cancel_delayed_work_sync(&chg->uusb_otg_work);
		vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
		smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
		schedule_delayed_work(&chg->uusb_otg_work,
				msecs_to_jiffies(chg->otg_delay_ms));
	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);

	rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
			rc);
		return IRQ_HANDLED;
	}

	if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) {
		rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
		if (rc < 0) {
			smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n",
				rc);
			return IRQ_HANDLED;
		}

irqreturn_t typec_state_change_irq_handler(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;
		if (stat & SNK_SRC_MODE_BIT) {
			chg->sink_src_mode = SRC_MODE;
			typec_sink_insertion(chg);
		} else {
			chg->sink_src_mode = SINK_MODE;
			typec_src_insertion(chg);
		}

	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
			|| chg->pr_swap_in_progress) {
		smblib_dbg(chg, PR_INTERRUPT,
				"Ignoring since pr_swap_in_progress\n");
		return IRQ_HANDLED;
	} else {
		switch (chg->sink_src_mode) {
		case SRC_MODE:
			typec_sink_removal(chg);
			break;
		case SINK_MODE:
			typec_src_removal(chg);
			break;
		default:
			break;
		}

	mutex_lock(&chg->lock);
	smblib_usb_typec_change(chg);
	mutex_unlock(&chg->lock);
		if (!chg->pr_swap_in_progress) {
			chg->ok_to_pd = false;
			chg->sink_src_mode = UNATTACHED_MODE;
			chg->early_usb_attach = false;
		}
	}

	power_supply_changed(chg->usb_psy);

	return IRQ_HANDLED;
}

@@ -3717,23 +3639,6 @@ static int smblib_create_votables(struct smb_charger *chg)
		return rc;
	}

	chg->pd_disallowed_votable_indirect
		= create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
			smblib_pd_disallowed_votable_indirect_callback, chg);
	if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
		rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
		chg->pd_disallowed_votable_indirect = NULL;
		return rc;
	}

	chg->pd_allowed_votable = create_votable("PD_ALLOWED",
					VOTE_SET_ANY, NULL, NULL);
	if (IS_ERR(chg->pd_allowed_votable)) {
		rc = PTR_ERR(chg->pd_allowed_votable);
		chg->pd_allowed_votable = NULL;
		return rc;
	}

	chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
					smblib_awake_vote_callback,
					chg);
@@ -3771,10 +3676,6 @@ static void smblib_destroy_votables(struct smb_charger *chg)
		destroy_votable(chg->dc_suspend_votable);
	if (chg->usb_icl_votable)
		destroy_votable(chg->usb_icl_votable);
	if (chg->pd_disallowed_votable_indirect)
		destroy_votable(chg->pd_disallowed_votable_indirect);
	if (chg->pd_allowed_votable)
		destroy_votable(chg->pd_allowed_votable);
	if (chg->awake_votable)
		destroy_votable(chg->awake_votable);
	if (chg->chg_disable_votable)
@@ -3786,7 +3687,6 @@ int smblib_init(struct smb_charger *chg)
	int rc = 0;

	mutex_init(&chg->lock);
	mutex_init(&chg->otg_oc_lock);
	INIT_WORK(&chg->bms_update_work, bms_update_work);
	INIT_WORK(&chg->pl_update_work, pl_update_work);
	INIT_WORK(&chg->jeita_update_work, jeita_update_work);
@@ -3799,6 +3699,7 @@ int smblib_init(struct smb_charger *chg)
	chg->fake_input_current_limited = -EINVAL;
	chg->fake_batt_status = -EINVAL;
	chg->jeita_configured = false;
	chg->sink_src_mode = UNATTACHED_MODE;

	switch (chg->mode) {
	case PARALLEL_MASTER:
+17 −11

File changed.

Preview size limit exceeded, changes collapsed.

+5 −0
Original line number Diff line number Diff line
@@ -215,6 +215,7 @@ enum {
#define HVDCP_AUTH_ALG_EN_CFG_BIT		BIT(6)
#define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT	BIT(5)
#define BC1P2_SRC_DETECT_BIT			BIT(3)
#define HVDCP_EN_BIT				BIT(2)

#define USBIN_OPTIONS_2_CFG_REG			(USBIN_BASE + 0x63)
#define FLOAT_OPTIONS_MASK			GENMASK(2, 0)
@@ -262,6 +263,9 @@ enum {
#define SRC_RA_OPEN_BIT				BIT(1)
#define AUDIO_ACCESS_RA_RA_BIT			BIT(0)

#define TYPE_C_STATE_MACHINE_STATUS_REG		(TYPEC_BASE + 0x09)
#define TYPEC_ATTACH_DETACH_STATE_BIT		BIT(5)

#define TYPE_C_MISC_STATUS_REG			(TYPEC_BASE + 0x0B)
#define SNK_SRC_MODE_BIT			BIT(6)
#define TYPEC_VBUS_ERROR_STATUS_BIT		BIT(4)
@@ -269,6 +273,7 @@ enum {
#define CC_ATTACHED_BIT				BIT(0)

#define LEGACY_CABLE_STATUS_REG			(TYPEC_BASE + 0x0D)
#define TYPEC_LEGACY_CABLE_STATUS_BIT		BIT(1)
#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT	BIT(0)

#define TYPEC_U_USB_STATUS_REG			(TYPEC_BASE + 0x0F)