aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r--drivers/usb/dwc3/core.c124
1 files changed, 79 insertions, 45 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c5c238ab3083..c0051e250d61 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -408,6 +408,10 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
reg |= FIELD_PREP(DWC3_GFLADJ_REFCLK_FLADJ_MASK, fladj)
| FIELD_PREP(DWC3_GFLADJ_240MHZDECR, decr >> 1)
| FIELD_PREP(DWC3_GFLADJ_240MHZDECR_PLS1, decr & 1);
+
+ if (dwc->gfladj_refclk_lpm_sel)
+ reg |= DWC3_GFLADJ_REFCLK_LPM_SEL;
+
dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
}
@@ -789,7 +793,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
else
reg |= DWC3_GUSB2PHYCFG_ENBLSLPM;
- if (dwc->dis_u2_freeclk_exists_quirk)
+ if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel)
reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
@@ -833,15 +837,16 @@ static void dwc3_core_exit(struct dwc3 *dwc)
{
dwc3_event_buffers_cleanup(dwc);
+ usb_phy_set_suspend(dwc->usb2_phy, 1);
+ usb_phy_set_suspend(dwc->usb3_phy, 1);
+ phy_power_off(dwc->usb2_generic_phy);
+ phy_power_off(dwc->usb3_generic_phy);
+
usb_phy_shutdown(dwc->usb2_phy);
usb_phy_shutdown(dwc->usb3_phy);
phy_exit(dwc->usb2_generic_phy);
phy_exit(dwc->usb3_generic_phy);
- usb_phy_set_suspend(dwc->usb2_phy, 1);
- usb_phy_set_suspend(dwc->usb3_phy, 1);
- phy_power_off(dwc->usb2_generic_phy);
- phy_power_off(dwc->usb3_generic_phy);
dwc3_clk_disable(dwc);
reset_control_assert(dwc->reset);
}
@@ -1179,6 +1184,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
}
+ /*
+ * When configured in HOST mode, after issuing U3/L2 exit controller
+ * fails to send proper CRC checksum in CRC5 feild. Because of this
+ * behaviour Transaction Error is generated, resulting in reset and
+ * re-enumeration of usb device attached. All the termsel, xcvrsel,
+ * opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1
+ * will correct this problem. This option is to support certain
+ * legacy ULPI PHYs.
+ */
+ if (dwc->resume_hs_terminations) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
+ reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST;
+ dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
+ }
+
if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
@@ -1522,8 +1542,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,dis-del-phy-power-chg-quirk");
dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
"snps,dis-tx-ipgap-linecheck-quirk");
+ dwc->resume_hs_terminations = device_property_read_bool(dev,
+ "snps,resume-hs-terminations");
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-ss-quirk");
+ dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev,
+ "snps,gfladj-refclk-lpm-sel-quirk");
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
"snps,tx_de_emphasis_quirk");
@@ -1751,15 +1775,11 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_get_properties(dwc);
- if (!dwc->sysdev_is_parent) {
- ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
- if (ret)
- return ret;
- }
-
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
- if (IS_ERR(dwc->reset))
- return PTR_ERR(dwc->reset);
+ if (IS_ERR(dwc->reset)) {
+ ret = PTR_ERR(dwc->reset);
+ goto put_usb_psy;
+ }
if (dev->of_node) {
/*
@@ -1769,45 +1789,57 @@ static int dwc3_probe(struct platform_device *pdev)
* check for them to retain backwards compatibility.
*/
dwc->bus_clk = devm_clk_get_optional(dev, "bus_early");
- if (IS_ERR(dwc->bus_clk))
- return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
- "could not get bus clock\n");
+ if (IS_ERR(dwc->bus_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
+ "could not get bus clock\n");
+ goto put_usb_psy;
+ }
if (dwc->bus_clk == NULL) {
dwc->bus_clk = devm_clk_get_optional(dev, "bus_clk");
- if (IS_ERR(dwc->bus_clk))
- return dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
- "could not get bus clock\n");
+ if (IS_ERR(dwc->bus_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(dwc->bus_clk),
+ "could not get bus clock\n");
+ goto put_usb_psy;
+ }
}
dwc->ref_clk = devm_clk_get_optional(dev, "ref");
- if (IS_ERR(dwc->ref_clk))
- return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
- "could not get ref clock\n");
+ if (IS_ERR(dwc->ref_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
+ "could not get ref clock\n");
+ goto put_usb_psy;
+ }
if (dwc->ref_clk == NULL) {
dwc->ref_clk = devm_clk_get_optional(dev, "ref_clk");
- if (IS_ERR(dwc->ref_clk))
- return dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
- "could not get ref clock\n");
+ if (IS_ERR(dwc->ref_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(dwc->ref_clk),
+ "could not get ref clock\n");
+ goto put_usb_psy;
+ }
}
dwc->susp_clk = devm_clk_get_optional(dev, "suspend");
- if (IS_ERR(dwc->susp_clk))
- return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
- "could not get suspend clock\n");
+ if (IS_ERR(dwc->susp_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
+ "could not get suspend clock\n");
+ goto put_usb_psy;
+ }
if (dwc->susp_clk == NULL) {
dwc->susp_clk = devm_clk_get_optional(dev, "suspend_clk");
- if (IS_ERR(dwc->susp_clk))
- return dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
- "could not get suspend clock\n");
+ if (IS_ERR(dwc->susp_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(dwc->susp_clk),
+ "could not get suspend clock\n");
+ goto put_usb_psy;
+ }
}
}
ret = reset_control_deassert(dwc->reset);
if (ret)
- return ret;
+ goto put_usb_psy;
ret = dwc3_clk_enable(dwc);
if (ret)
@@ -1821,7 +1853,13 @@ static int dwc3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
- device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
+
+ if (!dwc->sysdev_is_parent &&
+ DWC3_GHWPARAMS0_AWIDTH(dwc->hwparams.hwparams0) == 64) {
+ ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
+ if (ret)
+ goto disable_clks;
+ }
spin_lock_init(&dwc->lock);
mutex_init(&dwc->mutex);
@@ -1879,16 +1917,16 @@ err5:
dwc3_debugfs_exit(dwc);
dwc3_event_buffers_cleanup(dwc);
- usb_phy_shutdown(dwc->usb2_phy);
- usb_phy_shutdown(dwc->usb3_phy);
- phy_exit(dwc->usb2_generic_phy);
- phy_exit(dwc->usb3_generic_phy);
-
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
phy_power_off(dwc->usb2_generic_phy);
phy_power_off(dwc->usb3_generic_phy);
+ usb_phy_shutdown(dwc->usb2_phy);
+ usb_phy_shutdown(dwc->usb3_phy);
+ phy_exit(dwc->usb2_generic_phy);
+ phy_exit(dwc->usb3_generic_phy);
+
dwc3_ulpi_exit(dwc);
err4:
@@ -1908,7 +1946,7 @@ disable_clks:
dwc3_clk_disable(dwc);
assert_reset:
reset_control_assert(dwc->reset);
-
+put_usb_psy:
if (dwc->usb_psy)
power_supply_put(dwc->usb_psy);
@@ -1976,14 +2014,12 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
case DWC3_GCTL_PRTCAP_DEVICE:
if (pm_runtime_suspended(dwc->dev))
break;
- spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
synchronize_irq(dwc->irq_gadget);
dwc3_core_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
- if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) {
+ if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
dwc3_core_exit(dwc);
break;
}
@@ -2039,12 +2075,10 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
return ret;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
- spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
break;
case DWC3_GCTL_PRTCAP_HOST:
- if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) {
+ if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
ret = dwc3_core_init_for_resume(dwc);
if (ret)
return ret;