USB: Fix RK3288 USB HOST2(DWC_OTG) remote wakeup bug.
authorwlf <wulf@rock-chips.com>
Mon, 23 Jun 2014 07:20:24 +0000 (15:20 +0800)
committerwlf <wulf@rock-chips.com>
Mon, 23 Jun 2014 07:20:24 +0000 (15:20 +0800)
When the HOST2 DWC_OTG core detects a USB remote wakeup
sequence, the core starts driving resume signal but
the usb phy is halted. So try to do soft reset phy.

drivers/usb/dwc_otg_310/dwc_otg_cil_intr.c

index 9c54dceebdff286433717185723d0985ea1ce65d..a4327dc176f821a26260b7e88206330134de9f27 100755 (executable)
@@ -498,6 +498,34 @@ void w_wakeup_detected(void *data)
        core_if->lx_state = DWC_OTG_L0;
 }
 
+static inline void rk_dwc_otg_phy_soft_reset(dwc_otg_core_if_t *core_if)
+{
+       struct dwc_otg_platform_data *pldata;
+       guid_data_t guid;
+
+       pldata = core_if->otg_dev->pldata;
+       guid.d32 = core_if->core_global_regs->guid;
+
+       if ((cpu_is_rk3288()) && ((guid.d32 & 0x01) == 0)) {
+               /* only used for HOST20, OTG HOST do not need.
+                * first, do soft reset usb phy, and then usb phy
+                * can drive resume signal.
+                * second, set usb phy into suspend mode and
+                * normal mode once time, and then usb phy can
+                * send SOFs immediately after resume.
+                */
+               rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, true);
+               udelay(50);
+               rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, false);
+               udelay(50);
+
+               pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
+               udelay(50);
+               pldata->phy_suspend(pldata, USB_PHY_ENABLED);
+               udelay(100);
+       }
+}
+
 /**
  * This interrupt indicates that the DWC_otg controller has detected a
  * resume or remote wakeup sequence. If the DWC_otg controller is in
@@ -574,6 +602,10 @@ int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t *core_if)
                        /* Restart the Phy Clock */
                        pcgcctl.b.stoppclk = 1;
                        DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
+                       udelay(10);
+
+                       rk_dwc_otg_phy_soft_reset(core_if);
+
                        DWC_TASK_SCHEDULE(core_if->wkp_tasklet);
                } else {
                        /** Change to L0 state*/