diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 09:35:29 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 09:35:29 -0800 |
commit | 4c8c225abf972ce422c241579ce1d4d27eaeb166 (patch) | |
tree | 77bc67defdc53c494b20632e66b82ce9be3c06af /drivers/gpio/gpiolib-acpi.c | |
parent | 3eb05225ee8efb81fe50558f5f9d94e7477ade8f (diff) | |
parent | 9170100ee46402af6d318134525c728027318d67 (diff) |
Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux
Pull GPIO changes from Grant Likely:
"This branch contains the usual set of individual driver improvements
and bug fixes, as well as updates to the core code. The more notable
changes include:
- Internally add new API for referencing GPIOs by gpio_desc instead
of number. Eventually this will become a public API
- ACPI GPIO binding support"
* tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux: (33 commits)
arm64: select ARCH_WANT_OPTIONAL_GPIOLIB
gpio: em: Use irq_domain_add_simple() to fix runtime error
gpio: using common order: let 'static const' instead of 'const static'
gpio/vt8500: memory cleanup missing
gpiolib: Fix locking on gpio debugfs files
gpiolib: let gpio_chip reference its descriptors
gpiolib: use descriptors internally
gpiolib: use gpio_chips list in gpiochip_find_base
gpiolib: use gpio_chips list in sysfs ops
gpiolib: use gpio_chips list in gpiochip_find
gpiolib: use gpio_chips list in gpiolib_sysfs_init
gpiolib: link all gpio_chips using a list
gpio/langwell: cleanup driver
gpio/langwell: Add Cloverview ids to pci device table
gpio/lynxpoint: add chipset gpio driver.
gpiolib: add missing braces in gpio_direction_show
gpiolib-acpi: Fix error checks in interrupt requesting
gpio: mpc8xxx: don't set IRQ_TYPE_NONE when creating irq mapping
gpiolib: remove gpiochip_reserve()
arm: pxa: tosa: do not use gpiochip_reserve()
...
Diffstat (limited to 'drivers/gpio/gpiolib-acpi.c')
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index cbad6e908d3..a063eb04b6c 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -15,6 +15,7 @@ #include <linux/export.h> #include <linux/acpi_gpio.h> #include <linux/acpi.h> +#include <linux/interrupt.h> static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { @@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin) return chip->base + pin; } EXPORT_SYMBOL_GPL(acpi_get_gpio); + + +static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) +{ + acpi_handle handle = data; + + acpi_evaluate_object(handle, NULL, NULL, NULL); + + return IRQ_HANDLED; +} + +/** + * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events + * @chip: gpio chip + * + * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are + * handled by ACPI event methods which need to be called from the GPIO + * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which + * gpio pins have acpi event methods and assigns interrupt handlers that calls + * the acpi event methods for those pins. + * + * Interrupts are automatically freed on driver detach + */ + +void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_resource *res; + acpi_handle handle, ev_handle; + acpi_status status; + unsigned int pin; + int irq, ret; + char ev_name[5]; + + if (!chip->dev || !chip->to_irq) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_event_resources(handle, &buf); + if (ACPI_FAILURE(status)) + return; + + /* If a gpio interrupt has an acpi event handler method, then + * set up an interrupt handler that calls the acpi event handler + */ + + for (res = buf.pointer; + res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); + res = ACPI_NEXT_RESOURCE(res)) { + + if (res->type != ACPI_RESOURCE_TYPE_GPIO || + res->data.gpio.connection_type != + ACPI_RESOURCE_GPIO_TYPE_INT) + continue; + + pin = res->data.gpio.pin_table[0]; + if (pin > chip->ngpio) + continue; + + sprintf(ev_name, "_%c%02X", + res->data.gpio.triggering ? 'E' : 'L', pin); + + status = acpi_get_handle(handle, ev_name, &ev_handle); + if (ACPI_FAILURE(status)) + continue; + + irq = chip->to_irq(chip, pin); + if (irq < 0) + continue; + + /* Assume BIOS sets the triggering, so no flags */ + ret = devm_request_threaded_irq(chip->dev, irq, NULL, + acpi_gpio_irq_handler, + 0, + "GPIO-signaled-ACPI-event", + ev_handle); + if (ret) + dev_err(chip->dev, + "Failed to request IRQ %d ACPI event handler\n", + irq); + } +} +EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); |