aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/runtime.c45
-rw-r--r--drivers/base/power/sysfs.c51
-rw-r--r--include/linux/pm.h1
-rw-r--r--include/linux/pm_runtime.h4
4 files changed, 101 insertions, 0 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index f8b044e8aef7..626dd147b75f 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1011,6 +1011,50 @@ void pm_runtime_enable(struct device *dev)
1011EXPORT_SYMBOL_GPL(pm_runtime_enable); 1011EXPORT_SYMBOL_GPL(pm_runtime_enable);
1012 1012
1013/** 1013/**
1014 * pm_runtime_forbid - Block run-time PM of a device.
1015 * @dev: Device to handle.
1016 *
1017 * Increase the device's usage count and clear its power.runtime_auto flag,
1018 * so that it cannot be suspended at run time until pm_runtime_allow() is called
1019 * for it.
1020 */
1021void pm_runtime_forbid(struct device *dev)
1022{
1023 spin_lock_irq(&dev->power.lock);
1024 if (!dev->power.runtime_auto)
1025 goto out;
1026
1027 dev->power.runtime_auto = false;
1028 atomic_inc(&dev->power.usage_count);
1029 __pm_runtime_resume(dev, false);
1030
1031 out:
1032 spin_unlock_irq(&dev->power.lock);
1033}
1034EXPORT_SYMBOL_GPL(pm_runtime_forbid);
1035
1036/**
1037 * pm_runtime_allow - Unblock run-time PM of a device.
1038 * @dev: Device to handle.
1039 *
1040 * Decrease the device's usage count and set its power.runtime_auto flag.
1041 */
1042void pm_runtime_allow(struct device *dev)
1043{
1044 spin_lock_irq(&dev->power.lock);
1045 if (dev->power.runtime_auto)
1046 goto out;
1047
1048 dev->power.runtime_auto = true;
1049 if (atomic_dec_and_test(&dev->power.usage_count))
1050 __pm_runtime_idle(dev);
1051
1052 out:
1053 spin_unlock_irq(&dev->power.lock);
1054}
1055EXPORT_SYMBOL_GPL(pm_runtime_allow);
1056
1057/**
1014 * pm_runtime_init - Initialize run-time PM fields in given device object. 1058 * pm_runtime_init - Initialize run-time PM fields in given device object.
1015 * @dev: Device object to initialize. 1059 * @dev: Device object to initialize.
1016 */ 1060 */
@@ -1028,6 +1072,7 @@ void pm_runtime_init(struct device *dev)
1028 1072
1029 atomic_set(&dev->power.child_count, 0); 1073 atomic_set(&dev->power.child_count, 0);
1030 pm_suspend_ignore_children(dev, false); 1074 pm_suspend_ignore_children(dev, false);
1075 dev->power.runtime_auto = true;
1031 1076
1032 dev->power.request_pending = false; 1077 dev->power.request_pending = false;
1033 dev->power.request = RPM_REQ_NONE; 1078 dev->power.request = RPM_REQ_NONE;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 596aeecfdffe..c011ff15632c 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -4,9 +4,25 @@
4 4
5#include <linux/device.h> 5#include <linux/device.h>
6#include <linux/string.h> 6#include <linux/string.h>
7#include <linux/pm_runtime.h>
7#include "power.h" 8#include "power.h"
8 9
9/* 10/*
11 * control - Report/change current runtime PM setting of the device
12 *
13 * Runtime power management of a device can be blocked with the help of
14 * this attribute. All devices have one of the following two values for
15 * the power/control file:
16 *
17 * + "auto\n" to allow the device to be power managed at run time;
18 * + "on\n" to prevent the device from being power managed at run time;
19 *
20 * The default for all devices is "auto", which means that devices may be
21 * subject to automatic power management, depending on their drivers.
22 * Changing this attribute to "on" prevents the driver from power managing
23 * the device at run time. Doing that while the device is suspended causes
24 * it to be woken up.
25 *
10 * wakeup - Report/change current wakeup option for device 26 * wakeup - Report/change current wakeup option for device
11 * 27 *
12 * Some devices support "wakeup" events, which are hardware signals 28 * Some devices support "wakeup" events, which are hardware signals
@@ -43,6 +59,38 @@
43static const char enabled[] = "enabled"; 59static const char enabled[] = "enabled";
44static const char disabled[] = "disabled"; 60static const char disabled[] = "disabled";
45 61
62#ifdef CONFIG_PM_RUNTIME
63static const char ctrl_auto[] = "auto";
64static const char ctrl_on[] = "on";
65
66static ssize_t control_show(struct device *dev, struct device_attribute *attr,
67 char *buf)
68{
69 return sprintf(buf, "%s\n",
70 dev->power.runtime_auto ? ctrl_auto : ctrl_on);
71}
72
73static ssize_t control_store(struct device * dev, struct device_attribute *attr,
74 const char * buf, size_t n)
75{
76 char *cp;
77 int len = n;
78
79 cp = memchr(buf, '\n', n);
80 if (cp)
81 len = cp - buf;
82 if (len == sizeof ctrl_auto - 1 && strncmp(buf, ctrl_auto, len) == 0)
83 pm_runtime_allow(dev);
84 else if (len == sizeof ctrl_on - 1 && strncmp(buf, ctrl_on, len) == 0)
85 pm_runtime_forbid(dev);
86 else
87 return -EINVAL;
88 return n;
89}
90
91static DEVICE_ATTR(control, 0644, control_show, control_store);
92#endif
93
46static ssize_t 94static ssize_t
47wake_show(struct device * dev, struct device_attribute *attr, char * buf) 95wake_show(struct device * dev, struct device_attribute *attr, char * buf)
48{ 96{
@@ -79,6 +127,9 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
79 127
80 128
81static struct attribute * power_attrs[] = { 129static struct attribute * power_attrs[] = {
130#ifdef CONFIG_PM_RUNTIME
131 &dev_attr_control.attr,
132#endif
82 &dev_attr_wakeup.attr, 133 &dev_attr_wakeup.attr,
83 NULL, 134 NULL,
84}; 135};
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 198b8f9fe05e..25b1eca8049d 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -430,6 +430,7 @@ struct dev_pm_info {
430 unsigned int request_pending:1; 430 unsigned int request_pending:1;
431 unsigned int deferred_resume:1; 431 unsigned int deferred_resume:1;
432 unsigned int run_wake:1; 432 unsigned int run_wake:1;
433 unsigned int runtime_auto:1;
433 enum rpm_request request; 434 enum rpm_request request;
434 enum rpm_status runtime_status; 435 enum rpm_status runtime_status;
435 int runtime_error; 436 int runtime_error;
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 370ce0a6fe4a..7d773aac5314 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -28,6 +28,8 @@ extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
28extern int pm_runtime_barrier(struct device *dev); 28extern int pm_runtime_barrier(struct device *dev);
29extern void pm_runtime_enable(struct device *dev); 29extern void pm_runtime_enable(struct device *dev);
30extern void __pm_runtime_disable(struct device *dev, bool check_resume); 30extern void __pm_runtime_disable(struct device *dev, bool check_resume);
31extern void pm_runtime_allow(struct device *dev);
32extern void pm_runtime_forbid(struct device *dev);
31 33
32static inline bool pm_children_suspended(struct device *dev) 34static inline bool pm_children_suspended(struct device *dev)
33{ 35{
@@ -78,6 +80,8 @@ static inline int __pm_runtime_set_status(struct device *dev,
78static inline int pm_runtime_barrier(struct device *dev) { return 0; } 80static inline int pm_runtime_barrier(struct device *dev) { return 0; }
79static inline void pm_runtime_enable(struct device *dev) {} 81static inline void pm_runtime_enable(struct device *dev) {}
80static inline void __pm_runtime_disable(struct device *dev, bool c) {} 82static inline void __pm_runtime_disable(struct device *dev, bool c) {}
83static inline void pm_runtime_allow(struct device *dev) {}
84static inline void pm_runtime_forbid(struct device *dev) {}
81 85
82static inline bool pm_children_suspended(struct device *dev) { return false; } 86static inline bool pm_children_suspended(struct device *dev) { return false; }
83static inline void pm_suspend_ignore_children(struct device *dev, bool en) {} 87static inline void pm_suspend_ignore_children(struct device *dev, bool en) {}