When dr_mode is "otg" the dwc3 is initially configured in _OTG mode; However in this mode the gadget functionality doesn't work without further configuration. To resolve that on gadget start switch to _DEVICE mode globally and go back to _OTG on stop again.
For this the dwc3_set_mode is renamed to dwc3_core_set_mode to avoid a conflict with the same function exposed by xhci-dwc3 Signed-off-by: Sjoerd Simons <sjo...@collabora.com> --- Changes in v4: - New patch drivers/usb/dwc3/core.c | 10 +++++----- drivers/usb/dwc3/core.h | 1 + drivers/usb/dwc3/gadget.c | 6 ++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4b4fcd8a22e..d22d4c4bb6a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -42,7 +42,7 @@ static LIST_HEAD(dwc3_list); /* -------------------------------------------------------------------------- */ -static void dwc3_set_mode(struct dwc3 *dwc, u32 mode) +void dwc3_core_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -736,7 +736,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + dwc3_core_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dwc->dev, "failed to initialize gadget\n"); @@ -744,7 +744,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + dwc3_core_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { dev_err(dwc->dev, "failed to initialize host\n"); @@ -752,7 +752,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_OTG: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + dwc3_core_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { dev_err(dwc->dev, "failed to initialize host\n"); @@ -810,7 +810,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) * switch back to peripheral mode * This enables the phy to enter idle and then, if enabled, suspend. */ - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + dwc3_core_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); dwc3_gadget_run(dwc); } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4162a682298..1e7eda89a34 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1057,6 +1057,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); void dwc3_of_parse(struct dwc3 *dwc); int dwc3_init(struct dwc3 *dwc); void dwc3_remove(struct dwc3 *dwc); +void dwc3_core_set_mode(struct dwc3 *dwc, u32 mode); static inline int dwc3_host_init(struct dwc3 *dwc) { return 0; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 406d36ceafe..69d9fe40e2f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1468,6 +1468,9 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc->gadget_driver = driver; + if (dwc->dr_mode == DWC3_GCTL_PRTCAP_OTG) + dwc3_core_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); @@ -1559,6 +1562,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g) __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); + if (dwc->dr_mode == DWC3_GCTL_PRTCAP_OTG) + dwc3_core_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + dwc->gadget_driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); -- 2.43.0