diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index 039bf241769a..7263fd7bdf4f 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -496,6 +496,8 @@ static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
 static int dwc3_setup_role_switch(struct dwc3 *dwc)
 {
 	struct usb_role_switch_desc dwc3_role_switch = {NULL};
+	struct device_node *dwc3_np = dev_of_node(dwc->dev);
+	struct device_node *xhci_np;
 	u32 mode;
 
 	dwc->role_switch_default_mode = usb_get_role_switch_default_mode(dwc->dev);
@@ -514,6 +516,10 @@ static int dwc3_setup_role_switch(struct dwc3 *dwc)
 	if (IS_ERR(dwc->role_sw))
 		return PTR_ERR(dwc->role_sw);
 
+	xhci_np = of_get_child_by_name(dwc3_np, "xhci");
+	if (xhci_np)
+		goto populate_skip;
+
 	if (dwc->dev->of_node) {
 		/* populate connector entry */
 		int ret = devm_of_platform_populate(dwc->dev);
@@ -526,6 +532,7 @@ static int dwc3_setup_role_switch(struct dwc3 *dwc)
 		}
 	}
 
+populate_skip:
 	dwc3_set_mode(dwc, mode);
 	return 0;
 }
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index f6f13e7f1ba1..8adfe45d9681 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -9,6 +9,7 @@
 
 #include <linux/irq.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 
 #include "core.h"
@@ -68,9 +69,22 @@ int dwc3_host_init(struct dwc3 *dwc)
 {
 	struct property_entry	props[4];
 	struct platform_device	*xhci;
+	struct device_node *dwc3_np = dev_of_node(dwc->dev);
+	struct device_node *xhci_np;
 	int			ret, irq;
 	int			prop_idx = 0;
 
+	xhci_np = of_get_child_by_name(dwc3_np, "xhci");
+	if (xhci_np) {
+		ret = of_platform_populate(dwc3_np, NULL, NULL, dwc->dev);
+		if (ret) {
+			dev_err(dwc->dev, "failed to register xhci - %d\n", ret);
+			goto err;
+		}
+		dwc->xhci = of_find_device_by_node(xhci_np);
+		goto populate_done;
+	}
+
 	irq = dwc3_host_get_irq(dwc);
 	if (irq < 0)
 		return irq;
@@ -126,14 +140,29 @@ int dwc3_host_init(struct dwc3 *dwc)
 		goto err;
 	}
 
+populate_done:
 	return 0;
+
 err:
-	platform_device_put(xhci);
+	if (xhci_np)
+		of_platform_depopulate(dwc->dev);
+	else
+		platform_device_put(xhci);
+
 	return ret;
 }
 
 void dwc3_host_exit(struct dwc3 *dwc)
 {
-	platform_device_unregister(dwc->xhci);
+	struct device_node *dwc3_np = dev_of_node(dwc->dev);
+	struct device_node *xhci_np;
+
+	xhci_np = of_get_child_by_name(dwc3_np, "xhci");
+
+	if (xhci_np)
+		of_platform_depopulate(dwc->dev);
+	else
+		platform_device_unregister(dwc->xhci);
+
 	dwc->xhci = NULL;
 }
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 5fb55bf19493..0eeaf306076a 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -29,11 +29,15 @@ static struct hc_driver __read_mostly xhci_plat_hc_driver;
 
 static int xhci_plat_setup(struct usb_hcd *hcd);
 static int xhci_plat_start(struct usb_hcd *hcd);
+static int xhci_plat_bus_suspend(struct usb_hcd *hcd);
+static int xhci_plat_bus_resume(struct usb_hcd *hcd);
 
 static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
 	.extra_priv_size = sizeof(struct xhci_plat_priv),
 	.reset = xhci_plat_setup,
 	.start = xhci_plat_start,
+	.bus_suspend = xhci_plat_bus_suspend,
+	.bus_resume = xhci_plat_bus_resume,
 };
 
 static void xhci_priv_plat_start(struct usb_hcd *hcd)
@@ -86,6 +90,33 @@ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 	xhci->quirks |= XHCI_PLAT | priv->quirks;
 }
 
