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

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

Merge "power: smb-lib: start CC2 removal WA when VBUS is low"

parents a4da2aad 95d620e0
Loading
Loading
Loading
Loading
+90 −108
Original line number Diff line number Diff line
@@ -2353,16 +2353,7 @@ int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
			       union power_supply_propval *val)
{
	int rc;
	u8 ctrl;

	rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
			rc);
		return rc;
	}
	val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
	val->intval = chg->pd_hard_reset;
	return 0;
}

@@ -2744,88 +2735,70 @@ static struct reg_info cc2_detach_settings[] = {

static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
{
	int rc = 0;
	union power_supply_propval cc2_val = {0, };
	int rc, ccout, ufp_mode;
	u8 stat;

	if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
		return rc;
		return 0;

	if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
		return rc;
	if (chg->cc2_detach_wa_active)
		return 0;

	rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
		return rc;
	}
	if (cc2_val.intval == 1)
		return rc;
	ccout = (stat & CC_ATTACHED_BIT) ?
					(!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
	ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
					!(stat & UFP_DFP_MODE_STATUS_BIT) : 0;

	rc = smblib_get_prop_typec_mode(chg, &cc2_val);
	if (rc < 0) {
		smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
		return rc;
	}
	if (ccout != 2)
		return 0;

	switch (cc2_val.intval) {
	case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
	if (!ufp_mode)
		return 0;

	chg->cc2_detach_wa_active = true;
	/* The CC2 removal WA will cause a type-c-change IRQ storm */
	smblib_reg_block_update(chg, cc2_detach_settings);
		chg->cc2_sink_detach_flag = CC2_SINK_STD;
	schedule_work(&chg->rdstd_cc2_detach_work);
		break;
	case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
	case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
		chg->cc2_sink_detach_flag = CC2_SINK_MEDIUM_HIGH;
		break;
	default:
		break;
	}

	return rc;
}

static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
{
	int rc = 0;

	if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
		return rc;
		return 0;

	if (!chg->cc2_detach_wa_active)
		return 0;

	if (chg->cc2_sink_detach_flag == CC2_SINK_STD) {
	chg->cc2_detach_wa_active = false;
	cancel_work_sync(&chg->rdstd_cc2_detach_work);
	smblib_reg_block_restore(chg, cc2_detach_settings);
	}

	chg->cc2_sink_detach_flag = CC2_SINK_NONE;

	return rc;
	return 0;
}

int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
				const union power_supply_propval *val)
{
	int rc;
	int rc = 0;

	if (chg->pd_hard_reset == val->intval)
		return rc;

	chg->pd_hard_reset = val->intval;
	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
			EXIT_SNK_BASED_ON_CC_BIT,
				 (val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
	if (rc < 0) {
		smblib_err(chg, "Could not set EXIT_SNK_BASED_ON_CC rc=%d\n",
			(chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
	if (rc < 0)
		smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
				rc);
		return rc;
	}

	vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);

	if (val->intval)
		rc = smblib_cc2_sink_removal_enter(chg);
	else
		rc = smblib_cc2_sink_removal_exit(chg);

	if (rc < 0) {
		smblib_err(chg, "Could not detect cc2 removal rc=%d\n", rc);
		return rc;
	}
	vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
							chg->pd_hard_reset, 0);

	return rc;
}
@@ -3132,6 +3105,23 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
	return IRQ_HANDLED;
}

static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
{
	if (!vbus_rising) {
		smblib_update_usb_type(chg);
		extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
		smblib_uusb_removal(chg);
	}
}

static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
{
	if (vbus_rising)
		smblib_cc2_sink_removal_exit(chg);
	else
		smblib_cc2_sink_removal_enter(chg);
}

#define PL_DELAY_MS			30000
irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
{
@@ -3148,8 +3138,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
	}

	vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
	smblib_set_opt_freq_buck(chg,
		vbus_rising ? chg->chg_freq.freq_5V :
	smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
						chg->chg_freq.freq_removal);

	/* fetch the DPDM regulator */
@@ -3187,14 +3176,13 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
				smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
					rc);
		}

		if (chg->micro_usb_mode) {
			smblib_update_usb_type(chg);
			extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
			smblib_uusb_removal(chg);
		}
	}

	if (chg->micro_usb_mode)
		smblib_micro_usb_plugin(chg, vbus_rising);
	else
		smblib_typec_usb_plugin(chg, vbus_rising);

	power_supply_changed(chg->usb_psy);
	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
		irq_data->name, vbus_rising ? "attached" : "detached");
