#include <linux/usb/gadget.h>
 #include <linux/usb/of.h>
 #include <linux/usb/role.h>
+#include <linux/usb/rzv2m_usb3drd.h>
 
 /* register definitions */
 #define USB3_AXI_INT_STA       0x008
 
 struct renesas_usb3 {
        void __iomem *reg;
-       struct reset_control *drd_rstc;
+       void __iomem *drd_reg;
        struct reset_control *usbp_rstc;
 
        struct usb_gadget gadget;
        usb3_write(usb3, val, offs);
 }
 
+static void usb3_drd_write(struct renesas_usb3 *usb3, u32 data, u32 offs)
+{
+       void __iomem *reg;
+
+       if (usb3->is_rzv2m)
+               reg = usb3->drd_reg + offs - USB3_DRD_CON(usb3);
+       else
+               reg = usb3->reg + offs;
+
+       iowrite32(data, reg);
+}
+
+static u32 usb3_drd_read(struct renesas_usb3 *usb3, u32 offs)
+{
+       void __iomem *reg;
+
+       if (usb3->is_rzv2m)
+               reg = usb3->drd_reg + offs - USB3_DRD_CON(usb3);
+       else
+               reg = usb3->reg + offs;
+
+       return ioread32(reg);
+}
+
+static void usb3_drd_set_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs)
+{
+       u32 val = usb3_drd_read(usb3, offs);
+
+       val |= bits;
+       usb3_drd_write(usb3, val, offs);
+}
+
+static void usb3_drd_clear_bit(struct renesas_usb3 *usb3, u32 bits, u32 offs)
+{
+       u32 val = usb3_drd_read(usb3, offs);
+
+       val &= ~bits;
+       usb3_drd_write(usb3, val, offs);
+}
+
 static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask,
                     u32 expected)
 {
 
 static bool usb3_is_host(struct renesas_usb3 *usb3)
 {
-       return !(usb3_read(usb3, USB3_DRD_CON(usb3)) & DRD_CON_PERI_CON);
+       return !(usb3_drd_read(usb3, USB3_DRD_CON(usb3)) & DRD_CON_PERI_CON);
 }
 
 static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
 {
        if (usb3->is_rzv2m) {
                if (host) {
-                       usb3_set_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
-                       usb3_clear_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+                       usb3_drd_set_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+                       usb3_drd_clear_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
                } else {
-                       usb3_set_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
-                       usb3_clear_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
+                       usb3_drd_set_bit(usb3, DRD_CON_HOST_RST, USB3_DRD_CON(usb3));
+                       usb3_drd_clear_bit(usb3, DRD_CON_PERI_RST, USB3_DRD_CON(usb3));
                }
        }
 
        if (host)
-               usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
+               usb3_drd_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
        else
-               usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
+               usb3_drd_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON(usb3));
 }
 
 static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
 static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
 {
        if (enable)
-               usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
+               usb3_drd_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
        else
-               usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
+               usb3_drd_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON(usb3));
 }
 
 static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
 
 static bool usb3_is_a_device(struct renesas_usb3 *usb3)
 {
-       return !(usb3_read(usb3, USB3_USB_OTG_STA(usb3)) & USB_OTG_IDMON(usb3));
+       return !(usb3_drd_read(usb3, USB3_USB_OTG_STA(usb3)) & USB_OTG_IDMON(usb3));
 }
 
 static void usb3_check_id(struct renesas_usb3 *usb3)
        usb3_set_bit(usb3, USB_COM_CON_PN_WDATAIF_NL |
                     USB_COM_CON_PN_RDATAIF_NL | USB_COM_CON_PN_LSTTR_PP,
                     USB3_USB_COM_CON);
