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