#define   USB_CTRL_USB_PM_SOFT_RESET_MASK              0x40000000 /* option */
 #define   USB_CTRL_USB_PM_USB20_HC_RESETB_MASK         0x30000000 /* option */
 #define   USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK     0x00300000 /* option */
+#define   USB_CTRL_USB_PM_RMTWKUP_EN_MASK              0x00000001
+#define USB_CTRL_USB_PM_STATUS         0x38
 #define USB_CTRL_USB30_CTL1            0x60
 #define   USB_CTRL_USB30_CTL1_PHY3_PLL_SEQ_START_MASK  0x00000010
 #define   USB_CTRL_USB30_CTL1_PHY3_RESETB_MASK         0x00010000
        u32 reg;
        void __iomem *ctrl = params->ctrl_regs;
 
+       /* Clear any pending wake conditions */
+       reg = brcmusb_readl(USB_CTRL_REG(ctrl, USB_PM_STATUS));
+       brcmusb_writel(reg, USB_CTRL_REG(ctrl, USB_PM_STATUS));
+
        /* Take USB out of power down */
        if (USB_CTRL_MASK_FAMILY(params, PLL_CTL, PLL_IDDQ_PWRDN)) {
                USB_CTRL_UNSET_FAMILY(params, PLL_CTL, PLL_IDDQ_PWRDN);
        USB_CTRL_SET(params->ctrl_regs, USB30_PCTL, PHY3_IDDQ_OVERRIDE);
 }
 
+void brcm_usb_wake_enable(struct brcm_usb_init_params *params,
+                         int enable)
+{
+       void __iomem *ctrl = params->ctrl_regs;
+
+       if (enable)
+               USB_CTRL_SET(ctrl, USB_PM, RMTWKUP_EN);
+       else
+               USB_CTRL_UNSET(ctrl, USB_PM, RMTWKUP_EN);
+}
+
 void brcm_usb_set_family_map(struct brcm_usb_init_params *params)
 {
        int fam;
 
        bool                    has_xhci;
        struct clk              *usb_20_clk;
        struct clk              *usb_30_clk;
+       struct clk              *suspend_clk;
        struct mutex            mutex;  /* serialize phy init */
        int                     init_count;
+       int                     wake_irq;
        struct brcm_usb_phy     phys[BRCM_USB_PHY_ID_MAX];
 };
 
+static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id)
+{
+       struct phy *gphy = dev_id;
+
+       pm_wakeup_event(&gphy->dev, 0);
+
+       return IRQ_HANDLED;
+}
+
 static int brcm_usb_phy_init(struct phy *gphy)
 {
        struct brcm_usb_phy *phy = phy_get_drvdata(gphy);
        if (priv->init_count++ == 0) {
                clk_prepare_enable(priv->usb_20_clk);
                clk_prepare_enable(priv->usb_30_clk);
+               clk_prepare_enable(priv->suspend_clk);
                brcm_usb_init_common(&priv->ini);
        }
        mutex_unlock(&priv->mutex);
                brcm_usb_uninit_common(&priv->ini);
                clk_disable_unprepare(priv->usb_20_clk);
                clk_disable_unprepare(priv->usb_30_clk);
+               clk_disable_unprepare(priv->suspend_clk);
        }
        mutex_unlock(&priv->mutex);
        phy->inited = false;
        .attrs = brcm_usb_phy_attrs,
 };
 
-static int brcm_usb_phy_dvr_init(struct device *dev,
+static int brcm_usb_phy_dvr_init(struct platform_device *pdev,
                                 struct brcm_usb_phy_data *priv,
                                 struct device_node *dn)
 {
-       struct phy *gphy;
+       struct device *dev = &pdev->dev;
+       struct phy *gphy = NULL;
        int err;
 
        priv->usb_20_clk = of_clk_get_by_name(dn, "sw_usb");
                if (err)
                        return err;
        }
+
+       priv->suspend_clk = clk_get(dev, "usb0_freerun");
+       if (IS_ERR(priv->suspend_clk)) {
+               dev_err(dev, "Suspend Clock not found in Device Tree\n");
+               priv->suspend_clk = NULL;
+       }
+
+       priv->wake_irq = platform_get_irq_byname(pdev, "wake");
+       if (priv->wake_irq < 0)
+               priv->wake_irq = platform_get_irq_byname(pdev, "wakeup");
+       if (priv->wake_irq >= 0) {
+               err = devm_request_irq(dev, priv->wake_irq,
+                                      brcm_usb_phy_wake_isr, 0,
+                                      dev_name(dev), gphy);
+               if (err < 0)
+                       return err;
+               device_set_wakeup_capable(dev, 1);
+       } else {
+               dev_info(dev,
+                        "Wake interrupt missing, system wake not supported\n");
+       }
+
        return 0;
 }
 
        if (of_property_read_bool(dn, "brcm,has-eohci"))
                priv->has_eohci = true;
 
-       err = brcm_usb_phy_dvr_init(dev, priv, dn);
+       err = brcm_usb_phy_dvr_init(pdev, priv, dn);
        if (err)
                return err;
 
                if (priv->phys[BRCM_USB_PHY_2_0].inited)
                        brcm_usb_uninit_eohci(&priv->ini);
                brcm_usb_uninit_common(&priv->ini);
+               brcm_usb_wake_enable(&priv->ini, true);
                if (priv->phys[BRCM_USB_PHY_3_0].inited)
                        clk_disable_unprepare(priv->usb_30_clk);
                if (priv->phys[BRCM_USB_PHY_2_0].inited)
                        clk_disable_unprepare(priv->usb_20_clk);
+               if (priv->wake_irq >= 0)
+                       enable_irq_wake(priv->wake_irq);
        }
        return 0;
 }
 
        clk_prepare_enable(priv->usb_20_clk);
        clk_prepare_enable(priv->usb_30_clk);
+       brcm_usb_wake_enable(&priv->ini, false);
        brcm_usb_init_ipp(&priv->ini);
 
        /*
         * Uninitialize anything that wasn't previously initialized.
         */
        if (priv->init_count) {
+               if (priv->wake_irq >= 0)
+                       disable_irq_wake(priv->wake_irq);
                brcm_usb_init_common(&priv->ini);
                if (priv->phys[BRCM_USB_PHY_2_0].inited) {
                        brcm_usb_init_eohci(&priv->ini);