diff options
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r-- | drivers/acpi/device_pm.c | 102 |
1 files changed, 42 insertions, 60 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 993fd31394c8..28938b5a334e 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/pm_qos.h> | 24 | #include <linux/pm_qos.h> |
25 | #include <linux/pm_domain.h> | 25 | #include <linux/pm_domain.h> |
26 | #include <linux/pm_runtime.h> | 26 | #include <linux/pm_runtime.h> |
27 | #include <linux/suspend.h> | ||
27 | 28 | ||
28 | #include "internal.h" | 29 | #include "internal.h" |
29 | 30 | ||
@@ -385,6 +386,12 @@ EXPORT_SYMBOL(acpi_bus_power_manageable); | |||
385 | #ifdef CONFIG_PM | 386 | #ifdef CONFIG_PM |
386 | static DEFINE_MUTEX(acpi_pm_notifier_lock); | 387 | static DEFINE_MUTEX(acpi_pm_notifier_lock); |
387 | 388 | ||
389 | void acpi_pm_wakeup_event(struct device *dev) | ||
390 | { | ||
391 | pm_wakeup_dev_event(dev, 0, acpi_s2idle_wakeup()); | ||
392 | } | ||
393 | EXPORT_SYMBOL_GPL(acpi_pm_wakeup_event); | ||
394 | |||
388 | static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) | 395 | static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) |
389 | { | 396 | { |
390 | struct acpi_device *adev; | 397 | struct acpi_device *adev; |
@@ -399,9 +406,9 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) | |||
399 | mutex_lock(&acpi_pm_notifier_lock); | 406 | mutex_lock(&acpi_pm_notifier_lock); |
400 | 407 | ||
401 | if (adev->wakeup.flags.notifier_present) { | 408 | if (adev->wakeup.flags.notifier_present) { |
402 | __pm_wakeup_event(adev->wakeup.ws, 0); | 409 | pm_wakeup_ws_event(adev->wakeup.ws, 0, acpi_s2idle_wakeup()); |
403 | if (adev->wakeup.context.work.func) | 410 | if (adev->wakeup.context.func) |
404 | queue_pm_work(&adev->wakeup.context.work); | 411 | adev->wakeup.context.func(&adev->wakeup.context); |
405 | } | 412 | } |
406 | 413 | ||
407 | mutex_unlock(&acpi_pm_notifier_lock); | 414 | mutex_unlock(&acpi_pm_notifier_lock); |
@@ -413,7 +420,7 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) | |||
413 | * acpi_add_pm_notifier - Register PM notify handler for given ACPI device. | 420 | * acpi_add_pm_notifier - Register PM notify handler for given ACPI device. |
414 | * @adev: ACPI device to add the notify handler for. | 421 | * @adev: ACPI device to add the notify handler for. |
415 | * @dev: Device to generate a wakeup event for while handling the notification. | 422 | * @dev: Device to generate a wakeup event for while handling the notification. |
416 | * @work_func: Work function to execute when handling the notification. | 423 | * @func: Work function to execute when handling the notification. |
417 | * | 424 | * |
418 | * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of | 425 | * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of |
419 | * PM wakeup events. For example, wakeup events may be generated for bridges | 426 | * PM wakeup events. For example, wakeup events may be generated for bridges |
@@ -421,11 +428,11 @@ static void acpi_pm_notify_handler(acpi_handle handle, u32 val, void *not_used) | |||
421 | * bridge itself doesn't have a wakeup GPE associated with it. | 428 | * bridge itself doesn't have a wakeup GPE associated with it. |
422 | */ | 429 | */ |
423 | acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, | 430 | acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, |
424 | void (*work_func)(struct work_struct *work)) | 431 | void (*func)(struct acpi_device_wakeup_context *context)) |
425 | { | 432 | { |
426 | acpi_status status = AE_ALREADY_EXISTS; | 433 | acpi_status status = AE_ALREADY_EXISTS; |
427 | 434 | ||
428 | if (!dev && !work_func) | 435 | if (!dev && !func) |
429 | return AE_BAD_PARAMETER; | 436 | return AE_BAD_PARAMETER; |
430 | 437 | ||
431 | mutex_lock(&acpi_pm_notifier_lock); | 438 | mutex_lock(&acpi_pm_notifier_lock); |
@@ -435,8 +442,7 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev, | |||
435 | 442 | ||
436 | adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev)); | 443 | adev->wakeup.ws = wakeup_source_register(dev_name(&adev->dev)); |
437 | adev->wakeup.context.dev = dev; | 444 | adev->wakeup.context.dev = dev; |
438 | if (work_func) | 445 | adev->wakeup.context.func = func; |
439 | INIT_WORK(&adev->wakeup.context.work, work_func); | ||
440 | 446 | ||
441 | status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY, | 447 | status = acpi_install_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY, |
442 | acpi_pm_notify_handler, NULL); | 448 | acpi_pm_notify_handler, NULL); |
@@ -469,10 +475,7 @@ acpi_status acpi_remove_pm_notifier(struct acpi_device *adev) | |||
469 | if (ACPI_FAILURE(status)) | 475 | if (ACPI_FAILURE(status)) |
470 | goto out; | 476 | goto out; |
471 | 477 | ||
472 | if (adev->wakeup.context.work.func) { | 478 | adev->wakeup.context.func = NULL; |
473 | cancel_work_sync(&adev->wakeup.context.work); | ||
474 | adev->wakeup.context.work.func = NULL; | ||
475 | } | ||
476 | adev->wakeup.context.dev = NULL; | 479 | adev->wakeup.context.dev = NULL; |
477 | wakeup_source_unregister(adev->wakeup.ws); | 480 | wakeup_source_unregister(adev->wakeup.ws); |
478 | 481 | ||
@@ -493,6 +496,13 @@ bool acpi_bus_can_wakeup(acpi_handle handle) | |||
493 | } | 496 | } |
494 | EXPORT_SYMBOL(acpi_bus_can_wakeup); | 497 | EXPORT_SYMBOL(acpi_bus_can_wakeup); |
495 | 498 | ||
499 | bool acpi_pm_device_can_wakeup(struct device *dev) | ||
500 | { | ||
501 | struct acpi_device *adev = ACPI_COMPANION(dev); | ||
502 | |||
503 | return adev ? acpi_device_can_wakeup(adev) : false; | ||
504 | } | ||
505 | |||
496 | /** | 506 | /** |
497 | * acpi_dev_pm_get_state - Get preferred power state of ACPI device. | 507 | * acpi_dev_pm_get_state - Get preferred power state of ACPI device. |
498 | * @dev: Device whose preferred target power state to return. | 508 | * @dev: Device whose preferred target power state to return. |
@@ -658,16 +668,15 @@ EXPORT_SYMBOL(acpi_pm_device_sleep_state); | |||
658 | 668 | ||
659 | /** | 669 | /** |
660 | * acpi_pm_notify_work_func - ACPI devices wakeup notification work function. | 670 | * acpi_pm_notify_work_func - ACPI devices wakeup notification work function. |
661 | * @work: Work item to handle. | 671 | * @context: Device wakeup context. |
662 | */ | 672 | */ |
663 | static void acpi_pm_notify_work_func(struct work_struct *work) | 673 | static void acpi_pm_notify_work_func(struct acpi_device_wakeup_context *context) |
664 | { | 674 | { |
665 | struct device *dev; | 675 | struct device *dev = context->dev; |
666 | 676 | ||
667 | dev = container_of(work, struct acpi_device_wakeup_context, work)->dev; | ||
668 | if (dev) { | 677 | if (dev) { |
669 | pm_wakeup_event(dev, 0); | 678 | pm_wakeup_event(dev, 0); |
670 | pm_runtime_resume(dev); | 679 | pm_request_resume(dev); |
671 | } | 680 | } |
672 | } | 681 | } |
673 | 682 | ||
@@ -693,80 +702,53 @@ static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state, | |||
693 | acpi_status res; | 702 | acpi_status res; |
694 | int error; | 703 | int error; |
695 | 704 | ||
705 | if (adev->wakeup.flags.enabled) | ||
706 | return 0; | ||
707 | |||
696 | error = acpi_enable_wakeup_device_power(adev, target_state); | 708 | error = acpi_enable_wakeup_device_power(adev, target_state); |
697 | if (error) | 709 | if (error) |
698 | return error; | 710 | return error; |
699 | 711 | ||
700 | if (adev->wakeup.flags.enabled) | ||
701 | return 0; | ||
702 | |||
703 | res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); | 712 | res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); |
704 | if (ACPI_SUCCESS(res)) { | 713 | if (ACPI_FAILURE(res)) { |
705 | adev->wakeup.flags.enabled = 1; | ||
706 | } else { | ||
707 | acpi_disable_wakeup_device_power(adev); | 714 | acpi_disable_wakeup_device_power(adev); |
708 | return -EIO; | 715 | return -EIO; |
709 | } | 716 | } |
710 | } else { | 717 | adev->wakeup.flags.enabled = 1; |
711 | if (adev->wakeup.flags.enabled) { | 718 | } else if (adev->wakeup.flags.enabled) { |
712 | acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); | 719 | acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); |
713 | adev->wakeup.flags.enabled = 0; | ||
714 | } | ||
715 | acpi_disable_wakeup_device_power(adev); | 720 | acpi_disable_wakeup_device_power(adev); |
721 | adev->wakeup.flags.enabled = 0; | ||
716 | } | 722 | } |
717 | return 0; | 723 | return 0; |
718 | } | 724 | } |
719 | 725 | ||
720 | /** | 726 | /** |
721 | * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. | 727 | * acpi_pm_set_device_wakeup - Enable/disable remote wakeup for given device. |
722 | * @dev: Device to enable/disable the platform to wake up. | 728 | * @dev: Device to enable/disable to generate wakeup events. |
723 | * @enable: Whether to enable or disable the wakeup functionality. | 729 | * @enable: Whether to enable or disable the wakeup functionality. |
724 | */ | 730 | */ |
725 | int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) | 731 | int acpi_pm_set_device_wakeup(struct device *dev, bool enable) |
726 | { | ||
727 | struct acpi_device *adev; | ||
728 | |||
729 | if (!device_run_wake(phys_dev)) | ||
730 | return -EINVAL; | ||
731 | |||
732 | adev = ACPI_COMPANION(phys_dev); | ||
733 | if (!adev) { | ||
734 | dev_dbg(phys_dev, "ACPI companion missing in %s!\n", __func__); | ||
735 | return -ENODEV; | ||
736 | } | ||
737 | |||
738 | return acpi_device_wakeup(adev, ACPI_STATE_S0, enable); | ||
739 | } | ||
740 | EXPORT_SYMBOL(acpi_pm_device_run_wake); | ||
741 | |||
742 | #ifdef CONFIG_PM_SLEEP | ||
743 | /** | ||
744 | * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. | ||
745 | * @dev: Device to enable/desible to wake up the system from sleep states. | ||
746 | * @enable: Whether to enable or disable @dev to wake up the system. | ||
747 | */ | ||
748 | int acpi_pm_device_sleep_wake(struct device *dev, bool enable) | ||
749 | { | 732 | { |
750 | struct acpi_device *adev; | 733 | struct acpi_device *adev; |
751 | int error; | 734 | int error; |
752 | 735 | ||
753 | if (!device_can_wakeup(dev)) | ||
754 | return -EINVAL; | ||
755 | |||
756 | adev = ACPI_COMPANION(dev); | 736 | adev = ACPI_COMPANION(dev); |
757 | if (!adev) { | 737 | if (!adev) { |
758 | dev_dbg(dev, "ACPI companion missing in %s!\n", __func__); | 738 | dev_dbg(dev, "ACPI companion missing in %s!\n", __func__); |
759 | return -ENODEV; | 739 | return -ENODEV; |
760 | } | 740 | } |
761 | 741 | ||
742 | if (!acpi_device_can_wakeup(adev)) | ||
743 | return -EINVAL; | ||
744 | |||
762 | error = acpi_device_wakeup(adev, acpi_target_system_state(), enable); | 745 | error = acpi_device_wakeup(adev, acpi_target_system_state(), enable); |
763 | if (!error) | 746 | if (!error) |
764 | dev_info(dev, "System wakeup %s by ACPI\n", | 747 | dev_dbg(dev, "Wakeup %s by ACPI\n", enable ? "enabled" : "disabled"); |
765 | enable ? "enabled" : "disabled"); | ||
766 | 748 | ||
767 | return error; | 749 | return error; |
768 | } | 750 | } |
769 | #endif /* CONFIG_PM_SLEEP */ | 751 | EXPORT_SYMBOL(acpi_pm_set_device_wakeup); |
770 | 752 | ||
771 | /** | 753 | /** |
772 | * acpi_dev_pm_low_power - Put ACPI device into a low-power state. | 754 | * acpi_dev_pm_low_power - Put ACPI device into a low-power state. |