Make GPE disable more robust
[linux-2.6] / drivers / acpi / hardware / hwgpe.c
1
2 /******************************************************************************
3  *
4  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2008, Intel Corp.
10  * All rights reserved.
11  *
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.
26  *
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.
30  *
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.
43  */
44
45 #include <acpi/acpi.h>
46 #include <acpi/acevents.h>
47
48 #define _COMPONENT          ACPI_HARDWARE
49 ACPI_MODULE_NAME("hwgpe")
50
51 /* Local prototypes */
52 static acpi_status
53 acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
54                                 struct acpi_gpe_block_info *gpe_block);
55
56 /******************************************************************************
57  *
58  * FUNCTION:    acpi_hw_low_disable_gpe
59  *
60  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
61  *
62  * RETURN:      Status
63  *
64  * DESCRIPTION: Disable a single GPE in the enable register.
65  *
66  ******************************************************************************/
67
68 acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
69 {
70         struct acpi_gpe_register_info *gpe_register_info;
71         acpi_status status;
72         u32 enable_mask;
73
74         /* Get the info block for the entire GPE register */
75
76         gpe_register_info = gpe_event_info->register_info;
77         if (!gpe_register_info) {
78                 return (AE_NOT_EXIST);
79         }
80
81         /* Get current value of the enable register that contains this GPE */
82
83         status = acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask,
84                                         &gpe_register_info->enable_address);
85         if (ACPI_FAILURE(status)) {
86                 return (status);
87         }
88
89         /* Clear just the bit that corresponds to this GPE */
90
91         ACPI_CLEAR_BIT(enable_mask,
92                        ((u32) 1 <<
93                         (gpe_event_info->gpe_number -
94                          gpe_register_info->base_gpe_number)));
95
96         /* Write the updated enable mask */
97
98         status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask,
99                                          &gpe_register_info->enable_address);
100
101         return (status);
102 }
103
104 /******************************************************************************
105  *
106  * FUNCTION:    acpi_hw_write_gpe_enable_reg
107  *
108  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
109  *
110  * RETURN:      Status
111  *
112  * DESCRIPTION: Write a GPE enable register.  Note: The bit for this GPE must
113  *              already be cleared or set in the parent register
114  *              enable_for_run mask.
115  *
116  ******************************************************************************/
117
118 acpi_status
119 acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
120 {
121         struct acpi_gpe_register_info *gpe_register_info;
122         acpi_status status;
123
124         ACPI_FUNCTION_ENTRY();
125
126         /* Get the info block for the entire GPE register */
127
128         gpe_register_info = gpe_event_info->register_info;
129         if (!gpe_register_info) {
130                 return (AE_NOT_EXIST);
131         }
132
133         /* Write the entire GPE (runtime) enable register */
134
135         status = acpi_hw_low_level_write(8, gpe_register_info->enable_for_run,
136                                          &gpe_register_info->enable_address);
137
138         return (status);
139 }
140
141 /******************************************************************************
142  *
143  * FUNCTION:    acpi_hw_clear_gpe
144  *
145  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be cleared
146  *
147  * RETURN:      Status
148  *
149  * DESCRIPTION: Clear the status bit for a single GPE.
150  *
151  ******************************************************************************/
152
153 acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
154 {
155         acpi_status status;
156         u8 register_bit;
157
158         ACPI_FUNCTION_ENTRY();
159
160         register_bit = (u8)
161             (1 <<
162              (gpe_event_info->gpe_number -
163               gpe_event_info->register_info->base_gpe_number));
164
165         /*
166          * Write a one to the appropriate bit in the status register to
167          * clear this GPE.
168          */
169         status = acpi_hw_low_level_write(8, register_bit,
170                                          &gpe_event_info->register_info->
171                                          status_address);
172
173         return (status);
174 }
175
176 /******************************************************************************
177  *
178  * FUNCTION:    acpi_hw_get_gpe_status
179  *
180  * PARAMETERS:  gpe_event_info      - Info block for the GPE to queried
181  *              event_status        - Where the GPE status is returned
182  *
183  * RETURN:      Status
184  *
185  * DESCRIPTION: Return the status of a single GPE.
186  *
187  ******************************************************************************/
188
189 #ifdef ACPI_FUTURE_USAGE
190 acpi_status
191 acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
192                        acpi_event_status * event_status)
193 {
194         u32 in_byte;
195         u8 register_bit;
196         struct acpi_gpe_register_info *gpe_register_info;
197         acpi_status status;
198         acpi_event_status local_event_status = 0;
199
200         ACPI_FUNCTION_ENTRY();
201
202         if (!event_status) {
203                 return (AE_BAD_PARAMETER);
204         }
205
206         /* Get the info block for the entire GPE register */
207
208         gpe_register_info = gpe_event_info->register_info;
209
210         /* Get the register bitmask for this GPE */
211
212         register_bit = (u8)
213             (1 <<
214              (gpe_event_info->gpe_number -
215               gpe_event_info->register_info->base_gpe_number));
216
217         /* GPE currently enabled? (enabled for runtime?) */
218
219         if (register_bit & gpe_register_info->enable_for_run) {
220                 local_event_status |= ACPI_EVENT_FLAG_ENABLED;
221         }
222
223         /* GPE enabled for wake? */
224
225         if (register_bit & gpe_register_info->enable_for_wake) {
226                 local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
227         }
228
229         /* GPE currently active (status bit == 1)? */
230
231         status =
232             acpi_hw_low_level_read(8, &in_byte,
233                                    &gpe_register_info->status_address);
234         if (ACPI_FAILURE(status)) {
235                 goto unlock_and_exit;
236         }
237
238         if (register_bit & in_byte) {
239                 local_event_status |= ACPI_EVENT_FLAG_SET;
240         }
241
242         /* Set return value */
243
244         (*event_status) = local_event_status;
245
246       unlock_and_exit:
247         return (status);
248 }
249 #endif                          /*  ACPI_FUTURE_USAGE  */
250
251 /******************************************************************************
252  *
253  * FUNCTION:    acpi_hw_disable_gpe_block
254  *
255  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
256  *              gpe_block           - Gpe Block info
257  *
258  * RETURN:      Status
259  *
260  * DESCRIPTION: Disable all GPEs within a single GPE block
261  *
262  ******************************************************************************/
263
264 acpi_status
265 acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
266                           struct acpi_gpe_block_info * gpe_block)
267 {
268         u32 i;
269         acpi_status status;
270
271         /* Examine each GPE Register within the block */
272
273         for (i = 0; i < gpe_block->register_count; i++) {
274
275                 /* Disable all GPEs in this register */
276
277                 status = acpi_hw_low_level_write(8, 0x00,
278                                                  &gpe_block->register_info[i].
279                                                  enable_address);
280                 if (ACPI_FAILURE(status)) {
281                         return (status);
282                 }
283         }
284
285         return (AE_OK);
286 }
287
288 /******************************************************************************
289  *
290  * FUNCTION:    acpi_hw_clear_gpe_block
291  *
292  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
293  *              gpe_block           - Gpe Block info
294  *
295  * RETURN:      Status
296  *
297  * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
298  *
299  ******************************************************************************/
300
301 acpi_status
302 acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
303                         struct acpi_gpe_block_info * gpe_block)
304 {
305         u32 i;
306         acpi_status status;
307
308         /* Examine each GPE Register within the block */
309
310         for (i = 0; i < gpe_block->register_count; i++) {
311
312                 /* Clear status on all GPEs in this register */
313
314                 status = acpi_hw_low_level_write(8, 0xFF,
315                                                  &gpe_block->register_info[i].
316                                                  status_address);
317                 if (ACPI_FAILURE(status)) {
318                         return (status);
319                 }
320         }
321
322         return (AE_OK);
323 }
324
325 /******************************************************************************
326  *
327  * FUNCTION:    acpi_hw_enable_runtime_gpe_block
328  *
329  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
330  *              gpe_block           - Gpe Block info
331  *
332  * RETURN:      Status
333  *
334  * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
335  *              combination wake/run GPEs.
336  *
337  ******************************************************************************/
338
339 acpi_status
340 acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
341                                  struct acpi_gpe_block_info * gpe_block)
342 {
343         u32 i;
344         acpi_status status;
345
346         /* NOTE: assumes that all GPEs are currently disabled */
347
348         /* Examine each GPE Register within the block */
349
350         for (i = 0; i < gpe_block->register_count; i++) {
351                 if (!gpe_block->register_info[i].enable_for_run) {
352                         continue;
353                 }
354
355                 /* Enable all "runtime" GPEs in this register */
356
357                 status =
358                     acpi_hw_low_level_write(8,
359                                             gpe_block->register_info[i].
360                                             enable_for_run,
361                                             &gpe_block->register_info[i].
362                                             enable_address);
363                 if (ACPI_FAILURE(status)) {
364                         return (status);
365                 }
366         }
367
368         return (AE_OK);
369 }
370
371 /******************************************************************************
372  *
373  * FUNCTION:    acpi_hw_enable_wakeup_gpe_block
374  *
375  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
376  *              gpe_block           - Gpe Block info
377  *
378  * RETURN:      Status
379  *
380  * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
381  *              combination wake/run GPEs.
382  *
383  ******************************************************************************/
384
385 static acpi_status
386 acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
387                                 struct acpi_gpe_block_info *gpe_block)
388 {
389         u32 i;
390         acpi_status status;
391
392         /* Examine each GPE Register within the block */
393
394         for (i = 0; i < gpe_block->register_count; i++) {
395                 if (!gpe_block->register_info[i].enable_for_wake) {
396                         continue;
397                 }
398
399                 /* Enable all "wake" GPEs in this register */
400
401                 status = acpi_hw_low_level_write(8,
402                                                  gpe_block->register_info[i].
403                                                  enable_for_wake,
404                                                  &gpe_block->register_info[i].
405                                                  enable_address);
406                 if (ACPI_FAILURE(status)) {
407                         return (status);
408                 }
409         }
410
411         return (AE_OK);
412 }
413
414 /******************************************************************************
415  *
416  * FUNCTION:    acpi_hw_disable_all_gpes
417  *
418  * PARAMETERS:  None
419  *
420  * RETURN:      Status
421  *
422  * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
423  *
424  ******************************************************************************/
425
426 acpi_status acpi_hw_disable_all_gpes(void)
427 {
428         acpi_status status;
429
430         ACPI_FUNCTION_TRACE(hw_disable_all_gpes);
431
432         status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
433         status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
434         return_ACPI_STATUS(status);
435 }
436
437 /******************************************************************************
438  *
439  * FUNCTION:    acpi_hw_enable_all_runtime_gpes
440  *
441  * PARAMETERS:  None
442  *
443  * RETURN:      Status
444  *
445  * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
446  *
447  ******************************************************************************/
448
449 acpi_status acpi_hw_enable_all_runtime_gpes(void)
450 {
451         acpi_status status;
452
453         ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes);
454
455         status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block);
456         return_ACPI_STATUS(status);
457 }
458
459 /******************************************************************************
460  *
461  * FUNCTION:    acpi_hw_enable_all_wakeup_gpes
462  *
463  * PARAMETERS:  None
464  *
465  * RETURN:      Status
466  *
467  * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
468  *
469  ******************************************************************************/
470
471 acpi_status acpi_hw_enable_all_wakeup_gpes(void)
472 {
473         acpi_status status;
474
475         ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes);
476
477         status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block);
478         return_ACPI_STATUS(status);
479 }