diff options
Diffstat (limited to 'drivers/gpio/gpiolib-acpi.c')
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 214 |
1 files changed, 129 insertions, 85 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index be09e7526890..092ea4e5c9a8 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c | |||
@@ -70,9 +70,9 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) | |||
70 | 70 | ||
71 | static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) | 71 | static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) |
72 | { | 72 | { |
73 | acpi_handle handle = data; | 73 | struct acpi_gpio_event *event = data; |
74 | 74 | ||
75 | acpi_evaluate_object(handle, NULL, NULL, NULL); | 75 | acpi_evaluate_object(event->handle, NULL, NULL, NULL); |
76 | 76 | ||
77 | return IRQ_HANDLED; | 77 | return IRQ_HANDLED; |
78 | } | 78 | } |
@@ -91,111 +91,148 @@ static void acpi_gpio_chip_dh(acpi_handle handle, void *data) | |||
91 | /* The address of this function is used as a key. */ | 91 | /* The address of this function is used as a key. */ |
92 | } | 92 | } |
93 | 93 | ||
94 | /** | 94 | static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, |
95 | * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events | 95 | void *context) |
96 | * @acpi_gpio: ACPI 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. | ||
103 | */ | ||
104 | static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) | ||
105 | { | 96 | { |
106 | struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; | 97 | struct acpi_gpio_chip *acpi_gpio = context; |
107 | struct gpio_chip *chip = acpi_gpio->chip; | 98 | struct gpio_chip *chip = acpi_gpio->chip; |
108 | struct acpi_resource *res; | 99 | struct acpi_resource_gpio *agpio; |
109 | acpi_handle handle, evt_handle; | 100 | acpi_handle handle, evt_handle; |
110 | acpi_status status; | 101 | struct acpi_gpio_event *event; |
111 | unsigned int pin; | 102 | irq_handler_t handler = NULL; |
112 | int irq, ret; | 103 | struct gpio_desc *desc; |
113 | char ev_name[5]; | 104 | unsigned long irqflags; |
105 | int ret, pin, irq; | ||
114 | 106 | ||
115 | if (!chip->dev || !chip->to_irq) | 107 | if (ares->type != ACPI_RESOURCE_TYPE_GPIO) |
116 | return; | 108 | return AE_OK; |
109 | |||
110 | agpio = &ares->data.gpio; | ||
111 | if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) | ||
112 | return AE_OK; | ||
117 | 113 | ||
118 | handle = ACPI_HANDLE(chip->dev); | 114 | handle = ACPI_HANDLE(chip->dev); |
119 | if (!handle) | 115 | pin = agpio->pin_table[0]; |
120 | return; | 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; | ||
121 | 131 | ||
122 | INIT_LIST_HEAD(&acpi_gpio->events); | 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 | } | ||
123 | 137 | ||
124 | /* | 138 | ret = gpiochip_request_own_desc(desc, "ACPI:Event"); |
125 | * If a GPIO interrupt has an ACPI event handler method, or _EVT is | 139 | if (ret) { |
126 | * present, set up an interrupt handler that calls the ACPI event | 140 | dev_err(chip->dev, "Failed to request GPIO\n"); |
127 | * handler. | 141 | return AE_ERROR; |
128 | */ | 142 | } |
129 | for (res = buf.pointer; | ||
130 | res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); | ||
131 | res = ACPI_NEXT_RESOURCE(res)) { | ||
132 | irq_handler_t handler = NULL; | ||
133 | void *data; | ||
134 | |||
135 | if (res->type != ACPI_RESOURCE_TYPE_GPIO || | ||
136 | res->data.gpio.connection_type != | ||
137 | ACPI_RESOURCE_GPIO_TYPE_INT) | ||
138 | continue; | ||
139 | 143 | ||
140 | pin = res->data.gpio.pin_table[0]; | 144 | gpiod_direction_input(desc); |
141 | if (pin > chip->ngpio) | ||
142 | continue; | ||
143 | 145 | ||
144 | irq = chip->to_irq(chip, pin); | 146 | ret = gpiod_lock_as_irq(desc); |
145 | if (irq < 0) | 147 | if (ret) { |
146 | continue; | 148 | dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); |
149 | goto fail_free_desc; | ||
150 | } | ||
147 | 151 | ||
148 | if (pin <= 255) { | 152 | irq = gpiod_to_irq(desc); |
149 | acpi_handle ev_handle; | 153 | if (irq < 0) { |
154 | dev_err(chip->dev, "Failed to translate GPIO to IRQ\n"); | ||
155 | goto fail_unlock_irq; | ||
156 | } | ||
150 | 157 | ||
151 | sprintf(ev_name, "_%c%02X", | 158 | irqflags = IRQF_ONESHOT; |
152 | res->data.gpio.triggering ? 'E' : 'L', pin); | 159 | if (agpio->triggering == ACPI_LEVEL_SENSITIVE) { |
153 | status = acpi_get_handle(handle, ev_name, &ev_handle); | 160 | if (agpio->polarity == ACPI_ACTIVE_HIGH) |
154 | if (ACPI_SUCCESS(status)) { | 161 | irqflags |= IRQF_TRIGGER_HIGH; |
155 | handler = acpi_gpio_irq_handler; | 162 | else |
156 | data = ev_handle; | 163 | irqflags |= IRQF_TRIGGER_LOW; |
157 | } | 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; | ||
158 | } | 176 | } |
159 | if (!handler) { | 177 | } |
160 | struct acpi_gpio_event *event; | ||
161 | |||
162 | status = acpi_get_handle(handle, "_EVT", &evt_handle); | ||
163 | if (ACPI_FAILURE(status)) | ||
164 | continue | ||
165 | 178 | ||
166 | event = kzalloc(sizeof(*event), GFP_KERNEL); | 179 | event = kzalloc(sizeof(*event), GFP_KERNEL); |
167 | if (!event) | 180 | if (!event) |
168 | continue; | 181 | goto fail_unlock_irq; |
169 | 182 | ||
170 | list_add_tail(&event->node, &acpi_gpio->events); | 183 | event->handle = evt_handle; |
171 | event->handle = evt_handle; | 184 | event->irq = irq; |
172 | event->pin = pin; | 185 | event->pin = pin; |
173 | event->irq = irq; | ||
174 | handler = acpi_gpio_irq_handler_evt; | ||
175 | data = event; | ||
176 | } | ||
177 | if (!handler) | ||
178 | continue; | ||
179 | 186 | ||
180 | /* Assume BIOS sets the triggering, so no flags */ | 187 | ret = request_threaded_irq(event->irq, NULL, handler, irqflags, |
181 | ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, | 188 | "ACPI:Event", event); |
182 | 0, "GPIO-signaled-ACPI-event", | 189 | if (ret) { |
183 | data); | 190 | dev_err(chip->dev, "Failed to setup interrupt handler for %d\n", |
184 | if (ret) | 191 | event->irq); |
185 | dev_err(chip->dev, | 192 | goto fail_free_event; |
186 | "Failed to request IRQ %d ACPI event handler\n", | ||
187 | irq); | ||
188 | } | 193 | } |
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; | ||
189 | } | 206 | } |
190 | 207 | ||
191 | /** | 208 | /** |
192 | * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. | 209 | * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events |
193 | * @acpi_gpio: ACPI GPIO chip | 210 | * @acpi_gpio: ACPI GPIO chip |
194 | * | 211 | * |
195 | * Free interrupts associated with the _EVT method for the given GPIO chip. | 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 | ||
196 | * | 233 | * |
197 | * The remaining ACPI event interrupts associated with the chip are freed | 234 | * Free interrupts associated with GPIO ACPI event method for the given |
198 | * automatically. | 235 | * GPIO chip. |
199 | */ | 236 | */ |
200 | static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) | 237 | static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) |
201 | { | 238 | { |
@@ -206,7 +243,14 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) | |||
206 | return; | 243 | return; |
207 | 244 | ||
208 | list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { | 245 | list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { |
209 | devm_free_irq(chip->dev, event->irq, event); | 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); | ||
210 | list_del(&event->node); | 254 | list_del(&event->node); |
211 | kfree(event); | 255 | kfree(event); |
212 | } | 256 | } |