usb: dwc3: fix PM resume error for rockchip platforms
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc3 / core.c
index c2e55ee60176eade2c1394c9867a2ab33d32cb54..19254eb77beb89f8eaae966b42fdc58098cc1bf4 100644 (file)
 #include <linux/usb/of.h>
 #include <linux/usb/otg.h>
 
-#include "platform_data.h"
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
 
 #include "debug.h"
 
-/* -------------------------------------------------------------------------- */
+#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
 
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 {
@@ -60,6 +59,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 
+u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
+{
+       struct dwc3             *dwc = dep->dwc;
+       u32                     reg;
+
+       dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
+                       DWC3_GDBGFIFOSPACE_NUM(dep->number) |
+                       DWC3_GDBGFIFOSPACE_TYPE(type));
+
+       reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
+
+       return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
+}
+
 /**
  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
  * @dwc: pointer to our context structure
@@ -67,23 +80,9 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
 static int dwc3_core_soft_reset(struct dwc3 *dwc)
 {
        u32             reg;
+       int             retries = 1000;
        int             ret;
 
-       /* Before Resetting PHY, put Core in Reset */
-       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-       reg |= DWC3_GCTL_CORESOFTRESET;
-       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
-
-       /* Assert USB3 PHY reset */
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
-       reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
-       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
-
-       /* Assert USB2 PHY reset */
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-       reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
-       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
-
        usb_phy_init(dwc->usb2_phy);
        usb_phy_init(dwc->usb3_phy);
        ret = phy_init(dwc->usb2_generic_phy);
@@ -95,33 +94,35 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
                phy_exit(dwc->usb2_generic_phy);
                return ret;
        }
-       mdelay(100);
 
-       /* Clear USB3 PHY reset */
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
-       reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
-       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+       /*
+        * We're resetting only the device side because, if we're in host mode,
+        * 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)
+               return 0;
 
-       /* Clear USB2 PHY reset */
-       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-       reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
-       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       reg |= DWC3_DCTL_CSFTRST;
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
-       mdelay(100);
+       do {
+               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+               if (!(reg & DWC3_DCTL_CSFTRST))
+                       return 0;
 
-       /* After PHYs are stable we can take Core out of reset state */
-       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-       reg &= ~DWC3_GCTL_CORESOFTRESET;
-       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+               udelay(1);
+       } while (--retries);
 
-       return 0;
+       return -ETIMEDOUT;
 }
 
 /**
  * dwc3_soft_reset - Issue soft reset
  * @dwc: Pointer to our controller context structure
  */
