Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0 |
9840354f RQ |
2 | /** |
3 | * drd.c - DesignWare USB3 DRD Controller Dual-role support | |
4 | * | |
5 | * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com | |
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); | |
59 | dwc->otg_restart_host = 0; | |
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)) | |
85 | dwc->otg_restart_host = 1; | |
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 | ||
142 | irq = platform_get_irq_byname(dwc3_pdev, "otg"); | |
143 | if (irq > 0) | |
144 | goto out; | |
145 | ||
146 | if (irq == -EPROBE_DEFER) | |
147 | goto out; | |
148 | ||
149 | irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); | |
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 | ||
160 | if (irq != -EPROBE_DEFER) | |
161 | dev_err(dwc->dev, "missing OTG IRQ\n"); | |
162 | ||
163 | if (!irq) | |
164 | irq = -EINVAL; | |
165 | ||
166 | out: | |
167 | return irq; | |
168 | } | |
169 | ||
170 | void dwc3_otg_init(struct dwc3 *dwc) | |
171 | { | |
172 | u32 reg; | |
173 | ||
174 | /* | |
175 | * As per Figure 11-4 OTG Driver Overall Programming Flow, | |
176 | * block "Initialize GCTL for OTG operation". | |
177 | */ | |
178 | /* GCTL.PrtCapDir=2'b11 */ | |
179 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG); | |
180 | /* GUSB2PHYCFG0.SusPHY=0 */ | |
181 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | |
182 | reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; | |
183 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | |
184 | ||
185 | /* Initialize OTG registers */ | |
186 | dwc3_otgregs_init(dwc); | |
187 | } | |
188 | ||
189 | void dwc3_otg_exit(struct dwc3 *dwc) | |
190 | { | |
191 | /* disable all OTG IRQs */ | |
192 | dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS); | |
193 | /* clear all events */ | |
194 | dwc3_otg_clear_events(dwc); | |
195 | } | |
196 | ||
197 | /* should be called before Host controller driver is started */ | |
198 | void dwc3_otg_host_init(struct dwc3 *dwc) | |
199 | { | |
200 | u32 reg; | |
201 | ||
202 | /* As per Figure 11-10 A-Device Flow Diagram */ | |
203 | /* OCFG.HNPCap = 0, OCFG.SRPCap = 0. Already 0 */ | |
204 | ||
205 | /* | |
206 | * OCTL.PeriMode=0, OCTL.TermSelDLPulse = 0, | |
207 | * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0 | |
208 | */ | |
209 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
210 | reg &= ~(DWC3_OCTL_PERIMODE | DWC3_OCTL_TERMSELIDPULSE | | |
211 | DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN); | |
212 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
213 | ||
214 | /* | |
215 | * OCFG.DisPrtPwrCutoff = 0/1 | |
216 | */ | |
217 | reg = dwc3_readl(dwc->regs, DWC3_OCFG); | |
218 | reg &= ~DWC3_OCFG_DISPWRCUTTOFF; | |
219 | dwc3_writel(dwc->regs, DWC3_OCFG, reg); | |
220 | ||
221 | /* | |
222 | * OCFG.SRPCap = 1, OCFG.HNPCap = GHWPARAMS6.HNP_CAP | |
223 | * We don't want SRP/HNP for simple dual-role so leave | |
224 | * these disabled. | |
225 | */ | |
226 | ||
227 | /* | |
228 | * OEVTEN.OTGADevHostEvntEn = 1 | |
229 | * OEVTEN.OTGADevSessEndDetEvntEn = 1 | |
230 | * We don't want HNP/role-swap so leave these disabled. | |
231 | */ | |
232 | ||
233 | /* GUSB2PHYCFG.ULPIAutoRes = 1/0, GUSB2PHYCFG.SusPHY = 1 */ | |
234 | if (!dwc->dis_u2_susphy_quirk) { | |
235 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | |
236 | reg |= DWC3_GUSB2PHYCFG_SUSPHY; | |
237 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | |
238 | } | |
239 | ||
240 | /* Set Port Power to enable VBUS: OCTL.PrtPwrCtl = 1 */ | |
241 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
242 | reg |= DWC3_OCTL_PRTPWRCTL; | |
243 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
244 | } | |
245 | ||
246 | /* should be called after Host controller driver is stopped */ | |
247 | static void dwc3_otg_host_exit(struct dwc3 *dwc) | |
248 | { | |
249 | u32 reg; | |
250 | ||
251 | /* | |
252 | * Exit from A-device flow as per | |
253 | * Figure 11-4 OTG Driver Overall Programming Flow | |
254 | */ | |
255 | ||
256 | /* | |
257 | * OEVTEN.OTGADevBHostEndEvntEn=0, OEVTEN.OTGADevHNPChngEvntEn=0 | |
258 | * OEVTEN.OTGADevSessEndDetEvntEn=0, | |
259 | * OEVTEN.OTGADevHostEvntEn = 0 | |
260 | * But we don't disable any OTG events | |
261 | */ | |
262 | ||
263 | /* OCTL.HstSetHNPEn = 0, OCTL.PrtPwrCtl=0 */ | |
264 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
265 | reg &= ~(DWC3_OCTL_HSTSETHNPEN | DWC3_OCTL_PRTPWRCTL); | |
266 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
267 | } | |
268 | ||
269 | /* should be called before the gadget controller driver is started */ | |
270 | static void dwc3_otg_device_init(struct dwc3 *dwc) | |
271 | { | |
272 | u32 reg; | |
273 | ||
274 | /* As per Figure 11-20 B-Device Flow Diagram */ | |
275 | ||
276 | /* | |
277 | * OCFG.HNPCap = GHWPARAMS6.HNP_CAP, OCFG.SRPCap = 1 | |
278 | * but we keep them 0 for simple dual-role operation. | |
279 | */ | |
280 | reg = dwc3_readl(dwc->regs, DWC3_OCFG); | |
281 | /* OCFG.OTGSftRstMsk = 0/1 */ | |
282 | reg |= DWC3_OCFG_SFTRSTMASK; | |
283 | dwc3_writel(dwc->regs, DWC3_OCFG, reg); | |
284 | /* | |
285 | * OCTL.PeriMode = 1 | |
286 | * OCTL.TermSelDLPulse = 0/1, OCTL.HNPReq = 0 | |
287 | * OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0 | |
288 | */ | |
289 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
290 | reg |= DWC3_OCTL_PERIMODE; | |
291 | reg &= ~(DWC3_OCTL_TERMSELIDPULSE | DWC3_OCTL_HNPREQ | | |
292 | DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN); | |
293 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
294 | /* OEVTEN.OTGBDevSesVldDetEvntEn = 1 */ | |
295 | dwc3_otg_enable_events(dwc, DWC3_OEVTEN_BDEVSESSVLDDETEN); | |
296 | /* GUSB2PHYCFG.ULPIAutoRes = 0, GUSB2PHYCFG0.SusPHY = 1 */ | |
297 | if (!dwc->dis_u2_susphy_quirk) { | |
298 | reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); | |
299 | reg |= DWC3_GUSB2PHYCFG_SUSPHY; | |
300 | dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); | |
301 | } | |
302 | /* GCTL.GblHibernationEn = 0. Already 0. */ | |
303 | } | |
304 | ||
305 | /* should be called after the gadget controller driver is stopped */ | |
306 | static void dwc3_otg_device_exit(struct dwc3 *dwc) | |
307 | { | |
308 | u32 reg; | |
309 | ||
310 | /* | |
311 | * Exit from B-device flow as per | |
312 | * Figure 11-4 OTG Driver Overall Programming Flow | |
313 | */ | |
314 | ||
315 | /* | |
316 | * OEVTEN.OTGBDevHNPChngEvntEn = 0 | |
317 | * OEVTEN.OTGBDevVBusChngEvntEn = 0 | |
318 | * OEVTEN.OTGBDevBHostEndEvntEn = 0 | |
319 | */ | |
320 | dwc3_otg_disable_events(dwc, DWC3_OEVTEN_BDEVHNPCHNGEN | | |
321 | DWC3_OEVTEN_BDEVVBUSCHNGEN | | |
322 | DWC3_OEVTEN_BDEVBHOSTENDEN); | |
323 | ||
324 | /* OCTL.DevSetHNPEn = 0, OCTL.HNPReq = 0, OCTL.PeriMode=1 */ | |
325 | reg = dwc3_readl(dwc->regs, DWC3_OCTL); | |
326 | reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HNPREQ); | |
327 | reg |= DWC3_OCTL_PERIMODE; | |
328 | dwc3_writel(dwc->regs, DWC3_OCTL, reg); | |
329 | } | |
330 | ||
331 | void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) | |
332 | { | |
333 | int ret; | |
334 | u32 reg; | |
9840354f | 335 | int id; |
f09cc79b | 336 | unsigned long flags; |
9840354f | 337 | |
f09cc79b RQ |
338 | if (dwc->dr_mode != USB_DR_MODE_OTG) |
339 | return; | |
9840354f | 340 | |
f09cc79b RQ |
341 | /* don't do anything if debug user changed role to not OTG */ |
342 | if (dwc->current_dr_role != DWC3_GCTL_PRTCAP_OTG) | |
343 | return; | |
344 | ||
345 | if (!ignore_idstatus) { | |
346 | reg = dwc3_readl(dwc->regs, DWC3_OSTS); | |
347 | id = !!(reg & DWC3_OSTS_CONIDSTS); | |
348 | ||
349 | dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE : | |
350 | DWC3_OTG_ROLE_HOST; | |
351 | } | |
352 | ||
353 | if (dwc->desired_otg_role == dwc->current_otg_role) | |
354 | return; | |
355 | ||
356 | switch (dwc->current_otg_role) { | |
357 | case DWC3_OTG_ROLE_HOST: | |
358 | dwc3_host_exit(dwc); | |
359 | spin_lock_irqsave(&dwc->lock, flags); | |
360 | dwc3_otg_host_exit(dwc); | |
361 | spin_unlock_irqrestore(&dwc->lock, flags); | |
362 | break; | |
363 | case DWC3_OTG_ROLE_DEVICE: | |
364 | dwc3_gadget_exit(dwc); | |
365 | spin_lock_irqsave(&dwc->lock, flags); | |
366 | dwc3_event_buffers_cleanup(dwc); | |
367 | dwc3_otg_device_exit(dwc); | |
368 | spin_unlock_irqrestore(&dwc->lock, flags); | |
369 | break; | |
370 | default: | |
371 | break; | |
372 | } | |
373 | ||
374 | spin_lock_irqsave(&dwc->lock, flags); | |
375 | ||
376 | dwc->current_otg_role = dwc->desired_otg_role; | |
377 | ||
378 | spin_unlock_irqrestore(&dwc->lock, flags); | |
379 | ||
380 | switch (dwc->desired_otg_role) { | |
381 | case DWC3_OTG_ROLE_HOST: | |
382 | spin_lock_irqsave(&dwc->lock, flags); | |
383 | dwc3_otgregs_init(dwc); | |
384 | dwc3_otg_host_init(dwc); | |
385 | spin_unlock_irqrestore(&dwc->lock, flags); | |
386 | ret = dwc3_host_init(dwc); | |
387 | if (ret) { | |
388 | dev_err(dwc->dev, "failed to initialize host\n"); | |
389 | } else { | |
390 | if (dwc->usb2_phy) | |
391 | otg_set_vbus(dwc->usb2_phy->otg, true); | |
392 | if (dwc->usb2_generic_phy) | |
393 | phy_set_mode(dwc->usb2_generic_phy, | |
394 | PHY_MODE_USB_HOST); | |
395 | } | |
396 | break; | |
397 | case DWC3_OTG_ROLE_DEVICE: | |
398 | spin_lock_irqsave(&dwc->lock, flags); | |
399 | dwc3_otgregs_init(dwc); | |
400 | dwc3_otg_device_init(dwc); | |
401 | dwc3_event_buffers_setup(dwc); | |
402 | spin_unlock_irqrestore(&dwc->lock, flags); | |
403 | ||
404 | if (dwc->usb2_phy) | |
405 | otg_set_vbus(dwc->usb2_phy->otg, false); | |
406 | if (dwc->usb2_generic_phy) | |
407 | phy_set_mode(dwc->usb2_generic_phy, | |
408 | PHY_MODE_USB_DEVICE); | |
409 | ret = dwc3_gadget_init(dwc); | |
410 | if (ret) | |
411 | dev_err(dwc->dev, "failed to initialize peripheral\n"); | |
412 | break; | |
413 | default: | |
414 | break; | |
415 | } | |
416 | } | |
417 | ||
418 | static void dwc3_drd_update(struct dwc3 *dwc) | |
419 | { | |
420 | int id; | |
421 | ||
422 | if (dwc->edev) { | |
423 | id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); | |
424 | if (id < 0) | |
425 | id = 0; | |
426 | dwc3_set_mode(dwc, id ? | |
427 | DWC3_GCTL_PRTCAP_HOST : | |
428 | DWC3_GCTL_PRTCAP_DEVICE); | |
429 | } | |
9840354f RQ |
430 | } |
431 | ||
432 | static int dwc3_drd_notifier(struct notifier_block *nb, | |
433 | unsigned long event, void *ptr) | |
434 | { | |
435 | struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb); | |
436 | ||
437 | dwc3_set_mode(dwc, event ? | |
438 | DWC3_GCTL_PRTCAP_HOST : | |
439 | DWC3_GCTL_PRTCAP_DEVICE); | |
440 | ||
441 | return NOTIFY_DONE; | |
442 | } | |
443 | ||
edbbfe19 | 444 | static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) |
5f0b74e5 AH |
445 | { |
446 | struct device *dev = dwc->dev; | |
447 | struct device_node *np_phy, *np_conn; | |
448 | struct extcon_dev *edev; | |
268784ba | 449 | const char *name; |
5f0b74e5 | 450 | |
85383756 AS |
451 | if (device_property_read_bool(dev, "extcon")) |
452 | return extcon_get_edev_by_phandle(dev, 0); | |
5f0b74e5 | 453 | |
268784ba AS |
454 | /* |
455 | * Device tree platforms should get extcon via phandle. | |
456 | * On ACPI platforms, we get the name from a device property. | |
457 | * This device property is for kernel internal use only and | |
458 | * is expected to be set by the glue code. | |
459 | */ | |
460 | if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) | |
461 | return extcon_get_extcon_dev(name); | |
462 | ||
5f0b74e5 AH |
463 | np_phy = of_parse_phandle(dev->of_node, "phys", 0); |
464 | np_conn = of_graph_get_remote_node(np_phy, -1, -1); | |
465 | ||
466 | if (np_conn) | |
467 | edev = extcon_find_edev_by_node(np_conn); | |
468 | else | |
469 | edev = NULL; | |
470 | ||
471 | of_node_put(np_conn); | |
472 | of_node_put(np_phy); | |
473 | ||
474 | return edev; | |
475 | } | |
476 | ||
9840354f RQ |
477 | int dwc3_drd_init(struct dwc3 *dwc) |
478 | { | |
f09cc79b | 479 | int ret, irq; |
9840354f | 480 | |
5f0b74e5 AH |
481 | dwc->edev = dwc3_get_extcon(dwc); |
482 | if (IS_ERR(dwc->edev)) | |
483 | return PTR_ERR(dwc->edev); | |
9840354f | 484 | |
5f0b74e5 | 485 | if (dwc->edev) { |
9840354f RQ |
486 | dwc->edev_nb.notifier_call = dwc3_drd_notifier; |
487 | ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, | |
488 | &dwc->edev_nb); | |
489 | if (ret < 0) { | |
490 | dev_err(dwc->dev, "couldn't register cable notifier\n"); | |
491 | return ret; | |
492 | } | |
9840354f | 493 | |
f09cc79b RQ |
494 | dwc3_drd_update(dwc); |
495 | } else { | |
496 | dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG); | |
497 | dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG; | |
498 | ||
499 | /* use OTG block to get ID event */ | |
500 | irq = dwc3_otg_get_irq(dwc); | |
501 | if (irq < 0) | |
502 | return irq; | |
503 | ||
504 | dwc->otg_irq = irq; | |
505 | ||
506 | /* disable all OTG IRQs */ | |
507 | dwc3_otg_disable_events(dwc, DWC3_OTG_ALL_EVENTS); | |
508 | /* clear all events */ | |
509 | dwc3_otg_clear_events(dwc); | |
510 | ||
511 | ret = request_threaded_irq(dwc->otg_irq, dwc3_otg_irq, | |
512 | dwc3_otg_thread_irq, | |
513 | IRQF_SHARED, "dwc3-otg", dwc); | |
514 | if (ret) { | |
515 | dev_err(dwc->dev, "failed to request irq #%d --> %d\n", | |
516 | dwc->otg_irq, ret); | |
517 | ret = -ENODEV; | |
518 | return ret; | |
519 | } | |
520 | ||
521 | dwc3_otg_init(dwc); | |
522 | dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); | |
523 | } | |
9840354f RQ |
524 | |
525 | return 0; | |
526 | } | |
527 | ||
528 | void dwc3_drd_exit(struct dwc3 *dwc) | |
529 | { | |
f09cc79b RQ |
530 | unsigned long flags; |
531 | ||
532 | if (dwc->edev) | |
533 | extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, | |
534 | &dwc->edev_nb); | |
535 | ||
536 | cancel_work_sync(&dwc->drd_work); | |
537 | ||
538 | /* debug user might have changed role, clean based on current role */ | |
539 | switch (dwc->current_dr_role) { | |
540 | case DWC3_GCTL_PRTCAP_HOST: | |
541 | dwc3_host_exit(dwc); | |
542 | break; | |
543 | case DWC3_GCTL_PRTCAP_DEVICE: | |
544 | dwc3_gadget_exit(dwc); | |
545 | dwc3_event_buffers_cleanup(dwc); | |
546 | break; | |
547 | case DWC3_GCTL_PRTCAP_OTG: | |
548 | dwc3_otg_exit(dwc); | |
549 | spin_lock_irqsave(&dwc->lock, flags); | |
550 | dwc->desired_otg_role = DWC3_OTG_ROLE_IDLE; | |
551 | spin_unlock_irqrestore(&dwc->lock, flags); | |
552 | dwc3_otg_update(dwc, 1); | |
553 | break; | |
554 | default: | |
555 | break; | |
556 | } | |
9840354f | 557 | |
f09cc79b RQ |
558 | if (!dwc->edev) |
559 | free_irq(dwc->otg_irq, dwc); | |
9840354f | 560 | } |