2 * sleep.c - ACPI sleep support.
4 * Copyright (c) 2000-2003 Patrick Mochel
5 * Copyright (c) 2003 Open Source Development Lab
7 * This file is released under the GPLv2.
11 #include <linux/delay.h>
12 #include <linux/irq.h>
13 #include <linux/device.h>
14 #include <linux/suspend.h>
15 #include <acpi/acpi_bus.h>
16 #include <acpi/acpi_drivers.h>
19 u8 sleep_states[ACPI_S_STATE_COUNT];
21 static struct pm_ops acpi_pm_ops;
23 extern void do_suspend_lowlevel_s4bios(void);
24 extern void do_suspend_lowlevel(void);
26 static u32 acpi_suspend_states[] = {
27 [PM_SUSPEND_ON] = ACPI_STATE_S0,
28 [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
29 [PM_SUSPEND_MEM] = ACPI_STATE_S3,
30 [PM_SUSPEND_DISK] = ACPI_STATE_S4,
34 * acpi_pm_prepare - Do preliminary suspend work.
35 * @state: suspend state we're entering.
37 * Make sure we support the state. If we do, and we need it, set the
38 * firmware waking vector and do arch-specific nastiness to get the
39 * wakeup code to the waking vector.
42 static int acpi_pm_prepare(u32 state)
44 u32 acpi_state = acpi_suspend_states[state];
46 if (!sleep_states[acpi_state])
49 /* do we have a wakeup address for S2 and S3? */
50 /* Here, we support only S4BIOS, those we set the wakeup address */
51 /* S4OS is only supported for now via swsusp.. */
52 if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_DISK) {
53 if (!acpi_wakeup_address)
55 acpi_set_firmware_waking_vector(
56 (acpi_physical_address) acpi_wakeup_address);
58 ACPI_FLUSH_CPU_CACHE();
59 acpi_enter_sleep_state_prep(acpi_state);
65 * acpi_pm_enter - Actually enter a sleep state.
66 * @state: State we're entering.
68 * Flush caches and go to sleep. For STR or STD, we have to call
69 * arch-specific assembly, which in turn call acpi_enter_sleep_state().
70 * It's unfortunate, but it works. Please fix if you're feeling frisky.
73 static int acpi_pm_enter(u32 state)
75 acpi_status status = AE_OK;
76 unsigned long flags = 0;
77 u32 acpi_state = acpi_suspend_states[state];
79 ACPI_FLUSH_CPU_CACHE();
81 /* Do arch specific saving of state. */
82 if (state > PM_SUSPEND_STANDBY) {
83 int error = acpi_save_state_mem();
89 local_irq_save(flags);
92 case PM_SUSPEND_STANDBY:
94 status = acpi_enter_sleep_state(acpi_state);
98 do_suspend_lowlevel();
101 case PM_SUSPEND_DISK:
102 if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
103 status = acpi_enter_sleep_state(acpi_state);
105 do_suspend_lowlevel_s4bios();
110 local_irq_restore(flags);
111 printk(KERN_DEBUG "Back to C!\n");
113 /* restore processor state
114 * We should only be here if we're coming back from STR or STD.
115 * And, in the case of the latter, the memory image should have already
116 * been loaded from disk.
118 if (state > PM_SUSPEND_STANDBY)
119 acpi_restore_state_mem();
122 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
127 * acpi_pm_finish - Finish up suspend sequence.
128 * @state: State we're coming out of.
130 * This is called after we wake back up (or if entering the sleep state
134 static int acpi_pm_finish(u32 state)
136 acpi_leave_sleep_state(state);
138 /* reset firmware waking vector */
139 acpi_set_firmware_waking_vector((acpi_physical_address) 0);
141 if (dmi_broken & BROKEN_INIT_AFTER_S1) {
142 printk("Broken toshiba laptop -> kicking interrupts\n");
149 int acpi_suspend(u32 acpi_state)
152 [1] = PM_SUSPEND_STANDBY,
153 [3] = PM_SUSPEND_MEM,
154 [4] = PM_SUSPEND_DISK,
157 if (acpi_state <= 4 && states[acpi_state])
158 return pm_suspend(states[acpi_state]);
163 static struct pm_ops acpi_pm_ops = {
164 .prepare = acpi_pm_prepare,
165 .enter = acpi_pm_enter,
166 .finish = acpi_pm_finish,
169 static int __init acpi_sleep_init(void)
176 printk(KERN_INFO PREFIX "(supports");
177 for (i=0; i<ACPI_S_STATE_COUNT; i++) {
180 status = acpi_get_sleep_type_data(i, &type_a, &type_b);
181 if (ACPI_SUCCESS(status)) {
185 if (i == ACPI_STATE_S4) {
186 if (acpi_gbl_FACS->S4bios_f) {
189 acpi_pm_ops.pm_disk_mode = PM_DISK_FIRMWARE;
190 } else if (sleep_states[i])
191 acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM;
196 pm_set_ops(&acpi_pm_ops);
200 late_initcall(acpi_sleep_init);