[PATCH 05/10] usb: chipidea: msm: support the HSIC asynchronous wakeup interrupt

From: Dmitry Baryshkov

Date: Mon Aug 10 2026 - 11:56:05 EST


The HSIC instances of the chipidea controller runtime-suspend with
their clocks gated whenever the bus is empty. HSIC has no VBUS-style
connect detection: a device (such as an onboard hub coming out of
reset) signals a single connect event, and if the controller is
suspended at that moment the connect is never noticed and the device
never enumerates.

The hardware provides an asynchronous wakeup interrupt that fires on
HSIC bus activity while the controller is in low power mode. Pick it
up as an optional second interrupt and attach it as a dedicated wake
irq of the core device, so the PM core arms it over runtime suspend
and resumes the controller when the bus reports activity.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxxxxxxxx>
---
drivers/usb/chipidea/ci_hdrc_msm.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)

diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index 3ab3daa78e34..e28ea87f9898 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -4,6 +4,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.h>
#include <linux/usb/chipidea.h>
#include <linux/clk.h>
#include <linux/reset.h>
@@ -173,6 +174,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
{
struct ci_hdrc_msm *ci;
struct platform_device *plat_ci;
+ int wake_irq;
struct clk *clk;
struct reset_control *reset;
int ret;
@@ -261,6 +263,19 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)

ci->ci = plat_ci;

+ /*
+ * The optional second interrupt is the asynchronous wakeup interrupt
+ * of the HSIC instances: without it a bus connect arriving while the
+ * runtime-suspended controller has its clocks gated is never seen.
+ */
+ wake_irq = platform_get_irq_optional(pdev, 1);
+ if (wake_irq > 0) {
+ device_init_wakeup(&plat_ci->dev, true);
+ ret = dev_pm_set_dedicated_wake_irq(&plat_ci->dev, wake_irq);
+ if (ret)
+ dev_warn(&pdev->dev, "no wakeup interrupt: %d\n", ret);
+ }
+
pm_runtime_set_active(&pdev->dev);
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -279,6 +294,7 @@ static void ci_hdrc_msm_remove(struct platform_device *pdev)
struct ci_hdrc_msm *ci = platform_get_drvdata(pdev);

pm_runtime_disable(&pdev->dev);
+ dev_pm_clear_wake_irq(&ci->ci->dev);
ci_hdrc_remove_device(ci->ci);
clk_disable_unprepare(ci->iface_clk);
clk_disable_unprepare(ci->core_clk);

--
2.47.3