[PATCH 5/5] usb: dwc3: xilinx: unwind ZynqMP platform init on probe failure and remove

From: Radhey Shyam Pandey

Date: Mon Aug 10 2026 - 13:49:16 EST


Add dwc3_xlnx_exit_zynqmp() and wire it as the ZynqMP platform exit
callback. If probe steps fail after a successful plat->init(), call
plat->exit() to re-assert released resets and unwind the PHY before
disabling clocks. Call the same callback from remove() and shutdown.

Fixes: 84770f028fab ("usb: dwc3: Add driver for Xilinx platforms")
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xxxxxxx>
---
drivers/usb/dwc3/dwc3-xilinx.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 38613553937e..0d2232741d46 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -121,6 +121,20 @@ static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data)
return 0;
}

+static void dwc3_xlnx_exit_zynqmp(struct dwc3_xlnx *priv_data)
+{
+ phy_power_off(priv_data->usb3_phy);
+
+ if (priv_data->usb_resets_released) {
+ reset_control_assert(priv_data->usb_hibrst);
+ reset_control_assert(priv_data->usb_crst);
+ reset_control_assert(priv_data->usb_apbrst);
+ priv_data->usb_resets_released = false;
+ }
+
+ phy_exit(priv_data->usb3_phy);
+}
+
static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
{
struct device *dev = priv_data->dev;
@@ -257,6 +271,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)

static const struct dwc3_xlnx_platdata zynqmp_platdata = {
.init = dwc3_xlnx_init_zynqmp,
+ .exit = dwc3_xlnx_exit_zynqmp,
};

static const struct dwc3_xlnx_platdata versal_platdata = {
@@ -346,11 +361,11 @@ static int dwc3_xlnx_probe(struct platform_device *pdev)

ret = dwc3_set_swnode(dev);
if (ret)
- goto err_clk_put;
+ goto err_pltfm_exit;

ret = of_platform_populate(np, NULL, NULL, dev);
if (ret)
- goto err_clk_put;
+ goto err_pltfm_exit;

pm_runtime_set_active(dev);
ret = devm_pm_runtime_enable(dev);
@@ -367,7 +382,9 @@ static int dwc3_xlnx_probe(struct platform_device *pdev)
err_pm_set_suspended:
of_platform_depopulate(dev);
pm_runtime_set_suspended(dev);
-
+err_pltfm_exit:
+ if (priv_data->plat->exit)
+ priv_data->plat->exit(priv_data);
err_clk_put:
clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks);

@@ -381,6 +398,9 @@ static void dwc3_xlnx_remove(struct platform_device *pdev)

of_platform_depopulate(dev);

+ if (priv_data->plat->exit)
+ priv_data->plat->exit(priv_data);
+
clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks);
priv_data->num_clocks = 0;

--
2.43.0