]>
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 | { | |
6072b9dc | 73 | struct acpi_gpio_event *event = data; |
0d1c28a4 | 74 | |
6072b9dc | 75 | acpi_evaluate_object(event->handle, NULL, NULL, NULL); |
0d1c28a4 MN |
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 | ||
6072b9dc MW |
94 | static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, |
95 | void *context) | |
0d1c28a4 | 96 | { |
6072b9dc | 97 | struct acpi_gpio_chip *acpi_gpio = context; |
aa92b6f6 | 98 | struct gpio_chip *chip = acpi_gpio->chip; |
6072b9dc | 99 | struct acpi_resource_gpio *agpio; |
7fc7acb9 | 100 | acpi_handle handle, evt_handle; |
6072b9dc MW |
101 | struct acpi_gpio_event *event; |
102 | irq_handler_t handler = NULL; | |
103 | struct gpio_desc *desc; | |
104 | unsigned long irqflags; | |
105 | int ret, pin, irq; | |
0d1c28a4 | 106 | |
6072b9dc MW |
107 | if (ares->type != ACPI_RESOURCE_TYPE_GPIO) |
108 | return AE_OK; | |
109 | ||
110 | agpio = &ares->data.gpio; | |
111 | if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) | |
112 | return AE_OK; | |
0d1c28a4 MN |
113 | |
114 | handle = ACPI_HANDLE(chip->dev); | |
6072b9dc MW |
115 | pin = agpio->pin_table[0]; |
116 | ||
117 | if (pin <= 255) { | |
118 | char ev_name[5]; | |
119 | sprintf(ev_name, "_%c%02X", | |
120 | agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L', | |
121 | pin); | |
122 | if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle))) | |
123 | handler = acpi_gpio_irq_handler; | |
124 | } | |
125 | if (!handler) { | |
126 | if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle))) | |
127 | handler = acpi_gpio_irq_handler_evt; | |
128 | } | |
129 | if (!handler) | |
130 | return AE_BAD_PARAMETER; | |
0d1c28a4 | 131 | |
6072b9dc MW |
132 | desc = gpiochip_get_desc(chip, pin); |
133 | if (IS_ERR(desc)) { | |
134 | dev_err(chip->dev, "Failed to get GPIO descriptor\n"); | |
135 | return AE_ERROR; | |
136 | } | |
0d1c28a4 | 137 | |
6072b9dc MW |
138 | ret = gpiochip_request_own_desc(desc, "ACPI:Event"); |
139 | if (ret) { | |
140 | dev_err(chip->dev, "Failed to request GPIO\n"); | |
141 | return AE_ERROR; | |
142 | } | |
0d1c28a4 | 143 | |
6072b9dc | 144 | gpiod_direction_input(desc); |
0d1c28a4 | 145 | |
6072b9dc MW |
146 | ret = gpiod_lock_as_irq(desc); |
147 | if (ret) { | |
148 | dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); | |
149 | goto fail_free_desc; | |
150 | } | |
0d1c28a4 | 151 | |
6072b9dc MW |
152 | irq = gpiod_to_irq(desc); |
153 | if (irq < 0) { | |
154 | dev_err(chip->dev, "Failed to translate GPIO to IRQ\n"); | |
155 | goto fail_unlock_irq; | |
156 | } | |
7fc7acb9 | 157 | |
6072b9dc MW |
158 | irqflags = IRQF_ONESHOT; |
159 | if (agpio->triggering == ACPI_LEVEL_SENSITIVE) { | |
160 | if (agpio->polarity == ACPI_ACTIVE_HIGH) | |
161 | irqflags |= IRQF_TRIGGER_HIGH; | |
162 | else | |
163 | irqflags |= IRQF_TRIGGER_LOW; | |
164 | } else { | |
165 | switch (agpio->polarity) { | |
166 | case ACPI_ACTIVE_HIGH: | |
167 | irqflags |= IRQF_TRIGGER_RISING; | |
168 | break; | |
169 | case ACPI_ACTIVE_LOW: | |
170 | irqflags |= IRQF_TRIGGER_FALLING; | |
171 | break; | |
172 | default: | |
173 | irqflags |= IRQF_TRIGGER_RISING | | |
174 | IRQF_TRIGGER_FALLING; | |
175 | break; | |
7fc7acb9 | 176 | } |
6072b9dc | 177 | } |
aa92b6f6 | 178 | |
6072b9dc MW |
179 | event = kzalloc(sizeof(*event), GFP_KERNEL); |
180 | if (!event) | |
181 | goto fail_unlock_irq; | |
7fc7acb9 | 182 | |
6072b9dc MW |
183 | event->handle = evt_handle; |
184 | event->irq = irq; | |
185 | event->pin = pin; | |
7fc7acb9 | 186 | |
6072b9dc MW |
187 | ret = request_threaded_irq(event->irq, NULL, handler, irqflags, |
188 | "ACPI:Event", event); | |
189 | if (ret) { | |
190 | dev_err(chip->dev, "Failed to setup interrupt handler for %d\n", | |
191 | event->irq); | |
192 | goto fail_free_event; | |
0d1c28a4 | 193 | } |
6072b9dc MW |
194 | |
195 | list_add_tail(&event->node, &acpi_gpio->events); | |
196 | return AE_OK; | |
197 | ||
198 | fail_free_event: | |
199 | kfree(event); | |
200 | fail_unlock_irq: | |
201 | gpiod_unlock_as_irq(desc); | |
202 | fail_free_desc: | |
203 | gpiochip_free_own_desc(desc); | |
204 | ||
205 | return AE_ERROR; | |
0d1c28a4 | 206 | } |
7fc7acb9 | 207 | |
70b53411 | 208 | /** |
6072b9dc | 209 | * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events |
aa92b6f6 | 210 | * @acpi_gpio: ACPI GPIO chip |
70b53411 | 211 | * |
6072b9dc MW |
212 | * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are |
213 | * handled by ACPI event methods which need to be called from the GPIO | |
214 | * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which | |
215 | * gpio pins have acpi event methods and assigns interrupt handlers that calls | |
216 | * the acpi event methods for those pins. | |
217 | */ | |
218 | static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) | |
219 | { | |
220 | struct gpio_chip *chip = acpi_gpio->chip; | |
221 | ||
222 | if (!chip->dev || !chip->to_irq) | |
223 | return; | |
224 | ||
225 | INIT_LIST_HEAD(&acpi_gpio->events); | |
226 | acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI", | |
227 | acpi_gpiochip_request_interrupt, acpi_gpio); | |
228 | } | |
229 | ||
230 | /** | |
231 | * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. | |
232 | * @acpi_gpio: ACPI GPIO chip | |
70b53411 | 233 | * |
6072b9dc MW |
234 | * Free interrupts associated with GPIO ACPI event method for the given |
235 | * GPIO chip. | |
70b53411 | 236 | */ |
aa92b6f6 | 237 | static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) |
70b53411 | 238 | { |
4b01a14b | 239 | struct acpi_gpio_event *event, *ep; |
aa92b6f6 | 240 | struct gpio_chip *chip = acpi_gpio->chip; |
70b53411 MW |
241 | |
242 | if (!chip->dev || !chip->to_irq) | |
243 | return; | |
244 | ||
4b01a14b | 245 | list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { |
6072b9dc MW |
246 | struct gpio_desc *desc; |
247 | ||
248 | free_irq(event->irq, event); | |
249 | desc = gpiochip_get_desc(chip, event->pin); | |
250 | if (WARN_ON(IS_ERR(desc))) | |
251 | continue; | |
252 | gpiod_unlock_as_irq(desc); | |
253 | gpiochip_free_own_desc(desc); | |
4b01a14b MW |
254 | list_del(&event->node); |
255 | kfree(event); | |
70b53411 | 256 | } |
70b53411 | 257 | } |
70b53411 | 258 | |
12028d2d MW |
259 | struct acpi_gpio_lookup { |
260 | struct acpi_gpio_info info; | |
261 | int index; | |
936e15dd | 262 | struct gpio_desc *desc; |
12028d2d MW |
263 | int n; |
264 | }; | |
265 | ||
266 | static int acpi_find_gpio(struct acpi_resource *ares, void *data) | |
267 | { | |
268 | struct acpi_gpio_lookup *lookup = data; | |
269 | ||
270 | if (ares->type != ACPI_RESOURCE_TYPE_GPIO) | |
271 | return 1; | |
272 | ||
936e15dd | 273 | if (lookup->n++ == lookup->index && !lookup->desc) { |
12028d2d MW |
274 | const struct acpi_resource_gpio *agpio = &ares->data.gpio; |
275 | ||
936e15dd MW |
276 | lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, |
277 | agpio->pin_table[0]); | |
12028d2d MW |
278 | lookup->info.gpioint = |
279 | agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; | |
e01f440a MW |
280 | lookup->info.active_low = |
281 | agpio->polarity == ACPI_ACTIVE_LOW; | |
12028d2d MW |
282 | } |
283 | ||
284 | return 1; | |
285 | } | |
286 | ||
287 | /** | |
936e15dd | 288 | * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources |
12028d2d MW |
289 | * @dev: pointer to a device to get GPIO from |
290 | * @index: index of GpioIo/GpioInt resource (starting from %0) | |
291 | * @info: info pointer to fill in (optional) | |
292 | * | |
293 | * Function goes through ACPI resources for @dev and based on @index looks | |
936e15dd | 294 | * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, |
12028d2d MW |
295 | * and returns it. @index matches GpioIo/GpioInt resources only so if there |
296 | * are total %3 GPIO resources, the index goes from %0 to %2. | |
297 | * | |
936e15dd | 298 | * If the GPIO cannot be translated or there is an error an ERR_PTR is |
12028d2d MW |
299 | * returned. |
300 | * | |
301 | * Note: if the GPIO resource has multiple entries in the pin list, this | |
302 | * function only returns the first. | |
303 | */ | |
936e15dd MW |
304 | struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, |
305 | struct acpi_gpio_info *info) | |
12028d2d MW |
306 | { |
307 | struct acpi_gpio_lookup lookup; | |
308 | struct list_head resource_list; | |
309 | struct acpi_device *adev; | |
310 | acpi_handle handle; | |
311 | int ret; | |
312 | ||
313 | if (!dev) | |
936e15dd | 314 | return ERR_PTR(-EINVAL); |
12028d2d MW |
315 | |
316 | handle = ACPI_HANDLE(dev); | |
317 | if (!handle || acpi_bus_get_device(handle, &adev)) | |
936e15dd | 318 | return ERR_PTR(-ENODEV); |
12028d2d MW |
319 | |
320 | memset(&lookup, 0, sizeof(lookup)); | |
321 | lookup.index = index; | |
12028d2d MW |
322 | |
323 | INIT_LIST_HEAD(&resource_list); | |
324 | ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, | |
325 | &lookup); | |
326 | if (ret < 0) | |
936e15dd | 327 | return ERR_PTR(ret); |
12028d2d MW |
328 | |
329 | acpi_dev_free_resource_list(&resource_list); | |
330 | ||
936e15dd | 331 | if (lookup.desc && info) |
12028d2d MW |
332 | *info = lookup.info; |
333 | ||
a00580c2 | 334 | return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); |
12028d2d | 335 | } |
664e3e5a MW |
336 | |
337 | void acpi_gpiochip_add(struct gpio_chip *chip) | |
338 | { | |
aa92b6f6 MW |
339 | struct acpi_gpio_chip *acpi_gpio; |
340 | acpi_handle handle; | |
341 | acpi_status status; | |
342 | ||
343 | handle = ACPI_HANDLE(chip->dev); | |
344 | if (!handle) | |
345 | return; | |
346 | ||
347 | acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL); | |
348 | if (!acpi_gpio) { | |
349 | dev_err(chip->dev, | |
350 | "Failed to allocate memory for ACPI GPIO chip\n"); | |
351 | return; | |
352 | } | |
353 | ||
354 | acpi_gpio->chip = chip; | |
355 | ||
356 | status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); | |
357 | if (ACPI_FAILURE(status)) { | |
358 | dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n"); | |
359 | kfree(acpi_gpio); | |
360 | return; | |
361 | } | |
362 | ||
363 | acpi_gpiochip_request_interrupts(acpi_gpio); | |
664e3e5a MW |
364 | } |
365 | ||
366 | void acpi_gpiochip_remove(struct gpio_chip *chip) | |
367 | { | |
aa92b6f6 MW |
368 | struct acpi_gpio_chip *acpi_gpio; |
369 | acpi_handle handle; | |
370 | acpi_status status; | |
371 | ||
372 | handle = ACPI_HANDLE(chip->dev); | |
373 | if (!handle) | |
374 | return; | |
375 | ||
376 | status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); | |
377 | if (ACPI_FAILURE(status)) { | |
378 | dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n"); | |
379 | return; | |
380 | } | |
381 | ||
382 | acpi_gpiochip_free_interrupts(acpi_gpio); | |
383 | ||
384 | acpi_detach_data(handle, acpi_gpio_chip_dh); | |
385 | kfree(acpi_gpio); | |
664e3e5a | 386 | } |