15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
27679defcSLee Jones /*
39840354fSRoger Quadros * drd.c - DesignWare USB3 DRD Controller Dual-role support
49840354fSRoger Quadros *
510623b87SAlexander A. Klimov * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com
69840354fSRoger Quadros *
79840354fSRoger Quadros * Authors: Roger Quadros <rogerq@ti.com>
89840354fSRoger Quadros */
99840354fSRoger Quadros
109840354fSRoger Quadros #include <linux/extcon.h>
11a102f07eSAlexander Stein #include <linux/of_platform.h>
12f09cc79bSRoger Quadros #include <linux/platform_device.h>
1385383756SAndy Shevchenko #include <linux/property.h>
149840354fSRoger Quadros
159840354fSRoger Quadros #include "debug.h"
169840354fSRoger Quadros #include "core.h"
179840354fSRoger Quadros #include "gadget.h"
189840354fSRoger Quadros
dwc3_otg_disable_events(struct dwc3 * dwc,u32 disable_mask)19f09cc79bSRoger Quadros static void dwc3_otg_disable_events(struct dwc3 *dwc, u32 disable_mask)
20f09cc79bSRoger Quadros {
21f09cc79bSRoger Quadros u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
22f09cc79bSRoger Quadros
23f09cc79bSRoger Quadros reg &= ~(disable_mask);
24f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
25f09cc79bSRoger Quadros }
26f09cc79bSRoger Quadros
dwc3_otg_enable_events(struct dwc3 * dwc,u32 enable_mask)27f09cc79bSRoger Quadros static void dwc3_otg_enable_events(struct dwc3 *dwc, u32 enable_mask)
28f09cc79bSRoger Quadros {
29f09cc79bSRoger Quadros u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
30f09cc79bSRoger Quadros
31f09cc79bSRoger Quadros reg |= (enable_mask);
32f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
33f09cc79bSRoger Quadros }
34f09cc79bSRoger Quadros
dwc3_otg_clear_events(struct dwc3 * dwc)35f09cc79bSRoger Quadros static void dwc3_otg_clear_events(struct dwc3 *dwc)
36f09cc79bSRoger Quadros {
37f09cc79bSRoger Quadros u32 reg = dwc3_readl(dwc->regs, DWC3_OEVT);
38f09cc79bSRoger Quadros
39f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
40f09cc79bSRoger Quadros }
41f09cc79bSRoger Quadros
42f09cc79bSRoger Quadros #define DWC3_OTG_ALL_EVENTS (DWC3_OEVTEN_XHCIRUNSTPSETEN | \
43f09cc79bSRoger Quadros DWC3_OEVTEN_DEVRUNSTPSETEN | DWC3_OEVTEN_HIBENTRYEN | \
44f09cc79bSRoger Quadros DWC3_OEVTEN_CONIDSTSCHNGEN | DWC3_OEVTEN_HRRCONFNOTIFEN | \
45f09cc79bSRoger Quadros DWC3_OEVTEN_HRRINITNOTIFEN | DWC3_OEVTEN_ADEVIDLEEN | \
46f09cc79bSRoger Quadros DWC3_OEVTEN_ADEVBHOSTENDEN | DWC3_OEVTEN_ADEVHOSTEN | \
47f09cc79bSRoger Quadros DWC3_OEVTEN_ADEVHNPCHNGEN | DWC3_OEVTEN_ADEVSRPDETEN | \
48f09cc79bSRoger Quadros DWC3_OEVTEN_ADEVSESSENDDETEN | DWC3_OEVTEN_BDEVBHOSTENDEN | \
49f09cc79bSRoger Quadros DWC3_OEVTEN_BDEVHNPCHNGEN | DWC3_OEVTEN_BDEVSESSVLDDETEN | \
50f09cc79bSRoger Quadros DWC3_OEVTEN_BDEVVBUSCHNGEN)
51f09cc79bSRoger Quadros
dwc3_otg_thread_irq(int irq,void * _dwc)52f09cc79bSRoger Quadros static irqreturn_t dwc3_otg_thread_irq(int irq, void *_dwc)
53f09cc79bSRoger Quadros {
54f09cc79bSRoger Quadros struct dwc3 *dwc = _dwc;
55f09cc79bSRoger Quadros
56f09cc79bSRoger Quadros spin_lock(&dwc->lock);
57f09cc79bSRoger Quadros if (dwc->otg_restart_host) {
58f09cc79bSRoger Quadros dwc3_otg_host_init(dwc);
59c685114fSJason Yan dwc->otg_restart_host = false;
60f09cc79bSRoger Quadros }
61f09cc79bSRoger Quadros
62f09cc79bSRoger Quadros spin_unlock(&dwc->lock);
63f09cc79bSRoger Quadros
64f09cc79bSRoger Quadros dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
65f09cc79bSRoger Quadros
66f09cc79bSRoger Quadros return IRQ_HANDLED;
67f09cc79bSRoger Quadros }
68f09cc79bSRoger Quadros
dwc3_otg_irq(int irq,void * _dwc)69f09cc79bSRoger Quadros static irqreturn_t dwc3_otg_irq(int irq, void *_dwc)
70f09cc79bSRoger Quadros {
71f09cc79bSRoger Quadros u32 reg;
72f09cc79bSRoger Quadros struct dwc3 *dwc = _dwc;
73f09cc79bSRoger Quadros irqreturn_t ret = IRQ_NONE;
74f09cc79bSRoger Quadros
75f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OEVT);
76f09cc79bSRoger Quadros if (reg) {
77f09cc79bSRoger Quadros /* ignore non OTG events, we can't disable them in OEVTEN */
78f09cc79bSRoger Quadros if (!(reg & DWC3_OTG_ALL_EVENTS)) {
79f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OEVT, reg);
80f09cc79bSRoger Quadros return IRQ_NONE;
81f09cc79bSRoger Quadros }
82f09cc79bSRoger Quadros
83f09cc79bSRoger Quadros if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST &&
84f09cc79bSRoger Quadros !(reg & DWC3_OEVT_DEVICEMODE))
85c685114fSJason Yan dwc->otg_restart_host = true;
86f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OEVT, reg);
87f09cc79bSRoger Quadros ret = IRQ_WAKE_THREAD;
88f09cc79bSRoger Quadros }
89f09cc79bSRoger Quadros
90f09cc79bSRoger Quadros return ret;
91f09cc79bSRoger Quadros }
92f09cc79bSRoger Quadros
dwc3_otgregs_init(struct dwc3 * dwc)93f09cc79bSRoger Quadros static void dwc3_otgregs_init(struct dwc3 *dwc)
94f09cc79bSRoger Quadros {
95f09cc79bSRoger Quadros u32 reg;
96f09cc79bSRoger Quadros
97f09cc79bSRoger Quadros /*
98f09cc79bSRoger Quadros * Prevent host/device reset from resetting OTG core.
99f09cc79bSRoger Quadros * If we don't do this then xhci_reset (USBCMD.HCRST) will reset
100f09cc79bSRoger Quadros * the signal outputs sent to the PHY, the OTG FSM logic of the
101f09cc79bSRoger Quadros * core and also the resets to the VBUS filters inside the core.
102f09cc79bSRoger Quadros */
103f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCFG);
104f09cc79bSRoger Quadros reg |= DWC3_OCFG_SFTRSTMASK;
105f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCFG, reg);
106f09cc79bSRoger Quadros
107f09cc79bSRoger Quadros /* Disable hibernation for simplicity */
108f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_GCTL);
109f09cc79bSRoger Quadros reg &= ~DWC3_GCTL_GBLHIBERNATIONEN;
110f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_GCTL, reg);
111f09cc79bSRoger Quadros
112f09cc79bSRoger Quadros /*
113f09cc79bSRoger Quadros * Initialize OTG registers as per
114f09cc79bSRoger Quadros * Figure 11-4 OTG Driver Overall Programming Flow
115f09cc79bSRoger Quadros */
116f09cc79bSRoger Quadros /* OCFG.SRPCap = 0, OCFG.HNPCap = 0 */
117f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCFG);
118f09cc79bSRoger Quadros reg &= ~(DWC3_OCFG_SRPCAP | DWC3_OCFG_HNPCAP);
119f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCFG, reg);
120f09cc79bSRoger Quadros /* OEVT = FFFF */
121f09cc79bSRoger Quadros dwc3_otg_clear_events(dwc);
122f09cc79bSRoger Quadros /* OEVTEN = 0 */
123f09cc79bSRoger Quadros dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
124f09cc79bSRoger Quadros /* OEVTEN.ConIDStsChngEn = 1. Instead we enable all events */
125f09cc79bSRoger Quadros dwc3_otg_enable_events(dwc, DWC3_OTG_ALL_EVENTS);
126f09cc79bSRoger Quadros /*
127f09cc79bSRoger Quadros * OCTL.PeriMode = 1, OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0,
128f09cc79bSRoger Quadros * OCTL.HNPReq = 0
129f09cc79bSRoger Quadros */
130f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCTL);
131f09cc79bSRoger Quadros reg |= DWC3_OCTL_PERIMODE;
132f09cc79bSRoger Quadros reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN |
133f09cc79bSRoger Quadros DWC3_OCTL_HNPREQ);
134f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCTL, reg);
135f09cc79bSRoger Quadros }
136f09cc79bSRoger Quadros
dwc3_otg_get_irq(struct dwc3 * dwc)137f09cc79bSRoger Quadros static int dwc3_otg_get_irq(struct dwc3 *dwc)
138f09cc79bSRoger Quadros {
139f09cc79bSRoger Quadros struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
140f09cc79bSRoger Quadros int irq;
141f09cc79bSRoger Quadros
142f146b40bSHans de Goede irq = platform_get_irq_byname_optional(dwc3_pdev, "otg");
143f09cc79bSRoger Quadros if (irq > 0)
144f09cc79bSRoger Quadros goto out;
145f09cc79bSRoger Quadros
146f09cc79bSRoger Quadros if (irq == -EPROBE_DEFER)
147f09cc79bSRoger Quadros goto out;
148f09cc79bSRoger Quadros
149f146b40bSHans de Goede irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
150f09cc79bSRoger Quadros if (irq > 0)
151f09cc79bSRoger Quadros goto out;
152f09cc79bSRoger Quadros
153f09cc79bSRoger Quadros if (irq == -EPROBE_DEFER)
154f09cc79bSRoger Quadros goto out;
155f09cc79bSRoger Quadros
156f09cc79bSRoger Quadros irq = platform_get_irq(dwc3_pdev, 0);
157f09cc79bSRoger Quadros if (irq > 0)
158f09cc79bSRoger Quadros goto out;
159f09cc79bSRoger Quadros
160f09cc79bSRoger Quadros if (!irq)
161f09cc79bSRoger Quadros irq = -EINVAL;
162f09cc79bSRoger Quadros
163f09cc79bSRoger Quadros out:
164f09cc79bSRoger Quadros return irq;
165f09cc79bSRoger Quadros }
166f09cc79bSRoger Quadros
dwc3_otg_init(struct dwc3 * dwc)167f09cc79bSRoger Quadros void dwc3_otg_init(struct dwc3 *dwc)
168f09cc79bSRoger Quadros {
169f09cc79bSRoger Quadros u32 reg;
170f09cc79bSRoger Quadros
171f09cc79bSRoger Quadros /*
172f09cc79bSRoger Quadros * As per Figure 11-4 OTG Driver Overall Programming Flow,
173f09cc79bSRoger Quadros * block "Initialize GCTL for OTG operation".
174f09cc79bSRoger Quadros */
175f09cc79bSRoger Quadros /* GCTL.PrtCapDir=2'b11 */
176*13f9b888SThinh Nguyen dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
177f09cc79bSRoger Quadros /* GUSB2PHYCFG0.SusPHY=0 */
178f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
179f09cc79bSRoger Quadros reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
180f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
181f09cc79bSRoger Quadros
182f09cc79bSRoger Quadros /* Initialize OTG registers */
183f09cc79bSRoger Quadros dwc3_otgregs_init(dwc);
184f09cc79bSRoger Quadros }
185f09cc79bSRoger Quadros
dwc3_otg_exit(struct dwc3 * dwc)186f09cc79bSRoger Quadros void dwc3_otg_exit(struct dwc3 *dwc)
187f09cc79bSRoger Quadros {
188f09cc79bSRoger Quadros /* disable all OTG IRQs */
189f09cc79bSRoger Quadros dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
190f09cc79bSRoger Quadros /* clear all events */
191f09cc79bSRoger Quadros dwc3_otg_clear_events(dwc);
192f09cc79bSRoger Quadros }
193f09cc79bSRoger Quadros
194f09cc79bSRoger Quadros /* should be called before Host controller driver is started */
dwc3_otg_host_init(struct dwc3 * dwc)195f09cc79bSRoger Quadros void dwc3_otg_host_init(struct dwc3 *dwc)
196f09cc79bSRoger Quadros {
197f09cc79bSRoger Quadros u32 reg;
198f09cc79bSRoger Quadros
199f09cc79bSRoger Quadros /* As per Figure 11-10 A-Device Flow Diagram */
200f09cc79bSRoger Quadros /* OCFG.HNPCap = 0, OCFG.SRPCap = 0. Already 0 */
201f09cc79bSRoger Quadros
202f09cc79bSRoger Quadros /*
203f09cc79bSRoger Quadros * OCTL.PeriMode=0, OCTL.TermSelDLPulse = 0,
204f09cc79bSRoger Quadros * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
205f09cc79bSRoger Quadros */
206f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCTL);
207f09cc79bSRoger Quadros reg &= ~(DWC3_OCTL_PERIMODE | DWC3_OCTL_TERMSELIDPULSE |
208f09cc79bSRoger Quadros DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
209f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCTL, reg);
210f09cc79bSRoger Quadros
211f09cc79bSRoger Quadros /*
212f09cc79bSRoger Quadros * OCFG.DisPrtPwrCutoff = 0/1
213f09cc79bSRoger Quadros */
214f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCFG);
215f09cc79bSRoger Quadros reg &= ~DWC3_OCFG_DISPWRCUTTOFF;
216f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCFG, reg);
217f09cc79bSRoger Quadros
218f09cc79bSRoger Quadros /*
219f09cc79bSRoger Quadros * OCFG.SRPCap = 1, OCFG.HNPCap = GHWPARAMS6.HNP_CAP
220f09cc79bSRoger Quadros * We don't want SRP/HNP for simple dual-role so leave
221f09cc79bSRoger Quadros * these disabled.
222f09cc79bSRoger Quadros */
223f09cc79bSRoger Quadros
224f09cc79bSRoger Quadros /*
225f09cc79bSRoger Quadros * OEVTEN.OTGADevHostEvntEn = 1
226f09cc79bSRoger Quadros * OEVTEN.OTGADevSessEndDetEvntEn = 1
227f09cc79bSRoger Quadros * We don't want HNP/role-swap so leave these disabled.
228f09cc79bSRoger Quadros */
229f09cc79bSRoger Quadros
230f09cc79bSRoger Quadros /* GUSB2PHYCFG.ULPIAutoRes = 1/0, GUSB2PHYCFG.SusPHY = 1 */
231f09cc79bSRoger Quadros if (!dwc->dis_u2_susphy_quirk) {
232f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
233f09cc79bSRoger Quadros reg |= DWC3_GUSB2PHYCFG_SUSPHY;
234f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
235f09cc79bSRoger Quadros }
236f09cc79bSRoger Quadros
237f09cc79bSRoger Quadros /* Set Port Power to enable VBUS: OCTL.PrtPwrCtl = 1 */
238f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCTL);
239f09cc79bSRoger Quadros reg |= DWC3_OCTL_PRTPWRCTL;
240f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCTL, reg);
241f09cc79bSRoger Quadros }
242f09cc79bSRoger Quadros
243f09cc79bSRoger Quadros /* should be called after Host controller driver is stopped */
dwc3_otg_host_exit(struct dwc3 * dwc)244f09cc79bSRoger Quadros static void dwc3_otg_host_exit(struct dwc3 *dwc)
245f09cc79bSRoger Quadros {
246f09cc79bSRoger Quadros u32 reg;
247f09cc79bSRoger Quadros
248f09cc79bSRoger Quadros /*
249f09cc79bSRoger Quadros * Exit from A-device flow as per
250f09cc79bSRoger Quadros * Figure 11-4 OTG Driver Overall Programming Flow
251f09cc79bSRoger Quadros */
252f09cc79bSRoger Quadros
253f09cc79bSRoger Quadros /*
254f09cc79bSRoger Quadros * OEVTEN.OTGADevBHostEndEvntEn=0, OEVTEN.OTGADevHNPChngEvntEn=0
255f09cc79bSRoger Quadros * OEVTEN.OTGADevSessEndDetEvntEn=0,
256f09cc79bSRoger Quadros * OEVTEN.OTGADevHostEvntEn = 0
257f09cc79bSRoger Quadros * But we don't disable any OTG events
258f09cc79bSRoger Quadros */
259f09cc79bSRoger Quadros
260f09cc79bSRoger Quadros /* OCTL.HstSetHNPEn = 0, OCTL.PrtPwrCtl=0 */
261f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCTL);
262f09cc79bSRoger Quadros reg &= ~(DWC3_OCTL_HSTSETHNPEN | DWC3_OCTL_PRTPWRCTL);
263f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCTL, reg);
264f09cc79bSRoger Quadros }
265f09cc79bSRoger Quadros
266f09cc79bSRoger Quadros /* should be called before the gadget controller driver is started */
dwc3_otg_device_init(struct dwc3 * dwc)267f09cc79bSRoger Quadros static void dwc3_otg_device_init(struct dwc3 *dwc)
268f09cc79bSRoger Quadros {
269f09cc79bSRoger Quadros u32 reg;
270f09cc79bSRoger Quadros
271f09cc79bSRoger Quadros /* As per Figure 11-20 B-Device Flow Diagram */
272f09cc79bSRoger Quadros
273f09cc79bSRoger Quadros /*
274f09cc79bSRoger Quadros * OCFG.HNPCap = GHWPARAMS6.HNP_CAP, OCFG.SRPCap = 1
275f09cc79bSRoger Quadros * but we keep them 0 for simple dual-role operation.
276f09cc79bSRoger Quadros */
277f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCFG);
278f09cc79bSRoger Quadros /* OCFG.OTGSftRstMsk = 0/1 */
279f09cc79bSRoger Quadros reg |= DWC3_OCFG_SFTRSTMASK;
280f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCFG, reg);
281f09cc79bSRoger Quadros /*
282f09cc79bSRoger Quadros * OCTL.PeriMode = 1
283f09cc79bSRoger Quadros * OCTL.TermSelDLPulse = 0/1, OCTL.HNPReq = 0
284f09cc79bSRoger Quadros * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
285f09cc79bSRoger Quadros */
286f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCTL);
287f09cc79bSRoger Quadros reg |= DWC3_OCTL_PERIMODE;
288f09cc79bSRoger Quadros reg &= ~(DWC3_OCTL_TERMSELIDPULSE | DWC3_OCTL_HNPREQ |
289f09cc79bSRoger Quadros DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
290f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCTL, reg);
291f09cc79bSRoger Quadros /* OEVTEN.OTGBDevSesVldDetEvntEn = 1 */
292f09cc79bSRoger Quadros dwc3_otg_enable_events(dwc, DWC3_OEVTEN_BDEVSESSVLDDETEN);
293f09cc79bSRoger Quadros /* GUSB2PHYCFG.ULPIAutoRes = 0, GUSB2PHYCFG0.SusPHY = 1 */
294f09cc79bSRoger Quadros if (!dwc->dis_u2_susphy_quirk) {
295f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
296f09cc79bSRoger Quadros reg |= DWC3_GUSB2PHYCFG_SUSPHY;
297f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
298f09cc79bSRoger Quadros }
299f09cc79bSRoger Quadros /* GCTL.GblHibernationEn = 0. Already 0. */
300f09cc79bSRoger Quadros }
301f09cc79bSRoger Quadros
302f09cc79bSRoger Quadros /* should be called after the gadget controller driver is stopped */
dwc3_otg_device_exit(struct dwc3 * dwc)303f09cc79bSRoger Quadros static void dwc3_otg_device_exit(struct dwc3 *dwc)
304f09cc79bSRoger Quadros {
305f09cc79bSRoger Quadros u32 reg;
306f09cc79bSRoger Quadros
307f09cc79bSRoger Quadros /*
308f09cc79bSRoger Quadros * Exit from B-device flow as per
309f09cc79bSRoger Quadros * Figure 11-4 OTG Driver Overall Programming Flow
310f09cc79bSRoger Quadros */
311f09cc79bSRoger Quadros
312f09cc79bSRoger Quadros /*
313f09cc79bSRoger Quadros * OEVTEN.OTGBDevHNPChngEvntEn = 0
314f09cc79bSRoger Quadros * OEVTEN.OTGBDevVBusChngEvntEn = 0
315f09cc79bSRoger Quadros * OEVTEN.OTGBDevBHostEndEvntEn = 0
316f09cc79bSRoger Quadros */
317f09cc79bSRoger Quadros dwc3_otg_disable_events(dwc, DWC3_OEVTEN_BDEVHNPCHNGEN |
318f09cc79bSRoger Quadros DWC3_OEVTEN_BDEVVBUSCHNGEN |
319f09cc79bSRoger Quadros DWC3_OEVTEN_BDEVBHOSTENDEN);
320f09cc79bSRoger Quadros
321f09cc79bSRoger Quadros /* OCTL.DevSetHNPEn = 0, OCTL.HNPReq = 0, OCTL.PeriMode=1 */
322f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OCTL);
323f09cc79bSRoger Quadros reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HNPREQ);
324f09cc79bSRoger Quadros reg |= DWC3_OCTL_PERIMODE;
325f09cc79bSRoger Quadros dwc3_writel(dwc->regs, DWC3_OCTL, reg);
326f09cc79bSRoger Quadros }
327f09cc79bSRoger Quadros
dwc3_otg_update(struct dwc3 * dwc,bool ignore_idstatus)328f09cc79bSRoger Quadros void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
329f09cc79bSRoger Quadros {
330f09cc79bSRoger Quadros int ret;
331f09cc79bSRoger Quadros u32 reg;
332f09cc79bSRoger Quadros int id;
333f09cc79bSRoger Quadros unsigned long flags;
334f09cc79bSRoger Quadros
335f09cc79bSRoger Quadros if (dwc->dr_mode != USB_DR_MODE_OTG)
336f09cc79bSRoger Quadros return;
337f09cc79bSRoger Quadros
338f09cc79bSRoger Quadros /* don't do anything if debug user changed role to not OTG */
339f09cc79bSRoger Quadros if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG)
340f09cc79bSRoger Quadros return;
341f09cc79bSRoger Quadros
342f09cc79bSRoger Quadros if (!ignore_idstatus) {
343f09cc79bSRoger Quadros reg = dwc3_readl(dwc->regs, DWC3_OSTS);
344f09cc79bSRoger Quadros id = !!(reg & DWC3_OSTS_CONIDSTS);
345f09cc79bSRoger Quadros
346f09cc79bSRoger Quadros dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE :
347f09cc79bSRoger Quadros DWC3_OTG_ROLE_HOST;
348f09cc79bSRoger Quadros }
349f09cc79bSRoger Quadros
350f09cc79bSRoger Quadros if (dwc->desired_otg_role == dwc->current_otg_role)
351f09cc79bSRoger Quadros return;
352f09cc79bSRoger Quadros
353f09cc79bSRoger Quadros switch (dwc->current_otg_role) {
354f09cc79bSRoger Quadros case DWC3_OTG_ROLE_HOST:
355f09cc79bSRoger Quadros dwc3_host_exit(dwc);
356f09cc79bSRoger Quadros spin_lock_irqsave(&dwc->lock, flags);
357f09cc79bSRoger Quadros dwc3_otg_host_exit(dwc);
358f09cc79bSRoger Quadros spin_unlock_irqrestore(&dwc->lock, flags);
359f09cc79bSRoger Quadros break;
360f09cc79bSRoger Quadros case DWC3_OTG_ROLE_DEVICE:
361f09cc79bSRoger Quadros dwc3_gadget_exit(dwc);
362f09cc79bSRoger Quadros spin_lock_irqsave(&dwc->lock, flags);
363f09cc79bSRoger Quadros dwc3_event_buffers_cleanup(dwc);
364f09cc79bSRoger Quadros dwc3_otg_device_exit(dwc);
365f09cc79bSRoger Quadros spin_unlock_irqrestore(&dwc->lock, flags);
366f09cc79bSRoger Quadros break;
367f09cc79bSRoger Quadros default:
368f09cc79bSRoger Quadros break;
369f09cc79bSRoger Quadros }
370f09cc79bSRoger Quadros
371f09cc79bSRoger Quadros spin_lock_irqsave(&dwc->lock, flags);
372f09cc79bSRoger Quadros
373f09cc79bSRoger Quadros dwc->current_otg_role = dwc->desired_otg_role;
374f09cc79bSRoger Quadros
375f09cc79bSRoger Quadros spin_unlock_irqrestore(&dwc->lock, flags);
376f09cc79bSRoger Quadros
377f09cc79bSRoger Quadros switch (dwc->desired_otg_role) {
378f09cc79bSRoger Quadros case DWC3_OTG_ROLE_HOST:
379f09cc79bSRoger Quadros spin_lock_irqsave(&dwc->lock, flags);
380f09cc79bSRoger Quadros dwc3_otgregs_init(dwc);
381f09cc79bSRoger Quadros dwc3_otg_host_init(dwc);
382f09cc79bSRoger Quadros spin_unlock_irqrestore(&dwc->lock, flags);
383f09cc79bSRoger Quadros ret = dwc3_host_init(dwc);
384f09cc79bSRoger Quadros if (ret) {
385f09cc79bSRoger Quadros dev_err(dwc->dev, "failed to initialize host\n");
386f09cc79bSRoger Quadros } else {
387f09cc79bSRoger Quadros if (dwc->usb2_phy)
388f09cc79bSRoger Quadros otg_set_vbus(dwc->usb2_phy->otg, true);
389f09cc79bSRoger Quadros if (dwc->usb2_generic_phy)
390f09cc79bSRoger Quadros phy_set_mode(dwc->usb2_generic_phy,
391f09cc79bSRoger Quadros PHY_MODE_USB_HOST);
392f09cc79bSRoger Quadros }
393f09cc79bSRoger Quadros break;
394f09cc79bSRoger Quadros case DWC3_OTG_ROLE_DEVICE:
395f09cc79bSRoger Quadros spin_lock_irqsave(&dwc->lock, flags);
396f09cc79bSRoger Quadros dwc3_otgregs_init(dwc);
397f09cc79bSRoger Quadros dwc3_otg_device_init(dwc);
398f09cc79bSRoger Quadros dwc3_event_buffers_setup(dwc);
399f09cc79bSRoger Quadros spin_unlock_irqrestore(&dwc->lock, flags);
400f09cc79bSRoger Quadros
401f09cc79bSRoger Quadros if (dwc->usb2_phy)
402f09cc79bSRoger Quadros otg_set_vbus(dwc->usb2_phy->otg, false);
403f09cc79bSRoger Quadros if (dwc->usb2_generic_phy)
404f09cc79bSRoger Quadros phy_set_mode(dwc->usb2_generic_phy,
405f09cc79bSRoger Quadros PHY_MODE_USB_DEVICE);
406f09cc79bSRoger Quadros ret = dwc3_gadget_init(dwc);
407f09cc79bSRoger Quadros if (ret)
408f09cc79bSRoger Quadros dev_err(dwc->dev, "failed to initialize peripheral\n");
409f09cc79bSRoger Quadros break;
410f09cc79bSRoger Quadros default:
411f09cc79bSRoger Quadros break;
412f09cc79bSRoger Quadros }
413f09cc79bSRoger Quadros }
414f09cc79bSRoger Quadros
dwc3_drd_update(struct dwc3 * dwc)4159840354fSRoger Quadros static void dwc3_drd_update(struct dwc3 *dwc)
4169840354fSRoger Quadros {
4179840354fSRoger Quadros int id;
4189840354fSRoger Quadros
419f09cc79bSRoger Quadros if (dwc->edev) {
4209840354fSRoger Quadros id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
4219840354fSRoger Quadros if (id < 0)
4229840354fSRoger Quadros id = 0;
4239840354fSRoger Quadros dwc3_set_mode(dwc, id ?
4249840354fSRoger Quadros DWC3_GCTL_PRTCAP_HOST :
4259840354fSRoger Quadros DWC3_GCTL_PRTCAP_DEVICE);
4269840354fSRoger Quadros }
427f09cc79bSRoger Quadros }
4289840354fSRoger Quadros
dwc3_drd_notifier(struct notifier_block * nb,unsigned long event,void * ptr)4299840354fSRoger Quadros static int dwc3_drd_notifier(struct notifier_block *nb,
4309840354fSRoger Quadros unsigned long event, void *ptr)
4319840354fSRoger Quadros {
4329840354fSRoger Quadros struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
4339840354fSRoger Quadros
4349840354fSRoger Quadros dwc3_set_mode(dwc, event ?
4359840354fSRoger Quadros DWC3_GCTL_PRTCAP_HOST :
4369840354fSRoger Quadros DWC3_GCTL_PRTCAP_DEVICE);
4379840354fSRoger Quadros
4389840354fSRoger Quadros return NOTIFY_DONE;
4399840354fSRoger Quadros }
4409840354fSRoger Quadros
4418a0a1379SYu Chen #if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
4428a0a1379SYu Chen #define ROLE_SWITCH 1
dwc3_usb_role_switch_set(struct usb_role_switch * sw,enum usb_role role)4430339f7fbSStephen Rothwell static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
4440339f7fbSStephen Rothwell enum usb_role role)
4458a0a1379SYu Chen {
4460339f7fbSStephen Rothwell struct dwc3 *dwc = usb_role_switch_get_drvdata(sw);
4478a0a1379SYu Chen u32 mode;
4488a0a1379SYu Chen
4498a0a1379SYu Chen switch (role) {
4508a0a1379SYu Chen case USB_ROLE_HOST:
4518a0a1379SYu Chen mode = DWC3_GCTL_PRTCAP_HOST;
4528a0a1379SYu Chen break;
4538a0a1379SYu Chen case USB_ROLE_DEVICE:
4548a0a1379SYu Chen mode = DWC3_GCTL_PRTCAP_DEVICE;
4558a0a1379SYu Chen break;
4568a0a1379SYu Chen default:
45798ed256aSJohn Stultz if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
45898ed256aSJohn Stultz mode = DWC3_GCTL_PRTCAP_HOST;
45998ed256aSJohn Stultz else
4608a0a1379SYu Chen mode = DWC3_GCTL_PRTCAP_DEVICE;
4618a0a1379SYu Chen break;
4628a0a1379SYu Chen }
4638a0a1379SYu Chen
4648a0a1379SYu Chen dwc3_set_mode(dwc, mode);
4658a0a1379SYu Chen return 0;
4668a0a1379SYu Chen }
4678a0a1379SYu Chen
dwc3_usb_role_switch_get(struct usb_role_switch * sw)4680339f7fbSStephen Rothwell static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
4698a0a1379SYu Chen {
4700339f7fbSStephen Rothwell struct dwc3 *dwc = usb_role_switch_get_drvdata(sw);
4718a0a1379SYu Chen unsigned long flags;
4728a0a1379SYu Chen enum usb_role role;
4738a0a1379SYu Chen
4748a0a1379SYu Chen spin_lock_irqsave(&dwc->lock, flags);
4758a0a1379SYu Chen switch (dwc->current_dr_role) {
4768a0a1379SYu Chen case DWC3_GCTL_PRTCAP_HOST:
4778a0a1379SYu Chen role = USB_ROLE_HOST;
4788a0a1379SYu Chen break;
4798a0a1379SYu Chen case DWC3_GCTL_PRTCAP_DEVICE:
4808a0a1379SYu Chen role = USB_ROLE_DEVICE;
4818a0a1379SYu Chen break;
4828a0a1379SYu Chen case DWC3_GCTL_PRTCAP_OTG:
4838a0a1379SYu Chen role = dwc->current_otg_role;
4848a0a1379SYu Chen break;
4858a0a1379SYu Chen default:
48698ed256aSJohn Stultz if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
48798ed256aSJohn Stultz role = USB_ROLE_HOST;
48898ed256aSJohn Stultz else
4898a0a1379SYu Chen role = USB_ROLE_DEVICE;
4908a0a1379SYu Chen break;
4918a0a1379SYu Chen }
4928a0a1379SYu Chen spin_unlock_irqrestore(&dwc->lock, flags);
4938a0a1379SYu Chen return role;
4948a0a1379SYu Chen }
4958a0a1379SYu Chen
dwc3_setup_role_switch(struct dwc3 * dwc)4968a0a1379SYu Chen static int dwc3_setup_role_switch(struct dwc3 *dwc)
4978a0a1379SYu Chen {
4988a0a1379SYu Chen struct usb_role_switch_desc dwc3_role_switch = {NULL};
49998ed256aSJohn Stultz u32 mode;
50098ed256aSJohn Stultz
50126f94fe8SChunfeng Yun dwc->role_switch_default_mode = usb_get_role_switch_default_mode(dwc->dev);
50226f94fe8SChunfeng Yun if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) {
50398ed256aSJohn Stultz mode = DWC3_GCTL_PRTCAP_HOST;
50498ed256aSJohn Stultz } else {
50598ed256aSJohn Stultz dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL;
50698ed256aSJohn Stultz mode = DWC3_GCTL_PRTCAP_DEVICE;
50798ed256aSJohn Stultz }
5087985c3d7SAlexander Stein dwc3_set_mode(dwc, mode);
5098a0a1379SYu Chen
5108a0a1379SYu Chen dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
5118a0a1379SYu Chen dwc3_role_switch.set = dwc3_usb_role_switch_set;
5128a0a1379SYu Chen dwc3_role_switch.get = dwc3_usb_role_switch_get;
5130339f7fbSStephen Rothwell dwc3_role_switch.driver_data = dwc;
5148a0a1379SYu Chen dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch);
5158a0a1379SYu Chen if (IS_ERR(dwc->role_sw))
5168a0a1379SYu Chen return PTR_ERR(dwc->role_sw);
5178a0a1379SYu Chen
518e51879d8SThinh Nguyen if (dwc->dev->of_node) {
519a102f07eSAlexander Stein /* populate connector entry */
520a102f07eSAlexander Stein int ret = devm_of_platform_populate(dwc->dev);
521a102f07eSAlexander Stein
522a102f07eSAlexander Stein if (ret) {
523a102f07eSAlexander Stein usb_role_switch_unregister(dwc->role_sw);
524a102f07eSAlexander Stein dwc->role_sw = NULL;
525a102f07eSAlexander Stein dev_err(dwc->dev, "DWC3 platform devices creation failed: %i\n", ret);
526a102f07eSAlexander Stein return ret;
527a102f07eSAlexander Stein }
528a102f07eSAlexander Stein }
529a102f07eSAlexander Stein
5308a0a1379SYu Chen return 0;
5318a0a1379SYu Chen }
5328a0a1379SYu Chen #else
5338a0a1379SYu Chen #define ROLE_SWITCH 0
5348a0a1379SYu Chen #define dwc3_setup_role_switch(x) 0
5358a0a1379SYu Chen #endif
5368a0a1379SYu Chen
dwc3_drd_init(struct dwc3 * dwc)5379840354fSRoger Quadros int dwc3_drd_init(struct dwc3 *dwc)
5389840354fSRoger Quadros {
539f09cc79bSRoger Quadros int ret, irq;
5409840354fSRoger Quadros
5418a0a1379SYu Chen if (ROLE_SWITCH &&
542ab7aa286SSven Peter device_property_read_bool(dwc->dev, "usb-role-switch"))
543ab7aa286SSven Peter return dwc3_setup_role_switch(dwc);
544ab7aa286SSven Peter
545ab7aa286SSven Peter if (dwc->edev) {
5469840354fSRoger Quadros dwc->edev_nb.notifier_call = dwc3_drd_notifier;
5479840354fSRoger Quadros ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
5489840354fSRoger Quadros &dwc->edev_nb);
5499840354fSRoger Quadros if (ret < 0) {
5509840354fSRoger Quadros dev_err(dwc->dev, "couldn't register cable notifier\n");
5519840354fSRoger Quadros return ret;
5529840354fSRoger Quadros }
5539840354fSRoger Quadros
5549840354fSRoger Quadros dwc3_drd_update(dwc);
555f09cc79bSRoger Quadros } else {
556*13f9b888SThinh Nguyen dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
557f09cc79bSRoger Quadros
558f09cc79bSRoger Quadros /* use OTG block to get ID event */
559f09cc79bSRoger Quadros irq = dwc3_otg_get_irq(dwc);
560f09cc79bSRoger Quadros if (irq < 0)
561f09cc79bSRoger Quadros return irq;
562f09cc79bSRoger Quadros
563f09cc79bSRoger Quadros dwc->otg_irq = irq;
564f09cc79bSRoger Quadros
565f09cc79bSRoger Quadros /* disable all OTG IRQs */
566f09cc79bSRoger Quadros dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS);
567f09cc79bSRoger Quadros /* clear all events */
568f09cc79bSRoger Quadros dwc3_otg_clear_events(dwc);
569f09cc79bSRoger Quadros
570f09cc79bSRoger Quadros ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq,
571f09cc79bSRoger Quadros dwc3_otg_thread_irq,
572f09cc79bSRoger Quadros IRQF_SHARED, "dwc3-otg", dwc);
573f09cc79bSRoger Quadros if (ret) {
574f09cc79bSRoger Quadros dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
575f09cc79bSRoger Quadros dwc->otg_irq, ret);
576f09cc79bSRoger Quadros ret = -ENODEV;
577f09cc79bSRoger Quadros return ret;
578f09cc79bSRoger Quadros }
579f09cc79bSRoger Quadros
580f09cc79bSRoger Quadros dwc3_otg_init(dwc);
581f09cc79bSRoger Quadros dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
582f09cc79bSRoger Quadros }
5839840354fSRoger Quadros
5849840354fSRoger Quadros return 0;
5859840354fSRoger Quadros }
5869840354fSRoger Quadros
dwc3_drd_exit(struct dwc3 * dwc)5879840354fSRoger Quadros void dwc3_drd_exit(struct dwc3 *dwc)
5889840354fSRoger Quadros {
589f09cc79bSRoger Quadros unsigned long flags;
590f09cc79bSRoger Quadros
5918a0a1379SYu Chen if (dwc->role_sw)
5928a0a1379SYu Chen usb_role_switch_unregister(dwc->role_sw);
5938a0a1379SYu Chen
594f09cc79bSRoger Quadros if (dwc->edev)
5959840354fSRoger Quadros extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
5969840354fSRoger Quadros &dwc->edev_nb);
5979840354fSRoger Quadros
598f09cc79bSRoger Quadros cancel_work_sync(&dwc->drd_work);
599f09cc79bSRoger Quadros
600f09cc79bSRoger Quadros /* debug user might have changed role, clean based on current role */
601f09cc79bSRoger Quadros switch (dwc->current_dr_role) {
602f09cc79bSRoger Quadros case DWC3_GCTL_PRTCAP_HOST:
603f09cc79bSRoger Quadros dwc3_host_exit(dwc);
604f09cc79bSRoger Quadros break;
605f09cc79bSRoger Quadros case DWC3_GCTL_PRTCAP_DEVICE:
6069840354fSRoger Quadros dwc3_gadget_exit(dwc);
607f09cc79bSRoger Quadros dwc3_event_buffers_cleanup(dwc);
608f09cc79bSRoger Quadros break;
609f09cc79bSRoger Quadros case DWC3_GCTL_PRTCAP_OTG:
610f09cc79bSRoger Quadros dwc3_otg_exit(dwc);
611f09cc79bSRoger Quadros spin_lock_irqsave(&dwc->lock, flags);
612f09cc79bSRoger Quadros dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE;
613f09cc79bSRoger Quadros spin_unlock_irqrestore(&dwc->lock, flags);
614f09cc79bSRoger Quadros dwc3_otg_update(dwc, 1);
615f09cc79bSRoger Quadros break;
616f09cc79bSRoger Quadros default:
617f09cc79bSRoger Quadros break;
618f09cc79bSRoger Quadros }
619f09cc79bSRoger Quadros
6208cc6d55bSThinh Nguyen if (dwc->otg_irq)
621f09cc79bSRoger Quadros free_irq(dwc->otg_irq, dwc);
6229840354fSRoger Quadros }
623