diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-01-17 08:11:08 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-01-19 16:09:22 -0500 |
commit | 9ce4e607111764673f7a59d7bc87a16ade5c7bba (patch) | |
tree | 54c7fbd2833e69b0c5e68eac418ef36d6e51e7a0 /drivers/acpi/bus.c | |
parent | 96bfd3cee2a741906b3ef5c1096d2f0a0b8025e0 (diff) |
ACPI / PM: Move device power management functions to device_pm.c
Move ACPI device power management functions from drivers/acpi/bus.c
to drivers/acpi/device_pm.c.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/bus.c')
-rw-r--r-- | drivers/acpi/bus.c | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 6c9b16c16660..01708a165368 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -178,299 +178,6 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) | |||
178 | } | 178 | } |
179 | EXPORT_SYMBOL(acpi_bus_get_private_data); | 179 | EXPORT_SYMBOL(acpi_bus_get_private_data); |
180 | 180 | ||
181 | /* -------------------------------------------------------------------------- | ||
182 | Power Management | ||
183 | -------------------------------------------------------------------------- */ | ||
184 | |||
185 | /** | ||
186 | * acpi_power_state_string - String representation of ACPI device power state. | ||
187 | * @state: ACPI device power state to return the string representation of. | ||
188 | */ | ||
189 | const char *acpi_power_state_string(int state) | ||
190 | { | ||
191 | switch (state) { | ||
192 | case ACPI_STATE_D0: | ||
193 | return "D0"; | ||
194 | case ACPI_STATE_D1: | ||
195 | return "D1"; | ||
196 | case ACPI_STATE_D2: | ||
197 | return "D2"; | ||
198 | case ACPI_STATE_D3_HOT: | ||
199 | return "D3hot"; | ||
200 | case ACPI_STATE_D3_COLD: | ||
201 | return "D3"; | ||
202 | default: | ||
203 | return "(unknown)"; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | /** | ||
208 | * acpi_device_get_power - Get power state of an ACPI device. | ||
209 | * @device: Device to get the power state of. | ||
210 | * @state: Place to store the power state of the device. | ||
211 | * | ||
212 | * This function does not update the device's power.state field, but it may | ||
213 | * update its parent's power.state field (when the parent's power state is | ||
214 | * unknown and the device's power state turns out to be D0). | ||
215 | */ | ||
216 | int acpi_device_get_power(struct acpi_device *device, int *state) | ||
217 | { | ||
218 | int result = ACPI_STATE_UNKNOWN; | ||
219 | |||
220 | if (!device || !state) | ||
221 | return -EINVAL; | ||
222 | |||
223 | if (!device->flags.power_manageable) { | ||
224 | /* TBD: Non-recursive algorithm for walking up hierarchy. */ | ||
225 | *state = device->parent ? | ||
226 | device->parent->power.state : ACPI_STATE_D0; | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Get the device's power state either directly (via _PSC) or | ||
232 | * indirectly (via power resources). | ||
233 | */ | ||
234 | if (device->power.flags.explicit_get) { | ||
235 | unsigned long long psc; | ||
236 | acpi_status status = acpi_evaluate_integer(device->handle, | ||
237 | "_PSC", NULL, &psc); | ||
238 | if (ACPI_FAILURE(status)) | ||
239 | return -ENODEV; | ||
240 | |||
241 | result = psc; | ||
242 | } | ||
243 | /* The test below covers ACPI_STATE_UNKNOWN too. */ | ||
244 | if (result <= ACPI_STATE_D2) { | ||
245 | ; /* Do nothing. */ | ||
246 | } else if (device->power.flags.power_resources) { | ||
247 | int error = acpi_power_get_inferred_state(device, &result); | ||
248 | if (error) | ||
249 | return error; | ||
250 | } else if (result == ACPI_STATE_D3_HOT) { | ||
251 | result = ACPI_STATE_D3; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * If we were unsure about the device parent's power state up to this | ||
256 | * point, the fact that the device is in D0 implies that the parent has | ||
257 | * to be in D0 too. | ||
258 | */ | ||
259 | if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN | ||
260 | && result == ACPI_STATE_D0) | ||
261 | device->parent->power.state = ACPI_STATE_D0; | ||
262 | |||
263 | *state = result; | ||
264 | |||
265 | out: | ||
266 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", | ||
267 | device->pnp.bus_id, acpi_power_state_string(*state))); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * acpi_device_set_power - Set power state of an ACPI device. | ||
275 | * @device: Device to set the power state of. | ||
276 | * @state: New power state to set. | ||
277 | * | ||
278 | * Callers must ensure that the device is power manageable before using this | ||
279 | * function. | ||
280 | */ | ||
281 | int acpi_device_set_power(struct acpi_device *device, int state) | ||
282 | { | ||
283 | int result = 0; | ||
284 | acpi_status status = AE_OK; | ||
285 | char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; | ||
286 | bool cut_power = false; | ||
287 | |||
288 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) | ||
289 | return -EINVAL; | ||
290 | |||
291 | /* Make sure this is a valid target state */ | ||
292 | |||
293 | if (state == device->power.state) { | ||
294 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", | ||
295 | acpi_power_state_string(state))); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | if (!device->power.states[state].flags.valid) { | ||
300 | printk(KERN_WARNING PREFIX "Device does not support %s\n", | ||
301 | acpi_power_state_string(state)); | ||
302 | return -ENODEV; | ||
303 | } | ||
304 | if (device->parent && (state < device->parent->power.state)) { | ||
305 | printk(KERN_WARNING PREFIX | ||
306 | "Cannot set device to a higher-powered" | ||
307 | " state than parent\n"); | ||
308 | return -ENODEV; | ||
309 | } | ||
310 | |||
311 | /* For D3cold we should first transition into D3hot. */ | ||
312 | if (state == ACPI_STATE_D3_COLD | ||
313 | && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) { | ||
314 | state = ACPI_STATE_D3_HOT; | ||
315 | object_name[3] = '3'; | ||
316 | cut_power = true; | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * Transition Power | ||
321 | * ---------------- | ||
322 | * On transitions to a high-powered state we first apply power (via | ||
323 | * power resources) then evalute _PSx. Conversly for transitions to | ||
324 | * a lower-powered state. | ||
325 | */ | ||
326 | if (state < device->power.state) { | ||
327 | if (device->power.state >= ACPI_STATE_D3_HOT && | ||
328 | state != ACPI_STATE_D0) { | ||
329 | printk(KERN_WARNING PREFIX | ||
330 | "Cannot transition to non-D0 state from D3\n"); | ||
331 | return -ENODEV; | ||
332 | } | ||
333 | if (device->power.flags.power_resources) { | ||
334 | result = acpi_power_transition(device, state); | ||
335 | if (result) | ||
336 | goto end; | ||
337 | } | ||
338 | if (device->power.states[state].flags.explicit_set) { | ||
339 | status = acpi_evaluate_object(device->handle, | ||
340 | object_name, NULL, NULL); | ||
341 | if (ACPI_FAILURE(status)) { | ||
342 | result = -ENODEV; | ||
343 | goto end; | ||
344 | } | ||
345 | } | ||
346 | } else { | ||
347 | if (device->power.states[state].flags.explicit_set) { | ||
348 | status = acpi_evaluate_object(device->handle, | ||
349 | object_name, NULL, NULL); | ||
350 | if (ACPI_FAILURE(status)) { | ||
351 | result = -ENODEV; | ||
352 | goto end; | ||
353 | } | ||
354 | } | ||
355 | if (device->power.flags.power_resources) { | ||
356 | result = acpi_power_transition(device, state); | ||
357 | if (result) | ||
358 | goto end; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | if (cut_power) | ||
363 | result = acpi_power_transition(device, ACPI_STATE_D3_COLD); | ||
364 | |||
365 | end: | ||
366 | if (result) | ||
367 | printk(KERN_WARNING PREFIX | ||
368 | "Device [%s] failed to transition to %s\n", | ||
369 | device->pnp.bus_id, | ||
370 | acpi_power_state_string(state)); | ||
371 | else { | ||
372 | device->power.state = state; | ||
373 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
374 | "Device [%s] transitioned to %s\n", | ||
375 | device->pnp.bus_id, | ||
376 | acpi_power_state_string(state))); | ||
377 | } | ||
378 | |||
379 | return result; | ||
380 | } | ||
381 | EXPORT_SYMBOL(acpi_device_set_power); | ||
382 | |||
383 | |||
384 | int acpi_bus_set_power(acpi_handle handle, int state) | ||
385 | { | ||
386 | struct acpi_device *device; | ||
387 | int result; | ||
388 | |||
389 | result = acpi_bus_get_device(handle, &device); | ||
390 | if (result) | ||
391 | return result; | ||
392 | |||
393 | if (!device->flags.power_manageable) { | ||
394 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
395 | "Device [%s] is not power manageable\n", | ||
396 | dev_name(&device->dev))); | ||
397 | return -ENODEV; | ||
398 | } | ||
399 | |||
400 | return acpi_device_set_power(device, state); | ||
401 | } | ||
402 | EXPORT_SYMBOL(acpi_bus_set_power); | ||
403 | |||
404 | |||
405 | int acpi_bus_init_power(struct acpi_device *device) | ||
406 | { | ||
407 | int state; | ||
408 | int result; | ||
409 | |||
410 | if (!device) | ||
411 | return -EINVAL; | ||
412 | |||
413 | device->power.state = ACPI_STATE_UNKNOWN; | ||
414 | |||
415 | result = acpi_device_get_power(device, &state); | ||
416 | if (result) | ||
417 | return result; | ||
418 | |||
419 | if (device->power.flags.power_resources) | ||
420 | result = acpi_power_on_resources(device, state); | ||
421 | |||
422 | if (!result) | ||
423 | device->power.state = state; | ||
424 | |||
425 | return result; | ||
426 | } | ||
427 | |||
428 | |||
429 | int acpi_bus_update_power(acpi_handle handle, int *state_p) | ||
430 | { | ||
431 | struct acpi_device *device; | ||
432 | int state; | ||
433 | int result; | ||
434 | |||
435 | result = acpi_bus_get_device(handle, &device); | ||
436 | if (result) | ||
437 | return result; | ||
438 | |||
439 | result = acpi_device_get_power(device, &state); | ||
440 | if (result) | ||
441 | return result; | ||
442 | |||
443 | result = acpi_device_set_power(device, state); | ||
444 | if (!result && state_p) | ||
445 | *state_p = state; | ||
446 | |||
447 | return result; | ||
448 | } | ||
449 | EXPORT_SYMBOL_GPL(acpi_bus_update_power); | ||
450 | |||
451 | |||
452 | bool acpi_bus_power_manageable(acpi_handle handle) | ||
453 | { | ||
454 | struct acpi_device *device; | ||
455 | int result; | ||
456 | |||
457 | result = acpi_bus_get_device(handle, &device); | ||
458 | return result ? false : device->flags.power_manageable; | ||
459 | } | ||
460 | |||
461 | EXPORT_SYMBOL(acpi_bus_power_manageable); | ||
462 | |||
463 | bool acpi_bus_can_wakeup(acpi_handle handle) | ||
464 | { | ||
465 | struct acpi_device *device; | ||
466 | int result; | ||
467 | |||
468 | result = acpi_bus_get_device(handle, &device); | ||
469 | return result ? false : device->wakeup.flags.valid; | ||
470 | } | ||
471 | |||
472 | EXPORT_SYMBOL(acpi_bus_can_wakeup); | ||
473 | |||
474 | static void acpi_print_osc_error(acpi_handle handle, | 181 | static void acpi_print_osc_error(acpi_handle handle, |
475 | struct acpi_osc_context *context, char *error) | 182 | struct acpi_osc_context *context, char *error) |
476 | { | 183 | { |