Skip to content

Commit b94b631

Browse files
Xu Yanggregkh
authored andcommitted
usb: chipidea: core: allow ci_irq_handler() handle both ID and VBUS change
For USB role switch-triggered IRQ, ID and VBUS change come together, for example when switching from host to device mode. ID indicate a role switch and VBUS is required to determine whether the device controller can start operating. Currently, ci_irq_handler() handles only a single event per invocation. This can cause an issue where switching to device mode results in the device controller not working at all. Allowing ci_irq_handler() to handle both ID and VBUS change in one call resolves this issue. Meanwhile, this change also affects the VBUS event handling logic. Previously, if an ID event indicated host mode the VBUS IRQ will be ignored as the device disable BSE when stop() is called. With the new behavior, if ID and VBUS IRQ occur together and the target mode is host, the VBUS event is queued and ci_handle_vbus_change() will call usb_gadget_vbus_connect(), after which USBMODE is switched to device mode, causing host mode to stop working. To prevent this, an additional check is added to skip handling VBUS event when current role is not device mode. Suggested-by: Peter Chen <peter.chen@kernel.org> Fixes: e1b5d2b ("usb: chipidea: core: handle usb role switch in a common way") Cc: stable@vger.kernel.org Signed-off-by: Xu Yang <xu.yang_2@nxp.com> Link: https://patch.msgid.link/20260402071457.2516021-2-xu.yang_2@nxp.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent abad793 commit b94b631

2 files changed

Lines changed: 26 additions & 22 deletions

File tree

drivers/usb/chipidea/core.c

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -544,30 +544,31 @@ static irqreturn_t ci_irq_handler(int irq, void *data)
544544
if (ret == IRQ_HANDLED)
545545
return ret;
546546
}
547-
}
548547

549-
/*
550-
* Handle id change interrupt, it indicates device/host function
551-
* switch.
552-
*/
553-
if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
554-
ci->id_event = true;
555-
/* Clear ID change irq status */
556-
hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
557-
ci_otg_queue_work(ci);
558-
return IRQ_HANDLED;
559-
}
548+
/*
549+
* Handle id change interrupt, it indicates device/host function
550+
* switch.
551+
*/
552+
if ((otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
553+
ci->id_event = true;
554+
/* Clear ID change irq status */
555+
hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
556+
}
560557

561-
/*
562-
* Handle vbus change interrupt, it indicates device connection
563-
* and disconnection events.
564-
*/
565-
if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
566-
ci->b_sess_valid_event = true;
567-
/* Clear BSV irq */
568-
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
569-
ci_otg_queue_work(ci);
570-
return IRQ_HANDLED;
558+
/*
559+
* Handle vbus change interrupt, it indicates device connection
560+
* and disconnection events.
561+
*/
562+
if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
563+
ci->b_sess_valid_event = true;
564+
/* Clear BSV irq */
565+
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
566+
}
567+
568+
if (ci->id_event || ci->b_sess_valid_event) {
569+
ci_otg_queue_work(ci);
570+
return IRQ_HANDLED;
571+
}
571572
}
572573

573574
/* Handle device/host interrupt */

drivers/usb/chipidea/otg.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci)
130130

131131
void ci_handle_vbus_change(struct ci_hdrc *ci)
132132
{
133+
if (ci->role != CI_ROLE_GADGET)
134+
return;
135+
133136
if (!ci->is_otg) {
134137
if (ci->platdata->flags & CI_HDRC_FORCE_VBUS_ACTIVE_ALWAYS)
135138
usb_gadget_vbus_connect(&ci->gadget);

0 commit comments

Comments
 (0)