usb: chipidea: usbmisc: group usbmisc operations for PM
authorLi Jun <jun.li@nxp.com>
Thu, 13 Oct 2022 15:14:39 +0000 (23:14 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 23 Oct 2022 12:34:53 +0000 (14:34 +0200)
As there maybe more APIs of usbmisc for suspend and resume, group
them into imx_usbmisc_suspend/resume. Besides, introduced .power_lost_check
API, so that proper resume operations can be performed in power lost case.

Signed-off-by: Li Jun <jun.li@nxp.com>
Link: https://lore.kernel.org/r/20221013151442.3262951-6-xu.yang_2@nxp.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_imx.h
drivers/usb/chipidea/usbmisc_imx.c

index 9ffcecd3058c173d36d603ca386189f6a4cce6f5..923f5c00a1d96154dcadeb472ff5009ac623577d 100644 (file)
@@ -527,16 +527,19 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
        ci_hdrc_imx_remove(pdev);
 }
 
-static int __maybe_unused imx_controller_suspend(struct device *dev)
+static int __maybe_unused imx_controller_suspend(struct device *dev,
+                                                pm_message_t msg)
 {
        struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
        int ret = 0;
 
        dev_dbg(dev, "at %s\n", __func__);
 
-       ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false);
+       ret = imx_usbmisc_suspend(data->usbmisc_data,
+                                 PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
        if (ret) {
-               dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
+               dev_err(dev,
+                       "usbmisc suspend failed, ret=%d\n", ret);
                return ret;
        }
 
@@ -549,7 +552,8 @@ static int __maybe_unused imx_controller_suspend(struct device *dev)
        return 0;
 }
 
-static int __maybe_unused imx_controller_resume(struct device *dev)
+static int __maybe_unused imx_controller_resume(struct device *dev,
+                                               pm_message_t msg)
 {
        struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
        int ret = 0;
@@ -570,22 +574,15 @@ static int __maybe_unused imx_controller_resume(struct device *dev)
 
        data->in_lpm = false;
 
-       ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
+       ret = imx_usbmisc_resume(data->usbmisc_data,
+                                PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
        if (ret) {
-               dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
+               dev_err(dev, "usbmisc resume failed, ret=%d\n", ret);
                goto clk_disable;
        }
 
-       ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true);
-       if (ret) {
-               dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
-               goto hsic_set_clk_fail;
-       }
-
        return 0;
 
-hsic_set_clk_fail:
-       imx_usbmisc_set_wakeup(data->usbmisc_data, true);
 clk_disable:
        imx_disable_unprepare_clks(dev);
        return ret;
@@ -601,16 +598,7 @@ static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev)
                /* The core's suspend doesn't run */
                return 0;
 
-       if (device_may_wakeup(dev)) {
-               ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
-               if (ret) {
-                       dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
-                                       ret);
-                       return ret;
-               }
-       }
-
-       ret = imx_controller_suspend(dev);
+       ret = imx_controller_suspend(dev, PMSG_SUSPEND);
        if (ret)
                return ret;
 
@@ -624,7 +612,7 @@ static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
        int ret;
 
        pinctrl_pm_select_default_state(dev);
-       ret = imx_controller_resume(dev);
+       ret = imx_controller_resume(dev, PMSG_RESUME);
        if (!ret && data->supports_runtime_pm) {
                pm_runtime_disable(dev);
                pm_runtime_set_active(dev);
@@ -637,25 +625,18 @@ static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
 static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev)
 {
        struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
-       int ret;
 
        if (data->in_lpm) {
                WARN_ON(1);
                return 0;
        }
 
-       ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
-       if (ret) {
-               dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
-               return ret;
-       }
-
-       return imx_controller_suspend(dev);
+       return imx_controller_suspend(dev, PMSG_AUTO_SUSPEND);
 }
 
 static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev)
 {
-       return imx_controller_resume(dev);
+       return imx_controller_resume(dev, PMSG_AUTO_RESUME);
 }
 
 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
index 7daccb9c5006a35aaa5b40f8711ccafdc419ced2..7135b9a5d9138307d1936bf0079e65767a75e26a 100644 (file)
@@ -32,9 +32,9 @@ struct imx_usbmisc_data {
 
 int imx_usbmisc_init(struct imx_usbmisc_data *data);
 int imx_usbmisc_init_post(struct imx_usbmisc_data *data);
-int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled);
 int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data);
