diff options
author | Amelie Delaunay <amelie.delaunay@foss.st.com> | 2021-10-05 12:53:04 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-11-18 21:16:54 +0300 |
commit | 27903e1ffbfa991c036d9473ae10d31ca2c8dc5c (patch) | |
tree | 0415cc2a229df7f832e1ed0535201764a0a469dc | |
parent | bd18f99c5c7835925f8a2afffa960a2aeb6c6739 (diff) | |
download | linux-27903e1ffbfa991c036d9473ae10d31ca2c8dc5c.tar.xz |
usb: dwc2: drd: fix dwc2_drd_role_sw_set when clock could be disabled
[ Upstream commit 8d387f61b0240854e81450c261beb775065bad5d ]
In case of USB_DR_MODE_PERIPHERAL, the OTG clock is disabled at the end of
the probe (it is not the case if USB_DR_MODE_HOST or USB_DR_MODE_OTG).
The clock is then enabled on udc_start.
If dwc2_drd_role_sw_set is called before udc_start (it is the case if the
usb cable is plugged at boot), GOTGCTL and GUSBCFG registers cannot be
read/written, so session cannot be overridden.
To avoid this case, check the ll_hw_enabled value and enable the clock if
it is available, and disable it after the override.
Fixes: 17f934024e84 ("usb: dwc2: override PHY input signals with usb role switch support")
Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
Link: https://lore.kernel.org/r/20211005095305.66397-3-amelie.delaunay@foss.st.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | drivers/usb/dwc2/drd.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c index 80eae88d76dd..99672360f34b 100644 --- a/drivers/usb/dwc2/drd.c +++ b/drivers/usb/dwc2/drd.c @@ -7,6 +7,7 @@ * Author(s): Amelie Delaunay <amelie.delaunay@st.com> */ +#include <linux/clk.h> #include <linux/iopoll.h> #include <linux/platform_device.h> #include <linux/usb/role.h> @@ -86,6 +87,20 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) } #endif + /* + * In case of USB_DR_MODE_PERIPHERAL, clock is disabled at the end of + * the probe and enabled on udc_start. + * If role-switch set is called before the udc_start, we need to enable + * the clock to read/write GOTGCTL and GUSBCFG registers to override + * mode and sessions. It is the case if cable is plugged at boot. + */ + if (!hsotg->ll_hw_enabled && hsotg->clk) { + int ret = clk_prepare_enable(hsotg->clk); + + if (ret) + return ret; + } + spin_lock_irqsave(&hsotg->lock, flags); if (role == USB_ROLE_HOST) { @@ -110,6 +125,9 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) /* This will raise a Connector ID Status Change Interrupt */ dwc2_force_mode(hsotg, role == USB_ROLE_HOST); + if (!hsotg->ll_hw_enabled && hsotg->clk) + clk_disable_unprepare(hsotg->clk); + dev_dbg(hsotg->dev, "%s-session valid\n", role == USB_ROLE_NONE ? "No" : role == USB_ROLE_HOST ? "A" : "B"); |