]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 Jul 2025 08:47:26 +0000 (10:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 Jul 2025 08:47:26 +0000 (10:47 +0200)
added patches:
usb-dwc3-qcom-don-t-leave-bcr-asserted.patch
usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch
usb-musb-fix-gadget-state-on-disconnect.patch

queue-5.10/series
queue-5.10/usb-dwc3-qcom-don-t-leave-bcr-asserted.patch [new file with mode: 0644]
queue-5.10/usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch [new file with mode: 0644]
queue-5.10/usb-musb-fix-gadget-state-on-disconnect.patch [new file with mode: 0644]

index b23b232684fd5e0dbf640e1ba6b601a1f595c72a..00656f27000da90f736a0c1f0cdfc2adbb6ac9ae 100644 (file)
@@ -45,3 +45,6 @@ net-sched-return-null-when-htb_lookup_leaf-encounter.patch
 usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch
 usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch
 usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch
+usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch
+usb-musb-fix-gadget-state-on-disconnect.patch
+usb-dwc3-qcom-don-t-leave-bcr-asserted.patch
diff --git a/queue-5.10/usb-dwc3-qcom-don-t-leave-bcr-asserted.patch b/queue-5.10/usb-dwc3-qcom-don-t-leave-bcr-asserted.patch
new file mode 100644 (file)
index 0000000..a74275c
--- /dev/null
@@ -0,0 +1,65 @@
+From ef8abc0ba49ce717e6bc4124e88e59982671f3b5 Mon Sep 17 00:00:00 2001
+From: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
+Date: Wed, 9 Jul 2025 18:59:00 +0530
+Subject: usb: dwc3: qcom: Don't leave BCR asserted
+
+From: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
+
+commit ef8abc0ba49ce717e6bc4124e88e59982671f3b5 upstream.
+
+Leaving the USB BCR asserted prevents the associated GDSC to turn on. This
+blocks any subsequent attempts of probing the device, e.g. after a probe
+deferral, with the following showing in the log:
+
+[    1.332226] usb30_prim_gdsc status stuck at 'off'
+
+Leave the BCR deasserted when exiting the driver to avoid this issue.
+
+Cc: stable <stable@kernel.org>
+Fixes: a4333c3a6ba9 ("usb: dwc3: Add Qualcomm DWC3 glue driver")
+Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
+Signed-off-by: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20250709132900.3408752-1-krishna.kurapati@oss.qualcomm.com
+[ adapted to individual clock management API instead of bulk clock operations ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc3/dwc3-qcom.c |    7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/dwc3/dwc3-qcom.c
++++ b/drivers/usb/dwc3/dwc3-qcom.c
+@@ -786,13 +786,13 @@ static int dwc3_qcom_probe(struct platfo
+       ret = reset_control_deassert(qcom->resets);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
+-              goto reset_assert;
++              return ret;
+       }
+       ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
+       if (ret) {
+               dev_err(dev, "failed to get clocks\n");
+-              goto reset_assert;
++              return ret;
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -892,8 +892,6 @@ clk_disable:
+               clk_disable_unprepare(qcom->clks[i]);
+               clk_put(qcom->clks[i]);
+       }
+-reset_assert:
+-      reset_control_assert(qcom->resets);
+       return ret;
+ }
+@@ -921,7 +919,6 @@ static int dwc3_qcom_remove(struct platf
+       qcom->num_clocks = 0;
+       dwc3_qcom_interconnect_exit(qcom);
+-      reset_control_assert(qcom->resets);
+       pm_runtime_allow(dev);
+       pm_runtime_disable(dev);
diff --git a/queue-5.10/usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch b/queue-5.10/usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch
new file mode 100644 (file)
index 0000000..ed0f4e2
--- /dev/null
@@ -0,0 +1,532 @@
+From 21acc656a06e912341d9db66c67b58cc7ed071e7 Mon Sep 17 00:00:00 2001
+From: Paul Cercueil <paul@crapouillou.net>
+Date: Wed, 26 Oct 2022 19:26:51 +0100
+Subject: usb: musb: Add and use inline functions musb_{get,set}_state
+
+From: Paul Cercueil <paul@crapouillou.net>
+
+commit 21acc656a06e912341d9db66c67b58cc7ed071e7 upstream.
+
+Instead of manipulating musb->xceiv->otg->state directly, use the newly
+introduced musb_get_state() and musb_set_state() inline functions.
+
+Later, these inline functions will be modified to get rid of the
+musb->xceiv dependency, which prevents the musb code from using the
+generic PHY subsystem.
+
+Signed-off-by: Paul Cercueil <paul@crapouillou.net>
+Link: https://lore.kernel.org/r/20221026182657.146630-2-paul@crapouillou.net
+Stable-dep-of: 67a59f82196c ("usb: musb: fix gadget state on disconnect")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/musb/musb_core.c    |   62 ++++++++++++++++++++--------------------
+ drivers/usb/musb/musb_core.h    |   11 +++++++
+ drivers/usb/musb/musb_debugfs.c |    6 +--
+ drivers/usb/musb/musb_gadget.c  |   28 +++++++++---------
+ drivers/usb/musb/musb_host.c    |    6 +--
+ drivers/usb/musb/musb_virthub.c |   18 +++++------
+ 6 files changed, 71 insertions(+), 60 deletions(-)
+
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -501,7 +501,7 @@ int musb_set_host(struct musb *musb)
+ init_data:
+       musb->is_active = 1;
+-      musb->xceiv->otg->state = OTG_STATE_A_IDLE;
++      musb_set_state(musb, OTG_STATE_A_IDLE);
+       MUSB_HST_MODE(musb);
+       return error;
+@@ -548,7 +548,7 @@ int musb_set_peripheral(struct musb *mus
+ init_data:
+       musb->is_active = 0;
+-      musb->xceiv->otg->state = OTG_STATE_B_IDLE;
++      musb_set_state(musb, OTG_STATE_B_IDLE);
+       MUSB_DEV_MODE(musb);
+       return error;
+@@ -598,12 +598,12 @@ static void musb_otg_timer_func(struct t
+       unsigned long   flags;
+       spin_lock_irqsave(&musb->lock, flags);
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_B_WAIT_ACON:
+               musb_dbg(musb,
+                       "HNP: b_wait_acon timeout; back to b_peripheral");
+               musb_g_disconnect(musb);
+-              musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++              musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+               musb->is_active = 0;
+               break;
+       case OTG_STATE_A_SUSPEND:
+@@ -611,7 +611,7 @@ static void musb_otg_timer_func(struct t
+               musb_dbg(musb, "HNP: %s timeout",
+                       usb_otg_state_string(musb->xceiv->otg->state));
+               musb_platform_set_vbus(musb, 0);
+-              musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
++              musb_set_state(musb, OTG_STATE_A_WAIT_VFALL);
+               break;
+       default:
+               musb_dbg(musb, "HNP: Unhandled mode %s",
+@@ -632,7 +632,7 @@ void musb_hnp_stop(struct musb *musb)
+       musb_dbg(musb, "HNP: stop from %s",
+                       usb_otg_state_string(musb->xceiv->otg->state));
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_A_PERIPHERAL:
+               musb_g_disconnect(musb);
+               musb_dbg(musb, "HNP: back to %s",
+@@ -642,7 +642,7 @@ void musb_hnp_stop(struct musb *musb)
+               musb_dbg(musb, "HNP: Disabling HR");
+               if (hcd)
+                       hcd->self.is_b_host = 0;
+-              musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++              musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+               MUSB_DEV_MODE(musb);
+               reg = musb_readb(mbase, MUSB_POWER);
+               reg |= MUSB_POWER_SUSPENDM;
+@@ -670,7 +670,7 @@ static void musb_handle_intr_resume(stru
+                       usb_otg_state_string(musb->xceiv->otg->state));
+       if (devctl & MUSB_DEVCTL_HM) {
+-              switch (musb->xceiv->otg->state) {
++              switch (musb_get_state(musb)) {
+               case OTG_STATE_A_SUSPEND:
+                       /* remote wakeup? */
+                       musb->port1_status |=
+@@ -678,14 +678,14 @@ static void musb_handle_intr_resume(stru
+                                       | MUSB_PORT_STAT_RESUME;
+                       musb->rh_timer = jiffies
+                               + msecs_to_jiffies(USB_RESUME_TIMEOUT);
+-                      musb->xceiv->otg->state = OTG_STATE_A_HOST;
++                      musb_set_state(musb, OTG_STATE_A_HOST);
+                       musb->is_active = 1;
+                       musb_host_resume_root_hub(musb);
+                       schedule_delayed_work(&musb->finish_resume_work,
+                               msecs_to_jiffies(USB_RESUME_TIMEOUT));
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+-                      musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++                      musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+                       musb->is_active = 1;
+                       MUSB_DEV_MODE(musb);
+                       break;
+@@ -695,10 +695,10 @@ static void musb_handle_intr_resume(stru
+                               usb_otg_state_string(musb->xceiv->otg->state));
+               }
+       } else {
+-              switch (musb->xceiv->otg->state) {
++              switch (musb_get_state(musb)) {
+               case OTG_STATE_A_SUSPEND:
+                       /* possibly DISCONNECT is upcoming */
+-                      musb->xceiv->otg->state = OTG_STATE_A_HOST;
++                      musb_set_state(musb, OTG_STATE_A_HOST);
+                       musb_host_resume_root_hub(musb);
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+@@ -749,7 +749,7 @@ static irqreturn_t musb_handle_intr_sess
+        */
+       musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+       musb->ep0_stage = MUSB_EP0_START;
+-      musb->xceiv->otg->state = OTG_STATE_A_IDLE;
++      musb_set_state(musb, OTG_STATE_A_IDLE);
+       MUSB_HST_MODE(musb);
+       musb_platform_set_vbus(musb, 1);
+@@ -776,7 +776,7 @@ static void musb_handle_intr_vbuserr(str
+        * REVISIT:  do delays from lots of DEBUG_KERNEL checks
+        * make trouble here, keeping VBUS < 4.4V ?
+        */
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_A_HOST:
+               /* recovery is dicey once we've gotten past the
+                * initial stages of enumeration, but if VBUS
+@@ -832,7 +832,7 @@ static void musb_handle_intr_suspend(str
+       musb_dbg(musb, "SUSPEND (%s) devctl %02x",
+               usb_otg_state_string(musb->xceiv->otg->state), devctl);
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_A_PERIPHERAL:
+               /* We also come here if the cable is removed, since
+                * this silicon doesn't report ID-no-longer-grounded.
+@@ -857,7 +857,7 @@ static void musb_handle_intr_suspend(str
+               musb_g_suspend(musb);
+               musb->is_active = musb->g.b_hnp_enable;
+               if (musb->is_active) {
+-                      musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
++                      musb_set_state(musb, OTG_STATE_B_WAIT_ACON);
+                       musb_dbg(musb, "HNP: Setting timer for b_ase0_brst");
+                       mod_timer(&musb->otg_timer, jiffies
+                               + msecs_to_jiffies(
+@@ -870,7 +870,7 @@ static void musb_handle_intr_suspend(str
+                               + msecs_to_jiffies(musb->a_wait_bcon));
+               break;
+       case OTG_STATE_A_HOST:
+-              musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
++              musb_set_state(musb, OTG_STATE_A_SUSPEND);
+               musb->is_active = musb->hcd->self.b_hnp_enable;
+               break;
+       case OTG_STATE_B_HOST:
+@@ -908,7 +908,7 @@ static void musb_handle_intr_connect(str
+               musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+       /* indicate new connection to OTG machine */
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_B_PERIPHERAL:
+               if (int_usb & MUSB_INTR_SUSPEND) {
+                       musb_dbg(musb, "HNP: SUSPEND+CONNECT, now b_host");
+@@ -920,7 +920,7 @@ static void musb_handle_intr_connect(str
+       case OTG_STATE_B_WAIT_ACON:
+               musb_dbg(musb, "HNP: CONNECT, now b_host");
+ b_host:
+-              musb->xceiv->otg->state = OTG_STATE_B_HOST;
++              musb_set_state(musb, OTG_STATE_B_HOST);
+               if (musb->hcd)
+                       musb->hcd->self.is_b_host = 1;
+               del_timer(&musb->otg_timer);
+@@ -928,7 +928,7 @@ b_host:
+       default:
+               if ((devctl & MUSB_DEVCTL_VBUS)
+                               == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
+-                      musb->xceiv->otg->state = OTG_STATE_A_HOST;
++                      musb_set_state(musb, OTG_STATE_A_HOST);
+                       if (hcd)
+                               hcd->self.is_b_host = 0;
+               }
+@@ -947,7 +947,7 @@ static void musb_handle_intr_disconnect(
+                       usb_otg_state_string(musb->xceiv->otg->state),
+                       MUSB_MODE(musb), devctl);
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_SUSPEND:
+               musb_host_resume_root_hub(musb);
+@@ -965,7 +965,7 @@ static void musb_handle_intr_disconnect(
+               musb_root_disconnect(musb);
+               if (musb->hcd)
+                       musb->hcd->self.is_b_host = 0;
+-              musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++              musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+               MUSB_DEV_MODE(musb);
+               musb_g_disconnect(musb);
+               break;
+@@ -1005,7 +1005,7 @@ static void musb_handle_intr_reset(struc
+       } else {
+               musb_dbg(musb, "BUS RESET as %s",
+                       usb_otg_state_string(musb->xceiv->otg->state));
+-              switch (musb->xceiv->otg->state) {
++              switch (musb_get_state(musb)) {
+               case OTG_STATE_A_SUSPEND:
+                       musb_g_reset(musb);
+                       fallthrough;
+@@ -1024,11 +1024,11 @@ static void musb_handle_intr_reset(struc
+               case OTG_STATE_B_WAIT_ACON:
+                       musb_dbg(musb, "HNP: RESET (%s), to b_peripheral",
+                               usb_otg_state_string(musb->xceiv->otg->state));
+-                      musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++                      musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+                       musb_g_reset(musb);
+                       break;
+               case OTG_STATE_B_IDLE:
+-                      musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++                      musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+                       fallthrough;
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_reset(musb);
+@@ -1215,8 +1215,8 @@ void musb_start(struct musb *musb)
+        * (c) peripheral initiates, using SRP
+        */
+       if (musb->port_mode != MUSB_HOST &&
+-                      musb->xceiv->otg->state != OTG_STATE_A_WAIT_BCON &&
+-                      (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
++          musb_get_state(musb) != OTG_STATE_A_WAIT_BCON &&
++          (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) {
+               musb->is_active = 1;
+       } else {
+               devctl |= MUSB_DEVCTL_SESSION;
+@@ -1907,7 +1907,7 @@ vbus_store(struct device *dev, struct de
+       spin_lock_irqsave(&musb->lock, flags);
+       /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
+       musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
+-      if (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)
++      if (musb_get_state(musb) == OTG_STATE_A_WAIT_BCON)
+               musb->is_active = 0;
+       musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
+       spin_unlock_irqrestore(&musb->lock, flags);
+@@ -2078,8 +2078,8 @@ static void musb_irq_work(struct work_st
+       musb_pm_runtime_check_session(musb);
+-      if (musb->xceiv->otg->state != musb->xceiv_old_state) {
+-              musb->xceiv_old_state = musb->xceiv->otg->state;
++      if (musb_get_state(musb) != musb->xceiv_old_state) {
++              musb->xceiv_old_state = musb_get_state(musb);
+               sysfs_notify(&musb->controller->kobj, NULL, "mode");
+       }
+@@ -2521,7 +2521,7 @@ musb_init_controller(struct device *dev,
+       }
+       MUSB_DEV_MODE(musb);
+-      musb->xceiv->otg->state = OTG_STATE_B_IDLE;
++      musb_set_state(musb, OTG_STATE_B_IDLE);
+       switch (musb->port_mode) {
+       case MUSB_HOST:
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -592,6 +592,17 @@ static inline void musb_platform_clear_e
+               musb->ops->clear_ep_rxintr(musb, epnum);
+ }
++static inline void musb_set_state(struct musb *musb,
++                                enum usb_otg_state otg_state)
++{
++      musb->xceiv->otg->state = otg_state;
++}
++
++static inline enum usb_otg_state musb_get_state(struct musb *musb)
++{
++      return musb->xceiv->otg->state;
++}
++
+ /*
+  * gets the "dr_mode" property from DT and converts it into musb_mode
+  * if the property is not found or not recognized returns MUSB_OTG
+--- a/drivers/usb/musb/musb_debugfs.c
++++ b/drivers/usb/musb/musb_debugfs.c
+@@ -235,7 +235,7 @@ static int musb_softconnect_show(struct
+       u8              reg;
+       int             connect;
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_WAIT_BCON:
+               pm_runtime_get_sync(musb->controller);
+@@ -275,7 +275,7 @@ static ssize_t musb_softconnect_write(st
+       pm_runtime_get_sync(musb->controller);
+       if (!strncmp(buf, "0", 1)) {
+-              switch (musb->xceiv->otg->state) {
++              switch (musb_get_state(musb)) {
+               case OTG_STATE_A_HOST:
+                       musb_root_disconnect(musb);
+                       reg = musb_readb(musb->mregs, MUSB_DEVCTL);
+@@ -286,7 +286,7 @@ static ssize_t musb_softconnect_write(st
+                       break;
+               }
+       } else if (!strncmp(buf, "1", 1)) {
+-              switch (musb->xceiv->otg->state) {
++              switch (musb_get_state(musb)) {
+               case OTG_STATE_A_WAIT_BCON:
+                       /*
+                        * musb_save_context() called in musb_runtime_suspend()
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -1523,7 +1523,7 @@ static int musb_gadget_wakeup(struct usb
+       spin_lock_irqsave(&musb->lock, flags);
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_B_PERIPHERAL:
+               /* NOTE:  OTG state machine doesn't include B_SUSPENDED;
+                * that's part of the standard usb 1.1 state machine, and
+@@ -1785,7 +1785,7 @@ int musb_gadget_setup(struct musb *musb)
+       musb->g.speed = USB_SPEED_UNKNOWN;
+       MUSB_DEV_MODE(musb);
+-      musb->xceiv->otg->state = OTG_STATE_B_IDLE;
++      musb_set_state(musb, OTG_STATE_B_IDLE);
+       /* this "gadget" abstracts/virtualizes the controller */
+       musb->g.name = musb_driver_name;
+@@ -1850,7 +1850,7 @@ static int musb_gadget_start(struct usb_
+       musb->is_active = 1;
+       otg_set_peripheral(otg, &musb->g);
+-      musb->xceiv->otg->state = OTG_STATE_B_IDLE;
++      musb_set_state(musb, OTG_STATE_B_IDLE);
+       spin_unlock_irqrestore(&musb->lock, flags);
+       musb_start(musb);
+@@ -1895,7 +1895,7 @@ static int musb_gadget_stop(struct usb_g
+       (void) musb_gadget_vbus_draw(&musb->g, 0);
+-      musb->xceiv->otg->state = OTG_STATE_UNDEFINED;
++      musb_set_state(musb, OTG_STATE_UNDEFINED);
+       musb_stop(musb);
+       otg_set_peripheral(musb->xceiv->otg, NULL);
+@@ -1926,7 +1926,7 @@ static int musb_gadget_stop(struct usb_g
+ void musb_g_resume(struct musb *musb)
+ {
+       musb->is_suspended = 0;
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_B_IDLE:
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+@@ -1952,10 +1952,10 @@ void musb_g_suspend(struct musb *musb)
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+       musb_dbg(musb, "musb_g_suspend: devctl %02x", devctl);
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_B_IDLE:
+               if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+-                      musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++                      musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               musb->is_suspended = 1;
+@@ -2001,22 +2001,22 @@ void musb_g_disconnect(struct musb *musb
+               spin_lock(&musb->lock);
+       }
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       default:
+               musb_dbg(musb, "Unhandled disconnect %s, setting a_idle",
+                       usb_otg_state_string(musb->xceiv->otg->state));
+-              musb->xceiv->otg->state = OTG_STATE_A_IDLE;
++              musb_set_state(musb, OTG_STATE_A_IDLE);
+               MUSB_HST_MODE(musb);
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+-              musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
++              musb_set_state(musb, OTG_STATE_A_WAIT_BCON);
+               MUSB_HST_MODE(musb);
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+       case OTG_STATE_B_HOST:
+       case OTG_STATE_B_PERIPHERAL:
+       case OTG_STATE_B_IDLE:
+-              musb->xceiv->otg->state = OTG_STATE_B_IDLE;
++              musb_set_state(musb, OTG_STATE_B_IDLE);
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               break;
+@@ -2080,13 +2080,13 @@ __acquires(musb->lock)
+                * In that case, do not rely on devctl for setting
+                * peripheral mode.
+                */
+-              musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++              musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+               musb->g.is_a_peripheral = 0;
+       } else if (devctl & MUSB_DEVCTL_BDEVICE) {
+-              musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
++              musb_set_state(musb, OTG_STATE_B_PERIPHERAL);
+               musb->g.is_a_peripheral = 0;
+       } else {
+-              musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL;
++              musb_set_state(musb, OTG_STATE_A_PERIPHERAL);
+               musb->g.is_a_peripheral = 1;
+       }
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -2514,7 +2514,7 @@ static int musb_bus_suspend(struct usb_h
+       if (!is_host_active(musb))
+               return 0;
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_A_SUSPEND:
+               return 0;
+       case OTG_STATE_A_WAIT_VRISE:
+@@ -2524,7 +2524,7 @@ static int musb_bus_suspend(struct usb_h
+                */
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+-                      musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
++                      musb_set_state(musb, OTG_STATE_A_WAIT_BCON);
+               break;
+       default:
+               break;
+@@ -2733,7 +2733,7 @@ int musb_host_setup(struct musb *musb, i
+       if (musb->port_mode == MUSB_HOST) {
+               MUSB_HST_MODE(musb);
+-              musb->xceiv->otg->state = OTG_STATE_A_IDLE;
++              musb_set_state(musb, OTG_STATE_A_IDLE);
+       }
+       otg_set_host(musb->xceiv->otg, &hcd->self);
+       /* don't support otg protocols */
+--- a/drivers/usb/musb/musb_virthub.c
++++ b/drivers/usb/musb/musb_virthub.c
+@@ -43,7 +43,7 @@ void musb_host_finish_resume(struct work
+       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+       usb_hcd_poll_rh_status(musb->hcd);
+       /* NOTE: it might really be A_WAIT_BCON ... */
+-      musb->xceiv->otg->state = OTG_STATE_A_HOST;
++      musb_set_state(musb, OTG_STATE_A_HOST);
+       spin_unlock_irqrestore(&musb->lock, flags);
+ }
+@@ -85,9 +85,9 @@ int musb_port_suspend(struct musb *musb,
+               musb_dbg(musb, "Root port suspended, power %02x", power);
+               musb->port1_status |= USB_PORT_STAT_SUSPEND;
+-              switch (musb->xceiv->otg->state) {
++              switch (musb_get_state(musb)) {
+               case OTG_STATE_A_HOST:
+-                      musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
++                      musb_set_state(musb, OTG_STATE_A_SUSPEND);
+                       musb->is_active = otg->host->b_hnp_enable;
+                       if (musb->is_active)
+                               mod_timer(&musb->otg_timer, jiffies
+@@ -96,7 +96,7 @@ int musb_port_suspend(struct musb *musb,
+                       musb_platform_try_idle(musb, 0);
+                       break;
+               case OTG_STATE_B_HOST:
+-                      musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
++                      musb_set_state(musb, OTG_STATE_B_WAIT_ACON);
+                       musb->is_active = otg->host->b_hnp_enable;
+                       musb_platform_try_idle(musb, 0);
+                       break;
+@@ -123,7 +123,7 @@ void musb_port_reset(struct musb *musb,
+       u8              power;
+       void __iomem    *mbase = musb->mregs;
+-      if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) {
++      if (musb_get_state(musb) == OTG_STATE_B_IDLE) {
+               musb_dbg(musb, "HNP: Returning from HNP; no hub reset from b_idle");
+               musb->port1_status &= ~USB_PORT_STAT_RESET;
+               return;
+@@ -204,20 +204,20 @@ void musb_root_disconnect(struct musb *m
+       usb_hcd_poll_rh_status(musb->hcd);
+       musb->is_active = 0;
+-      switch (musb->xceiv->otg->state) {
++      switch (musb_get_state(musb)) {
+       case OTG_STATE_A_SUSPEND:
+               if (otg->host->b_hnp_enable) {
+-                      musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL;
++                      musb_set_state(musb, OTG_STATE_A_PERIPHERAL);
+                       musb->g.is_a_peripheral = 1;
+                       break;
+               }
+               fallthrough;
+       case OTG_STATE_A_HOST:
+-              musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON;
++              musb_set_state(musb, OTG_STATE_A_WAIT_BCON);
+               musb->is_active = 0;
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+-              musb->xceiv->otg->state = OTG_STATE_B_IDLE;
++              musb_set_state(musb, OTG_STATE_B_IDLE);
+               break;
+       default:
+               musb_dbg(musb, "host disconnect (%s)",
diff --git a/queue-5.10/usb-musb-fix-gadget-state-on-disconnect.patch b/queue-5.10/usb-musb-fix-gadget-state-on-disconnect.patch
new file mode 100644 (file)
index 0000000..b7628a6
--- /dev/null
@@ -0,0 +1,48 @@
+From 67a59f82196c8c4f50c83329f0577acfb1349b50 Mon Sep 17 00:00:00 2001
+From: Drew Hamilton <drew.hamilton@zetier.com>
+Date: Tue, 1 Jul 2025 11:41:26 -0400
+Subject: usb: musb: fix gadget state on disconnect
+
+From: Drew Hamilton <drew.hamilton@zetier.com>
+
+commit 67a59f82196c8c4f50c83329f0577acfb1349b50 upstream.
+
+When unplugging the USB cable or disconnecting a gadget in usb peripheral mode with
+echo "" > /sys/kernel/config/usb_gadget/<your_gadget>/UDC,
+/sys/class/udc/musb-hdrc.0/state does not change from USB_STATE_CONFIGURED.
+
+Testing on dwc2/3 shows they both update the state to USB_STATE_NOTATTACHED.
+
+Add calls to usb_gadget_set_state in musb_g_disconnect and musb_gadget_stop
+to fix both cases.
+
+Fixes: 49401f4169c0 ("usb: gadget: introduce gadget state tracking")
+Cc: stable@vger.kernel.org
+Co-authored-by: Yehowshua Immanuel <yehowshua.immanuel@twosixtech.com>
+Signed-off-by: Yehowshua Immanuel <yehowshua.immanuel@twosixtech.com>
+Signed-off-by: Drew Hamilton <drew.hamilton@zetier.com>
+Link: https://lore.kernel.org/r/20250701154126.8543-1-drew.hamilton@zetier.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/musb/musb_gadget.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -1909,6 +1909,7 @@ static int musb_gadget_stop(struct usb_g
+        * gadget driver here and have everything work;
+        * that currently misbehaves.
+        */
++      usb_gadget_set_state(g, USB_STATE_NOTATTACHED);
+       /* Force check of devctl register for PM runtime */
+       schedule_delayed_work(&musb->irq_work, 0);
+@@ -2017,6 +2018,7 @@ void musb_g_disconnect(struct musb *musb
+       case OTG_STATE_B_PERIPHERAL:
+       case OTG_STATE_B_IDLE:
+               musb_set_state(musb, OTG_STATE_B_IDLE);
++              usb_gadget_set_state(&musb->g, USB_STATE_NOTATTACHED);
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               break;