diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 140 |
1 files changed, 120 insertions, 20 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index a063eb04b6ce..89336c4f82cd 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c | |||
@@ -17,6 +17,13 @@ | |||
17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | 19 | ||
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 | |||
20 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) | 27 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) |
21 | { | 28 | { |
22 | if (!gc->dev) | 29 | if (!gc->dev) |
@@ -54,7 +61,6 @@ int acpi_get_gpio(char *path, int pin) | |||
54 | } | 61 | } |
55 | EXPORT_SYMBOL_GPL(acpi_get_gpio); | 62 | EXPORT_SYMBOL_GPL(acpi_get_gpio); |
56 | 63 | ||
57 | |||
58 | static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) | 64 | static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) |
59 | { | 65 | { |
60 | acpi_handle handle = data; | 66 | acpi_handle handle = data; |
@@ -64,6 +70,27 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) | |||
64 | return IRQ_HANDLED; | 70 | return IRQ_HANDLED; |
65 | } | 71 | } |
66 | 72 | ||
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 | |||
67 | /** | 94 | /** |
68 | * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events | 95 | * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events |
69 | * @chip: gpio chip | 96 | * @chip: gpio chip |
@@ -73,15 +100,13 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) | |||
73 | * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which | 100 | * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which |
74 | * gpio pins have acpi event methods and assigns interrupt handlers that calls | 101 | * gpio pins have acpi event methods and assigns interrupt handlers that calls |
75 | * the acpi event methods for those pins. | 102 | * the acpi event methods for those pins. |
76 | * | ||
77 | * Interrupts are automatically freed on driver detach | ||
78 | */ | 103 | */ |
79 | |||
80 | void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) | 104 | void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) |
81 | { | 105 | { |
82 | struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; | 106 | struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; |
83 | struct acpi_resource *res; | 107 | struct acpi_resource *res; |
84 | acpi_handle handle, ev_handle; | 108 | acpi_handle handle, evt_handle; |
109 | struct list_head *evt_pins = NULL; | ||
85 | acpi_status status; | 110 | acpi_status status; |
86 | unsigned int pin; | 111 | unsigned int pin; |
87 | int irq, ret; | 112 | int irq, ret; |
@@ -98,13 +123,30 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) | |||
98 | if (ACPI_FAILURE(status)) | 123 | if (ACPI_FAILURE(status)) |
99 | return; | 124 | return; |
100 | 125 | ||
101 | /* If a gpio interrupt has an acpi event handler method, then | 126 | status = acpi_get_handle(handle, "_EVT", &evt_handle); |
102 | * set up an interrupt handler that calls the acpi event handler | 127 | if (ACPI_SUCCESS(status)) { |
103 | */ | 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 | } | ||
104 | 139 | ||
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 | */ | ||
105 | for (res = buf.pointer; | 145 | for (res = buf.pointer; |
106 | res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); | 146 | res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); |
107 | res = ACPI_NEXT_RESOURCE(res)) { | 147 | res = ACPI_NEXT_RESOURCE(res)) { |
148 | irq_handler_t handler = NULL; | ||
149 | void *data; | ||
108 | 150 | ||
109 | if (res->type != ACPI_RESOURCE_TYPE_GPIO || | 151 | if (res->type != ACPI_RESOURCE_TYPE_GPIO || |
110 | res->data.gpio.connection_type != | 152 | res->data.gpio.connection_type != |
@@ -115,23 +157,42 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) | |||
115 | if (pin > chip->ngpio) | 157 | if (pin > chip->ngpio) |
116 | continue; | 158 | continue; |
117 | 159 | ||
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); | 160 | irq = chip->to_irq(chip, pin); |
126 | if (irq < 0) | 161 | if (irq < 0) |
127 | continue; | 162 | continue; |
128 | 163 | ||
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 | |||
129 | /* Assume BIOS sets the triggering, so no flags */ | 192 | /* Assume BIOS sets the triggering, so no flags */ |
130 | ret = devm_request_threaded_irq(chip->dev, irq, NULL, | 193 | ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, |
131 | acpi_gpio_irq_handler, | 194 | 0, "GPIO-signaled-ACPI-event", |
132 | 0, | 195 | data); |
133 | "GPIO-signaled-ACPI-event", | ||
134 | ev_handle); | ||
135 | if (ret) | 196 | if (ret) |
136 | dev_err(chip->dev, | 197 | dev_err(chip->dev, |
137 | "Failed to request IRQ %d ACPI event handler\n", | 198 | "Failed to request IRQ %d ACPI event handler\n", |
@@ -139,3 +200,42 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) | |||
139 | } | 200 | } |
140 | } | 201 | } |
141 | EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); | 202 | EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); |
203 | |||
204 | |||
205 | /** | ||
206 | * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. | ||
207 | * @chip: gpio chip | ||
208 | * | ||
209 | * Free interrupts associated with the _EVT method for the given GPIO chip. | ||
210 | * | ||
211 | * The remaining ACPI event interrupts associated with the chip are freed | ||
212 | * automatically. | ||
213 | */ | ||
214 | void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) | ||
215 | { | ||
216 | acpi_handle handle; | ||
217 | acpi_status status; | ||
218 | struct list_head *evt_pins; | ||
219 | struct acpi_gpio_evt_pin *evt_pin, *ep; | ||
220 | |||
221 | if (!chip->dev || !chip->to_irq) | ||
222 | return; | ||
223 | |||
224 | handle = ACPI_HANDLE(chip->dev); | ||
225 | if (!handle) | ||
226 | return; | ||
227 | |||
228 | status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); | ||
229 | if (ACPI_FAILURE(status)) | ||
230 | return; | ||
231 | |||
232 | list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { | ||
233 | devm_free_irq(chip->dev, evt_pin->irq, evt_pin); | ||
234 | list_del(&evt_pin->node); | ||
235 | kfree(evt_pin); | ||
236 | } | ||
237 | |||
238 | acpi_detach_data(handle, acpi_gpio_evt_dh); | ||
239 | kfree(evt_pins); | ||
240 | } | ||
241 | EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); | ||