-       usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_STA(usb3));
-       usb3_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_ENA(usb3));
+       usb3_drd_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_STA(usb3));
+       usb3_drd_write(usb3, USB_OTG_IDMON(usb3), USB3_USB_OTG_INT_ENA(usb3));
 
        usb3_check_id(usb3);
        usb3_check_vbus(usb3);
 {
        usb3_disconnect(usb3);
        usb3_write(usb3, 0, USB3_P0_INT_ENA);
-       usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA(usb3));
+       usb3_drd_write(usb3, 0, USB3_USB_OTG_INT_ENA(usb3));
        usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
        usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
        usb3_write(usb3, 0, USB3_AXI_INT_ENA);
 
 static void usb3_irq_otg_int(struct renesas_usb3 *usb3)
 {
-       u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA(usb3));
+       u32 otg_int_sta = usb3_drd_read(usb3, USB3_USB_OTG_INT_STA(usb3));
 
-       otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA(usb3));
+       otg_int_sta &= usb3_drd_read(usb3, USB3_USB_OTG_INT_ENA(usb3));
        if (otg_int_sta)
-               usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA(usb3));
+               usb3_drd_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA(usb3));
 
        if (otg_int_sta & USB_OTG_IDMON(usb3))
                usb3_irq_idmon_change(usb3);
 
        usb_del_gadget_udc(&usb3->gadget);
        reset_control_assert(usb3->usbp_rstc);
-       reset_control_assert(usb3->drd_rstc);
        renesas_usb3_dma_free_prd(usb3, &pdev->dev);
 
        __renesas_usb3_ep_free_request(usb3->ep0_req);
 static int renesas_usb3_probe(struct platform_device *pdev)
 {
        struct renesas_usb3 *usb3;
-       int irq, drd_irq, ret;
+       int irq, ret;
        const struct renesas_usb3_priv *priv;
        const struct soc_device_attribute *attr;
 
        if (irq < 0)
                return irq;
 
-       if (priv->is_rzv2m) {
-               drd_irq = platform_get_irq_byname(pdev, "drd");
-               if (drd_irq < 0)
-                       return drd_irq;
-       }
-
        usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
        if (!usb3)
                return -ENOMEM;
                return ret;
 
        if (usb3->is_rzv2m) {
-               ret = devm_request_irq(&pdev->dev, drd_irq,
+               struct rzv2m_usb3drd *ddata = dev_get_drvdata(pdev->dev.parent);
+
+               usb3->drd_reg = ddata->reg;
+               ret = devm_request_irq(ddata->dev, ddata->drd_irq,
                                       renesas_usb3_otg_irq, 0,
-                                      dev_name(&pdev->dev), usb3);
+                                      dev_name(ddata->dev), usb3);
                if (ret < 0)
                        return ret;
        }
                goto err_add_udc;
        }
 
-       usb3->drd_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
-                                                               "drd_reset");
-       if (IS_ERR(usb3->drd_rstc)) {
-               ret = PTR_ERR(usb3->drd_rstc);
-               goto err_add_udc;
-       }
-
        usb3->usbp_rstc = devm_reset_control_get_optional_shared(&pdev->dev,
-                                                                "aresetn_p");
+                                                                NULL);
        if (IS_ERR(usb3->usbp_rstc)) {
                ret = PTR_ERR(usb3->usbp_rstc);
                goto err_add_udc;
        }
 
-       reset_control_deassert(usb3->drd_rstc);
        reset_control_deassert(usb3->usbp_rstc);
 
        pm_runtime_enable(&pdev->dev);
 
 err_reset:
        reset_control_assert(usb3->usbp_rstc);
