mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-04 08:08:54 +00:00
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:
parent
235ffc17d0
commit
b332d6d5c8
3 changed files with 107 additions and 67 deletions
|
@ -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 = {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue