summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc2/platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc2/platform.c')
-rw-r--r--drivers/usb/dwc2/platform.c101
1 files changed, 96 insertions, 5 deletions
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 3c6ce09a6db5..69972750e161 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -285,7 +285,9 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
if (ret) {
- dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
+ if (ret != -EPROBE_DEFER)
+ dev_err(hsotg->dev, "failed to request supplies: %d\n",
+ ret);
return ret;
}
return 0;
@@ -312,6 +314,9 @@ static int dwc2_driver_remove(struct platform_device *dev)
if (hsotg->gadget_enabled)
dwc2_hsotg_remove(hsotg);
+ if (hsotg->params.activate_stm_id_vb_detection)
+ regulator_disable(hsotg->usb33d);
+
if (hsotg->ll_hw_enabled)
dwc2_lowlevel_hw_disable(hsotg);
@@ -392,8 +397,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
return retval;
}
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- hsotg->regs = devm_ioremap_resource(&dev->dev, res);
+ hsotg->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res);
if (IS_ERR(hsotg->regs))
return PTR_ERR(hsotg->regs);
@@ -464,10 +468,35 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
goto error;
+ if (hsotg->params.activate_stm_id_vb_detection) {
+ u32 ggpio;
+
+ hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d");
+ if (IS_ERR(hsotg->usb33d)) {
+ retval = PTR_ERR(hsotg->usb33d);
+ if (retval != -EPROBE_DEFER)
+ dev_err(hsotg->dev,
+ "failed to request usb33d supply: %d\n",
+ retval);
+ goto error;
+ }
+ retval = regulator_enable(hsotg->usb33d);
+ if (retval) {
+ dev_err(hsotg->dev,
+ "failed to enable usb33d supply: %d\n", retval);
+ goto error;
+ }
+
+ ggpio = dwc2_readl(hsotg, GGPIO);
+ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
+ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
+ dwc2_writel(hsotg, ggpio, GGPIO);
+ }
+
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
retval = dwc2_gadget_init(hsotg);
if (retval)
- goto error;
+ goto error_init;
hsotg->gadget_enabled = 1;
}
@@ -493,7 +522,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval) {
if (hsotg->gadget_enabled)
dwc2_hsotg_remove(hsotg);
- goto error;
+ goto error_init;
}
hsotg->hcd_enabled = 1;
}
@@ -509,6 +538,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
return 0;
+error_init:
+ if (hsotg->params.activate_stm_id_vb_detection)
+ regulator_disable(hsotg->usb33d);
error:
dwc2_lowlevel_hw_disable(hsotg);
return retval;
@@ -523,6 +555,37 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
if (is_device_mode)
dwc2_hsotg_suspend(dwc2);
+ if (dwc2->params.activate_stm_id_vb_detection) {
+ unsigned long flags;
+ u32 ggpio, gotgctl;
+
+ /*
+ * Need to force the mode to the current mode to avoid Mode
+ * Mismatch Interrupt when ID detection will be disabled.
+ */
+ dwc2_force_mode(dwc2, !is_device_mode);
+
+ spin_lock_irqsave(&dwc2->lock, flags);
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
+ /* bypass debounce filter, enable overrides */
+ gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
+ gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN;
+ /* Force A / B session if needed */
+ if (gotgctl & GOTGCTL_ASESVLD)
+ gotgctl |= GOTGCTL_AVALOVAL;
+ if (gotgctl & GOTGCTL_BSESVLD)
+ gotgctl |= GOTGCTL_BVALOVAL;
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
+ spin_unlock_irqrestore(&dwc2->lock, flags);
+
+ ggpio = dwc2_readl(dwc2, GGPIO);
+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
+ ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
+ dwc2_writel(dwc2, ggpio, GGPIO);
+
+ regulator_disable(dwc2->usb33d);
+ }
+
if (dwc2->ll_hw_enabled &&
(is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
ret = __dwc2_lowlevel_hw_disable(dwc2);
@@ -544,6 +607,34 @@ static int __maybe_unused dwc2_resume(struct device *dev)
}
dwc2->phy_off_for_suspend = false;
+ if (dwc2->params.activate_stm_id_vb_detection) {
+ unsigned long flags;
+ u32 ggpio, gotgctl;
+
+ ret = regulator_enable(dwc2->usb33d);
+ if (ret)
+ return ret;
+
+ ggpio = dwc2_readl(dwc2, GGPIO);
+ ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
+ ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
+ dwc2_writel(dwc2, ggpio, GGPIO);
+
+ /* ID/VBUS detection startup time */
+ usleep_range(5000, 7000);
+
+ spin_lock_irqsave(&dwc2->lock, flags);
+ gotgctl = dwc2_readl(dwc2, GOTGCTL);
+ gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS;
+ gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN |
+ GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL);
+ dwc2_writel(dwc2, gotgctl, GOTGCTL);
+ spin_unlock_irqrestore(&dwc2->lock, flags);
+ }
+
+ /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
+ dwc2_force_dr_mode(dwc2);
+
if (dwc2_is_device_mode(dwc2))
ret = dwc2_hsotg_resume(dwc2);