hwgpe.c 13.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8

/******************************************************************************
 *
 * Module Name: hwgpe - Low level GPE enable/disable/clear functions
 *
 *****************************************************************************/

/*
9
 * Copyright (C) 2000 - 2010, Intel Corp.
L
Linus Torvalds 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
L
Len Brown 已提交
46 47
#include "accommon.h"
#include "acevents.h"
L
Linus Torvalds 已提交
48 49

#define _COMPONENT          ACPI_HARDWARE
L
Len Brown 已提交
50
ACPI_MODULE_NAME("hwgpe")
L
Linus Torvalds 已提交
51

R
Robert Moore 已提交
52 53
/* Local prototypes */
static acpi_status
L
Len Brown 已提交
54
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
55 56
				struct acpi_gpe_block_info *gpe_block,
				void *context);
L
Linus Torvalds 已提交
57

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
/******************************************************************************
 *
 * FUNCTION:	acpi_hw_gpe_register_bit
 *
 * PARAMETERS:	gpe_event_info	    - Info block for the GPE
 *		gpe_register_info   - Info block for the GPE register
 *
 * RETURN:	Status
 *
 * DESCRIPTION:	Compute GPE enable mask with one bit corresponding to the given
 *		GPE set.
 *
 ******************************************************************************/

u32 acpi_hw_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
			     struct acpi_gpe_register_info *gpe_register_info)
{
	return (u32)1 << (gpe_event_info->gpe_number -
				gpe_register_info->base_gpe_number);
}

B
Bob Moore 已提交
79 80
/******************************************************************************
 *
81
 * FUNCTION:	acpi_hw_low_set_gpe
B
Bob Moore 已提交
82 83
 *
 * PARAMETERS:	gpe_event_info	    - Info block for the GPE to be disabled
84
 *		action		    - Enable or disable
B
Bob Moore 已提交
85 86 87
 *
 * RETURN:	Status
 *
88
 * DESCRIPTION: Enable or disable a single GPE in its enable register.
B
Bob Moore 已提交
89 90 91
 *
 ******************************************************************************/

92 93
acpi_status
acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
B
Bob Moore 已提交
94 95 96 97
{
	struct acpi_gpe_register_info *gpe_register_info;
	acpi_status status;
	u32 enable_mask;
98
	u32 register_bit;
B
Bob Moore 已提交
99

100 101
	ACPI_FUNCTION_ENTRY();

B
Bob Moore 已提交
102 103 104 105 106 107 108 109 110
	/* Get the info block for the entire GPE register */

	gpe_register_info = gpe_event_info->register_info;
	if (!gpe_register_info) {
		return (AE_NOT_EXIST);
	}

	/* Get current value of the enable register that contains this GPE */

111
	status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address);
B
Bob Moore 已提交
112 113 114 115
	if (ACPI_FAILURE(status)) {
		return (status);
	}

116
	/* Set ot clear just the bit that corresponds to this GPE */
B
Bob Moore 已提交
117

118 119
	register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
						gpe_register_info);
120 121 122 123 124 125 126 127 128 129 130 131 132
	switch (action) {
	case ACPI_GPE_ENABLE:
		ACPI_SET_BIT(enable_mask, register_bit);
		break;

	case ACPI_GPE_DISABLE:
		ACPI_CLEAR_BIT(enable_mask, register_bit);
		break;

	default:
		ACPI_ERROR((AE_INFO, "Invalid action\n"));
		return (AE_BAD_PARAMETER);
	}
B
Bob Moore 已提交
133 134 135

	/* Write the updated enable mask */

136
	status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
B
Bob Moore 已提交
137 138 139
	return (status);
}

L
Linus Torvalds 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
/******************************************************************************
 *
 * FUNCTION:    acpi_hw_write_gpe_enable_reg
 *
 * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Write a GPE enable register.  Note: The bit for this GPE must
 *              already be cleared or set in the parent register
 *              enable_for_run mask.
 *
 ******************************************************************************/

