diff options
author | Piyush Mehta <piyush.mehta@amd.com> | 2022-09-12 13:10:17 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-09-22 15:52:30 +0200 |
commit | d6edcdc1ef06800f63519caac9b01b81274e25b7 (patch) | |
tree | 02ab09c74fc5395020510020e2ab2bced5e043fe /drivers/usb/dwc3 | |
parent | usb: dwc3: xilinx: add power management ops support (diff) | |
download | linux-d6edcdc1ef06800f63519caac9b01b81274e25b7.tar.xz linux-d6edcdc1ef06800f63519caac9b01b81274e25b7.zip |
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@amd.com>
Link: https://lore.kernel.org/r/20220912111017.901321-3-piyush.mehta@amd.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r-- | drivers/usb/dwc3/dwc3-xilinx.c | 30 |
1 files 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; } |