-       reset_control_assert(usb3->drd_rstc);
 
 err_add_udc:
        renesas_usb3_dma_free_prd(usb3, &pdev->dev);
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/V2M USB3DRD driver
+ *
+ * Copyright (C) 2022 Renesas Electronics Corporation
+ */
+
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/usb/rzv2m_usb3drd.h>
+
+#define USB_PERI_DRD_CON       0x000
+
+#define USB_PERI_DRD_CON_PERI_RST      BIT(31)
+#define USB_PERI_DRD_CON_HOST_RST      BIT(30)
+#define USB_PERI_DRD_CON_PERI_CON      BIT(24)
+
+static void rzv2m_usb3drd_set_bit(struct rzv2m_usb3drd *usb3, u32 bits,
+                                 u32 offs)
+{
+       u32 val = readl(usb3->reg + offs);
+
+       val |= bits;
+       writel(val, usb3->reg + offs);
+}
+
+static void rzv2m_usb3drd_clear_bit(struct rzv2m_usb3drd *usb3, u32 bits,
+                                   u32 offs)
+{
+       u32 val = readl(usb3->reg + offs);
+
+       val &= ~bits;
+       writel(val, usb3->reg + offs);
+}
+
+void rzv2m_usb3drd_reset(struct device *dev, bool host)
+{
+       struct rzv2m_usb3drd *usb3 = dev_get_drvdata(dev);
+
+       if (host) {
+               rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_PERI_CON,
+                                       USB_PERI_DRD_CON);
+               rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_HOST_RST,
+                                       USB_PERI_DRD_CON);
+               rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_PERI_RST,
+                                     USB_PERI_DRD_CON);
+       } else {
+               rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_PERI_CON,
+                                     USB_PERI_DRD_CON);
+               rzv2m_usb3drd_set_bit(usb3, USB_PERI_DRD_CON_HOST_RST,
+                                     USB_PERI_DRD_CON);
+               rzv2m_usb3drd_clear_bit(usb3, USB_PERI_DRD_CON_PERI_RST,
+                                       USB_PERI_DRD_CON);
+       }
+}
+EXPORT_SYMBOL_GPL(rzv2m_usb3drd_reset);
+
+static int rzv2m_usb3drd_remove(struct platform_device *pdev)
+{
+       struct rzv2m_usb3drd *usb3 = platform_get_drvdata(pdev);
+
+       of_platform_depopulate(usb3->dev);
+       pm_runtime_put(usb3->dev);
+       pm_runtime_disable(&pdev->dev);
+       reset_control_assert(usb3->drd_rstc);
+
+       return 0;
+}
+
+static int rzv2m_usb3drd_probe(struct platform_device *pdev)
+{
+       struct rzv2m_usb3drd *usb3;
+       int ret;
+
+       usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);
+       if (!usb3)
+               return -ENOMEM;
+
+       usb3->dev = &pdev->dev;
+
+       usb3->drd_irq = platform_get_irq_byname(pdev, "drd");
+       if (usb3->drd_irq < 0)
+               return usb3->drd_irq;
+
+       usb3->reg = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(usb3->reg))
+               return PTR_ERR(usb3->reg);
+
+       platform_set_drvdata(pdev, usb3);
+
+       usb3->drd_rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+       if (IS_ERR(usb3->drd_rstc))
+               return dev_err_probe(&pdev->dev, PTR_ERR(usb3->drd_rstc),
+                                    "failed to get drd reset");
+
+       reset_control_deassert(usb3->drd_rstc);
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_resume_and_get(usb3->dev);
+       if (ret)
+               goto err_rst;
+
+       ret = of_platform_populate(usb3->dev->of_node, NULL, NULL, usb3->dev);
+       if (ret)
+               goto err_pm;
+
+       return 0;
+
+err_pm:
+       pm_runtime_put(usb3->dev);
+
+err_rst:
+       pm_runtime_disable(&pdev->dev);
+       reset_control_assert(usb3->drd_rstc);
+       return ret;
+}
+
+static const struct of_device_id rzv2m_usb3drd_of_match[] = {
+       { .compatible = "renesas,rzv2m-usb3drd", },
+       { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzv2m_usb3drd_of_match);
+
+static struct platform_driver rzv2m_usb3drd_driver = {
+       .driver = {
+               .name = "rzv2m-usb3drd",
+               .of_match_table = of_match_ptr(rzv2m_usb3drd_of_match),
+       },
+       .probe = rzv2m_usb3drd_probe,
+       .remove = rzv2m_usb3drd_remove,
+};
+module_platform_driver(rzv2m_usb3drd_driver);
+
+MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/V2M USB3DRD driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rzv2m_usb3drd");