diff options
Diffstat (limited to 'drivers/acpi/acpica/exfield.c')
-rw-r--r-- | drivers/acpi/acpica/exfield.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 6907ce0c704c..b994845ed359 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c | |||
@@ -253,6 +253,37 @@ acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, | |||
253 | buffer = &buffer_desc->integer.value; | 253 | buffer = &buffer_desc->integer.value; |
254 | } | 254 | } |
255 | 255 | ||
256 | if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && | ||
257 | (obj_desc->field.region_obj->region.space_id == | ||
258 | ACPI_ADR_SPACE_GPIO)) { | ||
259 | /* | ||
260 | * For GPIO (general_purpose_io), the Address will be the bit offset | ||
261 | * from the previous Connection() operator, making it effectively a | ||
262 | * pin number index. The bit_length is the length of the field, which | ||
263 | * is thus the number of pins. | ||
264 | */ | ||
265 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, | ||
266 | "GPIO FieldRead [FROM]: Pin %u Bits %u\n", | ||
267 | obj_desc->field.pin_number_index, | ||
268 | obj_desc->field.bit_length)); | ||
269 | |||
270 | /* Lock entire transaction if requested */ | ||
271 | |||
272 | acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); | ||
273 | |||
274 | /* Perform the write */ | ||
275 | |||
276 | status = acpi_ex_access_region(obj_desc, 0, | ||
277 | (u64 *)buffer, ACPI_READ); | ||
278 | acpi_ex_release_global_lock(obj_desc->common_field.field_flags); | ||
279 | if (ACPI_FAILURE(status)) { | ||
280 | acpi_ut_remove_reference(buffer_desc); | ||
281 | } else { | ||
282 | *ret_buffer_desc = buffer_desc; | ||
283 | } | ||
284 | return_ACPI_STATUS(status); | ||
285 | } | ||
286 | |||
256 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, | 287 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, |
257 | "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", | 288 | "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", |
258 | obj_desc, obj_desc->common.type, buffer, | 289 | obj_desc, obj_desc->common.type, buffer, |
@@ -413,6 +444,42 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, | |||
413 | 444 | ||
414 | *result_desc = buffer_desc; | 445 | *result_desc = buffer_desc; |
415 | return_ACPI_STATUS(status); | 446 | return_ACPI_STATUS(status); |
447 | } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && | ||
448 | (obj_desc->field.region_obj->region.space_id == | ||
449 | ACPI_ADR_SPACE_GPIO)) { | ||
450 | /* | ||
451 | * For GPIO (general_purpose_io), we will bypass the entire field | ||
452 | * mechanism and handoff the bit address and bit width directly to | ||
453 | * the handler. The Address will be the bit offset | ||
454 | * from the previous Connection() operator, making it effectively a | ||
455 | * pin number index. The bit_length is the length of the field, which | ||
456 | * is thus the number of pins. | ||
457 | */ | ||
458 | if (source_desc->common.type != ACPI_TYPE_INTEGER) { | ||
459 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | ||
460 | } | ||
461 | |||
462 | ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, | ||
463 | "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X [TO]: Pin %u Bits %u\n", | ||
464 | acpi_ut_get_type_name(source_desc->common. | ||
465 | type), | ||
466 | source_desc->common.type, | ||
467 | (u32)source_desc->integer.value, | ||
468 | obj_desc->field.pin_number_index, | ||
469 | obj_desc->field.bit_length)); | ||
470 | |||
471 | buffer = &source_desc->integer.value; | ||
472 | |||
473 | /* Lock entire transaction if requested */ | ||
474 | |||
475 | acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); | ||
476 | |||
477 | /* Perform the write */ | ||
478 | |||
479 | status = acpi_ex_access_region(obj_desc, 0, | ||
480 | (u64 *)buffer, ACPI_WRITE); | ||
481 | acpi_ex_release_global_lock(obj_desc->common_field.field_flags); | ||
482 | return_ACPI_STATUS(status); | ||
416 | } | 483 | } |
417 | 484 | ||
418 | /* Get a pointer to the data to be written */ | 485 | /* Get a pointer to the data to be written */ |