Skip to content

Commit e3a0ebd

Browse files
Xu Yanggregkh
authored andcommitted
usb: chipidea: core: allow ci_irq_handler() handle both ID and VBUS change
commit b94b631 upstream. 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 82d0507 commit e3a0ebd

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
@@ -543,30 +543,31 @@ static irqreturn_t ci_irq_handler(int irq, void *data)
543543
if (ret == IRQ_HANDLED)
544544
return ret;
545545
}
546-
}
547546

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

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

572573
/* 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)