Commit | Line | Data |
---|---|---|
d690b2cd RW |
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> | |
1b6bc32f | 11 | #include <linux/export.h> |
58a1fbbb | 12 | #include <linux/suspend.h> |
d690b2cd | 13 | |
717e5d45 | 14 | #ifdef CONFIG_PM |
d690b2cd RW |
15 | /** |
16 | * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. | |
17 | * @dev: Device to suspend. | |
18 | * | |
19 | * If PM operations are defined for the @dev's driver and they include | |
20 | * ->runtime_suspend(), execute it and return its error code. Otherwise, | |
6675bc05 | 21 | * return 0. |
d690b2cd RW |
22 | */ |
23 | int pm_generic_runtime_suspend(struct device *dev) | |
24 | { | |
25 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
26 | int ret; | |
27 | ||
05aa55dd | 28 | ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0; |
d690b2cd RW |
29 | |
30 | return ret; | |
31 | } | |
32 | EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); | |
33 | ||
34 | /** | |
35 | * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. | |
36 | * @dev: Device to resume. | |
37 | * | |
38 | * If PM operations are defined for the @dev's driver and they include | |
39 | * ->runtime_resume(), execute it and return its error code. Otherwise, | |
6675bc05 | 40 | * return 0. |
d690b2cd RW |
41 | */ |
42 | int pm_generic_runtime_resume(struct device *dev) | |
43 | { | |
44 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
45 | int ret; | |
46 | ||
05aa55dd | 47 | ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0; |
d690b2cd RW |
48 | |
49 | return ret; | |
50 | } | |
51 | EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); | |
717e5d45 | 52 | #endif /* CONFIG_PM */ |
d690b2cd RW |
53 | |
54 | #ifdef CONFIG_PM_SLEEP | |
6538df80 RW |
55 | /** |
56 | * pm_generic_prepare - Generic routine preparing a device for power transition. | |
57 | * @dev: Device to prepare. | |
58 | * | |
59 | * Prepare a device for a system-wide power transition. | |
60 | */ | |
61 | int pm_generic_prepare(struct device *dev) | |
62 | { | |
63 | struct device_driver *drv = dev->driver; | |
64 | int ret = 0; | |
65 | ||
66 | if (drv && drv->pm && drv->pm->prepare) | |
67 | ret = drv->pm->prepare(dev); | |
68 | ||
69 | return ret; | |
70 | } | |
71 | ||
d690b2cd | 72 | /** |
e470d066 RW |
73 | * pm_generic_suspend_noirq - Generic suspend_noirq callback for subsystems. |
74 | * @dev: Device to suspend. | |
d690b2cd | 75 | */ |
e470d066 | 76 | int pm_generic_suspend_noirq(struct device *dev) |
d690b2cd RW |
77 | { |
78 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
d690b2cd | 79 | |
e470d066 | 80 | return pm && pm->suspend_noirq ? pm->suspend_noirq(dev) : 0; |
d690b2cd | 81 | } |
e470d066 | 82 | EXPORT_SYMBOL_GPL(pm_generic_suspend_noirq); |
d690b2cd | 83 | |
e5291928 | 84 | /** |
e470d066 | 85 | * pm_generic_suspend_late - Generic suspend_late callback for subsystems. |
e5291928 RW |
86 | * @dev: Device to suspend. |
87 | */ | |
e470d066 | 88 | int pm_generic_suspend_late(struct device *dev) |
e5291928 | 89 | { |
e470d066 RW |
90 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
91 | ||
92 | return pm && pm->suspend_late ? pm->suspend_late(dev) : 0; | |
e5291928 | 93 | } |
e470d066 | 94 | EXPORT_SYMBOL_GPL(pm_generic_suspend_late); |
e5291928 | 95 | |
d690b2cd RW |
96 | /** |
97 | * pm_generic_suspend - Generic suspend callback for subsystems. | |
98 | * @dev: Device to suspend. | |
99 | */ | |
100 | int pm_generic_suspend(struct device *dev) | |
101 | { | |
e470d066 RW |
102 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
103 | ||
104 | return pm && pm->suspend ? pm->suspend(dev) : 0; | |
d690b2cd RW |
105 | } |
106 | EXPORT_SYMBOL_GPL(pm_generic_suspend); | |
107 | ||
e5291928 RW |
108 | /** |
109 | * pm_generic_freeze_noirq - Generic freeze_noirq callback for subsystems. | |
110 | * @dev: Device to freeze. | |
111 | */ | |
112 | int pm_generic_freeze_noirq(struct device *dev) | |
113 | { | |
e470d066 RW |
114 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
115 | ||
116 | return pm && pm->freeze_noirq ? pm->freeze_noirq(dev) : 0; | |
e5291928 RW |
117 | } |
118 | EXPORT_SYMBOL_GPL(pm_generic_freeze_noirq); | |
119 | ||
e470d066 RW |
120 | /** |
121 | * pm_generic_freeze_late - Generic freeze_late callback for subsystems. | |
122 | * @dev: Device to freeze. | |
123 | */ | |
124 | int pm_generic_freeze_late(struct device *dev) | |
125 | { | |
126 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
127 | ||
128 | return pm && pm->freeze_late ? pm->freeze_late(dev) : 0; | |
129 | } | |
130 | EXPORT_SYMBOL_GPL(pm_generic_freeze_late); | |
131 | ||
d690b2cd RW |
132 | /** |
133 | * pm_generic_freeze - Generic freeze callback for subsystems. | |
134 | * @dev: Device to freeze. | |
135 | */ | |
136 | int pm_generic_freeze(struct device *dev) | |
137 | { | |
e470d066 RW |
138 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
139 | ||
140 | return pm && pm->freeze ? pm->freeze(dev) : 0; | |
d690b2cd RW |
141 | } |
142 | EXPORT_SYMBOL_GPL(pm_generic_freeze); | |
143 | ||
e5291928 RW |
144 | /** |
145 | * pm_generic_poweroff_noirq - Generic poweroff_noirq callback for subsystems. | |
146 | * @dev: Device to handle. | |
147 | */ | |
148 | int pm_generic_poweroff_noirq(struct device *dev) | |
149 | { | |
e470d066 RW |
150 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
151 | ||
152 | return pm && pm->poweroff_noirq ? pm->poweroff_noirq(dev) : 0; | |
e5291928 RW |
153 | } |
154 | EXPORT_SYMBOL_GPL(pm_generic_poweroff_noirq); | |
155 | ||
e470d066 RW |
156 | /** |
157 | * pm_generic_poweroff_late - Generic poweroff_late callback for subsystems. | |
158 | * @dev: Device to handle. | |
159 | */ | |
160 | int pm_generic_poweroff_late(struct device *dev) | |
161 | { | |
162 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
163 | ||
164 | return pm && pm->poweroff_late ? pm->poweroff_late(dev) : 0; | |
165 | } | |
166 | EXPORT_SYMBOL_GPL(pm_generic_poweroff_late); | |
167 | ||
d690b2cd RW |
168 | /** |
169 | * pm_generic_poweroff - Generic poweroff callback for subsystems. | |
170 | * @dev: Device to handle. | |
171 | */ | |
172 | int pm_generic_poweroff(struct device *dev) | |
173 | { | |
e470d066 RW |
174 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
175 | ||
176 | return pm && pm->poweroff ? pm->poweroff(dev) : 0; | |
d690b2cd RW |
177 | } |
178 | EXPORT_SYMBOL_GPL(pm_generic_poweroff); | |
179 | ||
e5291928 RW |
180 | /** |
181 | * pm_generic_thaw_noirq - Generic thaw_noirq callback for subsystems. | |
182 | * @dev: Device to thaw. | |
183 | */ | |
184 | int pm_generic_thaw_noirq(struct device *dev) | |
185 | { | |
e470d066 RW |
186 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
187 | ||
188 | return pm && pm->thaw_noirq ? pm->thaw_noirq(dev) : 0; | |
e5291928 RW |
189 | } |
190 | EXPORT_SYMBOL_GPL(pm_generic_thaw_noirq); | |
191 | ||
e470d066 RW |
192 | /** |
193 | * pm_generic_thaw_early - Generic thaw_early callback for subsystems. | |
194 | * @dev: Device to thaw. | |
195 | */ | |
196 | int pm_generic_thaw_early(struct device *dev) | |
197 | { | |
198 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
199 | ||
200 | return pm && pm->thaw_early ? pm->thaw_early(dev) : 0; | |
201 | } | |
202 | EXPORT_SYMBOL_GPL(pm_generic_thaw_early); | |
203 | ||
d690b2cd RW |
204 | /** |
205 | * pm_generic_thaw - Generic thaw callback for subsystems. | |
206 | * @dev: Device to thaw. | |
207 | */ | |
208 | int pm_generic_thaw(struct device *dev) | |
209 | { | |
e470d066 RW |
210 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
211 | ||
212 | return pm && pm->thaw ? pm->thaw(dev) : 0; | |
d690b2cd RW |
213 | } |
214 | EXPORT_SYMBOL_GPL(pm_generic_thaw); | |
215 | ||
e5291928 RW |
216 | /** |
217 | * pm_generic_resume_noirq - Generic resume_noirq callback for subsystems. | |
218 | * @dev: Device to resume. | |
219 | */ | |
220 | int pm_generic_resume_noirq(struct device *dev) | |
221 | { | |
e470d066 RW |
222 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
223 | ||
224 | return pm && pm->resume_noirq ? pm->resume_noirq(dev) : 0; | |
e5291928 RW |
225 | } |
226 | EXPORT_SYMBOL_GPL(pm_generic_resume_noirq); | |
227 | ||
e470d066 RW |
228 | /** |
229 | * pm_generic_resume_early - Generic resume_early callback for subsystems. | |
230 | * @dev: Device to resume. | |
231 | */ | |
232 | int pm_generic_resume_early(struct device *dev) | |
233 | { | |
234 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
235 | ||
236 | return pm && pm->resume_early ? pm->resume_early(dev) : 0; | |
237 | } | |
238 | EXPORT_SYMBOL_GPL(pm_generic_resume_early); | |
239 | ||
d690b2cd RW |
240 | /** |
241 | * pm_generic_resume - Generic resume callback for subsystems. | |
242 | * @dev: Device to resume. | |
243 | */ | |
244 | int pm_generic_resume(struct device *dev) | |
245 | { | |
e470d066 RW |
246 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
247 | ||
248 | return pm && pm->resume ? pm->resume(dev) : 0; | |
d690b2cd RW |
249 | } |
250 | EXPORT_SYMBOL_GPL(pm_generic_resume); | |
251 | ||
e5291928 RW |
252 | /** |
253 | * pm_generic_restore_noirq - Generic restore_noirq callback for subsystems. | |
254 | * @dev: Device to restore. | |
255 | */ | |
256 | int pm_generic_restore_noirq(struct device *dev) | |
257 | { | |
e470d066 RW |
258 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
259 | ||
260 | return pm && pm->restore_noirq ? pm->restore_noirq(dev) : 0; | |
e5291928 RW |
261 | } |
262 | EXPORT_SYMBOL_GPL(pm_generic_restore_noirq); | |
263 | ||
e470d066 RW |
264 | /** |
265 | * pm_generic_restore_early - Generic restore_early callback for subsystems. | |
266 | * @dev: Device to resume. | |
267 | */ | |
268 | int pm_generic_restore_early(struct device *dev) | |
269 | { | |
270 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | |
271 | ||
272 | return pm && pm->restore_early ? pm->restore_early(dev) : 0; | |
273 | } | |
274 | EXPORT_SYMBOL_GPL(pm_generic_restore_early); | |
275 | ||
d690b2cd RW |
276 | /** |
277 | * pm_generic_restore - Generic restore callback for subsystems. | |
278 | * @dev: Device to restore. | |
279 | */ | |
280 | int pm_generic_restore(struct device *dev) | |
281 | { | |
e470d066 RW |
282 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
283 | ||
284 | return pm && pm->restore ? pm->restore(dev) : 0; | |
d690b2cd RW |
285 | } |
286 | EXPORT_SYMBOL_GPL(pm_generic_restore); | |
6538df80 RW |
287 | |
288 | /** | |
9accff57 | 289 | * pm_generic_complete - Generic routine completing a device power transition. |
6538df80 RW |
290 | * @dev: Device to handle. |
291 | * | |
292 | * Complete a device power transition during a system-wide power transition. | |
293 | */ | |
294 | void pm_generic_complete(struct device *dev) | |
295 | { | |
296 | struct device_driver *drv = dev->driver; | |
297 | ||
298 | if (drv && drv->pm && drv->pm->complete) | |
299 | drv->pm->complete(dev); | |
6538df80 | 300 | } |
58a1fbbb RW |
301 | |
302 | /** | |
303 | * pm_complete_with_resume_check - Complete a device power transition. | |
304 | * @dev: Device to handle. | |
305 | * | |
306 | * Complete a device power transition during a system-wide power transition and | |
307 | * optionally schedule a runtime resume of the device if the system resume in | |
308 | * progress has been initated by the platform firmware and the device had its | |
309 | * power.direct_complete flag set. | |
310 | */ | |
311 | void pm_complete_with_resume_check(struct device *dev) | |
312 | { | |
313 | pm_generic_complete(dev); | |
314 | /* | |
315 | * If the device had been runtime-suspended before the system went into | |
316 | * the sleep state it is going out of and it has never been resumed till | |
317 | * now, resume it in case the firmware powered it up. | |
318 | */ | |
319 | if (dev->power.direct_complete && pm_resume_via_firmware()) | |
320 | pm_request_resume(dev); | |
321 | } | |
322 | EXPORT_SYMBOL_GPL(pm_complete_with_resume_check); | |
d690b2cd | 323 | #endif /* CONFIG_PM_SLEEP */ |