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

Commit 6d818b26 authored by Manu Gautam's avatar Manu Gautam
Browse files

USB: dwc3-msm: Perform HW reinitialization on HC died error



USB core provides atomic notifier that can be used by platform
drivers to perform hardware reset/recovery on HC died error.
This error is fatal and requires complete hardware
re-initialization. This will remove and add hcd again.

Change-Id: Ic889ef002717a8fa33e9b7c27fab14a8778bba89
CRs-fixed: 1048766
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent 8d6559d4
Loading
Loading
Loading
Loading
+35 −2
Original line number Diff line number Diff line
@@ -233,6 +233,8 @@ struct dwc3_msm {

	unsigned int		irq_to_affin;
	struct notifier_block	dwc3_cpu_notifier;
	struct notifier_block	usbdev_nb;
	bool			hc_died;

	int  pwr_event_irq;
	atomic_t                in_p3;
@@ -1543,6 +1545,33 @@ static void dwc3_restart_usb_work(struct work_struct *w)
	flush_delayed_work(&mdwc->sm_work);
}

static int msm_dwc3_usbdev_notify(struct notifier_block *self,
			unsigned long action, void *priv)
{
	struct dwc3_msm *mdwc = container_of(self, struct dwc3_msm, usbdev_nb);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	struct usb_bus *bus = priv;

	/* Interested only in recovery when HC dies */
	if (action != USB_BUS_DIED)
		return 0;

	dev_dbg(mdwc->dev, "%s initiate recovery from hc_died\n", __func__);
	/* Recovery already under process */
	if (mdwc->hc_died)
		return 0;

	if (bus->controller != &dwc->xhci->dev) {
		dev_dbg(mdwc->dev, "%s event for diff HCD\n", __func__);
		return 0;
	}

	mdwc->hc_died = true;
	schedule_delayed_work(&mdwc->sm_work, 0);
	return 0;
}


/*
 * Check whether the DWC3 requires resetting the ep
 * after going to Low Power Mode (lpm)
@@ -3176,6 +3205,8 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)

		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);

		mdwc->usbdev_nb.notifier_call = msm_dwc3_usbdev_notify;
		usb_register_atomic_notify(&mdwc->usbdev_nb);
		/*
		 * FIXME If micro A cable is disconnected during system suspend,
		 * xhci platform device will be removed before runtime pm is
@@ -3218,6 +3249,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
	} else {
		dev_dbg(mdwc->dev, "%s: turn off host\n", __func__);

		usb_unregister_atomic_notify(&mdwc->usbdev_nb);
		if (!IS_ERR(mdwc->vbus_reg))
			ret = regulator_disable(mdwc->vbus_reg);
		if (ret) {
@@ -3682,11 +3714,12 @@ static void dwc3_otg_sm_work(struct work_struct *w)
		break;

	case OTG_STATE_A_HOST:
		if (test_bit(ID, &mdwc->inputs)) {
			dev_dbg(mdwc->dev, "id\n");
		if (test_bit(ID, &mdwc->inputs) || mdwc->hc_died) {
			dev_dbg(mdwc->dev, "id || hc_died\n");
			dwc3_otg_start_host(mdwc, 0);
			mdwc->otg_state = OTG_STATE_B_IDLE;
			mdwc->vbus_retry_count = 0;
			mdwc->hc_died = false;
			work = 1;
		} else {
			dev_dbg(mdwc->dev, "still in a_host state. Resuming root hub.\n");