Merge branch 'core-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / base / power / generic_ops.c
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  */
21 int 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 }
34 EXPORT_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 0.
43  */
44 int 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) : 0;
50
51         return ret;
52 }
53 EXPORT_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 0.
62  */
63 int 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) : 0;
69
70         return ret;
71 }
72 EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
73 #endif /* CONFIG_PM_RUNTIME */
74
75 #ifdef CONFIG_PM_SLEEP
76 /**
77  * pm_generic_prepare - Generic routine preparing a device for power transition.
78  * @dev: Device to prepare.
79  *
80  * Prepare a device for a system-wide power transition.
81  */
82 int pm_generic_prepare(struct device *dev)
83 {
84         struct device_driver *drv = dev->driver;
85         int ret = 0;
86
87         if (drv && drv->pm && drv->pm->prepare)
88                 ret = drv->pm->prepare(dev);
89
90         return ret;
91 }
92
93 /**
94  * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback.
95  * @dev: Device to handle.
96  * @event: PM transition of the system under way.
97  *
98  * If the device has not been suspended at run time, execute the
99  * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and
100  * return its error code.  Otherwise, return zero.
101  */
102 static int __pm_generic_call(struct device *dev, int event)
103 {
104         const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
105         int (*callback)(struct device *);
106
107         if (!pm || pm_runtime_suspended(dev))
108                 return 0;
109
110         switch (event) {
111         case PM_EVENT_SUSPEND:
112                 callback = pm->suspend;
113                 break;
114         case PM_EVENT_FREEZE:
115                 callback = pm->freeze;
116                 break;
117         case PM_EVENT_HIBERNATE:
118                 callback = pm->poweroff;
119                 break;
120         case PM_EVENT_THAW:
121                 callback = pm->thaw;
122                 break;
123         default:
124                 callback = NULL;
125                 break;
126         }
127
128         return callback ? callback(dev) : 0;
129 }
130
131 /**
132  * pm_generic_suspend - Generic suspend callback for subsystems.
133  * @dev: Device to suspend.
134  */
135 int pm_generic_suspend(struct device *dev)
136 {
137         return __pm_generic_call(dev, PM_EVENT_SUSPEND);
138 }
139 EXPORT_SYMBOL_GPL(pm_generic_suspend);
140
141 /**
142  * pm_generic_freeze - Generic freeze callback for subsystems.
143  * @dev: Device to freeze.
144  */
145 int pm_generic_freeze(struct device *dev)
146 {
147         return __pm_generic_call(dev, PM_EVENT_FREEZE);
148 }
149 EXPORT_SYMBOL_GPL(pm_generic_freeze);
150
151 /**
152  * pm_generic_poweroff - Generic poweroff callback for subsystems.
153  * @dev: Device to handle.
154  */
155 int pm_generic_poweroff(struct device *dev)
156 {
157         return __pm_generic_call(dev, PM_EVENT_HIBERNATE);
158 }
159 EXPORT_SYMBOL_GPL(pm_generic_poweroff);
160
161 /**
162  * pm_generic_thaw - Generic thaw callback for subsystems.
163  * @dev: Device to thaw.
164  */
165 int pm_generic_thaw(struct device *dev)
166 {
167         return __pm_generic_call(dev, PM_EVENT_THAW);
168 }
169 EXPORT_SYMBOL_GPL(pm_generic_thaw);
170
171 /**
172  * __pm_generic_resume - Generic resume/restore callback for subsystems.
173  * @dev: Device to handle.
174  * @event: PM transition of the system under way.
175  *
176  * Execute the resume/resotre callback provided by the @dev's driver, if
177  * defined.  If it returns 0, change the device's runtime PM status to 'active'.
178  * Return the callback's error code.
179  */
180 static int __pm_generic_resume(struct device *dev, int event)
181 {
182         const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
183         int (*callback)(struct device *);
184         int ret;
185
186         if (!pm)
187                 return 0;
188
189         switch (event) {
190         case PM_EVENT_RESUME:
191                 callback = pm->resume;
192                 break;
193         case PM_EVENT_RESTORE:
194                 callback = pm->restore;
195                 break;
196         default:
197                 callback = NULL;
198                 break;
199         }
200
201         if (!callback)
202                 return 0;
203
204         ret = callback(dev);
205         if (!ret && pm_runtime_enabled(dev)) {
206                 pm_runtime_disable(dev);
207                 pm_runtime_set_active(dev);
208                 pm_runtime_enable(dev);
209         }
210
211         return ret;
212 }
213
214 /**
215  * pm_generic_resume - Generic resume callback for subsystems.
216  * @dev: Device to resume.
217  */
218 int pm_generic_resume(struct device *dev)
219 {
220         return __pm_generic_resume(dev, PM_EVENT_RESUME);
221 }
222 EXPORT_SYMBOL_GPL(pm_generic_resume);
223
224 /**
225  * pm_generic_restore - Generic restore callback for subsystems.
226  * @dev: Device to restore.
227  */
228 int pm_generic_restore(struct device *dev)
229 {
230         return __pm_generic_resume(dev, PM_EVENT_RESTORE);
231 }
232 EXPORT_SYMBOL_GPL(pm_generic_restore);
233
234 /**
235  * pm_generic_complete - Generic routine competing a device power transition.
236  * @dev: Device to handle.
237  *
238  * Complete a device power transition during a system-wide power transition.
239  */
240 void pm_generic_complete(struct device *dev)
241 {
242         struct device_driver *drv = dev->driver;
243
244         if (drv && drv->pm && drv->pm->complete)
245                 drv->pm->complete(dev);
246
247         /*
248          * Let runtime PM try to suspend devices that haven't been in use before
249          * going into the system-wide sleep state we're resuming from.
250          */
251         pm_runtime_idle(dev);
252 }
253 #endif /* CONFIG_PM_SLEEP */
254
255 struct dev_pm_ops generic_subsys_pm_ops = {
256 #ifdef CONFIG_PM_SLEEP
257         .prepare = pm_generic_prepare,
258         .suspend = pm_generic_suspend,
259         .resume = pm_generic_resume,
260         .freeze = pm_generic_freeze,
261         .thaw = pm_generic_thaw,
262         .poweroff = pm_generic_poweroff,
263         .restore = pm_generic_restore,
264         .complete = pm_generic_complete,
265 #endif
266 #ifdef CONFIG_PM_RUNTIME
267         .runtime_suspend = pm_generic_runtime_suspend,
268         .runtime_resume = pm_generic_runtime_resume,
269         .runtime_idle = pm_generic_runtime_idle,
270 #endif
271 };
272 EXPORT_SYMBOL_GPL(generic_subsys_pm_ops);