xref: /netbsd-src/sys/external/bsd/dwc2/dist/dwc2_coreintr.c (revision 9ca2ac75a14ab1ff8bba93730037d264edb97a25)
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