@@ -3615,6 +3603,8 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
{
	int rc;

	chg->cc2_detach_wa_active = false;

	cancel_delayed_work_sync(&chg->pl_enable_work);
	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
@@ -3699,24 +3689,6 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
	if (rc < 0)
		smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);

	/*
	 * HW BUG - after cable is removed, medium or high rd reading
	 * falls to std. Use it for signal of typec cc detachment in
	 * software WA.
	 */
	if (chg->cc2_sink_detach_flag == CC2_SINK_MEDIUM_HIGH
		&& pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {

		chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;

		rc = smblib_masked_write(chg,
				TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
				EXIT_SNK_BASED_ON_CC_BIT, 0);
		if (rc < 0)
			smblib_err(chg, "Couldn't get prop typec mode rc=%d\n",
				rc);
	}

	smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
		   rising ? "rising" : "falling",
		   smblib_typec_mode_name[pval.intval]);
@@ -3753,10 +3725,6 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
	if (chg->micro_usb_mode)
		return smblib_handle_usb_typec_change_for_uusb(chg);

	/* WA - not when PD hard_reset WIP on cc2 in sink mode */
	if (chg->cc2_sink_detach_flag == CC2_SINK_STD)
		return IRQ_HANDLED;

	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
@@ -3773,6 +3741,13 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
	sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
	legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);

	if (chg->cc2_detach_wa_active) {
		smblib_dbg(chg, PR_INTERRUPT, "Ignoring cc2_wrkarnd=%d dd=%d\n",
				chg->cc2_detach_wa_active,
				debounce_done);
		return IRQ_HANDLED;
	}

	smblib_handle_typec_debounce_done(chg,
			debounce_done, sink_attached, legacy_cable);

@@ -3910,11 +3885,14 @@ static void clear_hdc_work(struct work_struct *work)
static void rdstd_cc2_detach_work(struct work_struct *work)
{
	int rc;
	u8 stat;
	u8 stat4, stat5;
	struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
	struct smb_charger *chg = container_of(work, struct smb_charger,
						rdstd_cc2_detach_work);

	if (!chg->cc2_detach_wa_active)
		return;

	/*
	 * WA steps -
	 * 1. Enable both UFP and DFP, wait for 10ms.
@@ -3922,7 +3900,7 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
	 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
	 *    and TIMER_STAGE bits are gone, otherwise repeat all by
	 *    work rescheduling.
	 * Note, work will be cancelled when pd_hard_reset is 0.
	 * Note, work will be cancelled when USB_PLUGIN rises.
	 */

	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
@@ -3945,30 +3923,34 @@ static void rdstd_cc2_detach_work(struct work_struct *work)

	usleep_range(30000, 31000);

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

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

	if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
			|| (stat5 & TIMER_STAGE_2_BIT)) {
		smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
				(int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
				(int)(stat5 & TIMER_STAGE_2_BIT));
		goto rerun;
	}

	/* Bingo, cc2 removal detected */
	smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
	chg->cc2_detach_wa_active = false;
	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
						EXIT_SNK_BASED_ON_CC_BIT, 0);
	smblib_reg_block_restore(chg, cc2_detach_settings);
	chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
	irq_data.parent_data = chg;
	smblib_handle_usb_typec_change(0, &irq_data);

	return;

rerun:
+2 −8
Original line number Diff line number Diff line
@@ -71,13 +71,6 @@ enum smb_mode {
	NUM_MODES,
};

enum cc2_sink_type {
	CC2_SINK_NONE = 0,
	CC2_SINK_STD,
	CC2_SINK_MEDIUM_HIGH,
	CC2_SINK_WA_DONE,
};

enum {
	QC_CHARGER_DETECTION_WA_BIT	= BIT(0),
	BOOST_BACK_WA			= BIT(1),
@@ -313,10 +306,11 @@ struct smb_charger {
	int			default_icl_ua;
	int			otg_cl_ua;
	bool			uusb_apsd_rerun_done;
	bool			pd_hard_reset;

	/* workaround flag */
	u32			wa_flags;
	enum cc2_sink_type	cc2_sink_detach_flag;
	bool			cc2_detach_wa_active;
	int			boost_current_ua;
	int			temp_speed_reading_count;