|
@@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
|
|
|
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
|
|
|
reg |= DWC3_GCTL_PRTCAPDIR(mode);
|
|
|
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
|
|
+
|
|
|
+ dwc->current_dr_role = mode;
|
|
|
}
|
|
|
|
|
|
static void __dwc3_set_mode(struct work_struct *work)
|
|
@@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work)
|
|
|
|
|
|
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
|
|
|
|
|
|
- dwc->current_dr_role = dwc->desired_dr_role;
|
|
|
-
|
|
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
|
|
|
|
switch (dwc->desired_dr_role) {
|
|
@@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
|
|
|
* XHCI driver will reset the host block. If dwc3 was configured for
|
|
|
* host-only mode, then we can return early.
|
|
|
*/
|
|
|
- if (dwc->dr_mode == USB_DR_MODE_HOST)
|
|
|
+ if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
|
|
|
return 0;
|
|
|
|
|
|
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
|
@@ -234,6 +234,9 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
|
|
|
udelay(1);
|
|
|
} while (--retries);
|
|
|
|
|
|
+ phy_exit(dwc->usb3_generic_phy);
|
|
|
+ phy_exit(dwc->usb2_generic_phy);
|
|
|
+
|
|
|
return -ETIMEDOUT;
|
|
|
}
|
|
|
|
|
@@ -483,6 +486,22 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
|
|
parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
|
|
|
}
|
|
|
|
|
|
+static int dwc3_core_ulpi_init(struct dwc3 *dwc)
|
|
|
+{
|
|
|
+ int intf;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3);
|
|
|
+
|
|
|
+ if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI ||
|
|
|
+ (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI &&
|
|
|
+ dwc->hsphy_interface &&
|
|
|
+ !strncmp(dwc->hsphy_interface, "ulpi", 4)))
|
|
|
+ ret = dwc3_ulpi_init(dwc);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
|
|
|
* @dwc: Pointer to our controller context structure
|
|
@@ -494,7 +513,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
|
|
static int dwc3_phy_setup(struct dwc3 *dwc)
|
|
|
{
|
|
|
u32 reg;
|
|
|
- int ret;
|
|
|
|
|
|
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
|
|
|
|
@@ -565,9 +583,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
|
|
}
|
|
|
/* FALLTHROUGH */
|
|
|
case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
|
|
|
- ret = dwc3_ulpi_init(dwc);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
/* FALLTHROUGH */
|
|
|
default:
|
|
|
break;
|
|
@@ -724,6 +739,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
|
|
}
|
|
|
|
|
|
static int dwc3_core_get_phy(struct dwc3 *dwc);
|
|
|
+static int dwc3_core_ulpi_init(struct dwc3 *dwc);
|
|
|
|
|
|
/**
|
|
|
* dwc3_core_init - Low-level initialization of DWC3 Core
|
|
@@ -755,17 +771,27 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|
|
dwc->maximum_speed = USB_SPEED_HIGH;
|
|
|
}
|
|
|
|
|
|
- ret = dwc3_core_get_phy(dwc);
|
|
|
+ ret = dwc3_phy_setup(dwc);
|
|
|
if (ret)
|
|
|
goto err0;
|
|
|
|
|
|
- ret = dwc3_core_soft_reset(dwc);
|
|
|
- if (ret)
|
|
|
- goto err0;
|
|
|
+ if (!dwc->ulpi_ready) {
|
|
|
+ ret = dwc3_core_ulpi_init(dwc);
|
|
|
+ if (ret)
|
|
|
+ goto err0;
|
|
|
+ dwc->ulpi_ready = true;
|
|
|
+ }
|
|
|
|
|
|
- ret = dwc3_phy_setup(dwc);
|
|
|
+ if (!dwc->phys_ready) {
|
|
|
+ ret = dwc3_core_get_phy(dwc);
|
|
|
+ if (ret)
|
|
|
+ goto err0a;
|
|
|
+ dwc->phys_ready = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = dwc3_core_soft_reset(dwc);
|
|
|
if (ret)
|
|
|
- goto err0;
|
|
|
+ goto err0a;
|
|
|
|
|
|
dwc3_core_setup_global_control(dwc);
|
|
|
dwc3_core_num_eps(dwc);
|
|
@@ -838,6 +864,9 @@ err1:
|
|
|
phy_exit(dwc->usb2_generic_phy);
|
|
|
phy_exit(dwc->usb3_generic_phy);
|
|
|
|
|
|
+err0a:
|
|
|
+ dwc3_ulpi_exit(dwc);
|
|
|
+
|
|
|
err0:
|
|
|
return ret;
|
|
|
}
|
|
@@ -916,7 +945,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|
|
|
|
|
switch (dwc->dr_mode) {
|
|
|
case USB_DR_MODE_PERIPHERAL:
|
|
|
- dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
|
|
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
|
|
|
|
|
if (dwc->usb2_phy)
|
|
@@ -932,7 +960,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|
|
}
|
|
|
break;
|
|
|
case USB_DR_MODE_HOST:
|
|
|
- dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
|
|
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
|
|
|
|
|
if (dwc->usb2_phy)
|
|
@@ -1234,7 +1261,6 @@ err4:
|
|
|
|
|
|
err3:
|
|
|
dwc3_free_event_buffers(dwc);
|
|
|
- dwc3_ulpi_exit(dwc);
|
|
|
|
|
|
err2:
|
|
|
pm_runtime_allow(&pdev->dev);
|
|
@@ -1284,7 +1310,7 @@ static int dwc3_remove(struct platform_device *pdev)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
-static int dwc3_suspend_common(struct dwc3 *dwc)
|
|
|
+static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
|
|
@@ -1296,6 +1322,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
|
|
|
dwc3_core_exit(dwc);
|
|
|
break;
|
|
|
case DWC3_GCTL_PRTCAP_HOST:
|
|
|
+ /* do nothing during host runtime_suspend */
|
|
|
+ if (!PMSG_IS_AUTO(msg))
|
|
|
+ dwc3_core_exit(dwc);
|
|
|
+ break;
|
|
|
default:
|
|
|
/* do nothing */
|
|
|
break;
|
|
@@ -1304,7 +1334,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int dwc3_resume_common(struct dwc3 *dwc)
|
|
|
+static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
int ret;
|
|
@@ -1320,6 +1350,13 @@ static int dwc3_resume_common(struct dwc3 *dwc)
|
|
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
|
break;
|
|
|
case DWC3_GCTL_PRTCAP_HOST:
|
|
|
+ /* nothing to do on host runtime_resume */
|
|
|
+ if (!PMSG_IS_AUTO(msg)) {
|
|
|
+ ret = dwc3_core_init(dwc);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ break;
|
|
|
default:
|
|
|
/* do nothing */
|
|
|
break;
|
|
@@ -1331,12 +1368,11 @@ static int dwc3_resume_common(struct dwc3 *dwc)
|
|
|
static int dwc3_runtime_checks(struct dwc3 *dwc)
|
|
|
{
|
|
|
switch (dwc->current_dr_role) {
|
|
|
- case USB_DR_MODE_PERIPHERAL:
|
|
|
- case USB_DR_MODE_OTG:
|
|
|
+ case DWC3_GCTL_PRTCAP_DEVICE:
|
|
|
if (dwc->connected)
|
|
|
return -EBUSY;
|
|
|
break;
|
|
|
- case USB_DR_MODE_HOST:
|
|
|
+ case DWC3_GCTL_PRTCAP_HOST:
|
|
|
default:
|
|
|
/* do nothing */
|
|
|
break;
|
|
@@ -1353,7 +1389,7 @@ static int dwc3_runtime_suspend(struct device *dev)
|
|
|
if (dwc3_runtime_checks(dwc))
|
|
|
return -EBUSY;
|
|
|
|
|
|
- ret = dwc3_suspend_common(dwc);
|
|
|
+ ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -1369,7 +1405,7 @@ static int dwc3_runtime_resume(struct device *dev)
|
|
|
|
|
|
device_init_wakeup(dev, false);
|
|
|
|
|
|
- ret = dwc3_resume_common(dwc);
|
|
|
+ ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -1416,7 +1452,7 @@ static int dwc3_suspend(struct device *dev)
|
|
|
struct dwc3 *dwc = dev_get_drvdata(dev);
|
|
|
int ret;
|
|
|
|
|
|
- ret = dwc3_suspend_common(dwc);
|
|
|
+ ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -1432,7 +1468,7 @@ static int dwc3_resume(struct device *dev)
|
|
|
|
|
|
pinctrl_pm_select_default_state(dev);
|
|
|
|
|
|
- ret = dwc3_resume_common(dwc);
|
|
|
+ ret = dwc3_resume_common(dwc, PMSG_RESUME);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|