Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/base/power/generic_ops.c
15113 views
1
/*
2
* drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems
3
*
4
* Copyright (c) 2010 Rafael J. Wysocki <[email protected]>, 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);
273
274