From ef55f8215a78b7021401281e8a7fe056fd5ecdab Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 16 Apr 2018 10:27:15 -0700 Subject: bus: ti-sysc: Improve suspend and resume handling Based on testing with more devices I noticed that some devices don't suspend or resume properly. We need to PM runtime suspend and resume devices if we have ddata->needs_resume set. Let's also improve the error handling and add few debug statements to make it easier to notice suspend and resume related issues if DEBUG is set. Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 54 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) (limited to 'drivers/bus') diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 1f90b91dbfae..145dcc0cf48c 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -662,6 +662,7 @@ awake: static int sysc_suspend(struct device *dev) { struct sysc *ddata; + int error; ddata = dev_get_drvdata(dev); @@ -672,14 +673,27 @@ static int sysc_suspend(struct device *dev) if (!ddata->enabled) return 0; + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + + error = pm_runtime_put_sync_suspend(dev); + if (error < 0) { + dev_warn(ddata->dev, "%s not idle %i %s\n", + __func__, error, + ddata->name ? ddata->name : ""); + + return 0; + } + ddata->needs_resume = true; - return sysc_runtime_suspend(dev); + return 0; } static int sysc_resume(struct device *dev) { struct sysc *ddata; + int error; ddata = dev_get_drvdata(dev); @@ -691,9 +705,16 @@ static int sysc_resume(struct device *dev) dev_dbg(ddata->dev, "%s %s\n", __func__, ddata->name ? ddata->name : ""); - ddata->needs_resume = false; + error = pm_runtime_get_sync(dev); + if (error < 0) { + dev_err(ddata->dev, "%s error %i %s\n", + __func__, error, + ddata->name ? ddata->name : ""); - return sysc_runtime_resume(dev); + return error; + } + + ddata->needs_resume = false; } return 0; @@ -735,6 +756,9 @@ static int sysc_noirq_resume(struct device *dev) return 0; if (ddata->needs_resume) { + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + ddata->needs_resume = false; return sysc_runtime_resume(dev); @@ -1069,18 +1093,33 @@ static int sysc_child_suspend_noirq(struct device *dev) ddata = sysc_child_to_parent(dev); + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + error = pm_generic_suspend_noirq(dev); - if (error) + if (error) { + dev_err(dev, "%s error at %i: %i\n", + __func__, __LINE__, error); + return error; + } if (!pm_runtime_status_suspended(dev)) { error = pm_generic_runtime_suspend(dev); - if (error) + if (error) { + dev_err(dev, "%s error at %i: %i\n", + __func__, __LINE__, error); + return error; + } error = sysc_runtime_suspend(ddata->dev); - if (error) + if (error) { + dev_err(dev, "%s error at %i: %i\n", + __func__, __LINE__, error); + return error; + } ddata->child_needs_resume = true; } @@ -1095,6 +1134,9 @@ static int sysc_child_resume_noirq(struct device *dev) ddata = sysc_child_to_parent(dev); + dev_dbg(ddata->dev, "%s %s\n", __func__, + ddata->name ? ddata->name : ""); + if (ddata->child_needs_resume) { ddata->child_needs_resume = false; -- cgit v1.2.3