MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / acpi / hardware / hwsleep.c
blob6ffa80ba2466b4dc46fe6ef6b13a7b7f5157fca2
2 /******************************************************************************
4 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
6 *****************************************************************************/
8 /*
9 * Copyright (C) 2000 - 2004, R. Byron Moore
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions, and the following disclaimer,
17 * without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 * substantially similar to the "NO WARRANTY" disclaimer below
20 * ("Disclaimer") and any redistribution must be conditioned upon
21 * including a substantially similar Disclaimer requirement for further
22 * binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 * of any contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
45 #include <acpi/acpi.h>
47 #define _COMPONENT ACPI_HARDWARE
48 ACPI_MODULE_NAME ("hwsleep")
51 #define METHOD_NAME__BFS "\\_BFS"
52 #define METHOD_NAME__GTS "\\_GTS"
53 #define METHOD_NAME__PTS "\\_PTS"
54 #define METHOD_NAME__SST "\\_SI._SST"
55 #define METHOD_NAME__WAK "\\_WAK"
57 #define ACPI_SST_INDICATOR_OFF 0
58 #define ACPI_SST_WORKING 1
59 #define ACPI_SST_WAKING 2
60 #define ACPI_SST_SLEEPING 3
61 #define ACPI_SST_SLEEP_CONTEXT 4
64 /******************************************************************************
66 * FUNCTION: acpi_set_firmware_waking_vector
68 * PARAMETERS: physical_address - Physical address of ACPI real mode
69 * entry point.
71 * RETURN: Status
73 * DESCRIPTION: access function for d_firmware_waking_vector field in FACS
75 ******************************************************************************/
77 acpi_status
78 acpi_set_firmware_waking_vector (
79 acpi_physical_address physical_address)
82 ACPI_FUNCTION_TRACE ("acpi_set_firmware_waking_vector");
85 /* Set the vector */
87 if (acpi_gbl_common_fACS.vector_width == 32) {
88 *(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector))
89 = (u32) physical_address;
91 else {
92 *acpi_gbl_common_fACS.firmware_waking_vector
93 = physical_address;
96 return_ACPI_STATUS (AE_OK);
100 /******************************************************************************
102 * FUNCTION: acpi_get_firmware_waking_vector
104 * PARAMETERS: *physical_address - Output buffer where contents of
105 * the firmware_waking_vector field of
106 * the FACS will be stored.
108 * RETURN: Status
110 * DESCRIPTION: Access function for firmware_waking_vector field in FACS
112 ******************************************************************************/
114 acpi_status
115 acpi_get_firmware_waking_vector (
116 acpi_physical_address *physical_address)
119 ACPI_FUNCTION_TRACE ("acpi_get_firmware_waking_vector");
122 if (!physical_address) {
123 return_ACPI_STATUS (AE_BAD_PARAMETER);
126 /* Get the vector */
128 if (acpi_gbl_common_fACS.vector_width == 32) {
129 *physical_address = (acpi_physical_address)
130 *(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector));
132 else {
133 *physical_address =
134 *acpi_gbl_common_fACS.firmware_waking_vector;
137 return_ACPI_STATUS (AE_OK);
141 /******************************************************************************
143 * FUNCTION: acpi_enter_sleep_state_prep
145 * PARAMETERS: sleep_state - Which sleep state to enter
147 * RETURN: Status
149 * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
150 * This function must execute with interrupts enabled.
151 * We break sleeping into 2 stages so that OSPM can handle
152 * various OS-specific tasks between the two steps.
154 ******************************************************************************/
156 acpi_status
157 acpi_enter_sleep_state_prep (
158 u8 sleep_state)
160 acpi_status status;
161 struct acpi_object_list arg_list;
162 union acpi_object arg;
165 ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_prep");
169 * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
171 status = acpi_get_sleep_type_data (sleep_state,
172 &acpi_gbl_sleep_type_a, &acpi_gbl_sleep_type_b);
173 if (ACPI_FAILURE (status)) {
174 return_ACPI_STATUS (status);
177 /* Setup parameter object */
179 arg_list.count = 1;
180 arg_list.pointer = &arg;
182 arg.type = ACPI_TYPE_INTEGER;
183 arg.integer.value = sleep_state;
185 /* Run the _PTS and _GTS methods */
187 status = acpi_evaluate_object (NULL, METHOD_NAME__PTS, &arg_list, NULL);
188 if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
189 return_ACPI_STATUS (status);
192 status = acpi_evaluate_object (NULL, METHOD_NAME__GTS, &arg_list, NULL);
193 if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
194 return_ACPI_STATUS (status);
197 /* Setup the argument to _SST */
199 switch (sleep_state) {
200 case ACPI_STATE_S0:
201 arg.integer.value = ACPI_SST_WORKING;
202 break;
204 case ACPI_STATE_S1:
205 case ACPI_STATE_S2:
206 case ACPI_STATE_S3:
207 arg.integer.value = ACPI_SST_SLEEPING;
208 break;
210 case ACPI_STATE_S4:
211 arg.integer.value = ACPI_SST_SLEEP_CONTEXT;
212 break;
214 default:
215 arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */
216 break;
219 /* Set the system indicators to show the desired sleep state. */
221 status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
222 if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
223 ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
226 return_ACPI_STATUS (AE_OK);
230 /******************************************************************************
232 * FUNCTION: acpi_enter_sleep_state
234 * PARAMETERS: sleep_state - Which sleep state to enter
236 * RETURN: Status
238 * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
239 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
241 ******************************************************************************/
243 acpi_status asmlinkage
244 acpi_enter_sleep_state (
245 u8 sleep_state)
247 u32 PM1Acontrol;
248 u32 PM1Bcontrol;
249 struct acpi_bit_register_info *sleep_type_reg_info;
250 struct acpi_bit_register_info *sleep_enable_reg_info;
251 u32 in_value;
252 acpi_status status;
255 ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state");
258 if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
259 (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
260 ACPI_REPORT_ERROR (("Sleep values out of range: A=%X B=%X\n",
261 acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
262 return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
265 sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
266 sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
268 /* Clear wake status */
270 status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
271 if (ACPI_FAILURE (status)) {
272 return_ACPI_STATUS (status);
275 /* Clear all fixed and general purpose status bits */
277 status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
278 if (ACPI_FAILURE (status)) {
279 return_ACPI_STATUS (status);
282 if (sleep_state != ACPI_STATE_S5) {
283 /* Disable BM arbitration */
285 status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
286 if (ACPI_FAILURE (status)) {
287 return_ACPI_STATUS (status);
292 * 1) Disable/Clear all GPEs
293 * 2) Enable all wakeup GPEs
295 status = acpi_hw_disable_all_gpes (ACPI_ISR);
296 if (ACPI_FAILURE (status)) {
297 return_ACPI_STATUS (status);
299 acpi_gbl_system_awake_and_running = FALSE;
301 status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR);
302 if (ACPI_FAILURE (status)) {
303 return_ACPI_STATUS (status);
306 /* Get current value of PM1A control */
308 status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
309 if (ACPI_FAILURE (status)) {
310 return_ACPI_STATUS (status);
312 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Entering sleep state [S%d]\n", sleep_state));
314 /* Clear SLP_EN and SLP_TYP fields */
316 PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask);
317 PM1Bcontrol = PM1Acontrol;
319 /* Insert SLP_TYP bits */
321 PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
322 PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
325 * We split the writes of SLP_TYP and SLP_EN to workaround
326 * poorly implemented hardware.
329 /* Write #1: fill in SLP_TYP data */
331 status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
332 if (ACPI_FAILURE (status)) {
333 return_ACPI_STATUS (status);
336 status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
337 if (ACPI_FAILURE (status)) {
338 return_ACPI_STATUS (status);
341 /* Insert SLP_ENABLE bit */
343 PM1Acontrol |= sleep_enable_reg_info->access_bit_mask;
344 PM1Bcontrol |= sleep_enable_reg_info->access_bit_mask;
346 /* Write #2: SLP_TYP + SLP_EN */
348 ACPI_FLUSH_CPU_CACHE ();
350 status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
351 if (ACPI_FAILURE (status)) {
352 return_ACPI_STATUS (status);
355 status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
356 if (ACPI_FAILURE (status)) {
357 return_ACPI_STATUS (status);
360 if (sleep_state > ACPI_STATE_S3) {
362 * We wanted to sleep > S3, but it didn't happen (by virtue of the fact that
363 * we are still executing!)
365 * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines.
367 * We wait so long to allow chipsets that poll this reg very slowly to
368 * still read the right value. Ideally, this block would go
369 * away entirely.
371 acpi_os_stall (10000000);
373 status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL,
374 sleep_enable_reg_info->access_bit_mask);
375 if (ACPI_FAILURE (status)) {
376 return_ACPI_STATUS (status);
380 /* Wait until we enter sleep state */
382 do {
383 status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK);
384 if (ACPI_FAILURE (status)) {
385 return_ACPI_STATUS (status);
388 /* Spin until we wake */
390 } while (!in_value);
392 return_ACPI_STATUS (AE_OK);
396 /******************************************************************************
398 * FUNCTION: acpi_enter_sleep_state_s4bios
400 * PARAMETERS: None
402 * RETURN: Status
404 * DESCRIPTION: Perform a S4 bios request.
405 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
407 ******************************************************************************/
409 acpi_status asmlinkage
410 acpi_enter_sleep_state_s4bios (
411 void)
413 u32 in_value;
414 acpi_status status;
417 ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios");
420 status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
421 if (ACPI_FAILURE (status)) {
422 return_ACPI_STATUS (status);
425 status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
426 if (ACPI_FAILURE (status)) {
427 return_ACPI_STATUS (status);
431 * 1) Disable/Clear all GPEs
432 * 2) Enable all wakeup GPEs
434 status = acpi_hw_disable_all_gpes (ACPI_ISR);
435 if (ACPI_FAILURE (status)) {
436 return_ACPI_STATUS (status);
438 acpi_gbl_system_awake_and_running = FALSE;
440 status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR);
441 if (ACPI_FAILURE (status)) {
442 return_ACPI_STATUS (status);
445 ACPI_FLUSH_CPU_CACHE ();
447 status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8);
449 do {
450 acpi_os_stall(1000);
451 status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK);
452 if (ACPI_FAILURE (status)) {
453 return_ACPI_STATUS (status);
455 } while (!in_value);
457 return_ACPI_STATUS (AE_OK);
461 /******************************************************************************
463 * FUNCTION: acpi_leave_sleep_state
465 * PARAMETERS: sleep_state - Which sleep state we just exited
467 * RETURN: Status
469 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
470 * Called with interrupts ENABLED.
472 ******************************************************************************/
474 acpi_status
475 acpi_leave_sleep_state (
476 u8 sleep_state)
478 struct acpi_object_list arg_list;
479 union acpi_object arg;
480 acpi_status status;
481 struct acpi_bit_register_info *sleep_type_reg_info;
482 struct acpi_bit_register_info *sleep_enable_reg_info;
483 u32 PM1Acontrol;
484 u32 PM1Bcontrol;
487 ACPI_FUNCTION_TRACE ("acpi_leave_sleep_state");
491 * Set SLP_TYPE and SLP_EN to state S0.
492 * This is unclear from the ACPI Spec, but it is required
493 * by some machines.
495 status = acpi_get_sleep_type_data (ACPI_STATE_S0,
496 &acpi_gbl_sleep_type_a, &acpi_gbl_sleep_type_b);
497 if (ACPI_SUCCESS (status)) {
498 sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
499 sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
501 /* Get current value of PM1A control */
503 status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
504 ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
505 if (ACPI_SUCCESS (status)) {
506 /* Clear SLP_EN and SLP_TYP fields */
508 PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
509 sleep_enable_reg_info->access_bit_mask);
510 PM1Bcontrol = PM1Acontrol;
512 /* Insert SLP_TYP bits */
514 PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
515 PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
517 /* Just ignore any errors */
519 (void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
520 ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
521 (void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
522 ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
526 /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
528 acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
530 /* Setup parameter object */
532 arg_list.count = 1;
533 arg_list.pointer = &arg;
534 arg.type = ACPI_TYPE_INTEGER;
536 /* Ignore any errors from these methods */
538 arg.integer.value = ACPI_SST_WAKING;
539 status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
540 if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
541 ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
544 arg.integer.value = sleep_state;
545 status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL);
546 if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
547 ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status)));
550 status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL);
551 if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
552 ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status)));
554 /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
557 * Restore the GPEs:
558 * 1) Disable/Clear all GPEs
559 * 2) Enable all runtime GPEs
561 status = acpi_hw_disable_all_gpes (ACPI_NOT_ISR);
562 if (ACPI_FAILURE (status)) {
563 return_ACPI_STATUS (status);
565 acpi_gbl_system_awake_and_running = TRUE;
567 status = acpi_hw_enable_all_runtime_gpes (ACPI_NOT_ISR);
568 if (ACPI_FAILURE (status)) {
569 return_ACPI_STATUS (status);
572 /* Enable power button */
574 (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id,
575 1, ACPI_MTX_DO_NOT_LOCK);
576 (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id,
577 1, ACPI_MTX_DO_NOT_LOCK);
579 /* Enable BM arbitration */
581 status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK);
582 if (ACPI_FAILURE (status)) {
583 return_ACPI_STATUS (status);
586 arg.integer.value = ACPI_SST_WORKING;
587 status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
588 if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
589 ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
592 return_ACPI_STATUS (status);