[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20220912111017.901321-3-piyush.mehta@amd.com>
Date: Mon, 12 Sep 2022 16:40:17 +0530
From: Piyush Mehta <piyush.mehta@....com>
To: <balbi@...nel.org>, <gregkh@...uxfoundation.org>,
<michal.simek@...inx.com>, <michal.simek@....com>,
<linux-usb@...r.kernel.org>,
<linux-arm-kernel@...ts.infradead.org>,
<linux-kernel@...r.kernel.org>
CC: <git@....com>, <siva.durga.prasad.paladugu@....com>,
Piyush Mehta <piyush.mehta@....com>
Subject: [PATCH 2/2] usb: dwc3: xilinx: fix usb3 non-wakeup source resume failure
When USB is in super-speed mode and disabled as a wakeup source,
observed that on the resume path, lanes have not been configured
properly in the phy-zynqmp driver.
As a result, after the resume, USB device detection failed on host.
To resolved the above issue, added phy_init on resume and phy_exit
on suspend path, to configure the GT lanes correctly.
The re-initialization of phy, reset the device and re-enumerate
the USB subsystem.
This use-case is specific to Xilinx ZynqMP SoC.
Signed-off-by: Piyush Mehta <piyush.mehta@....com>
---
drivers/usb/dwc3/dwc3-xilinx.c | 30 +++++++++++++++++++++---------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index a0d0280a045e..8607d4c23283 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -47,6 +47,7 @@ struct dwc3_xlnx {
struct device *dev;
void __iomem *regs;
int (*pltfm_init)(struct dwc3_xlnx *data);
+ struct phy *usb3_phy;
};
static void dwc3_xlnx_mask_phy_rst(struct dwc3_xlnx *priv_data, bool mask)
@@ -100,13 +101,12 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
struct device *dev = priv_data->dev;
struct reset_control *crst, *hibrst, *apbrst;
struct gpio_desc *reset_gpio;
- struct phy *usb3_phy;
int ret = 0;
u32 reg;
- usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
- if (IS_ERR(usb3_phy)) {
- ret = PTR_ERR(usb3_phy);
+ priv_data->usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
+ if (IS_ERR(priv_data->usb3_phy)) {
+ ret = PTR_ERR(priv_data->usb3_phy);
dev_err_probe(dev, ret,
"failed to get USB3 PHY\n");
goto err;
@@ -121,7 +121,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
* in use but the usb3-phy entry is missing from the device tree.
* Therefore, skip these operations in this case.
*/
- if (!usb3_phy)
+ if (!priv_data->usb3_phy)
goto skip_usb3_phy;
crst = devm_reset_control_get_exclusive(dev, "usb_crst");
@@ -166,9 +166,9 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
goto err;
}
- ret = phy_init(usb3_phy);
+ ret = phy_init(priv_data->usb3_phy);
if (ret < 0) {
- phy_exit(usb3_phy);
+ phy_exit(priv_data->usb3_phy);
goto err;
}
@@ -196,9 +196,9 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
goto err;
}
- ret = phy_power_on(usb3_phy);
+ ret = phy_power_on(priv_data->usb3_phy);
if (ret < 0) {
- phy_exit(usb3_phy);
+ phy_exit(priv_data->usb3_phy);
goto err;
}
@@ -350,6 +350,8 @@ static int __maybe_unused dwc3_xlnx_suspend(struct device *dev)
{
struct dwc3_xlnx *priv_data = dev_get_drvdata(dev);
+ phy_exit(priv_data->usb3_phy);
+
/* Disable the clocks */
clk_bulk_disable(priv_data->num_clocks, priv_data->clks);
@@ -365,6 +367,16 @@ static int __maybe_unused dwc3_xlnx_resume(struct device *dev)
if (ret)
return ret;
+ ret = phy_init(priv_data->usb3_phy);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_power_on(priv_data->usb3_phy);
+ if (ret < 0) {
+ phy_exit(priv_data->usb3_phy);
+ return ret;
+ }
+
return 0;
}
--
2.25.1
Powered by blists - more mailing lists