[PATCH v2 3/3] usb: dwc2: Handle OTG interrupts that GINTSTS does not flag
From: Joseph Telaak via B4 Relay
Date: Wed Nov 11 2026 - 03:29:48 EST
From: Chuanhong Guo <gch981213@xxxxxxxxx>
The DWC OTG 3.30a of the Siflower SF19A2890 has battery charger support
enabled. It raises the MultValIpChng interrupt (bit 20 of GOTGINT)
without setting OTGInt in GINTSTS, so the interrupt is never handled
and the kernel disables the USB interrupt because nobody cared.
On a GL.iNet GL-SFT1200 it shows differently: after a few replugs of a
USB stick the system stops making progress, the console repeating its
last message with the same timestamp, until a power cycle.
Add an otg_int_unflagged parameter for such cores. With it set, the
common interrupt handler also reads GOTGINT on every interrupt and
handles any OTG interrupt it finds there, as it does when OTGInt is
set. The SF19A2890 sets it; other cores are unchanged.
Signed-off-by: Chuanhong Guo <gch981213@xxxxxxxxx>
[Joseph Telaak:
- handle the unflagged OTG interrupts only on cores with the new
otg_int_unflagged parameter, which the SF19A2890 sets
- do it in the one place that already handles flagged OTG
interrupts, and return IRQ_HANDLED
- describe what a GL-SFT1200 does without the patch, and the fix as
it is now
- subject]
Co-developed-by: Joseph Telaak <joseph@xxxxxxxxxx>
Signed-off-by: Joseph Telaak <joseph@xxxxxxxxxx>
---
drivers/usb/dwc2/core.h | 6 ++++++
drivers/usb/dwc2/core_intr.c | 5 ++++-
drivers/usb/dwc2/params.c | 1 +
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 015a5fb7842d..288baaaf4736 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -367,6 +367,11 @@ enum dwc2_ep0_state {
* @no_clock_gating: Specifies whether to avoid clock gating feature.
* 0 - No (use clock gating)
* 1 - Yes (avoid it)
+ * @otg_int_unflagged: Specifies whether the core raises OTG interrupts
+ * without setting OTGINT in GINTSTS, so that GOTGINT
+ * has to be checked on every interrupt.
+ * 0 - No
+ * 1 - Yes
* @lpm: Enable LPM support.
* 0 - No
* 1 - Yes
@@ -466,6 +471,7 @@ struct dwc2_core_params {
#define DWC2_POWER_DOWN_PARAM_PARTIAL 1
#define DWC2_POWER_DOWN_PARAM_HIBERNATION 2
bool no_clock_gating;
+ bool otg_int_unflagged;
bool lpm;
bool lpm_clock_gating;
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index 9565e6a52725..e7bb9709c985 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -874,8 +874,11 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
if (gintsts & GINTSTS_MODEMIS)
dwc2_handle_mode_mismatch_intr(hsotg);
- if (gintsts & GINTSTS_OTGINT)
+ if ((gintsts & GINTSTS_OTGINT) ||
+ (hsotg->params.otg_int_unflagged && dwc2_readl(hsotg, GOTGINT))) {
dwc2_handle_otg_intr(hsotg);
+ retval = IRQ_HANDLED;
+ }
if (gintsts & GINTSTS_CONIDSTSCHNG)
dwc2_handle_conn_id_status_change_intr(hsotg);
if (gintsts & GINTSTS_DISCONNINT)
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index b31fa1f5ad64..8e814a925dd1 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -243,6 +243,7 @@ static void dwc2_set_sf19a2890_params(struct dwc2_hsotg *hsotg)
p->max_transfer_size = 65535;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT;
+ p->otg_int_unflagged = true;
}
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
--
Git-155)