aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/device_pm.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-01 20:41:01 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-14 18:15:18 -0500
commite5cc8ef31267317f3e177415c84e3f3602e5bfc9 (patch)
tree2bfdef81387d47b80918d673f2aca74568187427 /drivers/acpi/device_pm.c
parenta6ae7594b1b157e0e7976ed105a7be27d69a5361 (diff)
ACPI / PM: Provide ACPI PM callback routines for subsystems
Some bus types don't support power management natively, but generally there may be device nodes in ACPI tables corresponding to the devices whose bus types they are (under ACPI 5 those bus types may be SPI, I2C and platform). If that is the case, standard ACPI power management may be applied to those devices, although currently the kernel has no means for that. For this reason, provide a set of routines that may be used as power management callbacks for such devices. This may be done in three different ways. (1) Device drivers handling the devices in question may run acpi_dev_pm_attach() in their .probe() routines, which (on success) will cause the devices to be added to the general ACPI PM domain and ACPI power management will be used for them going forward. Then, acpi_dev_pm_detach() may be used to remove the devices from the general ACPI PM domain if ACPI power management is not necessary for them any more. (2) The devices' subsystems may use acpi_subsys_runtime_suspend(), acpi_subsys_runtime_resume(), acpi_subsys_prepare(), acpi_subsys_suspend_late(), acpi_subsys_resume_early() as their power management callbacks in the same way as the general ACPI PM domain does that. (3) The devices' drivers may execute acpi_dev_suspend_late(), acpi_dev_resume_early(), acpi_dev_runtime_suspend(), acpi_dev_runtime_resume() from their power management callbacks as appropriate, if that's absolutely necessary, but it is not recommended to do that, because such drivers may not work without ACPI support as a result. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r--drivers/acpi/device_pm.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 7ddd93463a2e..a8e059f69d50 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -225,6 +225,22 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state);
225 225
226#ifdef CONFIG_PM_RUNTIME 226#ifdef CONFIG_PM_RUNTIME
227/** 227/**
228 * acpi_wakeup_device - Wakeup notification handler for ACPI devices.
229 * @handle: ACPI handle of the device the notification is for.
230 * @event: Type of the signaled event.
231 * @context: Device corresponding to @handle.
232 */
233static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context)
234{
235 struct device *dev = context;
236
237 if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) {
238 pm_wakeup_event(dev, 0);
239 pm_runtime_resume(dev);
240 }
241}
242
243/**
228 * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device. 244 * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device.
229 * @adev: ACPI device to enable/disable the remote wakeup for. 245 * @adev: ACPI device to enable/disable the remote wakeup for.
230 * @enable: Whether to enable or disable the wakeup functionality. 246 * @enable: Whether to enable or disable the wakeup functionality.
@@ -283,6 +299,9 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
283 return __acpi_device_run_wake(adev, enable); 299 return __acpi_device_run_wake(adev, enable);
284} 300}
285EXPORT_SYMBOL(acpi_pm_device_run_wake); 301EXPORT_SYMBOL(acpi_pm_device_run_wake);
302#else
303static inline void acpi_wakeup_device(acpi_handle handle, u32 event,
304 void *context) {}
286#endif /* CONFIG_PM_RUNTIME */ 305#endif /* CONFIG_PM_RUNTIME */
287 306
288 #ifdef CONFIG_PM_SLEEP 307 #ifdef CONFIG_PM_SLEEP
@@ -329,3 +348,301 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
329 return error; 348 return error;
330} 349}
331#endif /* CONFIG_PM_SLEEP */ 350#endif /* CONFIG_PM_SLEEP */
351
352/**
353 * acpi_dev_pm_get_node - Get ACPI device node for the given physical device.
354 * @dev: Device to get the ACPI node for.
355 */
356static struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
357{
358 acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
359 struct acpi_device *adev;
360
361 return handle && ACPI_SUCCESS(acpi_bus_get_device(handle, &adev)) ?
362 adev : NULL;
363}
364
365/**
366 * acpi_dev_pm_low_power - Put ACPI device into a low-power state.
367 * @dev: Device to put into a low-power state.
368 * @adev: ACPI device node corresponding to @dev.
369 * @system_state: System state to choose the device state for.
370 */
371static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev,
372 u32 system_state)
373{
374 int power_state;
375
376 if (!acpi_device_power_manageable(adev))
377 return 0;
378
379 power_state = acpi_device_power_state(dev, adev, system_state,
380 ACPI_STATE_D3, NULL);
381 if (power_state < ACPI_STATE_D0 || power_state > ACPI_STATE_D3)
382 return -EIO;
383
384 return acpi_device_set_power(adev, power_state);
385}
386
387/**
388 * acpi_dev_pm_full_power - Put ACPI device into the full-power state.
389 * @adev: ACPI device node to put into the full-power state.
390 */
391static int acpi_dev_pm_full_power(struct acpi_device *adev)
392{
393 return acpi_device_power_manageable(adev) ?
394 acpi_device_set_power(adev, ACPI_STATE_D0) : 0;
395}
396
397#ifdef CONFIG_PM_RUNTIME
398/**
399 * acpi_dev_runtime_suspend - Put device into a low-power state using ACPI.
400 * @dev: Device to put into a low-power state.
401 *
402 * Put the given device into a runtime low-power state using the standard ACPI
403 * mechanism. Set up remote wakeup if desired, choose the state to put the
404 * device into (this checks if remote wakeup is expected to work too), and set
405 * the power state of the device.
406 */
407int acpi_dev_runtime_suspend(struct device *dev)
408{
409 struct acpi_device *adev = acpi_dev_pm_get_node(dev);
410 bool remote_wakeup;
411 int error;
412
413 if (!adev)
414 return 0;
415
416 remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) >
417 PM_QOS_FLAGS_NONE;
418 error = __acpi_device_run_wake(adev, remote_wakeup);
419 if (remote_wakeup && error)
420 return -EAGAIN;
421
422 error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0);
423 if (error)
424 __acpi_device_run_wake(adev, false);
425
426 return error;
427}
428EXPORT_SYMBOL_GPL(acpi_dev_runtime_suspend);
429
430/**
431 * acpi_dev_runtime_resume - Put device into the full-power state using ACPI.
432 * @dev: Device to put into the full-power state.
433 *
434 * Put the given device into the full-power state using the standard ACPI
435 * mechanism at run time. Set the power state of the device to ACPI D0 and
436 * disable remote wakeup.
437 */
438int acpi_dev_runtime_resume(struct device *dev)
439{
440 struct acpi_device *adev = acpi_dev_pm_get_node(dev);
441 int error;
442
443 if (!adev)
444 return 0;
445
446 error = acpi_dev_pm_full_power(adev);
447 __acpi_device_run_wake(adev, false);
448 return error;
449}
450EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume);
451
452/**
453 * acpi_subsys_runtime_suspend - Suspend device using ACPI.
454 * @dev: Device to suspend.
455 *
456 * Carry out the generic runtime suspend procedure for @dev and use ACPI to put
457 * it into a runtime low-power state.
458 */
459int acpi_subsys_runtime_suspend(struct device *dev)
460{
461 int ret = pm_generic_runtime_suspend(dev);
462 return ret ? ret : acpi_dev_runtime_suspend(dev);
463}
464EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend);
465
466/**
467 * acpi_subsys_runtime_resume - Resume device using ACPI.
468 * @dev: Device to Resume.
469 *
470 * Use ACPI to put the given device into the full-power state and carry out the
471 * generic runtime resume procedure for it.
472 */
473int acpi_subsys_runtime_resume(struct device *dev)
474{
475 int ret = acpi_dev_runtime_resume(dev);
476 return ret ? ret : pm_generic_runtime_resume(dev);
477}
478EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume);
479#endif /* CONFIG_PM_RUNTIME */
480
481#ifdef CONFIG_PM_SLEEP
482/**
483 * acpi_dev_suspend_late - Put device into a low-power state using ACPI.
484 * @dev: Device to put into a low-power state.
485 *
486 * Put the given device into a low-power state during system transition to a
487 * sleep state using the standard ACPI mechanism. Set up system wakeup if
488 * desired, choose the state to put the device into (this checks if system
489 * wakeup is expected to work too), and set the power state of the device.
490 */
491int acpi_dev_suspend_late(struct device *dev)
492{
493 struct acpi_device *adev = acpi_dev_pm_get_node(dev);
494 u32 target_state;
495 bool wakeup;
496 int error;
497
498 if (!adev)
499 return 0;
500
501 target_state = acpi_target_system_state();
502 wakeup = device_may_wakeup(dev);
503 error = __acpi_device_sleep_wake(adev, target_state, wakeup);
504 if (wakeup && error)
505 return error;
506
507 error = acpi_dev_pm_low_power(dev, adev, target_state);
508 if (error)
509 __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
510
511 return error;
512}
513EXPORT_SYMBOL_GPL(acpi_dev_suspend_late);
514
515/**
516 * acpi_dev_resume_early - Put device into the full-power state using ACPI.
517 * @dev: Device to put into the full-power state.
518 *
519 * Put the given device into the full-power state using the standard ACPI
520 * mechanism during system transition to the working state. Set the power
521 * state of the device to ACPI D0 and disable remote wakeup.
522 */
523int acpi_dev_resume_early(struct device *dev)
524{
525 struct acpi_device *adev = acpi_dev_pm_get_node(dev);
526 int error;
527
528 if (!adev)
529 return 0;
530
531 error = acpi_dev_pm_full_power(adev);
532 __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false);
533 return error;
534}
535EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
536
537/**
538 * acpi_subsys_prepare - Prepare device for system transition to a sleep state.
539 * @dev: Device to prepare.
540 */
541int acpi_subsys_prepare(struct device *dev)
542{
543 /*
544 * Follow PCI and resume devices suspended at run time before running
545 * their system suspend callbacks.
546 */
547 pm_runtime_resume(dev);
548 return pm_generic_prepare(dev);
549}
550EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
551
552/**
553 * acpi_subsys_suspend_late - Suspend device using ACPI.
554 * @dev: Device to suspend.
555 *
556 * Carry out the generic late suspend procedure for @dev and use ACPI to put
557 * it into a low-power state during system transition into a sleep state.
558 */
559int acpi_subsys_suspend_late(struct device *dev)
560{
561 int ret = pm_generic_suspend_late(dev);
562 return ret ? ret : acpi_dev_suspend_late(dev);
563}
564EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late);
565
566/**
567 * acpi_subsys_resume_early - Resume device using ACPI.
568 * @dev: Device to Resume.
569 *
570 * Use ACPI to put the given device into the full-power state and carry out the
571 * generic early resume procedure for it during system transition into the
572 * working state.
573 */
574int acpi_subsys_resume_early(struct device *dev)
575{
576 int ret = acpi_dev_resume_early(dev);
577 return ret ? ret : pm_generic_resume_early(dev);
578}
579EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
580#endif /* CONFIG_PM_SLEEP */
581
582static struct dev_pm_domain acpi_general_pm_domain = {
583 .ops = {
584#ifdef CONFIG_PM_RUNTIME
585 .runtime_suspend = acpi_subsys_runtime_suspend,
586 .runtime_resume = acpi_subsys_runtime_resume,
587 .runtime_idle = pm_generic_runtime_idle,
588#endif
589#ifdef CONFIG_PM_SLEEP
590 .prepare = acpi_subsys_prepare,
591 .suspend_late = acpi_subsys_suspend_late,
592 .resume_early = acpi_subsys_resume_early,
593 .poweroff_late = acpi_subsys_suspend_late,
594 .restore_early = acpi_subsys_resume_early,
595#endif
596 },
597};
598
599/**
600 * acpi_dev_pm_attach - Prepare device for ACPI power management.
601 * @dev: Device to prepare.
602 *
603 * If @dev has a valid ACPI handle that has a valid struct acpi_device object
604 * attached to it, install a wakeup notification handler for the device and
605 * add it to the general ACPI PM domain.
606 *
607 * This assumes that the @dev's bus type uses generic power management callbacks
608 * (or doesn't use any power management callbacks at all).
609 *
610 * Callers must ensure proper synchronization of this function with power
611 * management callbacks.
612 */
613int acpi_dev_pm_attach(struct device *dev)
614{
615 struct acpi_device *adev = acpi_dev_pm_get_node(dev);
616
617 if (!adev)
618 return -ENODEV;
619
620 if (dev->pm_domain)
621 return -EEXIST;
622
623 acpi_add_pm_notifier(adev, acpi_wakeup_device, dev);
624 dev->pm_domain = &acpi_general_pm_domain;
625 return 0;
626}
627EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
628
629/**
630 * acpi_dev_pm_detach - Remove ACPI power management from the device.
631 * @dev: Device to take care of.
632 *
633 * Remove the device from the general ACPI PM domain and remove its wakeup
634 * notifier.
635 *
636 * Callers must ensure proper synchronization of this function with power
637 * management callbacks.
638 */
639void acpi_dev_pm_detach(struct device *dev)
640{
641 struct acpi_device *adev = acpi_dev_pm_get_node(dev);
642
643 if (adev && dev->pm_domain == &acpi_general_pm_domain) {
644 dev->pm_domain = NULL;
645 acpi_remove_pm_notifier(adev, acpi_wakeup_device);
646 }
647}
648EXPORT_SYMBOL_GPL(acpi_dev_pm_detach);