diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-11-26 04:03:06 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-11-26 04:03:06 -0500 |
commit | b88ce2a41562d1a9554f209e0f31a32d9f473794 (patch) | |
tree | ab9a0509fcc0e5f412cd8eade4a1b6ef5e13e889 /drivers/acpi/device_pm.c | |
parent | 1399dfcdfe89898ccd791216f9679ba734aea910 (diff) |
ACPI / PM: Allow attach/detach routines to change device power states
Make it possible to ask the routines used for adding/removing devices
to/from the general ACPI PM domain, acpi_dev_pm_attach() and
acpi_dev_pm_detach(), respectively, to change the power states of
devices so that they are put into the full-power state automatically
by acpi_dev_pm_attach() and into the lowest-power state available
automatically by acpi_dev_pm_detach().
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/acpi/device_pm.c')
-rw-r--r-- | drivers/acpi/device_pm.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index a8e059f69d50..f09dc987cf17 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c | |||
@@ -599,10 +599,12 @@ static struct dev_pm_domain acpi_general_pm_domain = { | |||
599 | /** | 599 | /** |
600 | * acpi_dev_pm_attach - Prepare device for ACPI power management. | 600 | * acpi_dev_pm_attach - Prepare device for ACPI power management. |
601 | * @dev: Device to prepare. | 601 | * @dev: Device to prepare. |
602 | * @power_on: Whether or not to power on the device. | ||
602 | * | 603 | * |
603 | * If @dev has a valid ACPI handle that has a valid struct acpi_device object | 604 | * 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 | * attached to it, install a wakeup notification handler for the device and |
605 | * add it to the general ACPI PM domain. | 606 | * add it to the general ACPI PM domain. If @power_on is set, the device will |
607 | * be put into the ACPI D0 state before the function returns. | ||
606 | * | 608 | * |
607 | * This assumes that the @dev's bus type uses generic power management callbacks | 609 | * This assumes that the @dev's bus type uses generic power management callbacks |
608 | * (or doesn't use any power management callbacks at all). | 610 | * (or doesn't use any power management callbacks at all). |
@@ -610,7 +612,7 @@ static struct dev_pm_domain acpi_general_pm_domain = { | |||
610 | * Callers must ensure proper synchronization of this function with power | 612 | * Callers must ensure proper synchronization of this function with power |
611 | * management callbacks. | 613 | * management callbacks. |
612 | */ | 614 | */ |
613 | int acpi_dev_pm_attach(struct device *dev) | 615 | int acpi_dev_pm_attach(struct device *dev, bool power_on) |
614 | { | 616 | { |
615 | struct acpi_device *adev = acpi_dev_pm_get_node(dev); | 617 | struct acpi_device *adev = acpi_dev_pm_get_node(dev); |
616 | 618 | ||
@@ -622,6 +624,10 @@ int acpi_dev_pm_attach(struct device *dev) | |||
622 | 624 | ||
623 | acpi_add_pm_notifier(adev, acpi_wakeup_device, dev); | 625 | acpi_add_pm_notifier(adev, acpi_wakeup_device, dev); |
624 | dev->pm_domain = &acpi_general_pm_domain; | 626 | dev->pm_domain = &acpi_general_pm_domain; |
627 | if (power_on) { | ||
628 | acpi_dev_pm_full_power(adev); | ||
629 | __acpi_device_run_wake(adev, false); | ||
630 | } | ||
625 | return 0; | 631 | return 0; |
626 | } | 632 | } |
627 | EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); | 633 | EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); |
@@ -629,20 +635,34 @@ EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); | |||
629 | /** | 635 | /** |
630 | * acpi_dev_pm_detach - Remove ACPI power management from the device. | 636 | * acpi_dev_pm_detach - Remove ACPI power management from the device. |
631 | * @dev: Device to take care of. | 637 | * @dev: Device to take care of. |
638 | * @power_off: Whether or not to try to remove power from the device. | ||
632 | * | 639 | * |
633 | * Remove the device from the general ACPI PM domain and remove its wakeup | 640 | * Remove the device from the general ACPI PM domain and remove its wakeup |
634 | * notifier. | 641 | * notifier. If @power_off is set, additionally remove power from the device if |
642 | * possible. | ||
635 | * | 643 | * |
636 | * Callers must ensure proper synchronization of this function with power | 644 | * Callers must ensure proper synchronization of this function with power |
637 | * management callbacks. | 645 | * management callbacks. |
638 | */ | 646 | */ |
639 | void acpi_dev_pm_detach(struct device *dev) | 647 | void acpi_dev_pm_detach(struct device *dev, bool power_off) |
640 | { | 648 | { |
641 | struct acpi_device *adev = acpi_dev_pm_get_node(dev); | 649 | struct acpi_device *adev = acpi_dev_pm_get_node(dev); |
642 | 650 | ||
643 | if (adev && dev->pm_domain == &acpi_general_pm_domain) { | 651 | if (adev && dev->pm_domain == &acpi_general_pm_domain) { |
644 | dev->pm_domain = NULL; | 652 | dev->pm_domain = NULL; |
645 | acpi_remove_pm_notifier(adev, acpi_wakeup_device); | 653 | acpi_remove_pm_notifier(adev, acpi_wakeup_device); |
654 | if (power_off) { | ||
655 | /* | ||
656 | * If the device's PM QoS resume latency limit or flags | ||
657 | * have been exposed to user space, they have to be | ||
658 | * hidden at this point, so that they don't affect the | ||
659 | * choice of the low-power state to put the device into. | ||
660 | */ | ||
661 | dev_pm_qos_hide_latency_limit(dev); | ||
662 | dev_pm_qos_hide_flags(dev); | ||
663 | __acpi_device_run_wake(adev, false); | ||
664 | acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); | ||
665 | } | ||
646 | } | 666 | } |
647 | } | 667 | } |
648 | EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); | 668 | EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); |