acpi_status
B
Bob Moore 已提交
155
acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
L
Linus Torvalds 已提交
156
{
L
Len Brown 已提交
157 158
	struct acpi_gpe_register_info *gpe_register_info;
	acpi_status status;
L
Linus Torvalds 已提交
159

L
Len Brown 已提交
160
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
161 162 163 164 165 166 167 168 169 170

	/* Get the info block for the entire GPE register */

	gpe_register_info = gpe_event_info->register_info;
	if (!gpe_register_info) {
		return (AE_NOT_EXIST);
	}

	/* Write the entire GPE (runtime) enable register */

171 172
	status = acpi_hw_write(gpe_register_info->enable_for_run,
			       &gpe_register_info->enable_address);
L
Linus Torvalds 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

	return (status);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_clear_gpe
 *
 * PARAMETERS:  gpe_event_info      - Info block for the GPE to be cleared
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Clear the status bit for a single GPE.
 *
 ******************************************************************************/

L
Len Brown 已提交
189
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
L
Linus Torvalds 已提交
190
{
191
	struct acpi_gpe_register_info *gpe_register_info;
L
Len Brown 已提交
192
	acpi_status status;
193
	u32 register_bit;
L
Linus Torvalds 已提交
194

L
Len Brown 已提交
195
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
196

197 198 199 200 201 202 203 204 205
	/* Get the info block for the entire GPE register */

	gpe_register_info = gpe_event_info->register_info;
	if (!gpe_register_info) {
		return (AE_NOT_EXIST);
	}

	register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
						gpe_register_info);
206

L
Linus Torvalds 已提交
207 208 209 210
	/*
	 * Write a one to the appropriate bit in the status register to
	 * clear this GPE.
	 */
211
	status = acpi_hw_write(register_bit,
212
			       &gpe_register_info->status_address);
L
Linus Torvalds 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228

	return (status);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_get_gpe_status
 *
 * PARAMETERS:  gpe_event_info      - Info block for the GPE to queried
 *              event_status        - Where the GPE status is returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Return the status of a single GPE.
 *
 ******************************************************************************/
R
Robert Moore 已提交
229

L
Linus Torvalds 已提交
230
acpi_status
L
Len Brown 已提交
231 232
acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
		       acpi_event_status * event_status)
L
Linus Torvalds 已提交
233
{
L
Len Brown 已提交
234
	u32 in_byte;
235
	u32 register_bit;
L
Len Brown 已提交
236 237 238
	struct acpi_gpe_register_info *gpe_register_info;
	acpi_status status;
	acpi_event_status local_event_status = 0;
L
Linus Torvalds 已提交
239

L
Len Brown 已提交
240
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
241 242 243 244 245 246 247 248 249 250 251

	if (!event_status) {
		return (AE_BAD_PARAMETER);
	}

	/* Get the info block for the entire GPE register */

	gpe_register_info = gpe_event_info->register_info;

	/* Get the register bitmask for this GPE */

252 253
	register_bit = acpi_hw_gpe_register_bit(gpe_event_info,
						gpe_register_info);
L
Linus Torvalds 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

	/* GPE currently enabled? (enabled for runtime?) */

	if (register_bit & gpe_register_info->enable_for_run) {
		local_event_status |= ACPI_EVENT_FLAG_ENABLED;
	}

	/* GPE enabled for wake? */

	if (register_bit & gpe_register_info->enable_for_wake) {
		local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
	}

	/* GPE currently active (status bit == 1)? */

269
	status = acpi_hw_read(&in_byte, &gpe_register_info->status_address);
L
Len Brown 已提交
270
	if (ACPI_FAILURE(status)) {
271
		return (status);
L
Linus Torvalds 已提交
272 273 274 275 276 277 278 279 280
	}

	if (register_bit & in_byte) {
		local_event_status |= ACPI_EVENT_FLAG_SET;
	}

	/* Set return value */

	(*event_status) = local_event_status;
281
	return (AE_OK);
L
Linus Torvalds 已提交
282 283 284 285 286 287 288 289 290 291 292
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_disable_gpe_block
 *
 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 *              gpe_block           - Gpe Block info
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
293
 * DESCRIPTION: Disable all GPEs within a single GPE block
L
Linus Torvalds 已提交
294 295 296 297
 *
 ******************************************************************************/

acpi_status
298 299
acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
			  struct acpi_gpe_block_info *gpe_block, void *context)
L
Linus Torvalds 已提交
300
{
L
Len Brown 已提交
301 302
	u32 i;
	acpi_status status;
L
Linus Torvalds 已提交
303 304 305 306

	/* Examine each GPE Register within the block */

	for (i = 0; i < gpe_block->register_count; i++) {
B
Bob Moore 已提交
307

L
Linus Torvalds 已提交
308 309
		/* Disable all GPEs in this register */

310
		status =
311 312
		    acpi_hw_write(0x00,
				  &gpe_block->register_info[i].enable_address);
L
Len Brown 已提交
313
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
			return (status);
		}
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_clear_gpe_block
 *
 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 *              gpe_block           - Gpe Block info
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
330
 * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
L
Linus Torvalds 已提交
331 332 333 334
 *
 ******************************************************************************/

acpi_status
335 336
acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
			struct acpi_gpe_block_info *gpe_block, void *context)
