diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 7a2d54f71d21..999f9793fa3f 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -281,6 +281,16 @@ config PHY_XILINX_ZYNQMP
 	  Enable this to support ZynqMP High Speed Gigabit Transceiver
 	  that is part of ZynqMP SoC.
 
+config PHY_MICROCHIP_SAMA7_USB
+       tristate "Microchip SAMA7 USB 2.0 PHY"
+       depends on PHY && ARCH_AT91
+       help
+	 Enable this to support SAMA7 USB 2.0 PHY.
+
+	 The USB 2.0 PHY integrates high-speed, full-speed and low-speed
+	 termination and signal switching. With a single resistor, it
+	 requires minimal external components.
+
 source "drivers/phy/rockchip/Kconfig"
 source "drivers/phy/cadence/Kconfig"
 source "drivers/phy/ti/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index aca365d219c4..0b609768774a 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
 obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
 obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
 obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o
+obj-$(CONFIG_PHY_MICROCHIP_SAMA7_USB)  += phy-sama7-utmi-clk.o phy-sama7-usb.o
 obj-y += cadence/
 obj-y += ti/
 obj-y += qcom/
diff --git a/drivers/phy/phy-sama7-usb.c b/drivers/phy/phy-sama7-usb.c
new file mode 100644
index 000000000000..200324d81281
--- /dev/null
+++ b/drivers/phy/phy-sama7-usb.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Support for Atmel/Microchip USB PHY's.
+ *
+ * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Sergiu Moga <sergiu.moga@microchip.com>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <syscon.h>
+#include <regmap.h>
+#include <mach/sama7-sfr.h>
+
+struct sama7_usb_phy {
+	struct clk *uclk;
+	struct regmap *sfr;
+	int port;
+};
+
+static int sama7_usb_phy_init(struct phy *phy)
+{
+	struct sama7_usb_phy *sama7_phy = dev_get_priv(phy->dev);
+	int port = sama7_phy->port;
+
+	regmap_update_bits(sama7_phy->sfr, SAMA7_SFR_UTMI0R(port),
+			   SAMA7_SFR_UTMI_RX_TX_PREEM_AMP_TUNE_1X,
+			   SAMA7_SFR_UTMI_RX_TX_PREEM_AMP_TUNE_1X);
+
+	regmap_update_bits(sama7_phy->sfr, SAMA7_SFR_UTMI0R(port),
+			   SAMA7_SFR_UTMI_RX_VBUS,
+			   SAMA7_SFR_UTMI_RX_VBUS);
+
+	return 0;
+}
+
+static int sama7_phy_power_on(struct phy *phy)
+{
+	struct sama7_usb_phy *sama7_phy = dev_get_priv(phy->dev);
+
+	clk_prepare_enable(sama7_phy->uclk);
+
+	return 0;
+}
+
+static int sama7_phy_power_off(struct phy *phy)
+{
+	struct sama7_usb_phy *sama7_phy = dev_get_priv(phy->dev);
+
+	clk_disable_unprepare(sama7_phy->uclk);
+
+	return 0;
+}
+
+static int sama7_usb_phy_probe(struct udevice *dev)
+{
+	struct sama7_usb_phy *sama7_phy = dev_get_priv(dev);
+
+	sama7_phy->uclk = devm_clk_get(dev, "utmi_clk");
+	if (IS_ERR(sama7_phy->uclk))
+		return PTR_ERR(sama7_phy->uclk);
+
+	sama7_phy->sfr = syscon_regmap_lookup_by_phandle(dev, "sfr-phandle");
+	if (IS_ERR(sama7_phy->sfr))
+		return PTR_ERR(sama7_phy->sfr);
+
+	return dev_read_u32(dev, "reg", &sama7_phy->port);
+}
+
+static const struct phy_ops sama7_usb_phy_ops = {
+	.init = sama7_usb_phy_init,
+	.power_on = sama7_phy_power_on,
+	.power_off = sama7_phy_power_off,
+};
+
+static const struct udevice_id sama7_usb_phy_of_match[] = {
+	{ .compatible = "microchip,sama7g5-usb-phy", },
+	{ },
+};
+
+U_BOOT_DRIVER(sama7_usb_phy_driver) = {
+	.name = "sama7-usb-phy",
+	.id = UCLASS_PHY,
+	.of_match = sama7_usb_phy_of_match,
+	.ops = &sama7_usb_phy_ops,
+	.probe = sama7_usb_phy_probe,
+	.priv_auto = sizeof(struct sama7_usb_phy),
+};
diff --git a/drivers/phy/phy-sama7-utmi-clk.c b/drivers/phy/phy-sama7-utmi-clk.c
new file mode 100644
index 000000000000..2371b4341cd5
--- /dev/null
+++ b/drivers/phy/phy-sama7-utmi-clk.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Support for Atmel/Microchip USB PHY's.
+ *
+ * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Sergiu Moga <sergiu.moga@microchip.com>
+ */
+
+#include <dm.h>
+#include <linux/clk-provider.h>
+#include <syscon.h>
+#include <regmap.h>
+#include <mach/sama7-sfr.h>
+#include <reset.h>
+#include <dt-bindings/clk/at91.h>
+
+struct sama7_utmi_clk {
+	struct clk		uclk;
+	struct regmap		*regmap_sfr;
+	struct reset_ctl	*reset;
+	u8 id;
+};
+
+#define to_sama7_utmi_clk(_c) container_of(_c, struct sama7_utmi_clk, uclk)
+
+#define UBOOT_DM_CLK_MICROCHIP_SAMA7G5_UTMI "sama7-utmi-clk"
+#define UBOOT_DM_MICROCHIP_SAMA7G5_UTMI "sama7-utmi"
+#define USB_RESET_NAME_MAX_LEN 16
+
+#define AT91_TO_CLK_ID(_t, _i)		(((_t) << 8) | ((_i) & 0xff))
+
+/*
+ * UTMI clock description
+ * @n:	clock name
+ * @p:	clock parent name
+ * @id: clock id in RSTC_GRSTR
+ */
+static struct {
+	const char *n;
+	const char *p;
+	u8 id;
+} sama7_utmick[] = {
+	{ .n = "utmi1",	.p = "utmick", .id = 0, },
+	{ .n = "utmi2",	.p = "utmi1",  .id = 1, },
+	{ .n = "utmi3",	.p = "utmi1",  .id = 2, },
+};
+
+static int sama7_utmi_clk_enable(struct clk *clk)
+{
+	int ret;
+
+	struct sama7_utmi_clk *utmi = to_sama7_utmi_clk(clk);
+	u8 id = utmi->id;
+
+	ret = reset_assert(utmi->reset);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(utmi->regmap_sfr, SAMA7_SFR_UTMI0R(id),
+				 SAMA7_SFR_UTMI_COMMONON, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = reset_deassert(utmi->reset);
+	if (ret)
+		return ret;
+
+	/* Datasheet states a minimum of 45 us before any USB operation */
+	udelay(50);
+
+	return 0;
+}
+
+static int sama7_utmi_clk_disable(struct clk *clk)
+{
+	int ret;
+	struct sama7_utmi_clk *utmi = to_sama7_utmi_clk(clk);
+	u8 id = utmi->id;
+
+	ret = reset_assert(utmi->reset);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(utmi->regmap_sfr, SAMA7_SFR_UTMI0R(id),
+			   SAMA7_SFR_UTMI_COMMONON, SAMA7_SFR_UTMI_COMMONON);
+
+	return 0;
+}
+
+static ulong sama7_utmi_clk_get_rate(struct clk *clk)
+{
+	/* Return utmick's rate: 480MHz */
+	return clk_get_parent_rate(clk);
+}
+
+static const struct clk_ops sama7_utmi_clk_ops = {
+	.enable = sama7_utmi_clk_enable,
+	.disable = sama7_utmi_clk_disable,
+	.get_rate = sama7_utmi_clk_get_rate,
+};
+
+static struct clk*
+sama7_utmi_clk_register(struct regmap *regmap_sfr, struct reset_ctl *reset,
+			const char *name, const char *parent_name, u8 id)
+{
+	struct clk *clk;
+	struct sama7_utmi_clk *utmi_clk;
+	int ret;
+
+	if (!regmap_sfr || !reset || !name || !parent_name)
+		return ERR_PTR(-EINVAL);
+
+	utmi_clk = kzalloc(sizeof(*utmi_clk), GFP_KERNEL);
+	if (!utmi_clk)
+		return ERR_PTR(-ENOMEM);
+
+	utmi_clk->reset = reset;
+	utmi_clk->regmap_sfr = regmap_sfr;
+	utmi_clk->id = id;
+
+	clk = &utmi_clk->uclk;
+	ret = clk_register(clk, UBOOT_DM_CLK_MICROCHIP_SAMA7G5_UTMI,
+			   name, parent_name);
+	if (ret) {
+		kfree(utmi_clk);
+		clk = ERR_PTR(ret);
+	}
+
+	clk_dm(AT91_TO_CLK_ID(USB_UTMI, utmi_clk->id), clk);
+
+	return clk;
+}
+
+static int sama7_utmi_probe(struct udevice *dev)
+{
+	struct clk *utmi_parent_clk, *utmi_clk[ARRAY_SIZE(sama7_utmick)];
+	char name[USB_RESET_NAME_MAX_LEN];
+	struct sama7_utmi_clk *uclk;
+	struct reset_ctl *phy_reset;
+	struct regmap *regmap_sfr;
+	int ret, i, j;
+
+	utmi_parent_clk = devm_clk_get(dev, "utmi_clk");
+	if (IS_ERR(utmi_parent_clk))
+		return PTR_ERR(utmi_parent_clk);
+
+	regmap_sfr = syscon_regmap_lookup_by_phandle(dev, "sfr-phandle");
+	if (IS_ERR(regmap_sfr))
+		return PTR_ERR(regmap_sfr);
+
+	for (i = 0; i < ARRAY_SIZE(sama7_utmick); i++) {
+		snprintf(name, sizeof(name), "usb%d_reset", i);
+		phy_reset = devm_reset_control_get(dev, name);
+		if (IS_ERR(phy_reset)) {
+			ret = PTR_ERR(phy_reset);
+			goto err_uclk_register;
+		}
+
+		utmi_clk[i] = sama7_utmi_clk_register(regmap_sfr, phy_reset,
+						      sama7_utmick[i].n,
+						      sama7_utmick[i].p,
+						      sama7_utmick[i].id);
+		if (IS_ERR(utmi_clk[i])) {
+			ret = PTR_ERR(utmi_clk[i]);
+			goto err_uclk_register;
+		}
+	}
+
+	return 0;
+
+err_uclk_register:
+	for (j = 0; j < i; j++) {
+		uclk = to_sama7_utmi_clk(utmi_clk[j]);
+		kfree(uclk);
+	}
+
+	return ret;
+};
+
+static const struct udevice_id sama7_utmi_clk_dt_ids[] = {
+	{ .compatible = "microchip,sama7g5-utmi-clk", },
+	{ /* sentinel */},
+};
+
+static int utmi_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
+{
+	if (args->args_count != 1) {
+		debug("UTMI: clk: Invalid args_count: %d\n", args->args_count);
+		return -EINVAL;
+	}
+
+	clk->id = AT91_TO_CLK_ID(USB_UTMI, args->args[0]);
+
+	return 0;
+}
+
+static const struct clk_ops sama7_utmi_ops = {
+	.of_xlate	= utmi_clk_of_xlate,
+	.enable		= ccf_clk_enable,
+	.disable	= ccf_clk_disable,
+};
+
+U_BOOT_DRIVER(microhip_sama7g5_utmi_clk) = {
+	.name = UBOOT_DM_CLK_MICROCHIP_SAMA7G5_UTMI,
+	.id = UCLASS_CLK,
+	.ops = &sama7_utmi_clk_ops,
+};
+
+U_BOOT_DRIVER(microhip_sama7g5_utmi) = {
+	.name = UBOOT_DM_MICROCHIP_SAMA7G5_UTMI,
+	.of_match = sama7_utmi_clk_dt_ids,
+	.id = UCLASS_CLK,
+	.ops = &sama7_utmi_ops,
+	.probe = sama7_utmi_probe,
+};
