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

Commit b0974d6b authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: dwc3: Issue core soft reset upon controller halt failure"

parents 0defd832 da619e58
Loading
Loading
Loading
Loading
+57 −15
Original line number Diff line number Diff line
@@ -814,19 +814,6 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
	dbg_log_string("START for %s(%d)", dep->name, dep->number);
	dwc3_stop_active_transfer(dwc, dep->number, true);

	/* - giveback all requests to gadget driver */
	while (!list_empty(&dep->started_list)) {
		req = next_request(&dep->started_list);

		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
	}

	while (!list_empty(&dep->pending_list)) {
		req = next_request(&dep->pending_list);

		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
	}

	if (dep->number == 1 && dwc->ep0state != EP0_SETUP_PHASE) {
		unsigned int dir;

@@ -841,6 +828,19 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
		dwc->eps[1]->trb_enqueue = 0;
	}

	/* - giveback all requests to gadget driver */
	while (!list_empty(&dep->started_list)) {
		req = next_request(&dep->started_list);
		if (req)
			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
	}

	while (!list_empty(&dep->pending_list)) {
		req = next_request(&dep->pending_list);
		if (req)
			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
	}

	dbg_log_string("DONE for %s(%d)", dep->name, dep->number);
}

@@ -2067,6 +2067,38 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
	return 0;
}

/**
 * dwc3_device_core_soft_reset - Issues device core soft reset
 * @dwc: pointer to our context structure
 */
static int dwc3_device_core_soft_reset(struct dwc3 *dwc)
{
	u32             reg;
	int             retries = 10;

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	reg |= DWC3_DCTL_CSFTRST;
	dwc3_writel(dwc->regs, DWC3_DCTL, reg);

	do {
		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
		if (!(reg & DWC3_DCTL_CSFTRST))
			goto done;

		usleep_range(1000, 1100);
	} while (--retries);

	dev_err(dwc->dev, "%s timedout\n", __func__);

	return -ETIMEDOUT;

done:
	/* phy sync delay as per data book */
	msleep(50);

	return 0;
}

static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
	u32			reg, reg1;
@@ -2229,6 +2261,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)

	ret = dwc3_gadget_run_stop(dwc, is_on, false);
	spin_unlock_irqrestore(&dwc->lock, flags);
	if (!is_on && ret == -ETIMEDOUT) {
		dev_err(dwc->dev, "%s: Core soft reset...\n", __func__);
		dwc3_device_core_soft_reset(dwc);
	}
	enable_irq(dwc->irq);

	pm_runtime_mark_last_busy(dwc->dev);
@@ -2313,6 +2349,7 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
{
	struct dwc3 *dwc = gadget_to_dwc(_gadget);
	unsigned long flags;
	int ret = 0;

	if (dwc->dr_mode != USB_DR_MODE_OTG && dwc->dr_mode != USB_DR_MODE_DRD)
		return -EPERM;
@@ -2340,9 +2377,9 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
			 * Both vbus was activated by otg and pullup was
			 * signaled by the gadget driver.
			 */
			dwc3_gadget_run_stop(dwc, 1, false);
			ret = dwc3_gadget_run_stop(dwc, 1, false);
		} else {
			dwc3_gadget_run_stop(dwc, 0, false);
			ret = dwc3_gadget_run_stop(dwc, 0, false);
		}
	}

@@ -2356,8 +2393,13 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
	}

	spin_unlock_irqrestore(&dwc->lock, flags);
	if (!is_active && ret == -ETIMEDOUT) {
		dev_err(dwc->dev, "%s: Core soft reset...\n", __func__);
		dwc3_device_core_soft_reset(dwc);
	}

	enable_irq(dwc->irq);

	return 0;
}