-int dwc3_soft_reset(struct dwc3 *dwc)
+static int dwc3_soft_reset(struct dwc3 *dwc)
 {
        unsigned long timeout;
        u32 reg;
@@ -147,9 +148,8 @@ int dwc3_soft_reset(struct dwc3 *dwc)
 /*
  * dwc3_frame_length_adjustment - Adjusts frame length if required
  * @dwc3: Pointer to our controller context structure
- * @fladj: Value of GFLADJ_30MHZ to adjust frame length
  */
-static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
+static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
 {
        u32 reg;
        u32 dft;
@@ -157,15 +157,15 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
        if (dwc->revision < DWC3_REVISION_250A)
                return;
 
-       if (fladj == 0)
+       if (dwc->fladj == 0)
                return;
 
        reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
        dft = reg & DWC3_GFLADJ_30MHZ_MASK;
-       if (!dev_WARN_ONCE(dwc->dev, dft == fladj,
+       if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
            "request value same as default, ignoring\n")) {
                reg &= ~DWC3_GFLADJ_30MHZ_MASK;
-               reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
+               reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
                dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
        }
 }
@@ -215,13 +215,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
 static void dwc3_free_event_buffers(struct dwc3 *dwc)
 {
        struct dwc3_event_buffer        *evt;
-       int i;
 
-       for (i = 0; i < dwc->num_event_buffers; i++) {
-               evt = dwc->ev_buffs[i];
-               if (evt)
-                       dwc3_free_one_event_buffer(dwc, evt);
-       }
+       evt = dwc->ev_buf;
+       if (evt)
+               dwc3_free_one_event_buffer(dwc, evt);
 }
 
 /**
@@ -234,27 +231,14 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
  */
 static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
 {
-       int                     num;
-       int                     i;
-
-       num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
-       dwc->num_event_buffers = num;
+       struct dwc3_event_buffer *evt;
 
-       dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
-                       GFP_KERNEL);
-       if (!dwc->ev_buffs)
-               return -ENOMEM;
-
-       for (i = 0; i < num; i++) {
-               struct dwc3_event_buffer        *evt;
-
-               evt = dwc3_alloc_one_event_buffer(dwc, length);
-               if (IS_ERR(evt)) {
-                       dev_err(dwc->dev, "can't allocate event buffer\n");
-                       return PTR_ERR(evt);
-               }
-               dwc->ev_buffs[i] = evt;
+       evt = dwc3_alloc_one_event_buffer(dwc, length);
+       if (IS_ERR(evt)) {
+               dev_err(dwc->dev, "can't allocate event buffer\n");
+               return PTR_ERR(evt);
        }
+       dwc->ev_buf = evt;
 
        return 0;
 }
@@ -265,48 +249,42 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
  *
  * Returns 0 on success otherwise negative errno.
  */
-int dwc3_event_buffers_setup(struct dwc3 *dwc)
+static int dwc3_event_buffers_setup(struct dwc3 *dwc)
 {
        struct dwc3_event_buffer        *evt;
-       int                             n;
 
-       for (n = 0; n < dwc->num_event_buffers; n++) {
-               evt = dwc->ev_buffs[n];
-               dwc3_trace(trace_dwc3_core,
-                               "Event buf %p dma %08llx length %d\n",
-                               evt->buf, (unsigned long long) evt->dma,
-                               evt->length);
-
-               evt->lpos = 0;
-
-               dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
-                               lower_32_bits(evt->dma));
-               dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
-                               upper_32_bits(evt->dma));
-               dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
-                               DWC3_GEVNTSIZ_SIZE(evt->length));
-               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
-       }
+       evt = dwc->ev_buf;
+       dwc3_trace(trace_dwc3_core,
+                       "Event buf %p dma %08llx length %d\n",
+                       evt->buf, (unsigned long long) evt->dma,
+                       evt->length);
+
+       evt->lpos = 0;
+
+       dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
+                       lower_32_bits(evt->dma));
+       dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
+                       upper_32_bits(evt->dma));
+       dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
+                       DWC3_GEVNTSIZ_SIZE(evt->length));
+       dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
 
        return 0;
 }
 
-void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
 {
        struct dwc3_event_buffer        *evt;
-       int                             n;
 
-       for (n = 0; n < dwc->num_event_buffers; n++) {
-               evt = dwc->ev_buffs[n];
+       evt = dwc->ev_buf;
 
-               evt->lpos = 0;
+       evt->lpos = 0;
 
-               dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
-               dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
-               dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
-                               | DWC3_GEVNTSIZ_SIZE(0));
-               dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
-       }
+       dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
+       dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
+       dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
+                       | DWC3_GEVNTSIZ_SIZE(0));
+       dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
 }
 
 static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
@@ -427,10 +405,9 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
  * initialized. The PHY interfaces and the PHYs get initialized together with
  * the core in dwc3_core_init.
  */
-static int dwc3_phy_setup(struct dwc3 *dwc)
+int dwc3_phy_setup(struct dwc3 *dwc)
 {
        u32 reg;
-       u32 usbtrdtim;
        int ret;
 
        reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
@@ -447,6 +424,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->u2ss_inp3_quirk)
                reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
 
+       if (dwc->dis_rxdet_inp3_quirk)
+               reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
+
        if (dwc->req_p1p2p3_quirk)
                reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
 
@@ -508,6 +488,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
                break;
        }
 
