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 MN |
19 | |
20 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) | |
21 | { | |
22 | if (!gc->dev) | |
23 | return false; | |
24 | ||
25 | return ACPI_HANDLE(gc->dev) == data; | |
26 | } | |
27 | ||
28 | /** | |
29 | * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API | |
30 | * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") | |
31 | * @pin: ACPI GPIO pin number (0-based, controller-relative) | |
32 | * | |
33 | * Returns GPIO number to use with Linux generic GPIO API, or errno error value | |
34 | */ | |
35 | ||
36 | int acpi_get_gpio(char *path, int pin) | |
37 | { | |
38 | struct gpio_chip *chip; | |
39 | acpi_handle handle; | |
40 | acpi_status status; | |
41 | ||
42 | status = acpi_get_handle(NULL, path, &handle); | |
43 | if (ACPI_FAILURE(status)) | |
44 | return -ENODEV; | |
45 | ||
46 | chip = gpiochip_find(handle, acpi_gpiochip_find); | |
47 | if (!chip) | |
48 | return -ENODEV; | |
49 | ||
50 | if (!gpio_is_valid(chip->base + pin)) | |
51 | return -EINVAL; | |
52 | ||
53 | return chip->base + pin; | |
54 | } | |
55 | EXPORT_SYMBOL_GPL(acpi_get_gpio); | |
0d1c28a4 MN |
56 | |
57 | ||
58 | static 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 | ||
80 | void 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; | |
1107ca10 MN |
86 | unsigned int pin; |
87 | int irq, ret; | |
0d1c28a4 MN |
88 | char ev_name[5]; |
89 | ||
90 | if (!chip->dev || !chip->to_irq) | |
91 | return; | |
92 | ||
93 | handle = ACPI_HANDLE(chip->dev); | |
94 | if (!handle) | |
95 | return; | |
96 | ||
97 | status = acpi_get_event_resources(handle, &buf); | |
98 | if (ACPI_FAILURE(status)) | |
99 | return; | |
100 | ||
101 | /* If a gpio interrupt has an acpi event handler method, then | |
102 | * set up an interrupt handler that calls the acpi event handler | |
103 | */ | |
104 | ||
105 | for (res = buf.pointer; | |
106 | res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); | |
107 | res = ACPI_NEXT_RESOURCE(res)) { | |
108 | ||
109 | if (res->type != ACPI_RESOURCE_TYPE_GPIO || | |
110 | res->data.gpio.connection_type != | |
111 | ACPI_RESOURCE_GPIO_TYPE_INT) | |
112 | continue; | |
113 | ||
114 | pin = res->data.gpio.pin_table[0]; | |
115 | if (pin > chip->ngpio) | |
116 | continue; | |
117 | ||
118 | sprintf(ev_name, "_%c%02X", | |
119 | res->data.gpio.triggering ? 'E' : 'L', pin); | |
120 | ||
121 | status = acpi_get_handle(handle, ev_name, &ev_handle); | |
122 | if (ACPI_FAILURE(status)) | |
123 | continue; | |
124 | ||
125 | irq = chip->to_irq(chip, pin); | |
126 | if (irq < 0) | |
127 | continue; | |
128 | ||
129 | /* Assume BIOS sets the triggering, so no flags */ | |
1107ca10 | 130 | ret = devm_request_threaded_irq(chip->dev, irq, NULL, |
0d1c28a4 MN |
131 | acpi_gpio_irq_handler, |
132 | 0, | |
133 | "GPIO-signaled-ACPI-event", | |
134 | ev_handle); | |
1107ca10 MN |
135 | if (ret) |
136 | dev_err(chip->dev, | |
137 | "Failed to request IRQ %d ACPI event handler\n", | |
138 | irq); | |
0d1c28a4 MN |
139 | } |
140 | } | |
141 | EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); |