On Mon, Mar 03, 2025 at 12:13:34PM -0500, Frank Li wrote: > On Mon, Mar 03, 2025 at 11:33:41AM +0800, Xu Yang wrote: > > In previous imx platform, normal USB controller interrupt and wakeup > > interrupt are bound to one irq line. However, it changes on latest > > i.MX95 platform since it has a dedicated irq line for wakeup interrupt. > > This will add wakeup interrupt handling for i.MX95 to support various > > wakeup events. > > > > Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx> > > --- > > Changes in v4: > > - warning if no irq provided for imx95 > > Changes in v3: > > - include <linux/irq.h> to fix possible build issue > > Changes in v2: > > - rename irq to wakeup_irq > > - disable irq by default > > - enable irq when suspend, disable irq when resume > > --- > > drivers/usb/chipidea/ci_hdrc_imx.c | 35 ++++++++++++++++++++++++++++++ > > 1 file changed, 35 insertions(+) > > > > diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c > > index 1a7fc638213e..2baae9e6e673 100644 > > --- a/drivers/usb/chipidea/ci_hdrc_imx.c > > +++ b/drivers/usb/chipidea/ci_hdrc_imx.c > > @@ -6,6 +6,7 @@ > > */ > > > > #include <linux/module.h> > > +#include <linux/irq.h> > > #include <linux/of.h> > > #include <linux/of_platform.h> > > #include <linux/platform_device.h> > > @@ -98,6 +99,7 @@ struct ci_hdrc_imx_data { > > struct clk *clk; > > struct clk *clk_wakeup; > > struct imx_usbmisc_data *usbmisc_data; > > + int wakeup_irq; > > bool supports_runtime_pm; > > bool override_phy_control; > > bool in_lpm; > > @@ -336,6 +338,16 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event) > > return ret; > > } > > > > +static irqreturn_t ci_wakeup_irq_handler(int irq, void *data) > > +{ > > + struct ci_hdrc_imx_data *imx_data = data; > > + > > + disable_irq_nosync(irq); > > + pm_runtime_resume(&imx_data->ci_pdev->dev); > > + > > + return IRQ_HANDLED; > > +} > > + > > static int ci_hdrc_imx_probe(struct platform_device *pdev) > > { > > struct ci_hdrc_imx_data *data; > > @@ -476,6 +488,18 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) > > if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) > > data->supports_runtime_pm = true; > > > > + data->wakeup_irq = platform_get_irq_optional(pdev, 1); > > + if (data->wakeup_irq > 0) { > > + ret = devm_request_threaded_irq(dev, data->wakeup_irq, > > + NULL, ci_wakeup_irq_handler, > > + IRQF_ONESHOT | IRQF_NO_AUTOEN, > > + pdata.name, data); > > + if (ret) > > + goto err_clk; > > + } else if (device_is_compatible(dev, "fsl,imx95-usb")) { > > + dev_warn(dev, "wakeup irq is missing\n"); > > + } > > + > > Suggest add imx95_usb_data, and new flags, like have_wakeup_irq. > > if (imx_platform_flag->have_wakeup_irq) { > ... > ret = devm_request_threaded_irq(); > if (ret) { > dev_warning(...); > goto err_clk; > } > } Thanks for your suggestion. I might have different understanding about it. I prefer to not add flag here. Given the following points: (1) the wakeup irq is optional, the USB controller can still functional well if properly set. (2) I may need add imx_usb_data for each new Soc, however, it seems like unnecessary. > > > ret = imx_usbmisc_init(data->usbmisc_data); > > if (ret) { > > dev_err(dev, "usbmisc init failed, ret=%d\n", ret); > > @@ -584,6 +608,7 @@ static int imx_controller_suspend(struct device *dev, > > } > > > > imx_disable_unprepare_clks(dev); > > + enable_irq(data->wakeup_irq); > > Suggest check data->wakeup_irq and other places. > > if (data->wakeup_irq > 0) > enable_irq(data->wakeup_irq); > > And you should check enable_irq()'s return value also. I just find dedicated wakeirq mechanism (drivers/base/power/wakeirq.c) basically fit my needs. I'm going to switch to use wakeirq. Then I'll needn't to do such thing manually. Thanks, Xu Yang > > Frank > > > if (data->plat_data->flags & CI_HDRC_PMQOS) > > cpu_latency_qos_remove_request(&data->pm_qos_req); > > > > @@ -608,6 +633,9 @@ static int imx_controller_resume(struct device *dev, > > if (data->plat_data->flags & CI_HDRC_PMQOS) > > cpu_latency_qos_add_request(&data->pm_qos_req, 0); > > > > + if (!irqd_irq_disabled(irq_get_irq_data(data->wakeup_irq))) > > + disable_irq_nosync(data->wakeup_irq); > > + > > ret = imx_prepare_enable_clks(dev); > > if (ret) > > return ret; > > @@ -643,6 +671,10 @@ static int ci_hdrc_imx_suspend(struct device *dev) > > return ret; > > > > pinctrl_pm_select_sleep_state(dev); > > + > > + if (device_may_wakeup(dev)) > > + enable_irq_wake(data->wakeup_irq); > > + > > return ret; > > } > > > > @@ -651,6 +683,9 @@ static int ci_hdrc_imx_resume(struct device *dev) > > struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); > > int ret; > > > > + if (device_may_wakeup(dev)) > > + disable_irq_wake(data->wakeup_irq); > > + > > pinctrl_pm_select_default_state(dev); > > ret = imx_controller_resume(dev, PMSG_RESUME); > > if (!ret && data->supports_runtime_pm) { > > -- > > 2.34.1 > >