+       switch (dwc->hsphy_mode) {
+       case USBPHY_INTERFACE_MODE_UTMI:
+               reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+               reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT);
+               break;
+       case USBPHY_INTERFACE_MODE_UTMIW:
+               reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+               reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) |
+                      DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT);
+               break;
+       default:
+               break;
+       }
+
        /*
         * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
         * '0' during coreConsultant configuration. So default value will
@@ -526,18 +523,24 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->dis_u2_freeclk_exists_quirk)
                reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
 
-       if (dwc->phyif_utmi_16_bits)
-               reg |= DWC3_GUSB2PHYCFG_PHYIF;
+       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
-       usbtrdtim = (reg & DWC3_GUSB2PHYCFG_PHYIF) ?
-                   USBTRDTIM_UTMI_16_BIT : USBTRDTIM_UTMI_8_BIT;
+       return 0;
+}
 
-       reg &= ~DWC3_GUSB2PHYCFG_USBTRDTIM_MASK;
-       reg |= (usbtrdtim << DWC3_GUSB2PHYCFG_USBTRDTIM_SHIFT);
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+       dwc3_event_buffers_cleanup(dwc);
 
-       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+       usb_phy_shutdown(dwc->usb2_phy);
+       usb_phy_shutdown(dwc->usb3_phy);
+       phy_exit(dwc->usb2_generic_phy);
+       phy_exit(dwc->usb3_generic_phy);
 
-       return 0;
+       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);
 }
 
 /**
@@ -589,6 +592,10 @@ static int dwc3_core_init(struct dwc3 *dwc)
        if (ret)
                goto err0;
 
+       ret = dwc3_phy_setup(dwc);
+       if (ret)
+               goto err0;
+
        reg = dwc3_readl(dwc->regs, DWC3_GCTL);
        reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
 
@@ -655,22 +662,45 @@ static int dwc3_core_init(struct dwc3 *dwc)
        if (dwc->revision < DWC3_REVISION_190A)
                reg |= DWC3_GCTL_U2RSTECN;
 
-       dwc3_core_num_eps(dwc);
-
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
-       ret = dwc3_alloc_scratch_buffers(dwc);
-       if (ret)
-               goto err1;
+       dwc3_core_num_eps(dwc);
 
        ret = dwc3_setup_scratch_buffers(dwc);
        if (ret)
+               goto err1;
+
+       /* Adjust Frame Length */
+       dwc3_frame_length_adjustment(dwc);
+
+       usb_phy_set_suspend(dwc->usb2_phy, 0);
+       usb_phy_set_suspend(dwc->usb3_phy, 0);
+       ret = phy_power_on(dwc->usb2_generic_phy);
+       if (ret < 0)
                goto err2;
 
+       ret = phy_power_on(dwc->usb3_generic_phy);
+       if (ret < 0)
+               goto err3;
+
+       ret = dwc3_event_buffers_setup(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to setup event buffers\n");
+               goto err4;
+       }
+
        return 0;
 
+err4:
+       phy_power_off(dwc->usb2_generic_phy);
+
+err3:
+       phy_power_off(dwc->usb3_generic_phy);
+
 err2:
-       dwc3_free_scratch_buffers(dwc);
+       usb_phy_set_suspend(dwc->usb2_phy, 1);
+       usb_phy_set_suspend(dwc->usb3_phy, 1);
+       dwc3_core_exit(dwc);
 
 err1:
        usb_phy_shutdown(dwc->usb2_phy);
@@ -682,15 +712,6 @@ err0:
        return ret;
 }
 
-static void dwc3_core_exit(struct dwc3 *dwc)
-{
-       dwc3_free_scratch_buffers(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);
-}
-
 static int dwc3_core_get_phy(struct dwc3 *dwc)
 {
        struct device           *dev = dwc->dev;
@@ -768,7 +789,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize gadget\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize gadget\n");
                        return ret;
                }
                break;
@@ -776,7 +798,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize host\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize host\n");
                        return ret;
                }
                break;
@@ -784,13 +807,15 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
                ret = dwc3_host_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize host\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize host\n");
                        return ret;
                }
 
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(dev, "failed to initialize gadget\n");
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "failed to initialize gadget\n");
                        return ret;
                }
                break;
@@ -821,88 +846,16 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
        }
 }
 
