Merge branch 'linus' into x86/amd-iommu
[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 acpi_status
190 acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
191                        acpi_event_status * event_status)
192 {
193         u32 in_byte;
194         u8 register_bit;
195         struct acpi_gpe_register_info *gpe_register_info;
196         acpi_status status;
197         acpi_event_status local_event_status = 0;
198
199         ACPI_FUNCTION_ENTRY();
200
201         if (!event_status) {
202                 return (AE_BAD_PARAMETER);
203         }
204
205         /* Get the info block for the entire GPE register */
206
207         gpe_register_info = gpe_event_info->register_info;
208
209         /* Get the register bitmask for this GPE */
210
211         register_bit = (u8)
212             (1 <<
213              (gpe_event_info->gpe_number -
214               gpe_event_info->register_info->base_gpe_number));
215
216         /* GPE currently enabled? (enabled for runtime?) */
217
218         if (register_bit & gpe_register_info->enable_for_run) {
219                 local_event_status |= ACPI_EVENT_FLAG_ENABLED;
220         }
221
222         /* GPE enabled for wake? */
223
224         if (register_bit & gpe_register_info->enable_for_wake) {
225                 local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
226         }
227
228         /* GPE currently active (status bit == 1)? */
229
230         status =
231             acpi_hw_low_level_read(8, &in_byte,
232                                    &gpe_register_info->status_address);
233         if (ACPI_FAILURE(status)) {
234                 goto unlock_and_exit;
235         }
236
237         if (register_bit & in_byte) {
238                 local_event_status |= ACPI_EVENT_FLAG_SET;
239         }
240
241         /* Set return value */
242
243         (*event_status) = local_event_status;
244
245       unlock_and_exit:
246         return (status);
247 }
248
249 /******************************************************************************
250  *
251  * FUNCTION:    acpi_hw_disable_gpe_block
252  *
253  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
254  *              gpe_block           - Gpe Block info
255  *
256  * RETURN:      Status
257  *
258  * DESCRIPTION: Disable all GPEs within a single GPE block
259  *
260  ******************************************************************************/
261
262 acpi_status
263 acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
264                           struct acpi_gpe_block_info * gpe_block)
265 {
266         u32 i;
267         acpi_status status;
268
269         /* Examine each GPE Register within the block */
270
271         for (i = 0; i < gpe_block->register_count; i++) {
272
273                 /* Disable all GPEs in this register */
274
275                 status = acpi_hw_low_level_write(8, 0x00,
276                                                  &gpe_block->register_info[i].
277                                                  enable_address);
278                 if (ACPI_FAILURE(status)) {
279                         return (status);
280                 }
281         }
282
283         return (AE_OK);
284 }
285
286 /******************************************************************************
287  *
288  * FUNCTION:    acpi_hw_clear_gpe_block
289  *
290  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
291  *              gpe_block           - Gpe Block info
292  *
293  * RETURN:      Status
294  *
295  * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
296  *
297  ******************************************************************************/
298
299 acpi_status
300 acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
301                         struct acpi_gpe_block_info * gpe_block)
302 {
303         u32 i;
304         acpi_status status;
305
306         /* Examine each GPE Register within the block */
307
308         for (i = 0; i < gpe_block->register_count; i++) {
309
310                 /* Clear status on all GPEs in this register */
311
312                 status = acpi_hw_low_level_write(8, 0xFF,
313                                                  &gpe_block->register_info[i].
314                                                  status_address);
315                 if (ACPI_FAILURE(status)) {
316                         return (status);
317                 }
318         }
319
320         return (AE_OK);
321 }
322
323 /******************************************************************************
324  *
325  * FUNCTION:    acpi_hw_enable_runtime_gpe_block
326  *
327  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
328  *              gpe_block           - Gpe Block info
329  *
330  * RETURN:      Status
331  *
332  * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
333  *              combination wake/run GPEs.
334  *
335  ******************************************************************************/
336
337 acpi_status
338 acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
339                                  struct acpi_gpe_block_info * gpe_block)
340 {
341         u32 i;
342         acpi_status status;
343
344         /* NOTE: assumes that all GPEs are currently disabled */
345
346         /* Examine each GPE Register within the block */
347
348         for (i = 0; i < gpe_block->register_count; i++) {
349                 if (!gpe_block->register_info[i].enable_for_run) {
350                         continue;
351                 }
352
353                 /* Enable all "runtime" GPEs in this register */
354
355                 status =
356                     acpi_hw_low_level_write(8,
357                                             gpe_block->register_info[i].
358                                             enable_for_run,
359                                             &gpe_block->register_info[i].
360                                             enable_address);
361                 if (ACPI_FAILURE(status)) {
362                         return (status);
363                 }
364         }
365
366         return (AE_OK);
367 }
368
369 /******************************************************************************
370  *
371  * FUNCTION:    acpi_hw_enable_wakeup_gpe_block
372  *
373  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
374  *              gpe_block           - Gpe Block info
375  *
376  * RETURN:      Status
377  *
378  * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
379  *              combination wake/run GPEs.
380  *
381  ******************************************************************************/
382
383 static acpi_status
384 acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
385                                 struct acpi_gpe_block_info *gpe_block)
386 {
387         u32 i;
388         acpi_status status;
389
390         /* Examine each GPE Register within the block */
391
392         for (i = 0; i < gpe_block->register_count; i++) {
393                 if (!gpe_block->register_info[i].enable_for_wake) {
394                         continue;
395                 }
396
397                 /* Enable all "wake" GPEs in this register */
398
399                 status = acpi_hw_low_level_write(8,
400                                                  gpe_block->register_info[i].
401                                                  enable_for_wake,
402                                                  &gpe_block->register_info[i].
403                                                  enable_address);
404                 if (ACPI_FAILURE(status)) {
405                         return (status);
406                 }
407         }
408
409         return (AE_OK);
410 }
411
412 /******************************************************************************
413  *
414  * FUNCTION:    acpi_hw_disable_all_gpes
415  *
416  * PARAMETERS:  None
417  *
418  * RETURN:      Status
419  *
420  * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
421  *
422  ******************************************************************************/
423
424 acpi_status acpi_hw_disable_all_gpes(void)
425 {
426         acpi_status status;
427
428         ACPI_FUNCTION_TRACE(hw_disable_all_gpes);
429
430         status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
431         status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
432         return_ACPI_STATUS(status);
433 }
434
435 /******************************************************************************
436  *
437  * FUNCTION:    acpi_hw_enable_all_runtime_gpes
438  *
439  * PARAMETERS:  None
440  *
441  * RETURN:      Status
442  *
443  * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
444  *
445  ******************************************************************************/
446
447 acpi_status acpi_hw_enable_all_runtime_gpes(void)
448 {
449         acpi_status status;
450
451         ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes);
452
453         status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block);
454         return_ACPI_STATUS(status);
455 }
456
457 /******************************************************************************
458  *
459  * FUNCTION:    acpi_hw_enable_all_wakeup_gpes
460  *
461  * PARAMETERS:  None
462  *
463  * RETURN:      Status
464  *
465  * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
466  *
467  ******************************************************************************/
468
469 acpi_status acpi_hw_enable_all_wakeup_gpes(void)
470 {
471         acpi_status status;
472
473         ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes);
474
475         status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block);
476         return_ACPI_STATUS(status);
477 }