-int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on);
 int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect);
+int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup);
+int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup);
 
 #endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */
index bac0f5458cab9902c3a4a0ae77d0163decbf0ce2..aa815f6d3fe9a916a93033b45571cd89db49e99d 100644 (file)
@@ -150,6 +150,8 @@ struct usbmisc_ops {
        int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled);
        /* usb charger detection */
        int (*charger_detection)(struct imx_usbmisc_data *data);
+       /* It's called when system resume from usb power lost */
+       int (*power_lost_check)(struct imx_usbmisc_data *data);
 };
 
 struct imx_usbmisc {
@@ -1009,30 +1011,29 @@ EXPORT_SYMBOL_GPL(imx_usbmisc_init);
 int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
 {
        struct imx_usbmisc *usbmisc;
+       int ret = 0;
 
        if (!data)
                return 0;
 
        usbmisc = dev_get_drvdata(data->dev);
-       if (!usbmisc->ops->post)
-               return 0;
-       return usbmisc->ops->post(data);
-}
-EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
-
-int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
-{
-       struct imx_usbmisc *usbmisc;
+       if (usbmisc->ops->post)
+               ret = usbmisc->ops->post(data);
+       if (ret) {
+               dev_err(data->dev, "post init failed, ret=%d\n", ret);
+               return ret;
+       }
 
-       if (!data)
-               return 0;
+       if (usbmisc->ops->set_wakeup)
+               ret = usbmisc->ops->set_wakeup(data, false);
+       if (ret) {
+               dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+               return ret;
+       }
 
-       usbmisc = dev_get_drvdata(data->dev);
-       if (!usbmisc->ops->set_wakeup)
-               return 0;
-       return usbmisc->ops->set_wakeup(data, enabled);
+       return 0;
 }
-EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
+EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
 
 int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
 {
@@ -1048,20 +1049,6 @@ int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
 }
 EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect);
 
-int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
-{
-       struct imx_usbmisc *usbmisc;
-
-       if (!data)
-               return 0;
-
-       usbmisc = dev_get_drvdata(data->dev);
-       if (!usbmisc->ops->hsic_set_clk || !data->hsic)
-               return 0;
-       return usbmisc->ops->hsic_set_clk(data, on);
-}
-EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk);
-
 int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
 {
        struct imx_usbmisc *usbmisc;
@@ -1094,6 +1081,78 @@ int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
 }
 EXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection);
 
+int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup)
+{
+       struct imx_usbmisc *usbmisc;
+       int ret = 0;
+
+       if (!data)
+               return 0;
+
+       usbmisc = dev_get_drvdata(data->dev);
+
+       if (wakeup && usbmisc->ops->set_wakeup)
+               ret = usbmisc->ops->set_wakeup(data, true);
+       if (ret) {
+               dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+               return ret;
+       }
+
+       if (usbmisc->ops->hsic_set_clk && data->hsic)
+               ret = usbmisc->ops->hsic_set_clk(data, false);
+       if (ret) {
+               dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_suspend);
+
+int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup)
+{
+       struct imx_usbmisc *usbmisc;
+       int ret = 0;
+
+       if (!data)
+               return 0;
+
+       usbmisc = dev_get_drvdata(data->dev);
+
+       if (usbmisc->ops->power_lost_check)
+               ret = usbmisc->ops->power_lost_check(data);
+       if (ret > 0) {
+               /* re-init if resume from power lost */
+               ret = imx_usbmisc_init(data);
+               if (ret) {
+                       dev_err(data->dev, "re-init failed, ret=%d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (wakeup && usbmisc->ops->set_wakeup)
+               ret = usbmisc->ops->set_wakeup(data, false);
+       if (ret) {
+               dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+               return ret;
+       }
+
+       if (usbmisc->ops->hsic_set_clk && data->hsic)
+               ret = usbmisc->ops->hsic_set_clk(data, true);
+       if (ret) {
+               dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
+               goto hsic_set_clk_fail;
+       }
+
+       return 0;
+
+hsic_set_clk_fail:
+       if (wakeup && usbmisc->ops->set_wakeup)
+               usbmisc->ops->set_wakeup(data, true);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_resume);
+
 static const struct of_device_id usbmisc_imx_dt_ids[] = {
        {
                .compatible = "fsl,imx25-usbmisc",