[PATCH 05/10] usb: chipidea: msm: support the HSIC asynchronous wakeup interrupt
Dmitry Baryshkov <[email protected]>
| Newsgroups | org.kernel.vger.linux-gpio,org.infradead.lists.linux-phy,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-usb |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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