diff options
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r-- | drivers/acpi/sleep.c | 63 |
1 files changed, 43 insertions, 20 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 5f2c379ab7bf..f74834a544fd 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -81,6 +81,23 @@ static int acpi_sleep_prepare(u32 acpi_state) | |||
81 | #ifdef CONFIG_ACPI_SLEEP | 81 | #ifdef CONFIG_ACPI_SLEEP |
82 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | 82 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; |
83 | /* | 83 | /* |
84 | * According to the ACPI specification the BIOS should make sure that ACPI is | ||
85 | * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still, | ||
86 | * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI | ||
87 | * on such systems during resume. Unfortunately that doesn't help in | ||
88 | * particularly pathological cases in which SCI_EN has to be set directly on | ||
89 | * resume, although the specification states very clearly that this flag is | ||
90 | * owned by the hardware. The set_sci_en_on_resume variable will be set in such | ||
91 | * cases. | ||
92 | */ | ||
93 | static bool set_sci_en_on_resume; | ||
94 | |||
95 | void __init acpi_set_sci_en_on_resume(void) | ||
96 | { | ||
97 | set_sci_en_on_resume = true; | ||
98 | } | ||
99 | |||
100 | /* | ||
84 | * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the | 101 | * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the |
85 | * user to request that behavior by using the 'acpi_old_suspend_ordering' | 102 | * user to request that behavior by using the 'acpi_old_suspend_ordering' |
86 | * kernel command line option that causes the following variable to be set. | 103 | * kernel command line option that causes the following variable to be set. |
@@ -170,18 +187,6 @@ static void acpi_pm_end(void) | |||
170 | #endif /* CONFIG_ACPI_SLEEP */ | 187 | #endif /* CONFIG_ACPI_SLEEP */ |
171 | 188 | ||
172 | #ifdef CONFIG_SUSPEND | 189 | #ifdef CONFIG_SUSPEND |
173 | /* | ||
174 | * According to the ACPI specification the BIOS should make sure that ACPI is | ||
175 | * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still, | ||
176 | * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI | ||
177 | * on such systems during resume. Unfortunately that doesn't help in | ||
178 | * particularly pathological cases in which SCI_EN has to be set directly on | ||
179 | * resume, although the specification states very clearly that this flag is | ||
180 | * owned by the hardware. The set_sci_en_on_resume variable will be set in such | ||
181 | * cases. | ||
182 | */ | ||
183 | static bool set_sci_en_on_resume; | ||
184 | |||
185 | extern void do_suspend_lowlevel(void); | 190 | extern void do_suspend_lowlevel(void); |
186 | 191 | ||
187 | static u32 acpi_suspend_states[] = { | 192 | static u32 acpi_suspend_states[] = { |
@@ -547,8 +552,17 @@ static void acpi_hibernation_leave(void) | |||
547 | hibernate_nvs_restore(); | 552 | hibernate_nvs_restore(); |
548 | } | 553 | } |
549 | 554 | ||
550 | static void acpi_pm_enable_gpes(void) | 555 | static int acpi_pm_pre_restore(void) |
551 | { | 556 | { |
557 | acpi_disable_all_gpes(); | ||
558 | acpi_os_wait_events_complete(NULL); | ||
559 | acpi_ec_suspend_transactions(); | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static void acpi_pm_restore_cleanup(void) | ||
564 | { | ||
565 | acpi_ec_resume_transactions(); | ||
552 | acpi_enable_all_runtime_gpes(); | 566 | acpi_enable_all_runtime_gpes(); |
553 | } | 567 | } |
554 | 568 | ||
@@ -560,8 +574,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops = { | |||
560 | .prepare = acpi_pm_prepare, | 574 | .prepare = acpi_pm_prepare, |
561 | .enter = acpi_hibernation_enter, | 575 | .enter = acpi_hibernation_enter, |
562 | .leave = acpi_hibernation_leave, | 576 | .leave = acpi_hibernation_leave, |
563 | .pre_restore = acpi_pm_disable_gpes, | 577 | .pre_restore = acpi_pm_pre_restore, |
564 | .restore_cleanup = acpi_pm_enable_gpes, | 578 | .restore_cleanup = acpi_pm_restore_cleanup, |
565 | }; | 579 | }; |
566 | 580 | ||
567 | /** | 581 | /** |
@@ -613,8 +627,8 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = { | |||
613 | .prepare = acpi_pm_disable_gpes, | 627 | .prepare = acpi_pm_disable_gpes, |
614 | .enter = acpi_hibernation_enter, | 628 | .enter = acpi_hibernation_enter, |
615 | .leave = acpi_hibernation_leave, | 629 | .leave = acpi_hibernation_leave, |
616 | .pre_restore = acpi_pm_disable_gpes, | 630 | .pre_restore = acpi_pm_pre_restore, |
617 | .restore_cleanup = acpi_pm_enable_gpes, | 631 | .restore_cleanup = acpi_pm_restore_cleanup, |
618 | .recover = acpi_pm_finish, | 632 | .recover = acpi_pm_finish, |
619 | }; | 633 | }; |
620 | #endif /* CONFIG_HIBERNATION */ | 634 | #endif /* CONFIG_HIBERNATION */ |
@@ -740,9 +754,18 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) | |||
740 | return -ENODEV; | 754 | return -ENODEV; |
741 | } | 755 | } |
742 | 756 | ||
743 | error = enable ? | 757 | if (enable) { |
744 | acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : | 758 | error = acpi_enable_wakeup_device_power(adev, |
745 | acpi_disable_wakeup_device_power(adev); | 759 | acpi_target_sleep_state); |
760 | if (!error) | ||
761 | acpi_enable_gpe(adev->wakeup.gpe_device, | ||
762 | adev->wakeup.gpe_number, | ||
763 | ACPI_GPE_TYPE_WAKE); | ||
764 | } else { | ||
765 | acpi_disable_gpe(adev->wakeup.gpe_device, adev->wakeup.gpe_number, | ||
766 | ACPI_GPE_TYPE_WAKE); | ||
767 | error = acpi_disable_wakeup_device_power(adev); | ||
768 | } | ||
746 | if (!error) | 769 | if (!error) |
747 | dev_info(dev, "wake-up capability %s by ACPI\n", | 770 | dev_info(dev, "wake-up capability %s by ACPI\n", |
748 | enable ? "enabled" : "disabled"); | 771 | enable ? "enabled" : "disabled"); |