extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
+#define dwc2_is_device_connected(hsotg) (hsotg->connected)
#else
static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
int testmode)
{ return 0; }
+#define dwc2_is_device_connected(hsotg) (0)
#endif
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
*/
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
{
+ int ret;
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
/* Clear Remote Wakeup Signaling */
dctl &= ~DCTL_RMTWKUPSIG;
writel(dctl, hsotg->regs + DCTL);
+ ret = dwc2_exit_hibernation(hsotg, true);
+ if (ret)
+ dev_err(hsotg->dev, "exit hibernation failed\n");
+
+ call_gadget(hsotg, resume);
}
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
{
u32 dsts;
+ int ret;
dev_dbg(hsotg->dev, "USB SUSPEND\n");
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
!!(dsts & DSTS_SUSPSTS),
hsotg->hw_params.power_optimized);
+ if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
+ /* Ignore suspend request before enumeration */
+ if (!dwc2_is_device_connected(hsotg)) {
+ dev_dbg(hsotg->dev,
+ "ignore suspend request before enumeration\n");
+ goto clear_int;
+ }
+
+ ret = dwc2_enter_hibernation(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev,
+ "enter hibernation failed\n");
+ goto skip_power_saving;
+ }
+
+ udelay(100);
+
+ /* Ask phy to be suspended */
+ if (!IS_ERR_OR_NULL(hsotg->uphy))
+ usb_phy_set_suspend(hsotg->uphy, true);
+skip_power_saving:
+ /* Call gadget suspend callback */
+ call_gadget(hsotg, suspend);
+ }
} else {
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
+clear_int:
/* Clear interrupt */
writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
}