bus: ti-sysc: Improve suspend and resume handling
authorTony Lindgren <tony@atomide.com>
Mon, 16 Apr 2018 17:27:15 +0000 (10:27 -0700)
committerTony Lindgren <tony@atomide.com>
Tue, 1 May 2018 13:54:17 +0000 (06:54 -0700)
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 <tony@atomide.com>
drivers/bus/ti-sysc.c

index 1f90b91dbfae6e6890559cb831f4e126ab639ac4..145dcc0cf48c309cc5d5c28ea235e682838c71f2 100644 (file)
@@ -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;