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

Commit c4be61c3 authored by Jack Pham's avatar Jack Pham
Browse files

usb: pd: Avoid blocking wait in SRC_TRANSITION_TO_DEFAULT



When sending/receiving a hard reset in source mode, the
PE_SRC_TRANSITION_TO_DEFAULT state turns off VBUS/VCONN and
sleeps for 750ms. During this fairly long period any Type-C
event such as cable disconnect or reconnect won't get
processed as the workqueue is blocked by this wait condition.
This can lead to incorrect state handling, for example when
a sink is removed and a source is attached; the state machine
will think a sink is still attached. Fix this by removing
the msleep() and set a timer to restart the state machine
to PE_UNKNOWN which will turn VBUS/VCONN back on and start
again in PE_SRC_STARTUP. This frees up the workqueue to
process any potential incoming events in the meantime.

Change-Id: I282551a58252a672f319d1559eac9f4ad4c3ca8a
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent be0f20ce
Loading
Loading
Loading
Loading
+10 −18
Original line number Diff line number Diff line
@@ -2053,6 +2053,10 @@ static void usbpd_sm(struct work_struct *w)

	switch (pd->current_state) {
	case PE_UNKNOWN:
		val.intval = 0;
		power_supply_set_property(pd->usb_psy,
				POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);

		if (pd->current_pr == PR_SINK) {
			usbpd_set_state(pd, PE_SNK_STARTUP);
		} else if (pd->current_pr == PR_SRC) {
@@ -2215,8 +2219,11 @@ static void usbpd_sm(struct work_struct *w)
	case PE_SRC_TRANSITION_TO_DEFAULT:
		if (pd->vconn_enabled)
			regulator_disable(pd->vconn);
		pd->vconn_enabled = false;

		if (pd->vbus_enabled)
			regulator_disable(pd->vbus);
		pd->vbus_enabled = false;

		if (pd->current_dr != DR_DFP) {
			extcon_set_state_sync(pd->extcon, EXTCON_USB, 0);
@@ -2224,24 +2231,9 @@ static void usbpd_sm(struct work_struct *w)
			pd_phy_update_roles(pd->current_dr, pd->current_pr);
		}

		msleep(SRC_RECOVER_TIME);

		pd->vbus_enabled = false;
		enable_vbus(pd);

		if (pd->vconn_enabled) {
			ret = regulator_enable(pd->vconn);
			if (ret) {
				usbpd_err(&pd->dev, "Unable to enable vconn\n");
				pd->vconn_enabled = false;
			}
		}

		val.intval = 0;
		power_supply_set_property(pd->usb_psy,
				POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);

		usbpd_set_state(pd, PE_SRC_STARTUP);
		/* PE_UNKNOWN will turn on VBUS and go back to PE_SRC_STARTUP */
		pd->current_state = PE_UNKNOWN;
		kick_sm(pd, SRC_RECOVER_TIME);
		break;

	case PE_SRC_HARD_RESET: