summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib-acpi.c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2015-10-30 06:02:05 -0400
committerLinus Walleij <linus.walleij@linaro.org>2015-10-31 17:12:31 -0400
commitc103a10f690cc49054c52f493eeeff143d5f59e7 (patch)
treec60e2d045841421a361aa0c2c0787069a173a60b /drivers/gpio/gpiolib-acpi.c
parentbc6a73bbfba5d8325b0e659545ce2f3ad983829b (diff)
gpio / ACPI: Allow shared GPIO event to be read via operation region
In Microsoft Surface3 the GPIO detecting lid state is shared between GPIO event and operation region. Below is simplied version of the DSDT from Surface3 including relevant parts: Scope (GPO0) { Name (_AEI, ResourceTemplate () { GpioInt (Edge, ActiveBoth, Shared, PullNone, 0x0000, "\\_SB.GPO0", 0x00, ResourceConsumer, , ) { // Pin list 0x004C } }) OperationRegion (GPOR, GeneralPurposeIo, Zero, One) Field (GPOR, ByteAcc, NoLock, Preserve) { Connection ( GpioIo (Shared, PullNone, 0x0000, 0x0000, IoRestrictionNone, "\\_SB.GPO0", 0x00, ResourceConsumer,,) { // Pin list 0x004C } ), HELD, 1 } Method (_E4C, 0, Serialized) // _Exx: Edge-Triggered GPE { If ((HELD == One)) { ^^LID.LIDB = One } Else { ^^LID.LIDB = Zero Notify (LID, 0x80) // Status Change } Notify (^^PCI0.SPI1.NTRG, One) // Device Check } } When GPIO 0x4c changes we call ASL method _E4C which tries to read HELD field (the same GPIO). This triggers following error on the console: ACPI Error: Method parse/execution failed [\_SB.GPO0._E4C] (Node ffff88013f4b4438), AE_ERROR (20150930/psparse-542) The error happens because ACPI GPIO operation region handler (acpi_gpio_adr_space_handler()) tries to acquire the very same GPIO which returns an error (-EBUSY) because the GPIO is already reserved for the GPIO event. Fix this so that we "borrow" the event GPIO if we find the GPIO belongs to an event. Allow this only for GPIOs that are read. To be able to go through acpi_gpio->events list for operation region access we need to make sure the list is properly initialized whenever GPIO chip is registered. Link: https://bugzilla.kernel.org/show_bug.cgi?id=106571 Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib-acpi.c')
-rw-r--r--drivers/gpio/gpiolib-acpi.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 143a9bdbaa53..bbcac3af2a7a 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -304,7 +304,6 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
304 if (ACPI_FAILURE(status)) 304 if (ACPI_FAILURE(status))
305 return; 305 return;
306 306
307 INIT_LIST_HEAD(&acpi_gpio->events);
308 acpi_walk_resources(handle, "_AEI", 307 acpi_walk_resources(handle, "_AEI",
309 acpi_gpiochip_request_interrupt, acpi_gpio); 308 acpi_gpiochip_request_interrupt, acpi_gpio);
310} 309}
@@ -603,6 +602,25 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
603 break; 602 break;
604 } 603 }
605 } 604 }
605
606 /*
607 * The same GPIO can be shared between operation region and
608 * event but only if the access here is ACPI_READ. In that
609 * case we "borrow" the event GPIO instead.
610 */
611 if (!found && agpio->sharable == ACPI_SHARED &&
612 function == ACPI_READ) {
613 struct acpi_gpio_event *event;
614
615 list_for_each_entry(event, &achip->events, node) {
616 if (event->pin == pin) {
617 desc = event->desc;
618 found = true;
619 break;
620 }
621 }
622 }
623
606 if (!found) { 624 if (!found) {
607 desc = gpiochip_request_own_desc(chip, pin, 625 desc = gpiochip_request_own_desc(chip, pin,
608 "ACPI:OpRegion"); 626 "ACPI:OpRegion");
@@ -719,6 +737,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
719 } 737 }
720 738
721 acpi_gpio->chip = chip; 739 acpi_gpio->chip = chip;
740 INIT_LIST_HEAD(&acpi_gpio->events);
722 741
723 status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); 742 status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
724 if (ACPI_FAILURE(status)) { 743 if (ACPI_FAILURE(status)) {