1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#include <linux/kernel.h>
41#include <linux/module.h>
42#include <linux/moduleparam.h>
43#include <linux/spinlock.h>
44#include <linux/interrupt.h>
45#include <linux/dma-mapping.h>
46#include <linux/io.h>
47#include <linux/slab.h>
48#include <linux/usb.h>
49
50#include <linux/usb/hcd.h>
51#include <linux/usb/ch11.h>
52
53#include "core.h"
54#include "hcd.h"
55
56static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
57{
58#ifdef DEBUG
59 switch (hsotg->op_state) {
60 case OTG_STATE_A_HOST:
61 return "a_host";
62 case OTG_STATE_A_SUSPEND:
63 return "a_suspend";
64 case OTG_STATE_A_PERIPHERAL:
65 return "a_peripheral";
66 case OTG_STATE_B_PERIPHERAL:
67 return "b_peripheral";
68 case OTG_STATE_B_HOST:
69 return "b_host";
70 default:
71 return "unknown";
72 }
73#else
74 return "";
75#endif
76}
77
78
79
80
81
82
83static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
84{
85 dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
86 dwc2_is_host_mode(hsotg) ? "Host" : "Device");
87
88
89 writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
90}
91
92
93
94
95
96
97
98static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
99{
100 u32 gotgint;
101 u32 gotgctl;
102 u32 gintmsk;
103
104 gotgint = readl(hsotg->regs + GOTGINT);
105 gotgctl = readl(hsotg->regs + GOTGCTL);
106 dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
107 dwc2_op_state_str(hsotg));
108
109 if (gotgint & GOTGINT_SES_END_DET) {
110 dev_dbg(hsotg->dev,
111 " ++OTG Interrupt: Session End Detected++ (%s)\n",
112 dwc2_op_state_str(hsotg));
113 gotgctl = readl(hsotg->regs + GOTGCTL);
114
115 if (hsotg->op_state == OTG_STATE_B_HOST) {
116 hsotg->op_state = OTG_STATE_B_PERIPHERAL;
117 } else {
118
119
120
121
122 if (gotgctl & GOTGCTL_DEVHNPEN) {
123 dev_dbg(hsotg->dev, "Session End Detected\n");
124 dev_err(hsotg->dev,
125 "Device Not Connected/Responding!\n");
126 }
127
128
129
130
131
132
133 hsotg->lx_state = DWC2_L0;
134 }
135
136 gotgctl = readl(hsotg->regs + GOTGCTL);
137 gotgctl &= ~GOTGCTL_DEVHNPEN;
138 writel(gotgctl, hsotg->regs + GOTGCTL);
139 }
140
141 if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
142 dev_dbg(hsotg->dev,
143 " ++OTG Interrupt: Session Request Success Status Change++\n");
144 gotgctl = readl(hsotg->regs + GOTGCTL);
145 if (gotgctl & GOTGCTL_SESREQSCS) {
146 if (hsotg->core_params->phy_type ==
147 DWC2_PHY_TYPE_PARAM_FS
148 && hsotg->core_params->i2c_enable > 0) {
149 hsotg->srp_success = 1;
150 } else {
151
152 gotgctl = readl(hsotg->regs + GOTGCTL);
153 gotgctl &= ~GOTGCTL_SESREQ;
154 writel(gotgctl, hsotg->regs + GOTGCTL);
155 }
156 }
157 }
158
159 if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) {
160
161
162
163
164 gotgctl = readl(hsotg->regs + GOTGCTL);
165
166
167
168
169 if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)
170 udelay(100);
171 if (gotgctl & GOTGCTL_HSTNEGSCS) {
172 if (dwc2_is_host_mode(hsotg)) {
173 hsotg->op_state = OTG_STATE_B_HOST;
174
175
176
177
178
179
180
181
182
183
184 gintmsk = readl(hsotg->regs + GINTMSK);
185 gintmsk &= ~GINTSTS_SOF;
186 writel(gintmsk, hsotg->regs + GINTMSK);
187
188
189
190
191
192 spin_unlock(&hsotg->lock);
193
194
195 dwc2_hcd_start(hsotg);
196 spin_lock(&hsotg->lock);
197 hsotg->op_state = OTG_STATE_B_HOST;
198 }
199 } else {
200 gotgctl = readl(hsotg->regs + GOTGCTL);
201 gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
202 writel(gotgctl, hsotg->regs + GOTGCTL);
203 dev_dbg(hsotg->dev, "HNP Failed\n");
204 dev_err(hsotg->dev,
205 "Device Not Connected/Responding\n");
206 }
207 }
208
209 if (gotgint & GOTGINT_HST_NEG_DET) {
210
211
212
213
214
215
216 dev_dbg(hsotg->dev,
217 " ++OTG Interrupt: Host Negotiation Detected++ (%s)\n",
218 (dwc2_is_host_mode(hsotg) ? "Host" : "Device"));
219 if (dwc2_is_device_mode(hsotg)) {
220 dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
221 hsotg->op_state);
222 spin_unlock(&hsotg->lock);
223 dwc2_hcd_disconnect(hsotg);
224 spin_lock(&hsotg->lock);
225 hsotg->op_state = OTG_STATE_A_PERIPHERAL;
226 } else {
227
228 gintmsk = readl(hsotg->regs + GINTMSK);
229 gintmsk &= ~GINTSTS_SOF;
230 writel(gintmsk, hsotg->regs + GINTMSK);
231 spin_unlock(&hsotg->lock);
232 dwc2_hcd_start(hsotg);
233 spin_lock(&hsotg->lock);
234 hsotg->op_state = OTG_STATE_A_HOST;
235 }
236 }
237
238 if (gotgint & GOTGINT_A_DEV_TOUT_CHG)
239 dev_dbg(hsotg->dev,
240 " ++OTG Interrupt: A-Device Timeout Change++\n");
241 if (gotgint & GOTGINT_DBNCE_DONE)
242 dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
243
244
245 writel(gotgint, hsotg->regs + GOTGINT);
246}
247
248
249
250
251
252
253
254
255
256
257
258static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
259{
260 u32 gintmsk = readl(hsotg->regs + GINTMSK);
261
262
263 gintmsk &= ~GINTSTS_SOF;
264 writel(gintmsk, hsotg->regs + GINTMSK);
265
266 dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
267 dwc2_is_host_mode(hsotg) ? "Host" : "Device");
268
269
270
271
272
273
274 spin_unlock(&hsotg->lock);
275 queue_work(hsotg->wq_otg, &hsotg->wf_otg);
276 spin_lock(&hsotg->lock);
277
278
279 writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
280}
281
282
283
284
285
286
287
288
289
290
291
292
293static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
294{
295 dev_dbg(hsotg->dev, "++Session Request Interrupt++\n");
296
297
298 writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
299}
300
301
302
303
304
305
306
307
308static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
309{
310 dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
311 dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
312
313 if (dwc2_is_device_mode(hsotg)) {
314 dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS));
315 if (hsotg->lx_state == DWC2_L2) {
316 u32 dctl = readl(hsotg->regs + DCTL);
317
318
319 dctl &= ~DCTL_RMTWKUPSIG;
320 writel(dctl, hsotg->regs + DCTL);
321 }
322
323 hsotg->lx_state = DWC2_L0;
324 } else {
325 if (hsotg->lx_state != DWC2_L1) {
326 u32 pcgcctl = readl(hsotg->regs + PCGCTL);
327
328
329 pcgcctl &= ~PCGCTL_STOPPCLK;
330 writel(pcgcctl, hsotg->regs + PCGCTL);
331 mod_timer(&hsotg->wkp_timer,
332 jiffies + msecs_to_jiffies(71));
333 } else {
334
335 hsotg->lx_state = DWC2_L0;
336 }
337 }
338
339
340 writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
341}
342
343
344
345
346
347static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
348{
349 dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
350 dwc2_is_host_mode(hsotg) ? "Host" : "Device",
351 dwc2_op_state_str(hsotg));
352
353
354 hsotg->lx_state = DWC2_L3;
355
356 writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
357}
358
359
360
361
362
363
364
365
366
367static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
368{
369 u32 dsts;
370
371 dev_dbg(hsotg->dev, "USB SUSPEND\n");
372
373 if (dwc2_is_device_mode(hsotg)) {
374
375
376
377
378 dsts = readl(hsotg->regs + DSTS);
379 dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
380 dev_dbg(hsotg->dev,
381 "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
382 !!(dsts & DSTS_SUSPSTS),
383 hsotg->hw_params.power_optimized);
384 } else {
385 if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
386 dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
387
388
389 spin_unlock(&hsotg->lock);
390 dwc2_hcd_start(hsotg);
391 spin_lock(&hsotg->lock);
392 hsotg->op_state = OTG_STATE_A_HOST;
393 }
394 }
395
396
397 hsotg->lx_state = DWC2_L2;
398
399
400 writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
401}
402
403#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
404 GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT | \
405 GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \
406 GINTSTS_USBSUSP | GINTSTS_PRTINT)
407
408
409
410
411static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
412{
413 u32 gintsts;
414 u32 gintmsk;
415 u32 gahbcfg;
416 u32 gintmsk_common = GINTMSK_COMMON;
417
418 gintsts = readl(hsotg->regs + GINTSTS);
419 gintmsk = readl(hsotg->regs + GINTMSK);
420 gahbcfg = readl(hsotg->regs + GAHBCFG);
421
422#ifdef DEBUG
423
424 if (gintsts & gintmsk_common)
425 dev_dbg(hsotg->dev, "gintsts=%08x gintmsk=%08x\n",
426 gintsts, gintmsk);
427#endif
428
429 if (gahbcfg & GAHBCFG_GLBL_INTR_EN)
430 return gintsts & gintmsk & gintmsk_common;
431 else
432 return 0;
433}
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
449{
450 struct dwc2_hsotg *hsotg = dev;
451 u32 gintsts;
452 irqreturn_t retval = IRQ_NONE;
453
454 if (dwc2_check_core_status(hsotg) < 0) {
455 dev_warn(hsotg->dev, "Controller is disconnected\n");
456 goto out;
457 }
458
459 spin_lock(&hsotg->lock);
460
461 gintsts = dwc2_read_common_intr(hsotg);
462 if (gintsts & ~GINTSTS_PRTINT)
463 retval = IRQ_HANDLED;
464
465 if (gintsts & GINTSTS_MODEMIS)
466 dwc2_handle_mode_mismatch_intr(hsotg);
467 if (gintsts & GINTSTS_OTGINT)
468 dwc2_handle_otg_intr(hsotg);
469 if (gintsts & GINTSTS_CONIDSTSCHNG)
470 dwc2_handle_conn_id_status_change_intr(hsotg);
471 if (gintsts & GINTSTS_DISCONNINT)
472 dwc2_handle_disconnect_intr(hsotg);
473 if (gintsts & GINTSTS_SESSREQINT)
474 dwc2_handle_session_req_intr(hsotg);
475 if (gintsts & GINTSTS_WKUPINT)
476 dwc2_handle_wakeup_detected_intr(hsotg);
477 if (gintsts & GINTSTS_USBSUSP)
478 dwc2_handle_usb_suspend_intr(hsotg);
479
480 if (gintsts & GINTSTS_PRTINT) {
481
482
483
484
485 if (dwc2_is_device_mode(hsotg)) {
486 dev_dbg(hsotg->dev,
487 " --Port interrupt received in Device mode--\n");
488 gintsts = GINTSTS_PRTINT;
489 writel(gintsts, hsotg->regs + GINTSTS);
490 retval = 1;
491 }
492 }
493
494 spin_unlock(&hsotg->lock);
495out:
496 return retval;
497}
498EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
499