diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 40b5de597112..5a17a9b1fbff 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -53,6 +53,14 @@ config USB_XHCI_PLATFORM
 
 	  If unsure, say N.
 
+config USB_XHCI_EXYNOS
+	tristate "xHCI support for Samsung Exynos SoCs"
+	depends on USB_XHCI_PLATFORM
+	depends on ARCH_EXYNOS || COMPILE_TEST
+	---help---
+	  Say 'Y' to enable the support for the xHCI host controller
+	  found in Samsung Exynos ARM SoCs.
+
 config USB_XHCI_HISTB
 	tristate "xHCI support for HiSilicon STB SoCs"
 	depends on USB_XHCI_PLATFORM && (ARCH_HISI || COMPILE_TEST)
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 84514f71ae44..34afd6680751 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -30,6 +30,9 @@ endif
 ifneq ($(CONFIG_USB_XHCI_RCAR), )
 	xhci-plat-hcd-y		+= xhci-rcar.o
 endif
+ifneq ($(CONFIG_USB_XHCI_EXYNOS), )
+	xhci-plat-hcd-y		+= xhci-exynos.o
+endif
 
 ifneq ($(CONFIG_DEBUG_FS),)
 	xhci-hcd-y		+= xhci-debugfs.o
diff --git a/drivers/usb/host/xhci-exynos.c b/drivers/usb/host/xhci-exynos.c
new file mode 100644
index 000000000000..446d33998382
--- /dev/null
+++ b/drivers/usb/host/xhci-exynos.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * xHCI host controller driver for Samsung Exynos5 SoCs
+ *
+ * Copyright (C) 2019 Samsung Electronics Co., Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+
+#include "xhci.h"
+#include "xhci-plat.h"
+#include "xhci-exynos.h"
+
+int xhci_exynos_init_quirk(struct usb_hcd *hcd)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct device *dev = hcd->self.controller;
+	struct xhci_plat_priv *xhci_priv = hcd_to_xhci_priv(hcd);
+	struct phy *usb2_generic_phy;
+	int ret;
+
+	usb2_generic_phy = devm_phy_get(dev->parent, "usb2-phy");
+	if (IS_ERR(usb2_generic_phy)) {
+		ret = PTR_ERR(usb2_generic_phy);
+		if (ret == -EPROBE_DEFER) {
+			return ret;
+		} else {
+			dev_err(dev, "no usb2 phy configured\n");
+			return ret;
+		}
+	}
+
+	phy_calibrate(usb2_generic_phy);
+	xhci_priv->priv = usb2_generic_phy;
+
+	xhci->quirks |= XHCI_RESET_ON_RESUME;
+
+	return 0;
+}
+
+int xhci_exynos_post_resume_quirk(struct usb_hcd *hcd)
+{
+	struct xhci_plat_priv *xhci_priv = hcd_to_xhci_priv(hcd);
+	struct phy *usb2_generic_phy = xhci_priv->priv;
+
+	phy_calibrate(usb2_generic_phy);
+
+	return 0;
+}
diff --git a/drivers/usb/host/xhci-exynos.h b/drivers/usb/host/xhci-exynos.h
new file mode 100644
index 000000000000..58ea3e9aea8d
--- /dev/null
+++ b/drivers/usb/host/xhci-exynos.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * drivers/usb/host/xhci-exynos.h
+ *
+ * Copyright (C) 2019 Samsung Electronics Co., Ltd.
+ */
+
+#ifndef _XHCI_EXYNOS_H
+#define _XHCI_EXYNOS_H
+
+
+#if IS_ENABLED(CONFIG_USB_XHCI_EXYNOS)
+int xhci_exynos_init_quirk(struct usb_hcd *hcd);
+int xhci_exynos_post_resume_quirk(struct usb_hcd *hcd);
+#else
+static inline int xhci_exynos_init_quirk(struct usb_hcd *hcd)
+{
+	return 0;
+}
+
+static inline int xhci_exynos_post_resume_quirk(struct usb_hcd *hcd)
+{
+	return 0;
+}
+#endif
+#endif /* _XHCI_EXYNOS_H */
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 998241f5fce3..6bc03cdb2f21 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -24,6 +24,7 @@
 #include "xhci-plat.h"
 #include "xhci-mvebu.h"
 #include "xhci-rcar.h"
+#include "xhci-exynos.h"
 
 static struct hc_driver __read_mostly xhci_plat_hc_driver;
 
@@ -64,6 +65,16 @@ static int xhci_priv_resume_quirk(struct usb_hcd *hcd)
 	return priv->resume_quirk(hcd);
 }
 
+static int xhci_priv_post_resume_quirk(struct usb_hcd *hcd)
+{
+	struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+
+	if (!priv->post_resume_quirk)
+		return 0;
+
+	return priv->post_resume_quirk(hcd);
+}
+
 static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 {
 	/*
@@ -102,6 +113,11 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
 	.init_quirk = xhci_mvebu_a3700_init_quirk,
 };
 
+static const struct xhci_plat_priv xhci_plat_samsung_exynos5 = {
+	.init_quirk = xhci_exynos_init_quirk,
+	.post_resume_quirk = xhci_exynos_post_resume_quirk,
+};
+
 static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
 	.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1,
 	.init_quirk = xhci_rcar_init_quirk,
@@ -260,6 +276,13 @@ static int xhci_plat_probe(struct platform_device *pdev)
 		goto disable_reg_clk;
 
 	priv_match = of_device_get_match_data(&pdev->dev);
+	if (!priv_match) {
+		const struct platform_device_id *id =
+						   platform_get_device_id(pdev);
+		if (id)
+			priv_match = (const struct xhci_plat_priv *)
+								id->driver_data;
+	}
 	if (priv_match) {
 		struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
 
@@ -413,7 +436,11 @@ static int __maybe_unused xhci_plat_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	return xhci_resume(xhci, 0);
+	ret = xhci_resume(xhci, 0);
+	if (ret)
+		return ret;
+
+	return xhci_priv_post_resume_quirk(hcd);
 }
 
 static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev)
@@ -447,9 +474,18 @@ static const struct acpi_device_id usb_xhci_acpi_match[] = {
 };
 MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match);
 
+static struct platform_device_id xhci_plat_driver_ids[] = {
+	{
+		.name		= "exynos5-dwc3-xhci",
+		.driver_data	= (long) &xhci_plat_samsung_exynos5,
+	}, { },
+};
+MODULE_DEVICE_TABLE(platform, xhci_plat_driver_ids);
+
 static struct platform_driver usb_xhci_driver = {
 	.probe	= xhci_plat_probe,
 	.remove	= xhci_plat_remove,
+	.id_table = xhci_plat_driver_ids,
 	.driver	= {
 		.name = "xhci-hcd",
 		.pm = &xhci_plat_pm_ops,
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index ae29f22ff5bd..f8a8e84b4ebe 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -12,9 +12,11 @@
 
 struct xhci_plat_priv {
 	const char *firmware_name;
+	void *priv;
 	void (*plat_start)(struct usb_hcd *);
 	int (*init_quirk)(struct usb_hcd *);
 	int (*resume_quirk)(struct usb_hcd *);
+	int (*post_resume_quirk)(struct usb_hcd *);
 };
 
 #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