-/* Returns true if the controller is capable of DRD. */
-bool dwc3_hw_is_drd(struct dwc3 *dwc)
-{
-       u32 op_mode = DWC3_GHWPARAMS0_USB3_MODE(dwc->hwparams.hwparams0);
-
-       return (op_mode == DWC3_GHWPARAMS0_USB3_DRD);
-}
-
-bool dwc3_force_mode(struct dwc3 *dwc, u32 mode)
-{
-       u32                     reg;
-       unsigned long           flags;
-       struct usb_hcd          *hcd;
-
-       /*
-        * Force mode has no effect if the hardware is not drd mode.
-        */
-       if (!dwc3_hw_is_drd(dwc))
-               return false;
-       /*
-        * If dr_mode is either peripheral or host only, there is no
-        * need to ever force the mode to the opposite mode.
-        */
-       if (WARN_ON(mode == DWC3_GCTL_PRTCAP_DEVICE &&
-                   dwc->dr_mode == USB_DR_MODE_HOST))
-               return false;
-
-       if (WARN_ON(mode == DWC3_GCTL_PRTCAP_HOST &&
-                   dwc->dr_mode == USB_DR_MODE_PERIPHERAL))
-               return false;
-
-       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-       if (DWC3_GCTL_PRTCAP(reg) == mode)
-               return false;
-
-       hcd = dev_get_drvdata(&dwc->xhci->dev);
-
-       switch (mode) {
-       case DWC3_GCTL_PRTCAP_DEVICE:
-               if (hcd->state != HC_STATE_HALT) {
-                       usb_remove_hcd(hcd->shared_hcd);
-                       usb_remove_hcd(hcd);
-               }
-
-               spin_lock_irqsave(&dwc->lock, flags);
-               dwc3_set_mode(dwc, mode);
-               dwc3_gadget_restart(dwc, true);
-               spin_unlock_irqrestore(&dwc->lock, flags);
-
-               break;
-       case DWC3_GCTL_PRTCAP_HOST:
-               spin_lock_irqsave(&dwc->lock, flags);
-               dwc3_gadget_restart(dwc, false);
-               dwc3_set_mode(dwc, mode);
-               spin_unlock_irqrestore(&dwc->lock, flags);
-
-               if (hcd->state == HC_STATE_HALT) {
-                       usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
-                       usb_add_hcd(hcd->shared_hcd, hcd->irq, IRQF_SHARED);
-               }
-
-               break;
-       default:
-               /* do nothing  */
-               break;
-       }
-
-       return true;
-}
-
 #define DWC3_ALIGN_MASK                (16 - 1)
 
 static int dwc3_probe(struct platform_device *pdev)
 {
        struct device           *dev = &pdev->dev;
-       struct dwc3_platform_data *pdata = dev_get_platdata(dev);
        struct resource         *res;
        struct dwc3             *dwc;
        u8                      lpm_nyet_threshold;
        u8                      tx_de_emphasis;
        u8                      hird_threshold;
-       u32                     fladj = 0;
 
        int                     ret;
 
@@ -932,16 +885,6 @@ static int dwc3_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(dev, "missing IRQ\n");
-               return -ENODEV;
-       }
-       dwc->xhci_resources[1].start = res->start;
-       dwc->xhci_resources[1].end = res->end;
-       dwc->xhci_resources[1].flags = res->flags;
-       dwc->xhci_resources[1].name = res->name;
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "missing memory resource\n");
@@ -983,6 +926,7 @@ static int dwc3_probe(struct platform_device *pdev)
 
        dwc->maximum_speed = usb_get_maximum_speed(dev);
        dwc->dr_mode = usb_get_dr_mode(dev);
+       dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
 
        dwc->has_lpm_erratum = device_property_read_bool(dev,
                                "snps,has-lpm-erratum");
@@ -995,9 +939,6 @@ static int dwc3_probe(struct platform_device *pdev)
        dwc->usb3_lpm_capable = device_property_read_bool(dev,
                                "snps,usb3_lpm_capable");
 
-       dwc->needs_fifo_resize = device_property_read_bool(dev,
-                               "tx-fifo-resize");
-
        dwc->disable_scramble_quirk = device_property_read_bool(dev,
                                "snps,disable_scramble_quirk");
        dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
@@ -1020,12 +961,14 @@ static int dwc3_probe(struct platform_device *pdev)
                                "snps,dis_u2_susphy_quirk");
        dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
                                "snps,dis_enblslpm_quirk");
