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. |
