summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichele Bisogno <[email protected]>2026-04-26 09:43:18 +0200
committerMarek Vasut <[email protected]>2026-04-26 17:52:36 +0200
commitdc9f0d7177802191f67a42849f7e17f01c4b47dc (patch)
tree81b11f3a89f2da56ead75c01dcb02fe86ab89d20
parent6602a93d39294cfc3c73073658da7ee26f167be5 (diff)
usb: gadget: rcar: Add support for reset controller
Some Renesas SoCs, such as the RZ/G2L, require the USBHS core to be explicitly deasserted from reset before register access is possible. Update the OTG probe to handle a bulk reset controller. To maintain hardware stability, the reset is deasserted after clocks are enabled in probe(), and asserted before clocks are disabled in remove(). Update the error paths in probe to ensures clocks are disabled if the reset initialization fails. Reviewed-by: Marek Vasut <[email protected]> Signed-off-by: Michele Bisogno <[email protected]>
-rw-r--r--drivers/usb/gadget/rcar/common.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/drivers/usb/gadget/rcar/common.c b/drivers/usb/gadget/rcar/common.c
index d40d6736a54..2bf0dcff393 100644
--- a/drivers/usb/gadget/rcar/common.c
+++ b/drivers/usb/gadget/rcar/common.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <reset.h>
#include <usb.h>
#include "common.h"
@@ -290,6 +291,9 @@ struct usbhs_priv_otg_data {
void __iomem *base;
void __iomem *phybase;
+ struct clk_bulk clk_bulk;
+ struct reset_ctl_bulk reset_bulk;
+
struct platform_device usbhs_dev;
struct usbhs_priv usbhs_priv;
@@ -355,8 +359,10 @@ static int usbhs_udc_otg_gadget_handle_interrupts(struct udevice *dev)
return 0;
}
-static int usbhs_probe(struct usbhs_priv *priv)
+static int usbhs_probe(struct udevice *dev)
{
+ struct usbhs_priv_otg_data *otg_priv = dev_get_priv(dev);
+ struct usbhs_priv *priv = &otg_priv->usbhs_priv;
int ret;
priv->dparam.type = USBHS_TYPE_RCAR_GEN3;
@@ -396,34 +402,41 @@ static int usbhs_udc_otg_probe(struct udevice *dev)
{
struct usbhs_priv_otg_data *priv = dev_get_priv(dev);
struct usb_gadget *gadget;
- struct clk_bulk clk_bulk;
int ret = -EINVAL;
priv->base = dev_read_addr_ptr(dev);
if (!priv->base)
return -EINVAL;
- ret = clk_get_bulk(dev, &clk_bulk);
+ ret = clk_get_bulk(dev, &priv->clk_bulk);
if (ret)
return ret;
- ret = clk_enable_bulk(&clk_bulk);
+ ret = clk_enable_bulk(&priv->clk_bulk);
if (ret)
- return ret;
+ goto err_clk_enable;
+
+ ret = reset_get_bulk(dev, &priv->reset_bulk);
+ if (ret)
+ goto err_clk;
+
+ ret = reset_deassert_bulk(&priv->reset_bulk);
+ if (ret)
+ goto err_reset_deassert;
clrsetbits_le32(priv->base + UGCTRL2, UGCTRL2_USB0SEL_MASK, UGCTRL2_USB0SEL_EHCI);
clrsetbits_le16(priv->base + LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
ret = generic_setup_phy(dev, &priv->phy, 0, PHY_MODE_USB_OTG, 1);
if (ret)
- goto err_clk;
+ goto err_reset;
priv->phybase = dev_read_addr_ptr(priv->phy.dev);
priv->usbhs_priv.pdev = &priv->usbhs_dev;
priv->usbhs_priv.base = priv->base;
priv->usbhs_dev.dev.driver_data = &priv->usbhs_priv;
- ret = usbhs_probe(&priv->usbhs_priv);
+ ret = usbhs_probe(dev);
if (ret < 0)
goto err_phy;
@@ -439,8 +452,15 @@ static int usbhs_udc_otg_probe(struct udevice *dev)
err_phy:
generic_shutdown_phy(&priv->phy);
+err_reset:
+ reset_assert_bulk(&priv->reset_bulk);
+err_reset_deassert:
+ reset_release_bulk(&priv->reset_bulk);
err_clk:
- clk_disable_bulk(&clk_bulk);
+ clk_disable_bulk(&priv->clk_bulk);
+err_clk_enable:
+ clk_release_bulk(&priv->clk_bulk);
+
return ret;
}
@@ -458,6 +478,12 @@ static int usbhs_udc_otg_remove(struct udevice *dev)
generic_shutdown_phy(&priv->phy);
+ reset_assert_bulk(&priv->reset_bulk);
+ reset_release_bulk(&priv->reset_bulk);
+
+ clk_disable_bulk(&priv->clk_bulk);
+ clk_release_bulk(&priv->clk_bulk);
+
return dm_scan_fdt_dev(dev);
}