aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/device_pm.c317
-rw-r--r--include/linux/acpi.h34
2 files changed, 351 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);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 90be98981102..0676b6ac57fa 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -430,4 +430,38 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state,
430#define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0) 430#define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0)
431#endif 431#endif
432 432
433#if defined(CONFIG_ACPI) && defined(CONFIG_PM_RUNTIME)
434int acpi_dev_runtime_suspend(struct device *dev);
435int acpi_dev_runtime_resume(struct device *dev);
436int acpi_subsys_runtime_suspend(struct device *dev);
437int acpi_subsys_runtime_resume(struct device *dev);
438#else
439static inline int acpi_dev_runtime_suspend(struct device *dev) { return 0; }
440static inline int acpi_dev_runtime_resume(struct device *dev) { return 0; }
441static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; }
442static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; }
443#endif
444
445#ifdef CONFIG_ACPI_SLEEP
446int acpi_dev_suspend_late(struct device *dev);
447int acpi_dev_resume_early(struct device *dev);
448int acpi_subsys_prepare(struct device *dev);
449int acpi_subsys_suspend_late(struct device *dev);
450int acpi_subsys_resume_early(struct device *dev);
451#else
452static inline int acpi_dev_suspend_late(struct device *dev) { return 0; }
453static inline int acpi_dev_resume_early(struct device *dev) { return 0; }
454static inline int acpi_subsys_prepare(struct device *dev) { return 0; }
455static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; }
456static inline int acpi_subsys_resume_early(struct device *dev) { return 0; }
457#endif
458
459#if defined(CONFIG_ACPI) && defined(CONFIG_PM)
460int acpi_dev_pm_attach(struct device *dev);
461int acpi_dev_pm_detach(struct device *dev);
462#else
463static inline int acpi_dev_pm_attach(struct device *dev) { return -ENODEV; }
464static inline void acpi_dev_pm_detach(struct device *dev) {}
465#endif
466
433#endif /*_LINUX_ACPI_H*/ 467#endif /*_LINUX_ACPI_H*/