return 0;
 
        cdns3_gadget_config(priv_dev);
+       if (hibernated)
+               writel(USB_CONF_DEVEN, &priv_dev->regs->usb_conf);
 
        return 0;
 }
 
 
 #include "core.h"
 #include "gadget-export.h"
+#include "drd.h"
 
 static int set_phy_power_on(struct cdns *cdns)
 {
        if (!cdns->in_lpm)
                return 0;
 
+       if (cdns_power_is_lost(cdns)) {
+               phy_exit(cdns->usb2_phy);
+               ret = phy_init(cdns->usb2_phy);
+               if (ret)
+                       return ret;
+
+               phy_exit(cdns->usb3_phy);
+               ret = phy_init(cdns->usb3_phy);
+               if (ret)
+                       return ret;
+       }
+
        ret = set_phy_power_on(cdns);
        if (ret)
                return ret;
 static int cdns3_plat_suspend(struct device *dev)
 {
        struct cdns *cdns = dev_get_drvdata(dev);
+       int ret;
 
        cdns_suspend(cdns);
 
-       return cdns3_controller_suspend(dev, PMSG_SUSPEND);
+       ret = cdns3_controller_suspend(dev, PMSG_SUSPEND);
+       if (ret)
+               return ret;
+
+       if (device_may_wakeup(dev) && cdns->wakeup_irq)
+               enable_irq_wake(cdns->wakeup_irq);
+
+       return ret;
 }
 
 static int cdns3_plat_resume(struct device *dev)
 
 int cdns_resume(struct cdns *cdns, u8 set_active)
 {
        struct device *dev = cdns->dev;
+       enum usb_role real_role;
+       bool role_changed = false;
+       int ret;
+
+       if (cdns_power_is_lost(cdns)) {
+               if (cdns->role_sw) {
+                       cdns->role = cdns_role_get(cdns->role_sw);
+               } else {
+                       real_role = cdns_hw_role_state_machine(cdns);
+                       if (real_role != cdns->role) {
+                               ret = cdns_hw_role_switch(cdns);
+                               if (ret)
+                                       return ret;
+                               role_changed = true;
+                       }
+               }
+
+               if (!role_changed) {
+                       if (cdns->role == USB_ROLE_HOST)
+                               ret = cdns_drd_host_on(cdns);
+                       else if (cdns->role == USB_ROLE_DEVICE)
+                               ret = cdns_drd_gadget_on(cdns);
+
+                       if (ret)
+                               return ret;
+               }
+       }
 
        if (cdns->roles[cdns->role]->resume)
-               cdns->roles[cdns->role]->resume(cdns, false);
+               cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns));
 
        if (set_active) {
                pm_runtime_disable(dev);
 
 
        return 0;
 }
+
+
+/* Indicate the cdns3 core was power lost before */
+bool cdns_power_is_lost(struct cdns *cdns)
+{
+       if (cdns->version == CDNS3_CONTROLLER_V1) {
+               if (!(readl(&cdns->otg_v1_regs->simulate) & BIT(0)))
+                       return true;
+       } else {
+               if (!(readl(&cdns->otg_v0_regs->simulate) & BIT(0)))
+                       return true;
+       }
+       return false;
+}
+EXPORT_SYMBOL_GPL(cdns_power_is_lost);
 
 void cdns_drd_gadget_off(struct cdns *cdns);
 int cdns_drd_host_on(struct cdns *cdns);
 void cdns_drd_host_off(struct cdns *cdns);
-
+bool cdns_power_is_lost(struct cdns *cdns);
 #endif /* __LINUX_CDNS3_DRD */