L
Linus Torvalds 已提交
337
{
L
Len Brown 已提交
338 339
	u32 i;
	acpi_status status;
L
Linus Torvalds 已提交
340 341 342 343

	/* Examine each GPE Register within the block */

	for (i = 0; i < gpe_block->register_count; i++) {
B
Bob Moore 已提交
344

L
Linus Torvalds 已提交
345 346
		/* Clear status on all GPEs in this register */

347
		status =
348 349
		    acpi_hw_write(0xFF,
				  &gpe_block->register_info[i].status_address);
L
Len Brown 已提交
350
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
			return (status);
		}
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_enable_runtime_gpe_block
 *
 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 *              gpe_block           - Gpe Block info
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
367 368
 * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
 *              combination wake/run GPEs.
L
Linus Torvalds 已提交
369 370 371 372
 *
 ******************************************************************************/

acpi_status
373 374
acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
				 struct acpi_gpe_block_info *gpe_block, void *context)
L
Linus Torvalds 已提交
375
{
L
Len Brown 已提交
376 377
	u32 i;
	acpi_status status;
L
Linus Torvalds 已提交
378 379 380 381 382 383 384 385 386 387 388 389

	/* NOTE: assumes that all GPEs are currently disabled */

	/* Examine each GPE Register within the block */

	for (i = 0; i < gpe_block->register_count; i++) {
		if (!gpe_block->register_info[i].enable_for_run) {
			continue;
		}

		/* Enable all "runtime" GPEs in this register */

390 391 392
		status =
		    acpi_hw_write(gpe_block->register_info[i].enable_for_run,
				  &gpe_block->register_info[i].enable_address);
L
Len Brown 已提交
393
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
			return (status);
		}
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_enable_wakeup_gpe_block
 *
 * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
 *              gpe_block           - Gpe Block info
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
410 411
 * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
 *              combination wake/run GPEs.
L
Linus Torvalds 已提交
412 413 414
 *
 ******************************************************************************/

R
Robert Moore 已提交
415
static acpi_status
L
Len Brown 已提交
416
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
417 418
				struct acpi_gpe_block_info *gpe_block,
				void *context)
L
Linus Torvalds 已提交
419
{
L
Len Brown 已提交
420 421
	u32 i;
	acpi_status status;
L
Linus Torvalds 已提交
422 423 424 425 426 427 428 429 430 431

	/* Examine each GPE Register within the block */

	for (i = 0; i < gpe_block->register_count; i++) {
		if (!gpe_block->register_info[i].enable_for_wake) {
			continue;
		}

		/* Enable all "wake" GPEs in this register */

432 433 434
		status =
		    acpi_hw_write(gpe_block->register_info[i].enable_for_wake,
				  &gpe_block->register_info[i].enable_address);
L
Len Brown 已提交
435
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
436 437 438 439 440 441 442 443 444 445 446
			return (status);
		}
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_disable_all_gpes
 *
447
 * PARAMETERS:  None
L
Linus Torvalds 已提交
448 449 450
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
451
 * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
L
Linus Torvalds 已提交
452 453 454
 *
 ******************************************************************************/

L
Len Brown 已提交
455
acpi_status acpi_hw_disable_all_gpes(void)
L
Linus Torvalds 已提交
456
{
L
Len Brown 已提交
457
	acpi_status status;
L
Linus Torvalds 已提交
458

B
Bob Moore 已提交
459
	ACPI_FUNCTION_TRACE(hw_disable_all_gpes);
L
Linus Torvalds 已提交
460

461 462
	status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
	status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
L
Len Brown 已提交
463
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
464 465 466 467 468 469
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_enable_all_runtime_gpes
 *
470
 * PARAMETERS:  None
L
Linus Torvalds 已提交
471 472 473
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
474
 * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
L
Linus Torvalds 已提交
475 476 477
 *
 ******************************************************************************/

L
Len Brown 已提交
478
acpi_status acpi_hw_enable_all_runtime_gpes(void)
L
Linus Torvalds 已提交
479
{
L
Len Brown 已提交
480
	acpi_status status;
L
Linus Torvalds 已提交
481

B
Bob Moore 已提交
482
	ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes);
L
Linus Torvalds 已提交
483

484
	status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL);
L
Len Brown 已提交
485
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
486 487 488 489 490 491
}

/******************************************************************************
 *
 * FUNCTION:    acpi_hw_enable_all_wakeup_gpes
 *
492
 * PARAMETERS:  None
L
Linus Torvalds 已提交
493 494 495
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
496
 * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
L
Linus Torvalds 已提交
497 498 499
 *
 ******************************************************************************/

L
Len Brown 已提交
500
acpi_status acpi_hw_enable_all_wakeup_gpes(void)
L
Linus Torvalds 已提交
501
{
L
Len Brown 已提交
502
	acpi_status status;
L
Linus Torvalds 已提交
503

B
Bob Moore 已提交
504
	ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes);
L
Linus Torvalds 已提交
505

506
	status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL);
L
Len Brown 已提交
507
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
508
}