diff options
-rw-r--r-- | drivers/base/power/runtime.c | 45 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 51 | ||||
-rw-r--r-- | include/linux/pm.h | 1 | ||||
-rw-r--r-- | include/linux/pm_runtime.h | 4 |
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) | |||
1011 | EXPORT_SYMBOL_GPL(pm_runtime_enable); | 1011 | EXPORT_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 | */ | ||
1021 | void 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 | } | ||
1034 | EXPORT_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 | */ | ||
1042 | void 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 | } | ||
1055 | EXPORT_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 @@ | |||
43 | static const char enabled[] = "enabled"; | 59 | static const char enabled[] = "enabled"; |
44 | static const char disabled[] = "disabled"; | 60 | static const char disabled[] = "disabled"; |
45 | 61 | ||
62 | #ifdef CONFIG_PM_RUNTIME | ||
63 | static const char ctrl_auto[] = "auto"; | ||
64 | static const char ctrl_on[] = "on"; | ||
65 | |||
66 | static 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 | |||
73 | static 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 | |||
91 | static DEVICE_ATTR(control, 0644, control_show, control_store); | ||
92 | #endif | ||
93 | |||
46 | static ssize_t | 94 | static ssize_t |
47 | wake_show(struct device * dev, struct device_attribute *attr, char * buf) | 95 | wake_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 | ||
81 | static struct attribute * power_attrs[] = { | 129 | static 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); | |||
28 | extern int pm_runtime_barrier(struct device *dev); | 28 | extern int pm_runtime_barrier(struct device *dev); |
29 | extern void pm_runtime_enable(struct device *dev); | 29 | extern void pm_runtime_enable(struct device *dev); |
30 | extern void __pm_runtime_disable(struct device *dev, bool check_resume); | 30 | extern void __pm_runtime_disable(struct device *dev, bool check_resume); |
31 | extern void pm_runtime_allow(struct device *dev); | ||
32 | extern void pm_runtime_forbid(struct device *dev); | ||
31 | 33 | ||
32 | static inline bool pm_children_suspended(struct device *dev) | 34 | static inline bool pm_children_suspended(struct device *dev) |
33 | { | 35 | { |
@@ -78,6 +80,8 @@ static inline int __pm_runtime_set_status(struct device *dev, | |||
78 | static inline int pm_runtime_barrier(struct device *dev) { return 0; } | 80 | static inline int pm_runtime_barrier(struct device *dev) { return 0; } |
79 | static inline void pm_runtime_enable(struct device *dev) {} | 81 | static inline void pm_runtime_enable(struct device *dev) {} |
80 | static inline void __pm_runtime_disable(struct device *dev, bool c) {} | 82 | static inline void __pm_runtime_disable(struct device *dev, bool c) {} |
83 | static inline void pm_runtime_allow(struct device *dev) {} | ||
84 | static inline void pm_runtime_forbid(struct device *dev) {} | ||
81 | 85 | ||
82 | static inline bool pm_children_suspended(struct device *dev) { return false; } | 86 | static inline bool pm_children_suspended(struct device *dev) { return false; } |
83 | static inline void pm_suspend_ignore_children(struct device *dev, bool en) {} | 87 | static inline void pm_suspend_ignore_children(struct device *dev, bool en) {} |