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