summaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea
diff options
context:
space:
mode:
authorLi Jun <jun.li@nxp.com>2022-10-13 23:14:39 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-10-23 14:34:53 +0200
commitb332d6d5c804085ac26d2e7e1a953b59b49644f3 (patch)
tree8131175e6770ad82a4810a43de56757cf7f50bdf /drivers/usb/chipidea
parent235ffc17d0146d806f6ad8c094c24ff4878f2edb (diff)
downloadlinux-stable-b332d6d5c804085ac26d2e7e1a953b59b49644f3.tar.gz
linux-stable-b332d6d5c804085ac26d2e7e1a953b59b49644f3.tar.bz2
linux-stable-b332d6d5c804085ac26d2e7e1a953b59b49644f3.zip
usb: chipidea: usbmisc: group usbmisc operations for PM
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>
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c49
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.h4
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c119
3 files changed, 106 insertions, 66 deletions
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 9ffcecd3058c..923f5c00a1d9 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -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 = {
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h
index 7daccb9c5006..7135b9a5d913 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.h
+++ b/drivers/usb/chipidea/ci_hdrc_imx.h
@@ -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 */
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index bac0f5458cab..aa815f6d3fe9 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -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",