+       dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
+                               "snps,dis_rxdet_inp3_quirk");
        dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
-                               "snps,dis_u2_freeclk_exists_quirk");
+                               "snps,dis-u2-freeclk-exists-quirk");
        dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
-                               "snps,dis_del_phy_power_chg_quirk");
-       dwc->phyif_utmi_16_bits = device_property_read_bool(dev,
-                               "snps,phyif_utmi_16_bits");
+                               "snps,dis-del-phy-power-chg-quirk");
+       dwc->xhci_slow_suspend_quirk = device_property_read_bool(dev,
+                               "snps,xhci-slow-suspend-quirk");
 
        dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
                                "snps,tx_de_emphasis_quirk");
@@ -1034,45 +977,7 @@ static int dwc3_probe(struct platform_device *pdev)
        device_property_read_string(dev, "snps,hsphy_interface",
                                    &dwc->hsphy_interface);
        device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
-                                &fladj);
-
-       if (pdata) {
-               dwc->maximum_speed = pdata->maximum_speed;
-               dwc->has_lpm_erratum = pdata->has_lpm_erratum;
-               if (pdata->lpm_nyet_threshold)
-                       lpm_nyet_threshold = pdata->lpm_nyet_threshold;
-               dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
-               if (pdata->hird_threshold)
-                       hird_threshold = pdata->hird_threshold;
-
-               dwc->needs_fifo_resize = pdata->tx_fifo_resize;
-               dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
-               dwc->dr_mode = pdata->dr_mode;
-
-               dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
-               dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
-               dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
-               dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
-               dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
-               dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
-               dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
-               dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
-               dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
-               dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
-               dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
-               dwc->dis_u2_freeclk_exists_quirk =
-                                       pdata->dis_u2_freeclk_exists_quirk;
-               dwc->dis_del_phy_power_chg_quirk =
-                                       pdata->dis_del_phy_power_chg_quirk;
-               dwc->phyif_utmi_16_bits = pdata->phyif_utmi_16_bits;
-
-               dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
-               if (pdata->tx_de_emphasis)
-                       tx_de_emphasis = pdata->tx_de_emphasis;
-
-               dwc->hsphy_interface = pdata->hsphy_interface;
-               fladj = pdata->fladj_value;
-       }
+                                &dwc->fladj);
 
        /* default to superspeed if no maximum_speed passed */
        if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
@@ -1087,10 +992,6 @@ static int dwc3_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, dwc);
        dwc3_cache_hwparams(dwc);
 
-       ret = dwc3_phy_setup(dwc);
-       if (ret)
-               goto err0;
-
        ret = dwc3_core_get_phy(dwc);
        if (ret)
                goto err0;
@@ -1103,47 +1004,42 @@ static int dwc3_probe(struct platform_device *pdev)
                dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
        }
 
+       pm_runtime_set_active(dev);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
        pm_runtime_enable(dev);
