aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib-acpi.c
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2013-01-28 09:23:10 -0500
committerLinus Walleij <linus.walleij@linaro.org>2013-01-29 05:47:06 -0500
commit0d1c28a449c6c23a126e3a08ee30914609aac227 (patch)
tree30995ef0e73b540d0eeb3fb0321e7baa8bcb01cf /drivers/gpio/gpiolib-acpi.c
parentb42748c970d1865685749960cb23f08e259a9f86 (diff)
gpiolib-acpi: Add ACPI5 event model support to gpio.
Add ability to handle ACPI events signalled by GPIO interrupts. 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 controller's interrupt handler. acpi_gpio_request_interrupt() finds out which gpio pins have acpi event methods and assigns interrupt handlers that calls the acpi event methods for those pins. Partially based on work by Rui Zhang <rui.zhang@intel.com> Signed-off-by: Mathias Nyman <mathias.nyman@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.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index cbad6e908d30..54ce2269ed25 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -15,6 +15,7 @@
15#include <linux/export.h> 15#include <linux/export.h>
16#include <linux/acpi_gpio.h> 16#include <linux/acpi_gpio.h>
17#include <linux/acpi.h> 17#include <linux/acpi.h>
18#include <linux/interrupt.h>
18 19
19static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) 20static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
20{ 21{
@@ -52,3 +53,84 @@ int acpi_get_gpio(char *path, int pin)
52 return chip->base + pin; 53 return chip->base + pin;
53} 54}
54EXPORT_SYMBOL_GPL(acpi_get_gpio); 55EXPORT_SYMBOL_GPL(acpi_get_gpio);
56
57
58static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
59{
60 acpi_handle handle = data;
61
62 acpi_evaluate_object(handle, NULL, NULL, NULL);
63
64 return IRQ_HANDLED;
65}
66
67/**
68 * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
69 * @chip: gpio chip
70 *
71 * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
72 * handled by ACPI event methods which need to be called from the GPIO
73 * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
74 * gpio pins have acpi event methods and assigns interrupt handlers that calls
75 * the acpi event methods for those pins.
76 *
77 * Interrupts are automatically freed on driver detach
78 */
79
80void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
81{
82 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
83 struct acpi_resource *res;
84 acpi_handle handle, ev_handle;
85 acpi_status status;
86 unsigned int pin, irq;
87 char ev_name[5];
88
89 if (!chip->dev || !chip->to_irq)
90 return;
91
92 handle = ACPI_HANDLE(chip->dev);
93 if (!handle)
94 return;
95
96 status = acpi_get_event_resources(handle, &buf);
97 if (ACPI_FAILURE(status))
98 return;
99
100 /* If a gpio interrupt has an acpi event handler method, then
101 * set up an interrupt handler that calls the acpi event handler
102 */
103
104 for (res = buf.pointer;
105 res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
106 res = ACPI_NEXT_RESOURCE(res)) {
107
108 if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
109 res->data.gpio.connection_type !=
110 ACPI_RESOURCE_GPIO_TYPE_INT)
111 continue;
112
113 pin = res->data.gpio.pin_table[0];
114 if (pin > chip->ngpio)
115 continue;
116
117 sprintf(ev_name, "_%c%02X",
118 res->data.gpio.triggering ? 'E' : 'L', pin);
119
120 status = acpi_get_handle(handle, ev_name, &ev_handle);
121 if (ACPI_FAILURE(status))
122 continue;
123
124 irq = chip->to_irq(chip, pin);
125 if (irq < 0)
126 continue;
127
128 /* Assume BIOS sets the triggering, so no flags */
129 devm_request_threaded_irq(chip->dev, irq, NULL,
130 acpi_gpio_irq_handler,
131 0,
132 "GPIO-signaled-ACPI-event",
133 ev_handle);
134 }
135}
136EXPORT_SYMBOL(acpi_gpiochip_request_interrupts);