]>
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> | |
14 | #include <linux/gpio.h> | |
15 | #include <linux/export.h> | |
16 | #include <linux/acpi_gpio.h> | |
17 | #include <linux/acpi.h> | |
0d1c28a4 | 18 | #include <linux/interrupt.h> |
e29482e8 | 19 | |
7fc7acb9 RW |
20 | struct acpi_gpio_evt_pin { |
21 | struct list_head node; | |
22 | acpi_handle *evt_handle; | |
23 | unsigned int pin; | |
24 | unsigned int irq; | |
25 | }; | |
26 | ||
e29482e8 MN |
27 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) |
28 | { | |
29 | if (!gc->dev) | |
30 | return false; | |
31 | ||
32 | return ACPI_HANDLE(gc->dev) == data; | |
33 | } | |
34 | ||
35 | /** | |
36 | * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API | |
37 | * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") | |
38 | * @pin: ACPI GPIO pin number (0-based, controller-relative) | |
39 | * | |
40 | * Returns GPIO number to use with Linux generic GPIO API, or errno error value | |
41 | */ | |
42 | ||
43 | int acpi_get_gpio(char *path, int pin) | |
44 | { | |
45 | struct gpio_chip *chip; | |
46 | acpi_handle handle; | |
47 | acpi_status status; | |
48 | ||
49 | status = acpi_get_handle(NULL, path, &handle); | |
50 | if (ACPI_FAILURE(status)) | |
51 | return -ENODEV; | |
52 | ||
53 | chip = gpiochip_find(handle, acpi_gpiochip_find); | |
54 | if (!chip) | |
55 | return -ENODEV; | |
56 | ||
57 | if (!gpio_is_valid(chip->base + pin)) | |
58 | return -EINVAL; | |
59 | ||
60 | return chip->base + pin; | |
61 | } | |
62 | EXPORT_SYMBOL_GPL(acpi_get_gpio); | |
0d1c28a4 | 63 | |
0d1c28a4 MN |
64 | static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) |
65 | { | |
66 | acpi_handle handle = data; | |
67 | ||
68 | acpi_evaluate_object(handle, NULL, NULL, NULL); | |
69 | ||
70 | return IRQ_HANDLED; | |
71 | } | |
72 | ||
7fc7acb9 RW |
73 | static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) |
74 | { | |
75 | struct acpi_gpio_evt_pin *evt_pin = data; | |
76 | struct acpi_object_list args; | |
77 | union acpi_object arg; | |
78 | ||
79 | arg.type = ACPI_TYPE_INTEGER; | |
80 | arg.integer.value = evt_pin->pin; | |
81 | args.count = 1; | |
82 | args.pointer = &arg; | |
83 | ||
84 | acpi_evaluate_object(evt_pin->evt_handle, NULL, &args, NULL); | |
85 | ||
86 | return IRQ_HANDLED; | |
87 | } | |
88 | ||
89 | static void acpi_gpio_evt_dh(acpi_handle handle, void *data) | |
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 | |
96 | * @chip: gpio chip | |
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 | */ |
0d1c28a4 MN |
104 | void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) |
105 | { | |
106 | struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; | |
107 | struct acpi_resource *res; | |
7fc7acb9 RW |
108 | acpi_handle handle, evt_handle; |
109 | struct list_head *evt_pins = NULL; | |
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 | ||
122 | status = acpi_get_event_resources(handle, &buf); | |
123 | if (ACPI_FAILURE(status)) | |
124 | return; | |
125 | ||
7fc7acb9 RW |
126 | status = acpi_get_handle(handle, "_EVT", &evt_handle); |
127 | if (ACPI_SUCCESS(status)) { | |
128 | evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL); | |
129 | if (evt_pins) { | |
130 | INIT_LIST_HEAD(evt_pins); | |
131 | status = acpi_attach_data(handle, acpi_gpio_evt_dh, | |
132 | evt_pins); | |
133 | if (ACPI_FAILURE(status)) { | |
134 | kfree(evt_pins); | |
135 | evt_pins = NULL; | |
136 | } | |
137 | } | |
138 | } | |
0d1c28a4 | 139 | |
7fc7acb9 RW |
140 | /* |
141 | * If a GPIO interrupt has an ACPI event handler method, or _EVT is | |
142 | * present, set up an interrupt handler that calls the ACPI event | |
143 | * handler. | |
144 | */ | |
0d1c28a4 MN |
145 | for (res = buf.pointer; |
146 | res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); | |
147 | res = ACPI_NEXT_RESOURCE(res)) { | |
7fc7acb9 RW |
148 | irq_handler_t handler = NULL; |
149 | void *data; | |
0d1c28a4 MN |
150 | |
151 | if (res->type != ACPI_RESOURCE_TYPE_GPIO || | |
152 | res->data.gpio.connection_type != | |
153 | ACPI_RESOURCE_GPIO_TYPE_INT) | |
154 | continue; | |
155 | ||
156 | pin = res->data.gpio.pin_table[0]; | |
157 | if (pin > chip->ngpio) | |
158 | continue; | |
159 | ||
0d1c28a4 MN |
160 | irq = chip->to_irq(chip, pin); |
161 | if (irq < 0) | |
162 | continue; | |
163 | ||
7fc7acb9 RW |
164 | if (pin <= 255) { |
165 | acpi_handle ev_handle; | |
166 | ||
167 | sprintf(ev_name, "_%c%02X", | |
168 | res->data.gpio.triggering ? 'E' : 'L', pin); | |
169 | status = acpi_get_handle(handle, ev_name, &ev_handle); | |
170 | if (ACPI_SUCCESS(status)) { | |
171 | handler = acpi_gpio_irq_handler; | |
172 | data = ev_handle; | |
173 | } | |
174 | } | |
175 | if (!handler && evt_pins) { | |
176 | struct acpi_gpio_evt_pin *evt_pin; | |
177 | ||
178 | evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); | |
179 | if (!evt_pin) | |
180 | continue; | |
181 | ||
182 | list_add_tail(&evt_pin->node, evt_pins); | |
183 | evt_pin->evt_handle = evt_handle; | |
184 | evt_pin->pin = pin; | |
185 | evt_pin->irq = irq; | |
186 | handler = acpi_gpio_irq_handler_evt; | |
187 | data = evt_pin; | |
188 | } | |
189 | if (!handler) | |
190 | continue; | |
191 | ||
0d1c28a4 | 192 | /* Assume BIOS sets the triggering, so no flags */ |
7fc7acb9 RW |
193 | ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, |
194 | 0, "GPIO-signaled-ACPI-event", | |
195 | data); | |
1107ca10 MN |
196 | if (ret) |
197 | dev_err(chip->dev, | |
198 | "Failed to request IRQ %d ACPI event handler\n", | |
199 | irq); | |
0d1c28a4 MN |
200 | } |
201 | } | |
202 | EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); | |
7fc7acb9 | 203 | |
12028d2d MW |
204 | struct acpi_gpio_lookup { |
205 | struct acpi_gpio_info info; | |
206 | int index; | |
207 | int gpio; | |
208 | int n; | |
209 | }; | |
210 | ||
211 | static int acpi_find_gpio(struct acpi_resource *ares, void *data) | |
212 | { | |
213 | struct acpi_gpio_lookup *lookup = data; | |
214 | ||
215 | if (ares->type != ACPI_RESOURCE_TYPE_GPIO) | |
216 | return 1; | |
217 | ||
218 | if (lookup->n++ == lookup->index && lookup->gpio < 0) { | |
219 | const struct acpi_resource_gpio *agpio = &ares->data.gpio; | |
220 | ||
221 | lookup->gpio = acpi_get_gpio(agpio->resource_source.string_ptr, | |
222 | agpio->pin_table[0]); | |
223 | lookup->info.gpioint = | |
224 | agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; | |
225 | } | |
226 | ||
227 | return 1; | |
228 | } | |
229 | ||
230 | /** | |
231 | * acpi_get_gpio_by_index() - get a GPIO number from device resources | |
232 | * @dev: pointer to a device to get GPIO from | |
233 | * @index: index of GpioIo/GpioInt resource (starting from %0) | |
234 | * @info: info pointer to fill in (optional) | |
235 | * | |
236 | * Function goes through ACPI resources for @dev and based on @index looks | |
237 | * up a GpioIo/GpioInt resource, translates it to the Linux GPIO number, | |
238 | * and returns it. @index matches GpioIo/GpioInt resources only so if there | |
239 | * are total %3 GPIO resources, the index goes from %0 to %2. | |
240 | * | |
241 | * If the GPIO cannot be translated or there is an error, negative errno is | |
242 | * returned. | |
243 | * | |
244 | * Note: if the GPIO resource has multiple entries in the pin list, this | |
245 | * function only returns the first. | |
246 | */ | |
247 | int acpi_get_gpio_by_index(struct device *dev, int index, | |
248 | struct acpi_gpio_info *info) | |
249 | { | |
250 | struct acpi_gpio_lookup lookup; | |
251 | struct list_head resource_list; | |
252 | struct acpi_device *adev; | |
253 | acpi_handle handle; | |
254 | int ret; | |
255 | ||
256 | if (!dev) | |
257 | return -EINVAL; | |
258 | ||
259 | handle = ACPI_HANDLE(dev); | |
260 | if (!handle || acpi_bus_get_device(handle, &adev)) | |
261 | return -ENODEV; | |
262 | ||
263 | memset(&lookup, 0, sizeof(lookup)); | |
264 | lookup.index = index; | |
265 | lookup.gpio = -ENODEV; | |
266 | ||
267 | INIT_LIST_HEAD(&resource_list); | |
268 | ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, | |
269 | &lookup); | |
270 | if (ret < 0) | |
271 | return ret; | |
272 | ||
273 | acpi_dev_free_resource_list(&resource_list); | |
274 | ||
275 | if (lookup.gpio >= 0 && info) | |
276 | *info = lookup.info; | |
277 | ||
278 | return lookup.gpio; | |
279 | } | |
280 | EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index); | |
7fc7acb9 RW |
281 | |
282 | /** | |
283 | * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. | |
284 | * @chip: gpio chip | |
285 | * | |
286 | * Free interrupts associated with the _EVT method for the given GPIO chip. | |
287 | * | |
288 | * The remaining ACPI event interrupts associated with the chip are freed | |
289 | * automatically. | |
290 | */ | |
291 | void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) | |
292 | { | |
293 | acpi_handle handle; | |
294 | acpi_status status; | |
295 | struct list_head *evt_pins; | |
296 | struct acpi_gpio_evt_pin *evt_pin, *ep; | |
297 | ||
298 | if (!chip->dev || !chip->to_irq) | |
299 | return; | |
300 | ||
301 | handle = ACPI_HANDLE(chip->dev); | |
302 | if (!handle) | |
303 | return; | |
304 | ||
305 | status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); | |
306 | if (ACPI_FAILURE(status)) | |
307 | return; | |
308 | ||
309 | list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { | |
310 | devm_free_irq(chip->dev, evt_pin->irq, evt_pin); | |
311 | list_del(&evt_pin->node); | |
312 | kfree(evt_pin); | |
313 | } | |
314 | ||
315 | acpi_detach_data(handle, acpi_gpio_evt_dh); | |
316 | kfree(evt_pins); | |
317 | } | |
318 | EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); |