-       pm_runtime_get_sync(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               goto err1;
+
        pm_runtime_forbid(dev);
 
        ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
        if (ret) {
                dev_err(dwc->dev, "failed to allocate event buffers\n");
                ret = -ENOMEM;
-               goto err1;
+               goto err2;
        }
 
-       if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+       if (IS_ENABLED(CONFIG_USB_DWC3_HOST) &&
+                       (dwc->dr_mode == USB_DR_MODE_OTG ||
+                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
                dwc->dr_mode = USB_DR_MODE_HOST;
-       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+       else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
+                       (dwc->dr_mode == USB_DR_MODE_OTG ||
+                                       dwc->dr_mode == USB_DR_MODE_UNKNOWN))
                dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
 
        if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
                dwc->dr_mode = USB_DR_MODE_OTG;
 
-       ret = dwc3_core_init(dwc);
-       if (ret) {
-               dev_err(dev, "failed to initialize core\n");
-               goto err1;
-       }
-
-       /* Adjust Frame Length */
-       dwc3_frame_length_adjustment(dwc, fladj);
-
-       usb_phy_set_suspend(dwc->usb2_phy, 0);
-       usb_phy_set_suspend(dwc->usb3_phy, 0);
-       ret = phy_power_on(dwc->usb2_generic_phy);
-       if (ret < 0)
-               goto err2;
-
-       ret = phy_power_on(dwc->usb3_generic_phy);
-       if (ret < 0)
+       ret = dwc3_alloc_scratch_buffers(dwc);
+       if (ret)
                goto err3;
 
-       ret = dwc3_event_buffers_setup(dwc);
+       ret = dwc3_core_init(dwc);
        if (ret) {
-               dev_err(dwc->dev, "failed to setup event buffers\n");
+               dev_err(dev, "failed to initialize core\n");
                goto err4;
        }
 
@@ -1151,36 +1047,27 @@ static int dwc3_probe(struct platform_device *pdev)
        if (ret)
                goto err5;
 
-       ret = dwc3_debugfs_init(dwc);
-       if (ret) {
-               dev_err(dev, "failed to initialize debugfs\n");
-               goto err6;
-       }
-
-       pm_runtime_allow(dev);
+       dwc3_debugfs_init(dwc);
+       pm_runtime_put(dev);
 
        return 0;
 
-err6:
-       dwc3_core_exit_mode(dwc);
-
 err5:
        dwc3_event_buffers_cleanup(dwc);
 
 err4:
-       phy_power_off(dwc->usb3_generic_phy);
+       dwc3_free_scratch_buffers(dwc);
 
 err3:
-       phy_power_off(dwc->usb2_generic_phy);
+       dwc3_free_event_buffers(dwc);
+       dwc3_ulpi_exit(dwc);
 
 err2:
-       usb_phy_set_suspend(dwc->usb2_phy, 1);
-       usb_phy_set_suspend(dwc->usb3_phy, 1);
-       dwc3_core_exit(dwc);
+       pm_runtime_allow(&pdev->dev);
 
 err1:
-       dwc3_free_event_buffers(dwc);
-       dwc3_ulpi_exit(dwc);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
 err0:
        /*
@@ -1198,6 +1085,7 @@ static int dwc3_remove(struct platform_device *pdev)
        struct dwc3     *dwc = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
+       pm_runtime_get_sync(&pdev->dev);
        /*
         * restore res->start back to its original value so that, in case the
         * probe is deferred, we don't end up getting error in request the
@@ -1207,112 +1095,198 @@ static int dwc3_remove(struct platform_device *pdev)
 
        dwc3_debugfs_exit(dwc);
        dwc3_core_exit_mode(dwc);
-       dwc3_event_buffers_cleanup(dwc);
-       dwc3_free_event_buffers(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);
 
        dwc3_core_exit(dwc);
        dwc3_ulpi_exit(dwc);
 
        pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_allow(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
+       dwc3_free_event_buffers(dwc);
+       dwc3_free_scratch_buffers(dwc);
+
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int dwc3_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int dwc3_suspend_common(struct dwc3 *dwc)
 {
-       struct dwc3     *dwc = dev_get_drvdata(dev);
        unsigned long   flags;
 
-       spin_lock_irqsave(&dwc->lock, flags);
-
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
        case USB_DR_MODE_OTG:
+               spin_lock_irqsave(&dwc->lock, flags);
                dwc3_gadget_suspend(dwc);
+               spin_unlock_irqrestore(&dwc->lock, flags);
+               break;
+       case USB_DR_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
+
+       dwc3_core_exit(dwc);
+
+       return 0;
+}
+
+static int dwc3_resume_common(struct dwc3 *dwc)
+{
+       unsigned long   flags;
+       int             ret;
+
+       ret = dwc3_core_init(dwc);
+       if (ret)
+               return ret;
+
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
+               spin_lock_irqsave(&dwc->lock, flags);
+               dwc3_gadget_resume(dwc);
+               spin_unlock_irqrestore(&dwc->lock, flags);
                /* FALLTHROUGH */
        case USB_DR_MODE_HOST:
        default:
-               dwc3_event_buffers_cleanup(dwc);
+               /* do nothing */
                break;
        }
 
-       dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
-       spin_unlock_irqrestore(&dwc->lock, flags);
+       return 0;
+}
 
