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>
This commit is contained in:
Li Jun 2022-10-13 23:14:39 +08:00 committed by Greg Kroah-Hartman
parent 235ffc17d0
commit b332d6d5c8
3 changed files with 107 additions and 67 deletions

View 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 = {

View 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 */

View 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,31 +1011,30 @@ 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);
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 (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;
}
return 0;
}
EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
{
struct imx_usbmisc *usbmisc;
if (!data)
return 0;
usbmisc = dev_get_drvdata(data->dev);
if (!usbmisc->ops->set_wakeup)
return 0;
return usbmisc->ops->set_wakeup(data, enabled);
}
EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc;
@ -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",