aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/power/runtime_pm.txt65
-rw-r--r--drivers/base/power/Makefile1
-rw-r--r--drivers/base/power/generic_ops.c233
-rw-r--r--include/linux/pm.h51
-rw-r--r--include/linux/pm_runtime.h6
5 files changed, 350 insertions, 6 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index f19370641684..ab00eeddecaf 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -335,6 +335,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
335 'power.runtime_error' is set or 'power.disable_depth' is greater than 335 'power.runtime_error' is set or 'power.disable_depth' is greater than
336 zero) 336 zero)
337 337
338 bool pm_runtime_suspended(struct device *dev);
339 - return true if the device's runtime PM status is 'suspended', or false
340 otherwise
341
338 void pm_runtime_allow(struct device *dev); 342 void pm_runtime_allow(struct device *dev);
339 - set the power.runtime_auto flag for the device and decrease its usage 343 - set the power.runtime_auto flag for the device and decrease its usage
340 counter (used by the /sys/devices/.../power/control interface to 344 counter (used by the /sys/devices/.../power/control interface to
@@ -459,3 +463,64 @@ The PM core always increments the run-time usage counter before calling the
459->prepare() callback and decrements it after calling the ->complete() callback. 463->prepare() callback and decrements it after calling the ->complete() callback.
460Hence disabling run-time PM temporarily like this will not cause any run-time 464Hence disabling run-time PM temporarily like this will not cause any run-time
461suspend callbacks to be lost. 465suspend callbacks to be lost.
466
4677. Generic subsystem callbacks
468
469Subsystems may wish to conserve code space by using the set of generic power
470management callbacks provided by the PM core, defined in
471driver/base/power/generic_ops.c:
472
473 int pm_generic_runtime_idle(struct device *dev);
474 - invoke the ->runtime_idle() callback provided by the driver of this
475 device, if defined, and call pm_runtime_suspend() for this device if the
476 return value is 0 or the callback is not defined
477
478 int pm_generic_runtime_suspend(struct device *dev);
479 - invoke the ->runtime_suspend() callback provided by the driver of this
480 device and return its result, or return -EINVAL if not defined
481
482 int pm_generic_runtime_resume(struct device *dev);
483 - invoke the ->runtime_resume() callback provided by the driver of this
484 device and return its result, or return -EINVAL if not defined
485
486 int pm_generic_suspend(struct device *dev);
487 - if the device has not been suspended at run time, invoke the ->suspend()
488 callback provided by its driver and return its result, or return 0 if not
489 defined
490
491 int pm_generic_resume(struct device *dev);
492 - invoke the ->resume() callback provided by the driver of this device and,
493 if successful, change the device's runtime PM status to 'active'
494
495 int pm_generic_freeze(struct device *dev);
496 - if the device has not been suspended at run time, invoke the ->freeze()
497 callback provided by its driver and return its result, or return 0 if not
498 defined
499
500 int pm_generic_thaw(struct device *dev);
501 - if the device has not been suspended at run time, invoke the ->thaw()
502 callback provided by its driver and return its result, or return 0 if not
503 defined
504
505 int pm_generic_poweroff(struct device *dev);
506 - if the device has not been suspended at run time, invoke the ->poweroff()
507 callback provided by its driver and return its result, or return 0 if not
508 defined
509
510 int pm_generic_restore(struct device *dev);
511 - invoke the ->restore() callback provided by the driver of this device and,
512 if successful, change the device's runtime PM status to 'active'
513
514These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(),
515->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(),
516or ->restore() callback pointers in the subsystem-level dev_pm_ops structures.
517
518If a subsystem wishes to use all of them at the same time, it can simply assign
519the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its
520dev_pm_ops structure pointer.
521
522Device drivers that wish to use the same function as a system suspend, freeze,
523poweroff and run-time suspend callback, and similarly for system resume, thaw,
524restore, and run-time resume, can achieve this with the help of the
525UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its
526last argument to NULL).
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 3ce3519e8f30..89de75325cea 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,7 @@
1obj-$(CONFIG_PM) += sysfs.o 1obj-$(CONFIG_PM) += sysfs.o
2obj-$(CONFIG_PM_SLEEP) += main.o 2obj-$(CONFIG_PM_SLEEP) += main.o
3obj-$(CONFIG_PM_RUNTIME) += runtime.o 3obj-$(CONFIG_PM_RUNTIME) += runtime.o
4obj-$(CONFIG_PM_OPS) += generic_ops.o
4obj-$(CONFIG_PM_TRACE_RTC) += trace.o 5obj-$(CONFIG_PM_TRACE_RTC) += trace.o
5 6
6ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG 7ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
new file mode 100644
index 000000000000..4b29d4981253
--- /dev/null
+++ b/drivers/base/power/generic_ops.c
@@ -0,0 +1,233 @@
1/*
2 * drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems
3 *
4 * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
5 *
6 * This file is released under the GPLv2.
7 */
8
9#include <linux/pm.h>
10#include <linux/pm_runtime.h>
11
12#ifdef CONFIG_PM_RUNTIME
13/**
14 * pm_generic_runtime_idle - Generic runtime idle callback for subsystems.
15 * @dev: Device to handle.
16 *
17 * If PM operations are defined for the @dev's driver and they include
18 * ->runtime_idle(), execute it and return its error code, if nonzero.
19 * Otherwise, execute pm_runtime_suspend() for the device and return 0.
20 */
21int pm_generic_runtime_idle(struct device *dev)
22{
23 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
24
25 if (pm && pm->runtime_idle) {
26 int ret = pm->runtime_idle(dev);
27 if (ret)
28 return ret;
29 }
30
31 pm_runtime_suspend(dev);
32 return 0;
33}
34EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);
35
36/**
37 * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
38 * @dev: Device to suspend.
39 *
40 * If PM operations are defined for the @dev's driver and they include
41 * ->runtime_suspend(), execute it and return its error code. Otherwise,
42 * return -EINVAL.
43 */
44int pm_generic_runtime_suspend(struct device *dev)
45{
46 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
47 int ret;
48
49 ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL;
50
51 return ret;
52}
53EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend);
54
55/**
56 * pm_generic_runtime_resume - Generic runtime resume callback for subsystems.
57 * @dev: Device to resume.
58 *
59 * If PM operations are defined for the @dev's driver and they include
60 * ->runtime_resume(), execute it and return its error code. Otherwise,
61 * return -EINVAL.
62 */
63int pm_generic_runtime_resume(struct device *dev)
64{
65 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
66 int ret;
67
68 ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL;
69
70 return ret;
71}
72EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
73#endif /* CONFIG_PM_RUNTIME */
74
75#ifdef CONFIG_PM_SLEEP
76/**
77 * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback.
78 * @dev: Device to handle.
79 * @event: PM transition of the system under way.
80 *
81 * If the device has not been suspended at run time, execute the
82 * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and
83 * return its error code. Otherwise, return zero.
84 */
85static int __pm_generic_call(struct device *dev, int event)
86{
87 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
88 int (*callback)(struct device *);
89
90 if (!pm || pm_runtime_suspended(dev))
91 return 0;
92
93 switch (event) {
94 case PM_EVENT_SUSPEND:
95 callback = pm->suspend;
96 break;
97 case PM_EVENT_FREEZE:
98 callback = pm->freeze;
99 break;
100 case PM_EVENT_HIBERNATE:
101 callback = pm->poweroff;
102 break;
103 case PM_EVENT_THAW:
104 callback = pm->thaw;
105 break;
106 default:
107 callback = NULL;
108 break;
109 }
110
111 return callback ? callback(dev) : 0;
112}
113
114/**
115 * pm_generic_suspend - Generic suspend callback for subsystems.
116 * @dev: Device to suspend.
117 */
118int pm_generic_suspend(struct device *dev)
119{
120 return __pm_generic_call(dev, PM_EVENT_SUSPEND);
121}
122EXPORT_SYMBOL_GPL(pm_generic_suspend);
123
124/**
125 * pm_generic_freeze - Generic freeze callback for subsystems.
126 * @dev: Device to freeze.
127 */
128int pm_generic_freeze(struct device *dev)
129{
130 return __pm_generic_call(dev, PM_EVENT_FREEZE);
131}
132EXPORT_SYMBOL_GPL(pm_generic_freeze);
133
134/**
135 * pm_generic_poweroff - Generic poweroff callback for subsystems.
136 * @dev: Device to handle.
137 */
138int pm_generic_poweroff(struct device *dev)
139{
140 return __pm_generic_call(dev, PM_EVENT_HIBERNATE);
141}
142EXPORT_SYMBOL_GPL(pm_generic_poweroff);
143
144/**
145 * pm_generic_thaw - Generic thaw callback for subsystems.
146 * @dev: Device to thaw.
147 */
148int pm_generic_thaw(struct device *dev)
149{
150 return __pm_generic_call(dev, PM_EVENT_THAW);
151}
152EXPORT_SYMBOL_GPL(pm_generic_thaw);
153
154/**
155 * __pm_generic_resume - Generic resume/restore callback for subsystems.
156 * @dev: Device to handle.
157 * @event: PM transition of the system under way.
158 *
159 * Execute the resume/resotre callback provided by the @dev's driver, if
160 * defined. If it returns 0, change the device's runtime PM status to 'active'.
161 * Return the callback's error code.
162 */
163static int __pm_generic_resume(struct device *dev, int event)
164{
165 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
166 int (*callback)(struct device *);
167 int ret;
168
169 if (!pm)
170 return 0;
171
172 switch (event) {
173 case PM_EVENT_RESUME:
174 callback = pm->resume;
175 break;
176 case PM_EVENT_RESTORE:
177 callback = pm->restore;
178 break;
179 default:
180 callback = NULL;
181 break;
182 }
183
184 if (!callback)
185 return 0;
186
187 ret = callback(dev);
188 if (!ret) {
189 pm_runtime_disable(dev);
190 pm_runtime_set_active(dev);
191 pm_runtime_enable(dev);
192 }
193
194 return ret;
195}
196
197/**
198 * pm_generic_resume - Generic resume callback for subsystems.
199 * @dev: Device to resume.
200 */
201int pm_generic_resume(struct device *dev)
202{
203 return __pm_generic_resume(dev, PM_EVENT_RESUME);
204}
205EXPORT_SYMBOL_GPL(pm_generic_resume);
206
207/**
208 * pm_generic_restore - Generic restore callback for subsystems.
209 * @dev: Device to restore.
210 */
211int pm_generic_restore(struct device *dev)
212{
213 return __pm_generic_resume(dev, PM_EVENT_RESTORE);
214}
215EXPORT_SYMBOL_GPL(pm_generic_restore);
216#endif /* CONFIG_PM_SLEEP */
217
218struct dev_pm_ops generic_subsys_pm_ops = {
219#ifdef CONFIG_PM_SLEEP
220 .suspend = pm_generic_suspend,
221 .resume = pm_generic_resume,
222 .freeze = pm_generic_freeze,
223 .thaw = pm_generic_thaw,
224 .poweroff = pm_generic_poweroff,
225 .restore = pm_generic_restore,
226#endif
227#ifdef CONFIG_PM_RUNTIME
228 .runtime_suspend = pm_generic_runtime_suspend,
229 .runtime_resume = pm_generic_runtime_resume,
230 .runtime_idle = pm_generic_runtime_idle,
231#endif
232};
233EXPORT_SYMBOL_GPL(generic_subsys_pm_ops);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index e80df06ad22a..8e258c727971 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -215,20 +215,59 @@ struct dev_pm_ops {
215 int (*runtime_idle)(struct device *dev); 215 int (*runtime_idle)(struct device *dev);
216}; 216};
217 217
218#ifdef CONFIG_PM_SLEEP
219#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
220 .suspend = suspend_fn, \
221 .resume = resume_fn, \
222 .freeze = suspend_fn, \
223 .thaw = resume_fn, \
224 .poweroff = suspend_fn, \
225 .restore = resume_fn,
226#else
227#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
228#endif
229
230#ifdef CONFIG_PM_RUNTIME
231#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
232 .runtime_suspend = suspend_fn, \
233 .runtime_resume = resume_fn, \
234 .runtime_idle = idle_fn,
235#else
236#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
237#endif
238
218/* 239/*
219 * Use this if you want to use the same suspend and resume callbacks for suspend 240 * Use this if you want to use the same suspend and resume callbacks for suspend
220 * to RAM and hibernation. 241 * to RAM and hibernation.
221 */ 242 */
222#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ 243#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
223const struct dev_pm_ops name = { \ 244const struct dev_pm_ops name = { \
224 .suspend = suspend_fn, \ 245 SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
225 .resume = resume_fn, \ 246}
226 .freeze = suspend_fn, \ 247
227 .thaw = resume_fn, \ 248/*
228 .poweroff = suspend_fn, \ 249 * Use this for defining a set of PM operations to be used in all situations
229 .restore = resume_fn, \ 250 * (sustem suspend, hibernation or runtime PM).
251 */
252#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \
253const struct dev_pm_ops name = { \
254 SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
255 SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
230} 256}
231 257
258/*
259 * Use this for subsystems (bus types, device types, device classes) that don't
260 * need any special suspend/resume handling in addition to invoking the PM
261 * callbacks provided by device drivers supporting both the system sleep PM and
262 * runtime PM, make the pm member point to generic_subsys_pm_ops.
263 */
264#ifdef CONFIG_PM_OPS
265extern struct dev_pm_ops generic_subsys_pm_ops;
266#define GENERIC_SUBSYS_PM_OPS (&generic_subsys_pm_ops)
267#else
268#define GENERIC_SUBSYS_PM_OPS NULL
269#endif
270
232/** 271/**
233 * PM_EVENT_ messages 272 * PM_EVENT_ messages
234 * 273 *
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 7d773aac5314..b776db737244 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -62,6 +62,11 @@ static inline void device_set_run_wake(struct device *dev, bool enable)
62 dev->power.run_wake = enable; 62 dev->power.run_wake = enable;
63} 63}
64 64
65static inline bool pm_runtime_suspended(struct device *dev)
66{
67 return dev->power.runtime_status == RPM_SUSPENDED;
68}
69
65#else /* !CONFIG_PM_RUNTIME */ 70#else /* !CONFIG_PM_RUNTIME */
66 71
67static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } 72static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; }
@@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresume(struct device *dev) {}
89static inline void pm_runtime_put_noidle(struct device *dev) {} 94static inline void pm_runtime_put_noidle(struct device *dev) {}
90static inline bool device_run_wake(struct device *dev) { return false; } 95static inline bool device_run_wake(struct device *dev) { return false; }
91static inline void device_set_run_wake(struct device *dev, bool enable) {} 96static inline void device_set_run_wake(struct device *dev, bool enable) {}
97static inline bool pm_runtime_suspended(struct device *dev) { return false; }
92 98
93#endif /* !CONFIG_PM_RUNTIME */ 99#endif /* !CONFIG_PM_RUNTIME */
94 100