Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0 |
7679defc | 2 | /* |
9840354f RQ |
3 | * drd.c - DesignWare USB3 DRD Controller Dual-role support |
4 | * | |
10623b87 | 5 | * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com |
9840354f RQ |
6 | * |
7 | * Authors: Roger Quadros <rogerq@ti.com> | |
9840354f RQ |
8 | */ |
9 | ||
10 | #include <linux/extcon.h> | |
5f0b74e5 | 11 | #include <linux/of_graph.h> |
f09cc79b | 12 | #include <linux/platform_device.h> |
85383756 | 13 | #include <linux/property.h> |
9840354f RQ |
14 | |
15 | #include "debug.h" | |
16 | #include "core.h" | |
17 | #include "gadget.h" | |
18 | ||
f09cc79b RQ |
19 | static void dwc3_otg_disable_events(struct dwc3 *dwc, u32 disable_mask) |
20 | { | |
21 | u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN); | |
22 | ||
23 | reg &= ~(disable_mask); | |
24 | dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); | |
25 | } | |
26 | ||
27 | static void dwc3_otg_enable_events(struct dwc3 *dwc, u32 enable_mask) | |
28 | { | |
29 | u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN); | |
30 | ||
31 | reg |= (enable_mask); | |
32 | dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); | |
33 | } | |
34 | ||
35 | static void dwc3_otg_clear_events(struct dwc3 *dwc) | |
36 | { | |
37 | u32 reg = dwc3_readl(dwc->regs, DWC3_OEVT); | |
38 | ||
39 | dwc3_writel(dwc->regs, DWC3_OEVTEN, reg); | |
40 | } | |
41 | ||
42 | #define DWC3_OTG_ALL_EVENTS (DWC3_OEVTEN_XHCIRUNSTPSETEN | \ | |
43 | DWC3_OEVTEN_DEVRUNSTPSETEN | DWC3_OEVTEN_HIBENTRYEN | \ | |
44 | DWC3_OEVTEN_CONIDSTSCHNGEN | DWC3_OEVTEN_HRRCONFNOTIFEN | \ | |
45 | DWC3_OEVTEN_HRRINITNOTIFEN | DWC3_OEVTEN_ADEVIDLEEN | \ | |
46 | DWC3_OEVTEN_ADEVBHOSTENDEN | DWC3_OEVTEN_ADEVHOSTEN | \ | |
47 | DWC3_OEVTEN_ADEVHNPCHNGEN | DWC3_OEVTEN_ADEVSRPDETEN | \ | |
48 | DWC3_OEVTEN_ADEVSESSENDDETEN | DWC3_OEVTEN_BDEVBHOSTENDEN | \ | |
49 | DWC3_OEVTEN_BDEVHNPCHNGEN | DWC3_OEVTEN_BDEVSESSVLDDETEN | \ | |
50 | DWC3_OEVTEN_BDEVVBUSCHNGEN) | |
51 | ||
52 | static irqreturn_t dwc3_otg_thread_irq(int irq, void *_dwc) | |
9840354f | 53 | { |
f09cc79b RQ |
54 | struct dwc3 *dwc = _dwc; |
55 | ||
56 | spin_lock(&dwc->lock); | |
57 | if (dwc->otg_restart_host) { | |
58 | dwc3_otg_host_init(dwc); | |
c685114f | 59 | dwc->otg_restart_host = false; |
f09cc79b RQ |
60 | } |
61 | ||
62 | spin_unlock(&dwc->lock); | |
63 | ||
64 | dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); | |
65 | ||
66 | return IRQ_HANDLED; | |
67 | } | |
68 | ||
69 | static irqreturn_t dwc3_otg_irq(int irq, void *_dwc) | |
70 | { | |
71 | u32 reg; | |
72 | struct dwc3 *dwc = _dwc; | |
73 | irqreturn_t ret = IRQ_NONE; | |
74 | ||
75 | reg = dwc3_readl(dwc->regs, DWC3_OEVT); | |
76 | if (reg) { | |
77 | /* ignore non OTG events, we can't disable them in OEVTEN */ | |
78 | if (!(reg & DWC3_OTG_ALL_EVENTS)) { | |
79 | dwc3_writel(dwc->regs, DWC3_OEVT, reg); | |
80 | return IRQ_NONE; | |
81 | } | |
82 | ||
83 | if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST && | |
84 | !(reg & DWC3_OEVT_DEVICEMODE)) | |
c685114f | 85 | dwc->otg_restart_host = true; |
f09cc79b RQ |
86 | dwc3_writel(dwc->regs, DWC3_OEVT, reg); |
87 | ret = IRQ_WAKE_THREAD; | |
88 | } | |
89 | ||
90 | return ret; | |
91 | } | |
92 | ||
93 | static void dwc3_otgregs_init(struct dwc3 *dwc) | |
94 | { | |
95 | u32 reg; | |
96 | ||
97 | /* | |
98 | * Prevent host/device reset from resetting OTG core. | |
99 | * If we don't do this then xhci_reset (USBCMD.HCRST) will reset | |
100 | * the signal outputs sent to the PHY, the OTG FSM logic of the | |
101 | * core and also the resets to the VBUS filters inside the core. | |
102 | */ | |
103 | reg = dwc3_readl(dwc->regs, DWC3_OCFG); | |
104 | reg |= DWC3_OCFG_SFTRSTMASK; | |
105 | dwc3_writel(dwc->regs, DWC3_OCFG, reg); | |
106 | ||
107 | /* Disable hibernation for simplicity */ | |
108 | reg = dwc3_readl(dwc->regs, DWC3_GCTL); | |
109 | reg &= ~DWC3_GCTL_GBLHIBERNATIONEN; | |
110 | dwc3_writel(dwc->regs, DWC3_GCTL, reg); | |
111 | ||
112 | /* | |
113 | * Initialize OTG registers as per | |
114 | * Figure 11-4 OTG Driver Overall Programming Flow | |
115 | */ | |
116 | /* OCFG.SRPCap = 0, OCFG.HNPCap = 0 */ | |
117 | reg = dwc3_readl(dwc->regs, DWC3_OCFG); | |
118 | reg &= ~(DWC3_OCFG_SRPCAP | DWC3_OCFG_HNPCAP); | |
119 | dwc3_writel(dwc->regs, DWC3_OCFG, reg); | |
120 | /* OEVT = FFFF */ | |
121 | dwc3_otg_clear_events(dwc); | |
122 | /* OEVTEN = 0 */ | |
123 | dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS); | |
124 | /* OEVTEN.ConIDStsChngEn = 1. Instead we enable all events */ | |
125 | dwc3_otg_enable_events(dwc, DWC3_OTG_ALL_EVENTS); | |
126 | /* | |
127 | * OCTL.PeriMode = 1, OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0, | |
128 | * OCTL.HNPReq = 0 | |
129 | */ | |
130 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
131 | reg |= DWC3_OCTL_PERIMODE; | |
132 | reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN | | |
133 | DWC3_OCTL_HNPREQ); | |
134 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
135 | } | |
136 | ||
137 | static int dwc3_otg_get_irq(struct dwc3 *dwc) | |
138 | { | |
139 | struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); | |
140 | int irq; | |
141 | ||
f146b40b | 142 | irq = platform_get_irq_byname_optional(dwc3_pdev, "otg"); |
f09cc79b RQ |
143 | if (irq > 0) |
144 | goto out; | |
145 | ||
146 | if (irq == -EPROBE_DEFER) | |
147 | goto out; | |
148 | ||
f146b40b | 149 | irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3"); |
f09cc79b RQ |
150 | if (irq > 0) |
151 | goto out; | |
152 | ||
153 | if (irq == -EPROBE_DEFER) | |
154 | goto out; | |
155 | ||
156 | irq = platform_get_irq(dwc3_pdev, 0); | |
157 | if (irq > 0) | |
158 | goto out; | |
159 | ||
f09cc79b RQ |
160 | if (!irq) |
161 | irq = -EINVAL; | |
162 | ||
163 | out: | |
164 | return irq; | |
165 | } | |
166 | ||
167 | void dwc3_otg_init(struct dwc3 *dwc) | |
168 | { | |
169 | u32 reg; | |
170 | ||
171 | /* | |
172 | * As per Figure 11-4 OTG Driver Overall Programming Flow, | |
173 | * block "Initialize GCTL for OTG operation". | |
174 | */ | |
175 | /* GCTL.PrtCapDir=2'b11 */ | |
176 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG); | |
177 | /* GUSB2PHYCFG0.SusPHY=0 */ | |
178 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | |
179 | reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; | |
180 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | |
181 | ||
182 | /* Initialize OTG registers */ | |
183 | dwc3_otgregs_init(dwc); | |
184 | } | |
185 | ||
186 | void dwc3_otg_exit(struct dwc3 *dwc) | |
187 | { | |
188 | /* disable all OTG IRQs */ | |
189 | dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS); | |
190 | /* clear all events */ | |
191 | dwc3_otg_clear_events(dwc); | |
192 | } | |
193 | ||
194 | /* should be called before Host controller driver is started */ | |
195 | void dwc3_otg_host_init(struct dwc3 *dwc) | |
196 | { | |
197 | u32 reg; | |
198 | ||
199 | /* As per Figure 11-10 A-Device Flow Diagram */ | |
200 | /* OCFG.HNPCap = 0, OCFG.SRPCap = 0. Already 0 */ | |
201 | ||
202 | /* | |
203 | * OCTL.PeriMode=0, OCTL.TermSelDLPulse = 0, | |
204 | * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0 | |
205 | */ | |
206 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
207 | reg &= ~(DWC3_OCTL_PERIMODE | DWC3_OCTL_TERMSELIDPULSE | | |
208 | DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN); | |
209 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
210 | ||
211 | /* | |
212 | * OCFG.DisPrtPwrCutoff = 0/1 | |
213 | */ | |
214 | reg = dwc3_readl(dwc->regs, DWC3_OCFG); | |
215 | reg &= ~DWC3_OCFG_DISPWRCUTTOFF; | |
216 | dwc3_writel(dwc->regs, DWC3_OCFG, reg); | |
217 | ||
218 | /* | |
219 | * OCFG.SRPCap = 1, OCFG.HNPCap = GHWPARAMS6.HNP_CAP | |
220 | * We don't want SRP/HNP for simple dual-role so leave | |
221 | * these disabled. | |
222 | */ | |
223 | ||
224 | /* | |
225 | * OEVTEN.OTGADevHostEvntEn = 1 | |
226 | * OEVTEN.OTGADevSessEndDetEvntEn = 1 | |
227 | * We don't want HNP/role-swap so leave these disabled. | |
228 | */ | |
229 | ||
230 | /* GUSB2PHYCFG.ULPIAutoRes = 1/0, GUSB2PHYCFG.SusPHY = 1 */ | |
231 | if (!dwc->dis_u2_susphy_quirk) { | |
232 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | |
233 | reg |= DWC3_GUSB2PHYCFG_SUSPHY; | |
234 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | |
235 | } | |
236 | ||
237 | /* Set Port Power to enable VBUS: OCTL.PrtPwrCtl = 1 */ | |
238 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
239 | reg |= DWC3_OCTL_PRTPWRCTL; | |
240 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
241 | } | |
242 | ||
243 | /* should be called after Host controller driver is stopped */ | |
244 | static void dwc3_otg_host_exit(struct dwc3 *dwc) | |
245 | { | |
246 | u32 reg; | |
247 | ||
248 | /* | |
249 | * Exit from A-device flow as per | |
250 | * Figure 11-4 OTG Driver Overall Programming Flow | |
251 | */ | |
252 | ||
253 | /* | |
254 | * OEVTEN.OTGADevBHostEndEvntEn=0, OEVTEN.OTGADevHNPChngEvntEn=0 | |
255 | * OEVTEN.OTGADevSessEndDetEvntEn=0, | |
256 | * OEVTEN.OTGADevHostEvntEn = 0 | |
257 | * But we don't disable any OTG events | |
258 | */ | |
259 | ||
260 | /* OCTL.HstSetHNPEn = 0, OCTL.PrtPwrCtl=0 */ | |
261 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
262 | reg &= ~(DWC3_OCTL_HSTSETHNPEN | DWC3_OCTL_PRTPWRCTL); | |
263 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
264 | } | |
265 | ||
266 | /* should be called before the gadget controller driver is started */ | |
267 | static void dwc3_otg_device_init(struct dwc3 *dwc) | |
268 | { | |
269 | u32 reg; | |
270 | ||
271 | /* As per Figure 11-20 B-Device Flow Diagram */ | |
272 | ||
273 | /* | |
274 | * OCFG.HNPCap = GHWPARAMS6.HNP_CAP, OCFG.SRPCap = 1 | |
275 | * but we keep them 0 for simple dual-role operation. | |
276 | */ | |
277 | reg = dwc3_readl(dwc->regs, DWC3_OCFG); | |
278 | /* OCFG.OTGSftRstMsk = 0/1 */ | |
279 | reg |= DWC3_OCFG_SFTRSTMASK; | |
280 | dwc3_writel(dwc->regs, DWC3_OCFG, reg); | |
281 | /* | |
282 | * OCTL.PeriMode = 1 | |
283 | * OCTL.TermSelDLPulse = 0/1, OCTL.HNPReq = 0 | |
284 | * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0 | |
285 | */ | |
286 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
287 | reg |= DWC3_OCTL_PERIMODE; | |
288 | reg &= ~(DWC3_OCTL_TERMSELIDPULSE | DWC3_OCTL_HNPREQ | | |
289 | DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN); | |
290 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
291 | /* OEVTEN.OTGBDevSesVldDetEvntEn = 1 */ | |
292 | dwc3_otg_enable_events(dwc, DWC3_OEVTEN_BDEVSESSVLDDETEN); | |
293 | /* GUSB2PHYCFG.ULPIAutoRes = 0, GUSB2PHYCFG0.SusPHY = 1 */ | |
294 | if (!dwc->dis_u2_susphy_quirk) { | |
295 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | |
296 | reg |= DWC3_GUSB2PHYCFG_SUSPHY; | |
297 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | |
298 | } | |
299 | /* GCTL.GblHibernationEn = 0. Already 0. */ | |
300 | } | |
301 | ||
302 | /* should be called after the gadget controller driver is stopped */ | |
303 | static void dwc3_otg_device_exit(struct dwc3 *dwc) | |
304 | { | |
305 | u32 reg; | |
306 | ||
307 | /* | |
308 | * Exit from B-device flow as per | |
309 | * Figure 11-4 OTG Driver Overall Programming Flow | |
310 | */ | |
311 | ||
312 | /* | |
313 | * OEVTEN.OTGBDevHNPChngEvntEn = 0 | |
314 | * OEVTEN.OTGBDevVBusChngEvntEn = 0 | |
315 | * OEVTEN.OTGBDevBHostEndEvntEn = 0 | |
316 | */ | |
317 | dwc3_otg_disable_events(dwc, DWC3_OEVTEN_BDEVHNPCHNGEN | | |
318 | DWC3_OEVTEN_BDEVVBUSCHNGEN | | |
319 | DWC3_OEVTEN_BDEVBHOSTENDEN); | |
320 | ||
321 | /* OCTL.DevSetHNPEn = 0, OCTL.HNPReq = 0, OCTL.PeriMode=1 */ | |
322 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
323 | reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HNPREQ); | |
324 | reg |= DWC3_OCTL_PERIMODE; | |
325 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
326 | } | |
327 | ||
328 | void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) | |
329 | { | |
330 | int ret; | |
331 | u32 reg; | |
9840354f | 332 | int id; |
f09cc79b | 333 | unsigned long flags; |
9840354f | 334 | |
f09cc79b RQ |
335 | if (dwc->dr_mode != USB_DR_MODE_OTG) |
336 | return; | |
9840354f | 337 | |
f09cc79b RQ |
338 | /* don't do anything if debug user changed role to not OTG */ |
339 | if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG) | |
340 | return; | |
341 | ||
342 | if (!ignore_idstatus) { | |
343 | reg = dwc3_readl(dwc->regs, DWC3_OSTS); | |
344 | id = !!(reg & DWC3_OSTS_CONIDSTS); | |
345 | ||
346 | dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE : | |
347 | DWC3_OTG_ROLE_HOST; | |
348 | } | |
349 | ||
350 | if (dwc->desired_otg_role == dwc->current_otg_role) | |
351 | return; | |
352 | ||
353 | switch (dwc->current_otg_role) { | |
354 | case DWC3_OTG_ROLE_HOST: | |
355 | dwc3_host_exit(dwc); | |
356 | spin_lock_irqsave(&dwc->lock, flags); | |
357 | dwc3_otg_host_exit(dwc); | |
358 | spin_unlock_irqrestore(&dwc->lock, flags); | |
359 | break; | |
360 | case DWC3_OTG_ROLE_DEVICE: | |
361 | dwc3_gadget_exit(dwc); | |
362 | spin_lock_irqsave(&dwc->lock, flags); | |
363 | dwc3_event_buffers_cleanup(dwc); | |
364 | dwc3_otg_device_exit(dwc); | |
365 | spin_unlock_irqrestore(&dwc->lock, flags); | |
366 | break; | |
367 | default: | |
368 | break; | |
369 | } | |
370 | ||
371 | spin_lock_irqsave(&dwc->lock, flags); | |
372 | ||
373 | dwc->current_otg_role = dwc->desired_otg_role; | |
374 | ||
375 | spin_unlock_irqrestore(&dwc->lock, flags); | |
376 | ||
377 | switch (dwc->desired_otg_role) { | |
378 | case DWC3_OTG_ROLE_HOST: | |
379 | spin_lock_irqsave(&dwc->lock, flags); | |
380 | dwc3_otgregs_init(dwc); | |
381 | dwc3_otg_host_init(dwc); | |
382 | spin_unlock_irqrestore(&dwc->lock, flags); | |
383 | ret = dwc3_host_init(dwc); | |
384 | if (ret) { | |
385 | dev_err(dwc->dev, "failed to initialize host\n"); | |
386 | } else { | |
387 | if (dwc->usb2_phy) | |
388 | otg_set_vbus(dwc->usb2_phy->otg, true); | |
389 | if (dwc->usb2_generic_phy) | |
390 | phy_set_mode(dwc->usb2_generic_phy, | |
391 | PHY_MODE_USB_HOST); | |
392 | } | |
393 | break; | |
394 | case DWC3_OTG_ROLE_DEVICE: | |
395 | spin_lock_irqsave(&dwc->lock, flags); | |
396 | dwc3_otgregs_init(dwc); | |
397 | dwc3_otg_device_init(dwc); | |
398 | dwc3_event_buffers_setup(dwc); | |
399 | spin_unlock_irqrestore(&dwc->lock, flags); | |
400 | ||
401 | if (dwc->usb2_phy) | |
402 | otg_set_vbus(dwc->usb2_phy->otg, false); | |
403 | if (dwc->usb2_generic_phy) | |
404 | phy_set_mode(dwc->usb2_generic_phy, | |
405 | PHY_MODE_USB_DEVICE); | |
406 | ret = dwc3_gadget_init(dwc); | |
407 | if (ret) | |
408 | dev_err(dwc->dev, "failed to initialize peripheral\n"); | |
409 | break; | |
410 | default: | |
411 | break; | |
412 | } | |
413 | } | |
414 | ||
415 | static void dwc3_drd_update(struct dwc3 *dwc) | |
416 | { | |
417 | int id; | |
418 | ||
419 | if (dwc->edev) { | |
420 | id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); | |
421 | if (id < 0) | |
422 | id = 0; | |
423 | dwc3_set_mode(dwc, id ? | |
424 | DWC3_GCTL_PRTCAP_HOST : | |
425 | DWC3_GCTL_PRTCAP_DEVICE); | |
426 | } | |
9840354f RQ |
427 | } |
428 | ||
429 | static int dwc3_drd_notifier(struct notifier_block *nb, | |
430 | unsigned long event, void *ptr) | |
431 | { | |
432 | struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb); | |
433 | ||
434 | dwc3_set_mode(dwc, event ? | |
435 | DWC3_GCTL_PRTCAP_HOST : | |
436 | DWC3_GCTL_PRTCAP_DEVICE); | |
437 | ||
438 | return NOTIFY_DONE; | |
439 | } | |
440 | ||
edbbfe19 | 441 | static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) |
5f0b74e5 AH |
442 | { |
443 | struct device *dev = dwc->dev; | |
444 | struct device_node *np_phy, *np_conn; | |
445 | struct extcon_dev *edev; | |
268784ba | 446 | const char *name; |
5f0b74e5 | 447 | |
85383756 AS |
448 | if (device_property_read_bool(dev, "extcon")) |
449 | return extcon_get_edev_by_phandle(dev, 0); | |
5f0b74e5 | 450 | |
268784ba AS |
451 | /* |
452 | * Device tree platforms should get extcon via phandle. | |
453 | * On ACPI platforms, we get the name from a device property. | |
454 | * This device property is for kernel internal use only and | |
455 | * is expected to be set by the glue code. | |
456 | */ | |
98bba546 AS |
457 | if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) { |
458 | edev = extcon_get_extcon_dev(name); | |
459 | if (!edev) | |
460 | return ERR_PTR(-EPROBE_DEFER); | |
461 | ||
462 | return edev; | |
463 | } | |
268784ba | 464 | |
5f0b74e5 AH |
465 | np_phy = of_parse_phandle(dev->of_node, "phys", 0); |
466 | np_conn = of_graph_get_remote_node(np_phy, -1, -1); | |
467 | ||
468 | if (np_conn) | |
469 | edev = extcon_find_edev_by_node(np_conn); | |
470 | else | |
471 | edev = NULL; | |
472 | ||
473 | of_node_put(np_conn); | |
474 | of_node_put(np_phy); | |
475 | ||
476 | return edev; | |
477 | } | |
478 | ||
8a0a1379 YC |
479 | #if IS_ENABLED(CONFIG_USB_ROLE_SWITCH) |
480 | #define ROLE_SWITCH 1 | |
0339f7fb SR |
481 | static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, |
482 | enum usb_role role) | |
8a0a1379 | 483 | { |
0339f7fb | 484 | struct dwc3 *dwc = usb_role_switch_get_drvdata(sw); |
8a0a1379 YC |
485 | u32 mode; |
486 | ||
487 | switch (role) { | |
488 | case USB_ROLE_HOST: | |
489 | mode = DWC3_GCTL_PRTCAP_HOST; | |
490 | break; | |
491 | case USB_ROLE_DEVICE: | |
492 | mode = DWC3_GCTL_PRTCAP_DEVICE; | |
493 | break; | |
494 | default: | |
98ed256a JS |
495 | if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) |
496 | mode = DWC3_GCTL_PRTCAP_HOST; | |
497 | else | |
498 | mode = DWC3_GCTL_PRTCAP_DEVICE; | |
8a0a1379 YC |
499 | break; |
500 | } | |
501 | ||
502 | dwc3_set_mode(dwc, mode); | |
503 | return 0; | |
504 | } | |
505 | ||
0339f7fb | 506 | static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw) |
8a0a1379 | 507 | { |
0339f7fb | 508 | struct dwc3 *dwc = usb_role_switch_get_drvdata(sw); |
8a0a1379 YC |
509 | unsigned long flags; |
510 | enum usb_role role; | |
511 | ||
512 | spin_lock_irqsave(&dwc->lock, flags); | |
513 | switch (dwc->current_dr_role) { | |
514 | case DWC3_GCTL_PRTCAP_HOST: | |
515 | role = USB_ROLE_HOST; | |
516 | break; | |
517 | case DWC3_GCTL_PRTCAP_DEVICE: | |
518 | role = USB_ROLE_DEVICE; | |
519 | break; | |
520 | case DWC3_GCTL_PRTCAP_OTG: | |
521 | role = dwc->current_otg_role; | |
522 | break; | |
523 | default: | |
98ed256a JS |
524 | if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) |
525 | role = USB_ROLE_HOST; | |
526 | else | |
527 | role = USB_ROLE_DEVICE; | |
8a0a1379 YC |
528 | break; |
529 | } | |
530 | spin_unlock_irqrestore(&dwc->lock, flags); | |
531 | return role; | |
532 | } | |
533 | ||
534 | static int dwc3_setup_role_switch(struct dwc3 *dwc) | |
535 | { | |
536 | struct usb_role_switch_desc dwc3_role_switch = {NULL}; | |
98ed256a JS |
537 | const char *str; |
538 | u32 mode; | |
539 | int ret; | |
540 | ||
541 | ret = device_property_read_string(dwc->dev, "role-switch-default-mode", | |
542 | &str); | |
543 | if (ret >= 0 && !strncmp(str, "host", strlen("host"))) { | |
544 | dwc->role_switch_default_mode = USB_DR_MODE_HOST; | |
545 | mode = DWC3_GCTL_PRTCAP_HOST; | |
546 | } else { | |
547 | dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL; | |
548 | mode = DWC3_GCTL_PRTCAP_DEVICE; | |
549 | } | |
8a0a1379 YC |
550 | |
551 | dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); | |
552 | dwc3_role_switch.set = dwc3_usb_role_switch_set; | |
553 | dwc3_role_switch.get = dwc3_usb_role_switch_get; | |
0339f7fb | 554 | dwc3_role_switch.driver_data = dwc; |
8a0a1379 YC |
555 | dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch); |
556 | if (IS_ERR(dwc->role_sw)) | |
557 | return PTR_ERR(dwc->role_sw); | |
558 | ||
98ed256a | 559 | dwc3_set_mode(dwc, mode); |
8a0a1379 YC |
560 | return 0; |
561 | } | |
562 | #else | |
563 | #define ROLE_SWITCH 0 | |
564 | #define dwc3_setup_role_switch(x) 0 | |
565 | #endif | |
566 | ||
9840354f RQ |
567 | int dwc3_drd_init(struct dwc3 *dwc) |
568 | { | |
f09cc79b | 569 | int ret, irq; |
9840354f | 570 | |
5f0b74e5 AH |
571 | dwc->edev = dwc3_get_extcon(dwc); |
572 | if (IS_ERR(dwc->edev)) | |
573 | return PTR_ERR(dwc->edev); | |
9840354f | 574 | |
8a0a1379 YC |
575 | if (ROLE_SWITCH && |
576 | device_property_read_bool(dwc->dev, "usb-role-switch")) { | |
577 | ret = dwc3_setup_role_switch(dwc); | |
578 | if (ret < 0) | |
579 | return ret; | |
580 | } else if (dwc->edev) { | |
9840354f RQ |
581 | dwc->edev_nb.notifier_call = dwc3_drd_notifier; |
582 | ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, | |
583 | &dwc->edev_nb); | |
584 | if (ret < 0) { | |
585 | dev_err(dwc->dev, "couldn't register cable notifier\n"); | |
586 | return ret; | |
587 | } | |
9840354f | 588 | |
f09cc79b RQ |
589 | dwc3_drd_update(dwc); |
590 | } else { | |
591 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG); | |
592 | dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG; | |
593 | ||
594 | /* use OTG block to get ID event */ | |
595 | irq = dwc3_otg_get_irq(dwc); | |
596 | if (irq < 0) | |
597 | return irq; | |
598 | ||
599 | dwc->otg_irq = irq; | |
600 | ||
601 | /* disable all OTG IRQs */ | |
602 | dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS); | |
603 | /* clear all events */ | |
604 | dwc3_otg_clear_events(dwc); | |
605 | ||
606 | ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq, | |
607 | dwc3_otg_thread_irq, | |
608 | IRQF_SHARED, "dwc3-otg", dwc); | |
609 | if (ret) { | |
610 | dev_err(dwc->dev, "failed to request irq #%d --> %d\n", | |
611 | dwc->otg_irq, ret); | |
612 | ret = -ENODEV; | |
613 | return ret; | |
614 | } | |
615 | ||
616 | dwc3_otg_init(dwc); | |
617 | dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); | |
618 | } | |
9840354f RQ |
619 | |
620 | return 0; | |
621 | } | |
622 | ||
623 | void dwc3_drd_exit(struct dwc3 *dwc) | |
624 | { | |
f09cc79b RQ |
625 | unsigned long flags; |
626 | ||
8a0a1379 YC |
627 | if (dwc->role_sw) |
628 | usb_role_switch_unregister(dwc->role_sw); | |
629 | ||
f09cc79b RQ |
630 | if (dwc->edev) |
631 | extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, | |
632 | &dwc->edev_nb); | |
633 | ||
634 | cancel_work_sync(&dwc->drd_work); | |
635 | ||
636 | /* debug user might have changed role, clean based on current role */ | |
637 | switch (dwc->current_dr_role) { | |
638 | case DWC3_GCTL_PRTCAP_HOST: | |
639 | dwc3_host_exit(dwc); | |
640 | break; | |
641 | case DWC3_GCTL_PRTCAP_DEVICE: | |
642 | dwc3_gadget_exit(dwc); | |
643 | dwc3_event_buffers_cleanup(dwc); | |
644 | break; | |
645 | case DWC3_GCTL_PRTCAP_OTG: | |
646 | dwc3_otg_exit(dwc); | |
647 | spin_lock_irqsave(&dwc->lock, flags); | |
648 | dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE; | |
649 | spin_unlock_irqrestore(&dwc->lock, flags); | |
650 | dwc3_otg_update(dwc, 1); | |
651 | break; | |
652 | default: | |
653 | break; | |
654 | } | |
9840354f | 655 | |
8cc6d55b | 656 | if (dwc->otg_irq) |
f09cc79b | 657 | free_irq(dwc->otg_irq, dwc); |
9840354f | 658 | } |