Commit | Line | Data |
---|---|---|
e29482e8 MN |
1 | /* |
2 | * ACPI helpers for GPIO API | |
3 | * | |
4 | * Copyright (C) 2012, Intel Corporation | |
5 | * Authors: Mathias Nyman <mathias.nyman@linux.intel.com> | |
6 | * Mika Westerberg <mika.westerberg@linux.intel.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/errno.h> | |
936e15dd | 14 | #include <linux/gpio/consumer.h> |
5ccff852 | 15 | #include <linux/gpio/driver.h> |
e29482e8 | 16 | #include <linux/export.h> |
e29482e8 | 17 | #include <linux/acpi.h> |
0d1c28a4 | 18 | #include <linux/interrupt.h> |
e29482e8 | 19 | |
5ccff852 MW |
20 | #include "gpiolib.h" |
21 | ||
4b01a14b | 22 | struct acpi_gpio_event { |
7fc7acb9 | 23 | struct list_head node; |
4b01a14b | 24 | acpi_handle handle; |
7fc7acb9 RW |
25 | unsigned int pin; |
26 | unsigned int irq; | |
27 | }; | |
28 | ||
aa92b6f6 MW |
29 | struct acpi_gpio_chip { |
30 | struct gpio_chip *chip; | |
4b01a14b | 31 | struct list_head events; |
aa92b6f6 MW |
32 | }; |
33 | ||
e29482e8 MN |
34 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) |
35 | { | |
36 | if (!gc->dev) | |
37 | return false; | |
38 | ||
39 | return ACPI_HANDLE(gc->dev) == data; | |
40 | } | |
41 | ||
42 | /** | |
936e15dd | 43 | * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API |
e29482e8 MN |
44 | * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") |
45 | * @pin: ACPI GPIO pin number (0-based, controller-relative) | |
46 | * | |
936e15dd MW |
47 | * Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR |
48 | * error value | |
e29482e8 MN |
49 | */ |
50 | ||
936e15dd | 51 | static struct gpio_desc *acpi_get_gpiod(char *path, int pin) |
e29482e8 MN |
52 | { |
53 | struct gpio_chip *chip; | |
54 | acpi_handle handle; | |
55 | acpi_status status; | |
56 | ||
57 | status = acpi_get_handle(NULL, path, &handle); | |
58 | if (ACPI_FAILURE(status)) | |
936e15dd | 59 | return ERR_PTR(-ENODEV); |
e29482e8 MN |
60 | |
61 | chip = gpiochip_find(handle, acpi_gpiochip_find); | |
62 | if (!chip) | |
936e15dd | 63 | return ERR_PTR(-ENODEV); |
e29482e8 | 64 | |
936e15dd MW |
65 | if (pin < 0 || pin > chip->ngpio) |
66 | return ERR_PTR(-EINVAL); | |
e29482e8 | 67 | |
390d82e3 | 68 | return gpiochip_get_desc(chip, pin); |
e29482e8 | 69 | } |
0d1c28a4 | 70 | |
0d1c28a4 MN |
71 | static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) |
72 | { | |
73 | acpi_handle handle = data; | |
74 | ||
75 | acpi_evaluate_object(handle, NULL, NULL, NULL); | |
76 | ||
77 | return IRQ_HANDLED; | |
78 | } | |
79 | ||
7fc7acb9 RW |
80 | static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) |
81 | { | |
4b01a14b | 82 | struct acpi_gpio_event *event = data; |
7fc7acb9 | 83 | |
4b01a14b | 84 | acpi_execute_simple_method(event->handle, NULL, event->pin); |
7fc7acb9 RW |
85 | |
86 | return IRQ_HANDLED; | |
87 | } | |
88 | ||
aa92b6f6 | 89 | static void acpi_gpio_chip_dh(acpi_handle handle, void *data) |
7fc7acb9 RW |
90 | { |
91 | /* The address of this function is used as a key. */ | |
92 | } | |
93 | ||
0d1c28a4 MN |
94 | /** |
95 | * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events | |
aa92b6f6 | 96 | * @acpi_gpio: ACPI GPIO chip |
0d1c28a4 MN |
97 | * |
98 | * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are | |
99 | * handled by ACPI event methods which need to be called from the GPIO | |
100 | * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which | |
101 | * gpio pins have acpi event methods and assigns interrupt handlers that calls | |
102 | * the acpi event methods for those pins. | |
0d1c28a4 | 103 | */ |
aa92b6f6 | 104 | static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) |
0d1c28a4 MN |
105 | { |
106 | struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; | |
aa92b6f6 | 107 | struct gpio_chip *chip = acpi_gpio->chip; |
0d1c28a4 | 108 | struct acpi_resource *res; |
7fc7acb9 | 109 | acpi_handle handle, evt_handle; |
0d1c28a4 | 110 | acpi_status status; |
1107ca10 MN |
111 | unsigned int pin; |
112 | int irq, ret; | |
0d1c28a4 MN |
113 | char ev_name[5]; |
114 | ||
115 | if (!chip->dev || !chip->to_irq) | |
116 | return; | |
117 | ||
118 | handle = ACPI_HANDLE(chip->dev); | |
119 | if (!handle) | |
120 | return; | |
121 | ||
4b01a14b | 122 | INIT_LIST_HEAD(&acpi_gpio->events); |
0d1c28a4 | 123 | |
7fc7acb9 RW |
124 | /* |
125 | * If a GPIO interrupt has an ACPI event handler method, or _EVT is | |
126 | * present, set up an interrupt handler that calls the ACPI event | |
127 | * handler. | |
128 | */ | |
0d1c28a4 MN |
129 | for (res = buf.pointer; |
130 | res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); | |
131 | res = ACPI_NEXT_RESOURCE(res)) { | |
7fc7acb9 RW |
132 | irq_handler_t handler = NULL; |
133 | void *data; | |
0d1c28a4 MN |
134 | |
135 | if (res->type != ACPI_RESOURCE_TYPE_GPIO || | |
136 | res->data.gpio.connection_type != | |
137 | ACPI_RESOURCE_GPIO_TYPE_INT) | |
138 | continue; | |
139 | ||
140 | pin = res->data.gpio.pin_table[0]; | |
141 | if (pin > chip->ngpio) | |
142 | continue; | |
143 | ||
0d1c28a4 MN |
144 | irq = chip->to_irq(chip, pin); |
145 | if (irq < 0) | |
146 | continue; | |
147 | ||
7fc7acb9 RW |
148 | if (pin <= 255) { |
149 | acpi_handle ev_handle; | |
150 | ||
151 | sprintf(ev_name, "_%c%02X", | |
152 | res->data.gpio.triggering ? 'E' : 'L', pin); | |
153 | status = acpi_get_handle(handle, ev_name, &ev_handle); | |
154 | if (ACPI_SUCCESS(status)) { | |
155 | handler = acpi_gpio_irq_handler; | |
156 | data = ev_handle; | |
157 | } | |
158 | } | |
aa92b6f6 | 159 | if (!handler) { |
4b01a14b | 160 | struct acpi_gpio_event *event; |
7fc7acb9 | 161 | |
aa92b6f6 MW |
162 | status = acpi_get_handle(handle, "_EVT", &evt_handle); |
163 | if (ACPI_FAILURE(status)) | |
164 | continue | |
165 | ||
4b01a14b MW |
166 | event = kzalloc(sizeof(*event), GFP_KERNEL); |
167 | if (!event) | |
7fc7acb9 RW |
168 | continue; |
169 | ||
4b01a14b MW |
170 | list_add_tail(&event->node, &acpi_gpio->events); |
171 | event->handle = evt_handle; | |
172 | event->pin = pin; | |
173 | event->irq = irq; | |
7fc7acb9 | 174 | handler = acpi_gpio_irq_handler_evt; |
4b01a14b | 175 | data = event; |
7fc7acb9 RW |
176 | } |
177 | if (!handler) | |
178 | continue; | |
179 | ||
0d1c28a4 | 180 | /* Assume BIOS sets the triggering, so no flags */ |
7fc7acb9 RW |
181 | ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, |
182 | 0, "GPIO-signaled-ACPI-event", | |
183 | data); | |
1107ca10 MN |
184 | if (ret) |
185 | dev_err(chip->dev, | |
186 | "Failed to request IRQ %d ACPI event handler\n", | |
187 | irq); | |
0d1c28a4 MN |
188 | } |
189 | } | |
7fc7acb9 | 190 | |
70b53411 MW |
191 | /** |
192 | * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. | |
aa92b6f6 | 193 | * @acpi_gpio: ACPI GPIO chip |
70b53411 MW |
194 | * |
195 | * Free interrupts associated with the _EVT method for the given GPIO chip. | |
196 | * | |
197 | * The remaining ACPI event interrupts associated with the chip are freed | |
198 | * automatically. | |
199 | */ | |
aa92b6f6 | 200 | static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) |
70b53411 | 201 | { |
4b01a14b | 202 | struct acpi_gpio_event *event, *ep; |
aa92b6f6 | 203 | struct gpio_chip *chip = acpi_gpio->chip; |
70b53411 MW |
204 | |
205 | if (!chip->dev || !chip->to_irq) | |
206 | return; | |
207 | ||
4b01a14b MW |
208 | list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { |
209 | devm_free_irq(chip->dev, event->irq, event); | |
210 | list_del(&event->node); | |
211 | kfree(event); | |
70b53411 | 212 | } |
70b53411 | 213 | } |
70b53411 | 214 | |
12028d2d MW |
215 | struct acpi_gpio_lookup { |
216 | struct acpi_gpio_info info; | |
217 | int index; | |
936e15dd | 218 | struct gpio_desc *desc; |
12028d2d MW |
219 | int n; |
220 | }; | |
221 | ||
222 | static int acpi_find_gpio(struct acpi_resource *ares, void *data) | |
223 | { | |
224 | struct acpi_gpio_lookup *lookup = data; | |
225 | ||
226 | if (ares->type != ACPI_RESOURCE_TYPE_GPIO) | |
227 | return 1; | |
228 | ||
936e15dd | 229 | if (lookup->n++ == lookup->index && !lookup->desc) { |
12028d2d MW |
230 | const struct acpi_resource_gpio *agpio = &ares->data.gpio; |
231 | ||
936e15dd MW |
232 | lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, |
233 | agpio->pin_table[0]); | |
12028d2d MW |
234 | lookup->info.gpioint = |
235 | agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; | |
e01f440a MW |
236 | lookup->info.active_low = |
237 | agpio->polarity == ACPI_ACTIVE_LOW; | |
12028d2d MW |
238 | } |
239 | ||
240 | return 1; | |
241 | } | |
242 | ||
243 | /** | |
936e15dd | 244 | * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources |
12028d2d MW |
245 | * @dev: pointer to a device to get GPIO from |
246 | * @index: index of GpioIo/GpioInt resource (starting from %0) | |
247 | * @info: info pointer to fill in (optional) | |
248 | * | |
249 | * Function goes through ACPI resources for @dev and based on @index looks | |
936e15dd | 250 | * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, |
12028d2d MW |
251 | * and returns it. @index matches GpioIo/GpioInt resources only so if there |
252 | * are total %3 GPIO resources, the index goes from %0 to %2. | |
253 | * | |
936e15dd | 254 | * If the GPIO cannot be translated or there is an error an ERR_PTR is |
12028d2d MW |
255 | * returned. |
256 | * | |
257 | * Note: if the GPIO resource has multiple entries in the pin list, this | |
258 | * function only returns the first. | |
259 | */ | |
936e15dd MW |
260 | struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, |
261 | struct acpi_gpio_info *info) | |
12028d2d MW |
262 | { |
263 | struct acpi_gpio_lookup lookup; | |
264 | struct list_head resource_list; | |
265 | struct acpi_device *adev; | |
266 | acpi_handle handle; | |
267 | int ret; | |
268 | ||
269 | if (!dev) | |
936e15dd | 270 | return ERR_PTR(-EINVAL); |
12028d2d MW |
271 | |
272 | handle = ACPI_HANDLE(dev); | |
273 | if (!handle || acpi_bus_get_device(handle, &adev)) | |
936e15dd | 274 | return ERR_PTR(-ENODEV); |
12028d2d MW |
275 | |
276 | memset(&lookup, 0, sizeof(lookup)); | |
277 | lookup.index = index; | |
12028d2d MW |
278 | |
279 | INIT_LIST_HEAD(&resource_list); | |
280 | ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, | |
281 | &lookup); | |
282 | if (ret < 0) | |
936e15dd | 283 | return ERR_PTR(ret); |
12028d2d MW |
284 | |
285 | acpi_dev_free_resource_list(&resource_list); | |
286 | ||
936e15dd | 287 | if (lookup.desc && info) |
12028d2d MW |
288 | *info = lookup.info; |
289 | ||
a00580c2 | 290 | return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); |
12028d2d | 291 | } |
664e3e5a MW |
292 | |
293 | void acpi_gpiochip_add(struct gpio_chip *chip) | |
294 | { | |
aa92b6f6 MW |
295 | struct acpi_gpio_chip *acpi_gpio; |
296 | acpi_handle handle; | |
297 | acpi_status status; | |
298 | ||
299 | handle = ACPI_HANDLE(chip->dev); | |
300 | if (!handle) | |
301 | return; | |
302 | ||
303 | acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL); | |
304 | if (!acpi_gpio) { | |
305 | dev_err(chip->dev, | |
306 | "Failed to allocate memory for ACPI GPIO chip\n"); | |
307 | return; | |
308 | } | |
309 | ||
310 | acpi_gpio->chip = chip; | |
311 | ||
312 | status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); | |
313 | if (ACPI_FAILURE(status)) { | |
314 | dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n"); | |
315 | kfree(acpi_gpio); | |
316 | return; | |
317 | } | |
318 | ||
319 | acpi_gpiochip_request_interrupts(acpi_gpio); | |
664e3e5a MW |
320 | } |
321 | ||
322 | void acpi_gpiochip_remove(struct gpio_chip *chip) | |
323 | { | |
aa92b6f6 MW |
324 | struct acpi_gpio_chip *acpi_gpio; |
325 | acpi_handle handle; | |
326 | acpi_status status; | |
327 | ||
328 | handle = ACPI_HANDLE(chip->dev); | |
329 | if (!handle) | |
330 | return; | |
331 | ||
332 | status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); | |
333 | if (ACPI_FAILURE(status)) { | |
334 | dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n"); | |
335 | return; | |
336 | } | |
337 | ||
338 | acpi_gpiochip_free_interrupts(acpi_gpio); | |
339 | ||
340 | acpi_detach_data(handle, acpi_gpio_chip_dh); | |
341 | kfree(acpi_gpio); | |
664e3e5a | 342 | } |