aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib-acpi.c
diff options
context:
space:
mode:
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);