aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2014-03-01 05:56:05 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-01 18:18:15 -0500
commit37f204164dfb0186a0caf20bc3e3120080bcd788 (patch)
tree71cd2729fa7509d3bed3048e1dad41f8e73ce91e
parent5f59df79837bb809f3945613aba5519cd9755a53 (diff)
PM: Add pm_runtime_suspend|resume_force functions
This patch provides two new runtime PM helper functions which intend to be used from system suspend/resume callbacks, to make sure devices are put into low power state during system suspend and brought back to full power at system resume. The prerequisite is to have all levels of a device's runtime PM callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which means these are available for CONFIG_PM. By using the new runtime PM helper functions especially the two scenarios below will be addressed. 1) The PM core prevents .runtime_suspend callbacks from being invoked during system suspend. That means even for a runtime PM centric subsystem and driver, the device needs to be put into low power state from a system suspend callback. Otherwise it may very well be left in full power state (runtime resumed) while the system is suspended. By using the new helper functions, we make sure to walk the hierarchy of a device's power domain, subsystem and driver. 2) Subsystems and drivers need to cope with all the combinations of CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions smothly addresses this. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/Makefile3
-rw-r--r--drivers/base/power/runtime.c84
-rw-r--r--include/linux/pm_runtime.h4
3 files changed, 89 insertions, 2 deletions
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 2e58ebb1f6c0..1cb8544598d5 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,5 @@
1obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o 1obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
2obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o 2obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
3obj-$(CONFIG_PM_RUNTIME) += runtime.o
4obj-$(CONFIG_PM_TRACE_RTC) += trace.o 3obj-$(CONFIG_PM_TRACE_RTC) += trace.o
5obj-$(CONFIG_PM_OPP) += opp.o 4obj-$(CONFIG_PM_OPP) += opp.o
6obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o 5obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index ac495b1357fa..4776cf528d08 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -44,6 +44,7 @@ static int (*rpm_get_resume_cb(struct device *dev))(struct device *)
44 return RPM_GET_CALLBACK(dev, runtime_resume); 44 return RPM_GET_CALLBACK(dev, runtime_resume);
45} 45}
46 46
47#ifdef CONFIG_PM_RUNTIME
47static int (*rpm_get_idle_cb(struct device *dev))(struct device *) 48static int (*rpm_get_idle_cb(struct device *dev))(struct device *)
48{ 49{
49 return RPM_GET_CALLBACK(dev, runtime_idle); 50 return RPM_GET_CALLBACK(dev, runtime_idle);
@@ -1401,3 +1402,86 @@ void pm_runtime_remove(struct device *dev)
1401 if (dev->power.irq_safe && dev->parent) 1402 if (dev->power.irq_safe && dev->parent)
1402 pm_runtime_put(dev->parent); 1403 pm_runtime_put(dev->parent);
1403} 1404}
1405#endif
1406
1407/**
1408 * pm_runtime_force_suspend - Force a device into suspend state if needed.
1409 * @dev: Device to suspend.
1410 *
1411 * Disable runtime PM so we safely can check the device's runtime PM status and
1412 * if it is active, invoke it's .runtime_suspend callback to bring it into
1413 * suspend state. Keep runtime PM disabled to preserve the state unless we
1414 * encounter errors.
1415 *
1416 * Typically this function may be invoked from a system suspend callback to make
1417 * sure the device is put into low power state.
1418 */
1419int pm_runtime_force_suspend(struct device *dev)
1420{
1421 int (*callback)(struct device *);
1422 int ret = 0;
1423
1424 pm_runtime_disable(dev);
1425
1426 /*
1427 * Note that pm_runtime_status_suspended() returns false while
1428 * !CONFIG_PM_RUNTIME, which means the device will be put into low
1429 * power state.
1430 */
1431 if (pm_runtime_status_suspended(dev))
1432 return 0;
1433
1434 callback = rpm_get_suspend_cb(dev);
1435
1436 if (!callback) {
1437 ret = -ENOSYS;
1438 goto err;
1439 }
1440
1441 ret = callback(dev);
1442 if (ret)
1443 goto err;
1444
1445 pm_runtime_set_suspended(dev);
1446 return 0;
1447err:
1448 pm_runtime_enable(dev);
1449 return ret;
1450}
1451EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
1452
1453/**
1454 * pm_runtime_force_resume - Force a device into resume state.
1455 * @dev: Device to resume.
1456 *
1457 * Prior invoking this function we expect the user to have brought the device
1458 * into low power state by a call to pm_runtime_force_suspend(). Here we reverse
1459 * those actions and brings the device into full power. We update the runtime PM
1460 * status and re-enables runtime PM.
1461 *
1462 * Typically this function may be invoked from a system resume callback to make
1463 * sure the device is put into full power state.
1464 */
1465int pm_runtime_force_resume(struct device *dev)
1466{
1467 int (*callback)(struct device *);
1468 int ret = 0;
1469
1470 callback = rpm_get_resume_cb(dev);
1471
1472 if (!callback) {
1473 ret = -ENOSYS;
1474 goto out;
1475 }
1476
1477 ret = callback(dev);
1478 if (ret)
1479 goto out;
1480
1481 pm_runtime_set_active(dev);
1482 pm_runtime_mark_last_busy(dev);
1483out:
1484 pm_runtime_enable(dev);
1485 return ret;
1486}
1487EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 16c9a62fa1c0..2a5897a4afbc 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -26,9 +26,13 @@
26#ifdef CONFIG_PM 26#ifdef CONFIG_PM
27extern int pm_generic_runtime_suspend(struct device *dev); 27extern int pm_generic_runtime_suspend(struct device *dev);
28extern int pm_generic_runtime_resume(struct device *dev); 28extern int pm_generic_runtime_resume(struct device *dev);
29extern int pm_runtime_force_suspend(struct device *dev);
30extern int pm_runtime_force_resume(struct device *dev);
29#else 31#else
30static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } 32static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
31static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } 33static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
34static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
35static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
32#endif 36#endif
33 37
34#ifdef CONFIG_PM_RUNTIME 38#ifdef CONFIG_PM_RUNTIME