+static int xhci_plat_bus_suspend(struct usb_hcd *hcd)
+{
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	if (xhci->quirks & XHCI_ROOTHUB_WAKEUP) {
+		if (hcd == xhci->main_hcd)
+			__pm_relax(xhci->main_wakelock);
+		else
+			__pm_relax(xhci->shared_wakelock);
+	}
+
+	return xhci_bus_suspend(hcd);
+}
+
+static int xhci_plat_bus_resume(struct usb_hcd *hcd)
+{
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	if (xhci->quirks & XHCI_ROOTHUB_WAKEUP) {
+		if (hcd == xhci->main_hcd)
+			__pm_stay_awake(xhci->main_wakelock);
+		else
+			__pm_stay_awake(xhci->shared_wakelock);
+	}
+	return xhci_bus_resume(hcd);
+}
+
 /* called during probe() after chip reset completes */
 static int xhci_plat_setup(struct usb_hcd *hcd)
 {
@@ -126,6 +157,10 @@ static const struct xhci_plat_priv xhci_plat_brcm = {
 	.quirks = XHCI_RESET_ON_RESUME | XHCI_SUSPEND_RESUME_CLKS,
 };
 
+static const struct xhci_plat_priv xhci_plat_exynos = {
+	.quirks = XHCI_ROOTHUB_WAKEUP,
+};
+
 static const struct of_device_id usb_xhci_of_match[] = {
 	{
 		.compatible = "generic-xhci",
@@ -167,6 +202,9 @@ static const struct of_device_id usb_xhci_of_match[] = {
 	}, {
 		.compatible = "brcm,bcm7445-xhci",
 		.data = &xhci_plat_brcm,
+	}, {
+		.compatible = "samsung,exynos-xhci",
+		.data = &xhci_plat_exynos,
 	},
 	{},
 };
@@ -185,7 +223,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
 	int			irq;
 	struct xhci_plat_priv	*priv = NULL;
 
-
 	if (usb_disabled())
 		return -ENODEV;
 
@@ -350,6 +387,21 @@ static int xhci_plat_probe(struct platform_device *pdev)
 			goto put_usb3_hcd;
 	}
 
+	if (xhci->quirks & XHCI_ROOTHUB_WAKEUP) {
+		/* Initialization wakelock for HCD */
+		xhci->main_wakelock = wakeup_source_register(&pdev->dev,
+							dev_name(&pdev->dev));
+		__pm_stay_awake(xhci->main_wakelock);
+		device_set_wakeup_enable(&xhci->main_hcd->self.root_hub->dev, true);
+
+		if (xhci->shared_hcd) {
+			xhci->shared_wakelock = wakeup_source_register(&pdev->dev,
+								dev_name(&pdev->dev));
+			__pm_stay_awake(xhci->shared_wakelock);
+			device_set_wakeup_enable(&xhci->shared_hcd->self.root_hub->dev, true);
+		}
+	}
+
 	device_enable_async_suspend(&pdev->dev);
 	pm_runtime_put_noidle(&pdev->dev);
 
@@ -398,6 +450,12 @@ static int xhci_plat_remove(struct platform_device *dev)
 	pm_runtime_get_sync(&dev->dev);
 	xhci->xhc_state |= XHCI_STATE_REMOVING;
 
+	if (xhci->quirks & XHCI_ROOTHUB_WAKEUP) {
+		wakeup_source_unregister(xhci->main_wakelock);
+		if (xhci->shared_wakelock)
+			wakeup_source_unregister(xhci->shared_wakelock);
+	}
+
 	if (shared_hcd) {
 		usb_remove_hcd(shared_hcd);
 		xhci->shared_hcd = NULL;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 79d7931c048a..693495054001 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5502,6 +5502,10 @@ void xhci_init_driver(struct hc_driver *drv,
 			drv->check_bandwidth = over->check_bandwidth;
 		if (over->reset_bandwidth)
 			drv->reset_bandwidth = over->reset_bandwidth;
+		if (over->bus_suspend)
+			drv->bus_suspend = over->bus_suspend;
+		if (over->bus_resume)
+			drv->bus_resume = over->bus_resume;
 	}
 }
 EXPORT_SYMBOL_GPL(xhci_init_driver);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c9f06c5e4e9d..cb9c54a6a22c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1752,6 +1752,8 @@ struct xhci_hub {
 struct xhci_hcd {
 	struct usb_hcd *main_hcd;
 	struct usb_hcd *shared_hcd;
+	struct wakeup_source *main_wakelock;
+	struct wakeup_source *shared_wakelock;
 	/* glue to PCI and HCD framework */
 	struct xhci_cap_regs __iomem *cap_regs;
 	struct xhci_op_regs __iomem *op_regs;
@@ -1898,6 +1900,7 @@ struct xhci_hcd {
 #define XHCI_EP_CTX_BROKEN_DCS	BIT_ULL(42)
 #define XHCI_SUSPEND_RESUME_CLKS	BIT_ULL(43)
 #define XHCI_RESET_TO_DEFAULT	BIT_ULL(44)
+#define XHCI_ROOTHUB_WAKEUP	BIT_ULL(45)
 
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
@@ -1943,6 +1946,8 @@ struct xhci_driver_overrides {
 			     struct usb_host_endpoint *ep);
 	int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
 	void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
+	int (*bus_suspend)(struct usb_hcd *hcd);
+	int (*bus_resume)(struct usb_hcd *hcd);
 };
 
 #define	XHCI_CFC_DELAY		10
