1 /*        $NetBSD: dwc2_coreintr.c,v 1.11 2016/02/24 22:17:54 skrll Exp $       */
2 
3 /*
4  * core_intr.c - DesignWare HS OTG Controller common interrupt handling
5  *
6  * Copyright (C) 2004-2013 Synopsys, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The names of the above-listed copyright holders may not be used
18  *    to endorse or promote products derived from this software without
19  *    specific prior written permission.
20  *
21  * ALTERNATIVELY, this software may be distributed under the terms of the
22  * GNU General Public License ("GPL") as published by the Free Software
23  * Foundation; either version 2 of the License, or (at your option) any
24  * later version.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
28  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
30  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * This file contains the common interrupt handlers
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: dwc2_coreintr.c,v 1.11 2016/02/24 22:17:54 skrll Exp $");
45 
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/mutex.h>
49 #include <sys/pool.h>
50 #include <sys/bus.h>
51 #include <sys/callout.h>
52 
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usbdi.h>
55 #include <dev/usb/usbdivar.h>
56 #include <dev/usb/usb_mem.h>
57 
58 #include <linux/kernel.h>
59 #include <linux/list.h>
60 #include <linux/err.h>
61 
62 #include <dwc2/dwc2.h>
63 #include <dwc2/dwc2var.h>
64 
65 #include "dwc2_core.h"
66 #include "dwc2_hcd.h"
67 
68 #ifdef DWC2_DEBUG
dwc2_op_state_str(struct dwc2_hsotg * hsotg)69 static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
70 {
71           switch (hsotg->op_state) {
72           case OTG_STATE_A_HOST:
73                     return "a_host";
74           case OTG_STATE_A_SUSPEND:
75                     return "a_suspend";
76           case OTG_STATE_A_PERIPHERAL:
77                     return "a_peripheral";
78           case OTG_STATE_B_PERIPHERAL:
79                     return "b_peripheral";
80           case OTG_STATE_B_HOST:
81                     return "b_host";
82           default:
83                     return "unknown";
84           }
85 }
86 #endif
87 
88 /**
89  * dwc2_handle_usb_port_intr - handles OTG PRTINT interrupts.
90  * When the PRTINT interrupt fires, there are certain status bits in the Host
91  * Port that needs to get cleared.
92  *
93  * @hsotg: Programming view of DWC_otg controller
94  */
dwc2_handle_usb_port_intr(struct dwc2_hsotg * hsotg)95 static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
96 {
97           u32 hprt0 = DWC2_READ_4(hsotg, HPRT0);
98 
99           if (hprt0 & HPRT0_ENACHG) {
100                     hprt0 &= ~HPRT0_ENA;
101                     DWC2_WRITE_4(hsotg, HPRT0, hprt0);
102           }
103 }
104 
105 /**
106  * dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message
107  *
108  * @hsotg: Programming view of DWC_otg controller
109  */
dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg * hsotg)110 static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
111 {
112           /* Clear interrupt */
113           DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_MODEMIS);
114 
115           dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
116                      dwc2_is_host_mode(hsotg) ? "Host" : "Device");
117 }
118 
119 /**
120  * dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG
121  * Interrupt Register (GOTGINT) to determine what interrupt has occurred.
122  *
123  * @hsotg: Programming view of DWC_otg controller
124  */
dwc2_handle_otg_intr(struct dwc2_hsotg * hsotg)125 static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
126 {
127           u32 gotgint;
128           u32 gotgctl;
129           u32 gintmsk;
130 
131           gotgint = DWC2_READ_4(hsotg, GOTGINT);
132           gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
133           dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
134                     dwc2_op_state_str(hsotg));
135 
136           if (gotgint & GOTGINT_SES_END_DET) {
137                     dev_dbg(hsotg->dev,
138                               " ++OTG Interrupt: Session End Detected++ (%s)\n",
139                               dwc2_op_state_str(hsotg));
140                     gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
141 
142                     if (dwc2_is_device_mode(hsotg))
143                               dwc2_hsotg_disconnect(hsotg);
144 
145                     if (hsotg->op_state == OTG_STATE_B_HOST) {
146                               hsotg->op_state = OTG_STATE_B_PERIPHERAL;
147                     } else {
148                               /*
149                                * If not B_HOST and Device HNP still set, HNP did
150                                * not succeed!
151                                */
152                               if (gotgctl & GOTGCTL_DEVHNPEN) {
153                                         dev_dbg(hsotg->dev, "Session End Detected\n");
154                                         dev_err(hsotg->dev,
155                                                   "Device Not Connected/Responding!\n");
156                               }
157 
158                               /*
159                                * If Session End Detected the B-Cable has been
160                                * disconnected
161                                */
162                               /* Reset to a clean state */
163                               hsotg->lx_state = DWC2_L0;
164                     }
165 
166                     gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
167                     gotgctl &= ~GOTGCTL_DEVHNPEN;
168                     DWC2_WRITE_4(hsotg, GOTGCTL, gotgctl);
169           }
170 
171           if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
172                     dev_dbg(hsotg->dev,
173                               " ++OTG Interrupt: Session Request Success Status Change++\n");
174                     gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
175                     if (gotgctl & GOTGCTL_SESREQSCS) {
176                               if (hsotg->core_params->phy_type ==
177                                                   DWC2_PHY_TYPE_PARAM_FS
178                                   && hsotg->core_params->i2c_enable > 0) {
179                                         hsotg->srp_success = 1;
180                               } else {
181                                         /* Clear Session Request */
182                                         gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
183                                         gotgctl &= ~GOTGCTL_SESREQ;
184                                         DWC2_WRITE_4(hsotg, GOTGCTL, gotgctl);
185                               }
186                     }
187           }
188 
189           if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) {
190                     /*
191                      * Print statements during the HNP interrupt handling
192                      * can cause it to fail
193                      */
194                     gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
195                     /*
196                      * WA for 3.00a- HW is not setting cur_mode, even sometimes
197                      * this does not help
198                      */
199                     if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)
200                               udelay(100);
201                     if (gotgctl & GOTGCTL_HSTNEGSCS) {
202                               if (dwc2_is_host_mode(hsotg)) {
203                                         hsotg->op_state = OTG_STATE_B_HOST;
204                                         /*
205                                          * Need to disable SOF interrupt immediately.
206                                          * When switching from device to host, the PCD
207                                          * interrupt handler won't handle the interrupt
208                                          * if host mode is already set. The HCD
209                                          * interrupt handler won't get called if the
210                                          * HCD state is HALT. This means that the
211                                          * interrupt does not get handled and Linux
212                                          * complains loudly.
213                                          */
214                                         gintmsk = DWC2_READ_4(hsotg, GINTMSK);
215                                         gintmsk &= ~GINTSTS_SOF;
216                                         DWC2_WRITE_4(hsotg, GINTMSK, gintmsk);
217 
218                                         /*
219                                          * Call callback function with spin lock
220                                          * released
221                                          */
222                                         spin_unlock(&hsotg->lock);
223 
224                                         /* Initialize the Core for Host mode */
225                                         dwc2_hcd_start(hsotg);
226                                         spin_lock(&hsotg->lock);
227                                         hsotg->op_state = OTG_STATE_B_HOST;
228                               }
229                     } else {
230                               gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
231                               gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
232                               DWC2_WRITE_4(hsotg, GOTGCTL, gotgctl);
233                               dev_dbg(hsotg->dev, "HNP Failed\n");
234                               dev_err(hsotg->dev,
235                                         "Device Not Connected/Responding\n");
236                     }
237           }
238 
239           if (gotgint & GOTGINT_HST_NEG_DET) {
240                     /*
241                      * The disconnect interrupt is set at the same time as
242                      * Host Negotiation Detected. During the mode switch all
243                      * interrupts are cleared so the disconnect interrupt
244                      * handler will not get executed.
245                      */
246                     dev_dbg(hsotg->dev,
247                               " ++OTG Interrupt: Host Negotiation Detected++ (%s)\n",
248                               (dwc2_is_host_mode(hsotg) ? "Host" : "Device"));
249                     if (dwc2_is_device_mode(hsotg)) {
250                               dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
251                                         hsotg->op_state);
252                               spin_unlock(&hsotg->lock);
253                               dwc2_hcd_disconnect(hsotg, false);
254                               spin_lock(&hsotg->lock);
255                               hsotg->op_state = OTG_STATE_A_PERIPHERAL;
256                     } else {
257                               /* Need to disable SOF interrupt immediately */
258                               gintmsk = DWC2_READ_4(hsotg, GINTMSK);
259                               gintmsk &= ~GINTSTS_SOF;
260                               DWC2_WRITE_4(hsotg, GINTMSK, gintmsk);
261                               spin_unlock(&hsotg->lock);
262                               dwc2_hcd_start(hsotg);
263                               spin_lock(&hsotg->lock);
264                               hsotg->op_state = OTG_STATE_A_HOST;
265                     }
266           }
267 
268           if (gotgint & GOTGINT_A_DEV_TOUT_CHG)
269                     dev_dbg(hsotg->dev,
270                               " ++OTG Interrupt: A-Device Timeout Change++\n");
271           if (gotgint & GOTGINT_DBNCE_DONE)
272                     dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
273 
274           /* Clear GOTGINT */
275           DWC2_WRITE_4(hsotg, GOTGINT, gotgint);
276 }
277 
278 /**
279  * dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status
280  * Change Interrupt
281  *
282  * @hsotg: Programming view of DWC_otg controller
283  *
284  * Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a
285  * Device to Host Mode transition or a Host to Device Mode transition. This only
286  * occurs when the cable is connected/removed from the PHY connector.
287  */
dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg * hsotg)288 static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
289 {
290           u32 gintmsk;
291 
292           /* Clear interrupt */
293           DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_CONIDSTSCHNG);
294 
295           /* Need to disable SOF interrupt immediately */
296           gintmsk = DWC2_READ_4(hsotg, GINTMSK);
297           gintmsk &= ~GINTSTS_SOF;
298           DWC2_WRITE_4(hsotg, GINTMSK, gintmsk);
299 
300           dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++  (%s)\n",
301                     dwc2_is_host_mode(hsotg) ? "Host" : "Device");
302 
303           /*
304            * Need to schedule a work, as there are possible DELAY function calls.
305            * Release lock before scheduling workq as it holds spinlock during
306            * scheduling.
307            */
308           if (hsotg->wq_otg) {
309                     spin_unlock(&hsotg->lock);
310                     queue_work(hsotg->wq_otg, &hsotg->wf_otg);
311                     spin_lock(&hsotg->lock);
312           }
313 }
314 
315 /**
316  * dwc2_handle_session_req_intr() - This interrupt indicates that a device is
317  * initiating the Session Request Protocol to request the host to turn on bus
318  * power so a new session can begin
319  *
320  * @hsotg: Programming view of DWC_otg controller
321  *
322  * This handler responds by turning on bus power. If the DWC_otg controller is
323  * in low power mode, this handler brings the controller out of low power mode
324  * before turning on bus power.
325  */
dwc2_handle_session_req_intr(struct dwc2_hsotg * hsotg)326 static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
327 {
328           int ret;
329 
330           /* Clear interrupt */
331           DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_SESSREQINT);
332 
333           dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
334                                                                       hsotg->lx_state);
335 
336           if (dwc2_is_device_mode(hsotg)) {
337                     if (hsotg->lx_state == DWC2_L2) {
338                               ret = dwc2_exit_hibernation(hsotg, true);
339                               if (ret && (ret != -ENOTSUPP))
340                                         dev_err(hsotg->dev,
341                                                   "exit hibernation failed\n");
342                     }
343 
344                     /*
345                      * Report disconnect if there is any previous session
346                      * established
347                      */
348                     dwc2_hsotg_disconnect(hsotg);
349           }
350 }
351 
352 /*
353  * This interrupt indicates that the DWC_otg controller has detected a
354  * resume or remote wakeup sequence. If the DWC_otg controller is in
355  * low power mode, the handler must brings the controller out of low
356  * power mode. The controller automatically begins resume signaling.
357  * The handler schedules a time to stop resume signaling.
358  */
dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg * hsotg)359 static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
360 {
361           int ret;
362 
363           /* Clear interrupt */
364           DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_WKUPINT);
365 
366           dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
367           dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
368 
369           if (dwc2_is_device_mode(hsotg)) {
370                     dev_dbg(hsotg->dev, "DSTS=0x%0x\n", DWC2_READ_4(hsotg, DSTS));
371                     if (hsotg->lx_state == DWC2_L2) {
372                               u32 dctl = DWC2_READ_4(hsotg, DCTL);
373 
374                               /* Clear Remote Wakeup Signaling */
375                               dctl &= ~DCTL_RMTWKUPSIG;
376                               DWC2_WRITE_4(hsotg, DCTL, dctl);
377                               ret = dwc2_exit_hibernation(hsotg, true);
378                               if (ret && (ret != -ENOTSUPP))
379                                         dev_err(hsotg->dev, "exit hibernation failed\n");
380 
381                               call_gadget(hsotg, resume);
382                     }
383                     /* Change to L0 state */
384                     hsotg->lx_state = DWC2_L0;
385           } else {
386                     if (hsotg->core_params->hibernation)
387                               return;
388 
389                     if (hsotg->lx_state != DWC2_L1) {
390                               u32 pcgcctl = DWC2_READ_4(hsotg, PCGCTL);
391 
392                               /* Restart the Phy Clock */
393                               pcgcctl &= ~PCGCTL_STOPPCLK;
394                               DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
395                               callout_reset(&hsotg->wkp_timer, mstohz(71),
396                                   dwc2_wakeup_detected, hsotg);
397                     } else {
398                               /* Change to L0 state */
399                               hsotg->lx_state = DWC2_L0;
400                     }
401           }
402 }
403 
404 /*
405  * This interrupt indicates that a device has been disconnected from the
406  * root port
407  */
dwc2_handle_disconnect_intr(struct dwc2_hsotg * hsotg)408 static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
409 {
410           DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_DISCONNINT);
411 
412           dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
413                     dwc2_is_host_mode(hsotg) ? "Host" : "Device",
414                     dwc2_op_state_str(hsotg));
415 
416           if (hsotg->op_state == OTG_STATE_A_HOST)
417                     dwc2_hcd_disconnect(hsotg, false);
418 }
419 
420 /*
421  * This interrupt indicates that SUSPEND state has been detected on the USB.
422  *
423  * For HNP the USB Suspend interrupt signals the change from "a_peripheral"
424  * to "a_host".
425  *
426  * When power management is enabled the core will be put in low power mode.
427  */
dwc2_handle_usb_suspend_intr(struct dwc2_hsotg * hsotg)428 static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
429 {
430           u32 dsts;
431           int ret;
432 
433           /* Clear interrupt */
434           DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_USBSUSP);
435 
436           dev_dbg(hsotg->dev, "USB SUSPEND\n");
437 
438           if (dwc2_is_device_mode(hsotg)) {
439                     /*
440                      * Check the Device status register to determine if the Suspend
441                      * state is active
442                      */
443                     dsts = DWC2_READ_4(hsotg, DSTS);
444                     dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
445                     dev_dbg(hsotg->dev,
446                               "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
447                               !!(dsts & DSTS_SUSPSTS),
448                               hsotg->hw_params.power_optimized);
449                     if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
450                               /* Ignore suspend request before enumeration */
451                               if (!dwc2_is_device_connected(hsotg)) {
452                                         dev_dbg(hsotg->dev,
453                                                             "ignore suspend request before enumeration\n");
454                                         return;
455                               }
456 
457                               ret = dwc2_enter_hibernation(hsotg);
458                               if (ret) {
459                                         if (ret != -ENOTSUPP)
460                                                   dev_err(hsotg->dev,
461                                                                       "enter hibernation failed\n");
462                                         goto skip_power_saving;
463                               }
464 
465                               udelay(100);
466 
467                               /* Ask phy to be suspended */
468                               if (!IS_ERR_OR_NULL(hsotg->uphy))
469                                         usb_phy_set_suspend(hsotg->uphy, true);
470 skip_power_saving:
471                               /*
472                                * Change to L2 (suspend) state before releasing
473                                * spinlock
474                                */
475                               hsotg->lx_state = DWC2_L2;
476 
477                               /* Call gadget suspend callback */
478                               call_gadget(hsotg, suspend);
479                     }
480           } else {
481                     if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
482                               dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
483 
484                               /* Change to L2 (suspend) state */
485                               hsotg->lx_state = DWC2_L2;
486                               /* Clear the a_peripheral flag, back to a_host */
487                               spin_unlock(&hsotg->lock);
488                               dwc2_hcd_start(hsotg);
489                               spin_lock(&hsotg->lock);
490                               hsotg->op_state = OTG_STATE_A_HOST;
491                     }
492           }
493 }
494 
495 #define GINTMSK_COMMON        (GINTSTS_WKUPINT | GINTSTS_SESSREQINT |           \
496                                GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT |          \
497                                GINTSTS_MODEMIS | GINTSTS_DISCONNINT |           \
498                                GINTSTS_USBSUSP | GINTSTS_PRTINT)
499 
500 /*
501  * This function returns the Core Interrupt register
502  */
dwc2_read_common_intr(struct dwc2_hsotg * hsotg)503 static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
504 {
505           u32 gintsts;
506           u32 gintmsk;
507           u32 gahbcfg;
508           u32 gintmsk_common = GINTMSK_COMMON;
509 
510           gintsts = DWC2_READ_4(hsotg, GINTSTS);
511           gintmsk = DWC2_READ_4(hsotg, GINTMSK);
512           gahbcfg = DWC2_READ_4(hsotg, GAHBCFG);
513 
514           /* If any common interrupts set */
515           if (gintsts & gintmsk_common)
516                     dev_dbg(hsotg->dev, "gintsts=%08x  gintmsk=%08x\n",
517                               gintsts, gintmsk);
518 
519           if (gahbcfg & GAHBCFG_GLBL_INTR_EN)
520                     return gintsts & gintmsk & gintmsk_common;
521           else
522                     return 0;
523 }
524 
525 /*
526  * Common interrupt handler
527  *
528  * The common interrupts are those that occur in both Host and Device mode.
529  * This handler handles the following interrupts:
530  * - Mode Mismatch Interrupt
531  * - OTG Interrupt
532  * - Connector ID Status Change Interrupt
533  * - Disconnect Interrupt
534  * - Session Request Interrupt
535  * - Resume / Remote Wakeup Detected Interrupt
536  * - Suspend Interrupt
537  */
dwc2_handle_common_intr(void * dev)538 irqreturn_t dwc2_handle_common_intr(void *dev)
539 {
540           struct dwc2_hsotg *hsotg = dev;
541           u32 gintsts;
542           irqreturn_t retval = IRQ_NONE;
543 
544           if (!dwc2_is_controller_alive(hsotg)) {
545                     dev_warn(hsotg->dev, "Controller is dead\n");
546                     goto out;
547           }
548 
549           KASSERT(mutex_owned(&hsotg->lock));
550 
551           gintsts = dwc2_read_common_intr(hsotg);
552           if (gintsts & ~GINTSTS_PRTINT)
553                     retval = IRQ_HANDLED;
554 
555           if (gintsts & GINTSTS_MODEMIS)
556                     dwc2_handle_mode_mismatch_intr(hsotg);
557           if (gintsts & GINTSTS_OTGINT)
558                     dwc2_handle_otg_intr(hsotg);
559           if (gintsts & GINTSTS_CONIDSTSCHNG)
560                     dwc2_handle_conn_id_status_change_intr(hsotg);
561           if (gintsts & GINTSTS_DISCONNINT)
562                     dwc2_handle_disconnect_intr(hsotg);
563           if (gintsts & GINTSTS_SESSREQINT)
564                     dwc2_handle_session_req_intr(hsotg);
565           if (gintsts & GINTSTS_WKUPINT)
566                     dwc2_handle_wakeup_detected_intr(hsotg);
567           if (gintsts & GINTSTS_USBSUSP)
568                     dwc2_handle_usb_suspend_intr(hsotg);
569 
570           if (gintsts & GINTSTS_PRTINT) {
571                     /*
572                      * The port interrupt occurs while in device mode with HPRT0
573                      * Port Enable/Disable
574                      */
575                     if (dwc2_is_device_mode(hsotg)) {
576                               dev_dbg(hsotg->dev,
577                                         " --Port interrupt received in Device mode--\n");
578                               dwc2_handle_usb_port_intr(hsotg);
579                               retval = IRQ_HANDLED;
580                     }
581           }
582 
583 out:
584           return retval;
585 }
586