-       usb_phy_shutdown(dwc->usb3_phy);
-       usb_phy_shutdown(dwc->usb2_phy);
-       phy_exit(dwc->usb2_generic_phy);
-       phy_exit(dwc->usb3_generic_phy);
+static int dwc3_runtime_checks(struct dwc3 *dwc)
+{
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
+               if (dwc->connected)
+                       return -EBUSY;
+               break;
+       case USB_DR_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
 
-       pinctrl_pm_select_sleep_state(dev);
+       return 0;
+}
+
+static int dwc3_runtime_suspend(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       int             ret;
+
+       if (dwc3_runtime_checks(dwc))
+               return -EBUSY;
+
+       ret = dwc3_suspend_common(dwc);
+       if (ret)
+               return ret;
+
+       device_init_wakeup(dev, true);
 
        return 0;
 }
 
-static int dwc3_resume(struct device *dev)
+static int dwc3_runtime_resume(struct device *dev)
 {
-       struct dwc3     *dwc = dev_get_drvdata(dev);
-       unsigned long   flags;
+       struct dwc3     *dwc = dev_get_drvdata(dev);
        int             ret;
 
-       pinctrl_pm_select_default_state(dev);
+       device_init_wakeup(dev, false);
 
-       usb_phy_init(dwc->usb3_phy);
-       usb_phy_init(dwc->usb2_phy);
-       ret = phy_init(dwc->usb2_generic_phy);
-       if (ret < 0)
+       ret = dwc3_resume_common(dwc);
+       if (ret)
                return ret;
 
-       ret = phy_init(dwc->usb3_generic_phy);
-       if (ret < 0)
-               goto err_usb2phy_init;
+       switch (dwc->dr_mode) {
+       case USB_DR_MODE_PERIPHERAL:
+       case USB_DR_MODE_OTG:
+               dwc3_gadget_process_pending_events(dwc);
+               break;
+       case USB_DR_MODE_HOST:
+       default:
+               /* do nothing */
+               break;
+       }
 
-       spin_lock_irqsave(&dwc->lock, flags);
+       pm_runtime_mark_last_busy(dev);
 
-       dwc3_event_buffers_setup(dwc);
-       dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
+       return 0;
+}
+
+static int dwc3_runtime_idle(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
 
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
        case USB_DR_MODE_OTG:
-               dwc3_gadget_resume(dwc);
-               /* FALLTHROUGH */
+               if (dwc3_runtime_checks(dwc))
+                       return -EBUSY;
+               break;
        case USB_DR_MODE_HOST:
        default:
                /* do nothing */
                break;
        }
 
-       spin_unlock_irqrestore(&dwc->lock, flags);
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_autosuspend(dev);
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_suspend(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       int             ret;
+
+       if (pm_runtime_suspended(dwc->dev))
+               return 0;
+
+       ret = dwc3_suspend_common(dwc);
+       if (ret)
+               return ret;
+
+       pinctrl_pm_select_sleep_state(dev);
+
+       return 0;
+}
+
+static int dwc3_resume(struct device *dev)
+{
+       struct dwc3     *dwc = dev_get_drvdata(dev);
+       int             ret;
+
+       if (pm_runtime_suspended(dwc->dev))
+               return 0;
+
+       pinctrl_pm_select_default_state(dev);
+
+       ret = dwc3_resume_common(dwc);
+       if (ret)
+               return ret;
 
        pm_runtime_disable(dev);
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
 
        return 0;
-
-err_usb2phy_init:
-       phy_exit(dwc->usb2_generic_phy);
-
-       return ret;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops dwc3_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
+       SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
+                       dwc3_runtime_idle)
 };
 
-#define DWC3_PM_OPS    &(dwc3_dev_pm_ops)
-#else
-#define DWC3_PM_OPS    NULL
-#endif
-
 #ifdef CONFIG_OF
 static const struct of_device_id of_dwc3_match[] = {
        {
@@ -1344,7 +1318,7 @@ static struct platform_driver dwc3_driver = {
                .name   = "dwc3",
                .of_match_table = of_match_ptr(of_dwc3_match),
                .acpi_match_table = ACPI_PTR(dwc3_acpi_match),
-               .pm     = DWC3_PM_OPS,
+               .pm     = &dwc3_dev_pm_ops,
        },
 };