diff options
author | Amelie Delaunay <amelie.delaunay@st.com> | 2020-09-09 11:35:10 +0200 |
---|---|---|
committer | Felipe Balbi <balbi@kernel.org> | 2020-10-02 12:29:13 +0200 |
commit | 17f934024e84e73cd55dd620a48c1b9e21fac87f (patch) | |
tree | fd59a26241335974abd16ffb20a4459118316476 /drivers/usb/dwc2/platform.c | |
parent | dt-bindings: usb: dwc2: add optional usb-role-switch property (diff) | |
download | linux-17f934024e84e73cd55dd620a48c1b9e21fac87f.tar.xz linux-17f934024e84e73cd55dd620a48c1b9e21fac87f.zip |
usb: dwc2: override PHY input signals with usb role switch support
This patch adds support for usb role switch to dwc2, by using overriding
control of the PHY voltage valid and ID input signals.
iddig signal (ID) can be overridden:
- when setting GUSBCFG_FORCEHOSTMODE, iddig input pin is overridden with 1;
- when setting GUSBCFG_FORCEDEVMODE, iddig input pin is overridden with 0.
avalid/bvalid/vbusvalid signals can be overridden respectively with:
- GOTGCTL_AVALOEN + GOTGCTL_AVALOVAL
- GOTGCTL_BVALOEN + GOTGCTL_BVALOVAL
- GOTGCTL_VBVALEN + GOTGCTL_VBVALOVAL
It is possible to determine valid sessions thanks to usb role switch:
- if USB_ROLE_NONE then !avalid && !bvalid && !vbusvalid
- if USB_ROLE_DEVICE then !avalid && bvalid && vbusvalid
- if USB_ROLE_HOST then avalid && !bvalid && vbusvalid
Acked-by: Minas Harutyunyan <hminas@synopsys.com>
Acked-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
Diffstat (limited to 'drivers/usb/dwc2/platform.c')
-rw-r--r-- | drivers/usb/dwc2/platform.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index c8844aea5607..e2820676beb1 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -323,6 +323,8 @@ static int dwc2_driver_remove(struct platform_device *dev) if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); + dwc2_drd_exit(hsotg); + if (hsotg->params.activate_stm_id_vb_detection) regulator_disable(hsotg->usb33d); @@ -542,10 +544,17 @@ static int dwc2_driver_probe(struct platform_device *dev) dwc2_writel(hsotg, ggpio, GGPIO); } + retval = dwc2_drd_init(hsotg); + if (retval) { + if (retval != -EPROBE_DEFER) + dev_err(hsotg->dev, "failed to initialize dual-role\n"); + goto error_init; + } + if (hsotg->dr_mode != USB_DR_MODE_HOST) { retval = dwc2_gadget_init(hsotg); if (retval) - goto error_init; + goto error_drd; hsotg->gadget_enabled = 1; } @@ -571,7 +580,7 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) { if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); - goto error_init; + goto error_drd; } hsotg->hcd_enabled = 1; } @@ -603,6 +612,9 @@ error_debugfs: dwc2_debugfs_exit(hsotg); if (hsotg->hcd_enabled) dwc2_hcd_remove(hsotg); +error_drd: + dwc2_drd_exit(hsotg); + error_init: if (hsotg->params.activate_stm_id_vb_detection) regulator_disable(hsotg->usb33d); @@ -621,6 +633,8 @@ static int __maybe_unused dwc2_suspend(struct device *dev) if (is_device_mode) dwc2_hsotg_suspend(dwc2); + dwc2_drd_suspend(dwc2); + if (dwc2->params.activate_stm_id_vb_detection) { unsigned long flags; u32 ggpio, gotgctl; @@ -701,6 +715,8 @@ static int __maybe_unused dwc2_resume(struct device *dev) /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ dwc2_force_dr_mode(dwc2); + dwc2_drd_resume(dwc2); + if (dwc2_is_device_mode(dwc2)) ret = dwc2_hsotg_resume(dwc2); |