Commit | Line | Data |
---|---|---|
9569dae7 LB |
1 | /* |
2 | * arch/arm/plat-orion/gpio.c | |
3 | * | |
4 | * Marvell Orion SoC GPIO handling. | |
5 | * | |
6 | * This file is licensed under the terms of the GNU General Public | |
7 | * License version 2. This program is licensed "as is" without any | |
8 | * warranty of any kind, whether express or implied. | |
9 | */ | |
10 | ||
11 | #include <linux/kernel.h> | |
12 | #include <linux/init.h> | |
07332318 | 13 | #include <linux/irq.h> |
9569dae7 LB |
14 | #include <linux/module.h> |
15 | #include <linux/spinlock.h> | |
16 | #include <linux/bitops.h> | |
17 | #include <linux/io.h> | |
a8865655 | 18 | #include <linux/gpio.h> |
9569dae7 | 19 | |
9eac6d0a LB |
20 | /* |
21 | * GPIO unit register offsets. | |
22 | */ | |
23 | #define GPIO_OUT_OFF 0x0000 | |
24 | #define GPIO_IO_CONF_OFF 0x0004 | |
25 | #define GPIO_BLINK_EN_OFF 0x0008 | |
26 | #define GPIO_IN_POL_OFF 0x000c | |
27 | #define GPIO_DATA_IN_OFF 0x0010 | |
28 | #define GPIO_EDGE_CAUSE_OFF 0x0014 | |
29 | #define GPIO_EDGE_MASK_OFF 0x0018 | |
30 | #define GPIO_LEVEL_MASK_OFF 0x001c | |
31 | ||
32 | struct orion_gpio_chip { | |
33 | struct gpio_chip chip; | |
34 | spinlock_t lock; | |
35 | void __iomem *base; | |
36 | unsigned long valid_input; | |
37 | unsigned long valid_output; | |
38 | int mask_offset; | |
39 | int secondary_irq_base; | |
40 | }; | |
41 | ||
42 | static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip) | |
43 | { | |
44 | return ochip->base + GPIO_OUT_OFF; | |
45 | } | |
46 | ||
47 | static void __iomem *GPIO_IO_CONF(struct orion_gpio_chip *ochip) | |
48 | { | |
49 | return ochip->base + GPIO_IO_CONF_OFF; | |
50 | } | |
51 | ||
52 | static void __iomem *GPIO_BLINK_EN(struct orion_gpio_chip *ochip) | |
53 | { | |
54 | return ochip->base + GPIO_BLINK_EN_OFF; | |
55 | } | |
56 | ||
57 | static void __iomem *GPIO_IN_POL(struct orion_gpio_chip *ochip) | |
58 | { | |
59 | return ochip->base + GPIO_IN_POL_OFF; | |
60 | } | |
61 | ||
62 | static void __iomem *GPIO_DATA_IN(struct orion_gpio_chip *ochip) | |
63 | { | |
64 | return ochip->base + GPIO_DATA_IN_OFF; | |
65 | } | |
66 | ||
67 | static void __iomem *GPIO_EDGE_CAUSE(struct orion_gpio_chip *ochip) | |
68 | { | |
69 | return ochip->base + GPIO_EDGE_CAUSE_OFF; | |
70 | } | |
71 | ||
72 | static void __iomem *GPIO_EDGE_MASK(struct orion_gpio_chip *ochip) | |
73 | { | |
74 | return ochip->base + ochip->mask_offset + GPIO_EDGE_MASK_OFF; | |
75 | } | |
76 | ||
77 | static void __iomem *GPIO_LEVEL_MASK(struct orion_gpio_chip *ochip) | |
78 | { | |
79 | return ochip->base + ochip->mask_offset + GPIO_LEVEL_MASK_OFF; | |
80 | } | |
81 | ||
9569dae7 | 82 | |
9eac6d0a LB |
83 | static struct orion_gpio_chip orion_gpio_chips[2]; |
84 | static int orion_gpio_chip_count; | |
85 | ||
86 | static inline void | |
87 | __set_direction(struct orion_gpio_chip *ochip, unsigned pin, int input) | |
9569dae7 LB |
88 | { |
89 | u32 u; | |
90 | ||
9eac6d0a | 91 | u = readl(GPIO_IO_CONF(ochip)); |
9569dae7 | 92 | if (input) |
9eac6d0a | 93 | u |= 1 << pin; |
9569dae7 | 94 | else |
9eac6d0a LB |
95 | u &= ~(1 << pin); |
96 | writel(u, GPIO_IO_CONF(ochip)); | |
9569dae7 LB |
97 | } |
98 | ||
9eac6d0a | 99 | static void __set_level(struct orion_gpio_chip *ochip, unsigned pin, int high) |
9569dae7 LB |
100 | { |
101 | u32 u; | |
102 | ||
9eac6d0a | 103 | u = readl(GPIO_OUT(ochip)); |
9569dae7 | 104 | if (high) |
9eac6d0a | 105 | u |= 1 << pin; |
9569dae7 | 106 | else |
9eac6d0a LB |
107 | u &= ~(1 << pin); |
108 | writel(u, GPIO_OUT(ochip)); | |
9569dae7 LB |
109 | } |
110 | ||
9eac6d0a LB |
111 | static inline void |
112 | __set_blinking(struct orion_gpio_chip *ochip, unsigned pin, int blink) | |
9569dae7 | 113 | { |
a8865655 | 114 | u32 u; |
9569dae7 | 115 | |
9eac6d0a | 116 | u = readl(GPIO_BLINK_EN(ochip)); |
a8865655 | 117 | if (blink) |
9eac6d0a | 118 | u |= 1 << pin; |
a8865655 | 119 | else |
9eac6d0a LB |
120 | u &= ~(1 << pin); |
121 | writel(u, GPIO_BLINK_EN(ochip)); | |
a8865655 | 122 | } |
9569dae7 | 123 | |
9eac6d0a LB |
124 | static inline int |
125 | orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode) | |
a8865655 | 126 | { |
9eac6d0a LB |
127 | if (pin >= ochip->chip.ngpio) |
128 | goto err_out; | |
129 | ||
130 | if ((mode & GPIO_INPUT_OK) && !test_bit(pin, &ochip->valid_input)) | |
131 | goto err_out; | |
132 | ||
133 | if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, &ochip->valid_output)) | |
134 | goto err_out; | |
135 | ||
136 | return 1; | |
9569dae7 | 137 | |
a8865655 EB |
138 | err_out: |
139 | pr_debug("%s: invalid GPIO %d\n", __func__, pin); | |
140 | return false; | |
9569dae7 | 141 | } |
9569dae7 | 142 | |
a8865655 EB |
143 | /* |
144 | * GENERIC_GPIO primitives. | |
145 | */ | |
9eac6d0a LB |
146 | static int orion_gpio_request(struct gpio_chip *chip, unsigned pin) |
147 | { | |
148 | struct orion_gpio_chip *ochip = | |
149 | container_of(chip, struct orion_gpio_chip, chip); | |
150 | ||
151 | if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) || | |
152 | orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK)) | |
153 | return 0; | |
154 | ||
155 | return -EINVAL; | |
156 | } | |
157 | ||
a8865655 | 158 | static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin) |
9569dae7 | 159 | { |
9eac6d0a LB |
160 | struct orion_gpio_chip *ochip = |
161 | container_of(chip, struct orion_gpio_chip, chip); | |
9569dae7 | 162 | unsigned long flags; |
9569dae7 | 163 | |
9eac6d0a | 164 | if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK)) |
9569dae7 | 165 | return -EINVAL; |
9569dae7 | 166 | |
9eac6d0a LB |
167 | spin_lock_irqsave(&ochip->lock, flags); |
168 | __set_direction(ochip, pin, 1); | |
169 | spin_unlock_irqrestore(&ochip->lock, flags); | |
9569dae7 LB |
170 | |
171 | return 0; | |
172 | } | |
9569dae7 | 173 | |
9eac6d0a | 174 | static int orion_gpio_get(struct gpio_chip *chip, unsigned pin) |
9569dae7 | 175 | { |
9eac6d0a LB |
176 | struct orion_gpio_chip *ochip = |
177 | container_of(chip, struct orion_gpio_chip, chip); | |
9569dae7 LB |
178 | int val; |
179 | ||
9eac6d0a LB |
180 | if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) { |
181 | val = readl(GPIO_DATA_IN(ochip)) ^ readl(GPIO_IN_POL(ochip)); | |
182 | } else { | |
183 | val = readl(GPIO_OUT(ochip)); | |
184 | } | |
9569dae7 | 185 | |
9eac6d0a | 186 | return (val >> pin) & 1; |
9569dae7 | 187 | } |
9569dae7 | 188 | |
9eac6d0a LB |
189 | static int |
190 | orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value) | |
9569dae7 | 191 | { |
9eac6d0a LB |
192 | struct orion_gpio_chip *ochip = |
193 | container_of(chip, struct orion_gpio_chip, chip); | |
9569dae7 | 194 | unsigned long flags; |
a8865655 | 195 | |
9eac6d0a | 196 | if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK)) |
a8865655 | 197 | return -EINVAL; |
9569dae7 | 198 | |
9eac6d0a LB |
199 | spin_lock_irqsave(&ochip->lock, flags); |
200 | __set_blinking(ochip, pin, 0); | |
201 | __set_level(ochip, pin, value); | |
202 | __set_direction(ochip, pin, 0); | |
203 | spin_unlock_irqrestore(&ochip->lock, flags); | |
a8865655 EB |
204 | |
205 | return 0; | |
9569dae7 | 206 | } |
9569dae7 | 207 | |
9eac6d0a | 208 | static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value) |
9569dae7 | 209 | { |
9eac6d0a LB |
210 | struct orion_gpio_chip *ochip = |
211 | container_of(chip, struct orion_gpio_chip, chip); | |
9569dae7 | 212 | unsigned long flags; |
9569dae7 | 213 | |
9eac6d0a LB |
214 | spin_lock_irqsave(&ochip->lock, flags); |
215 | __set_level(ochip, pin, value); | |
216 | spin_unlock_irqrestore(&ochip->lock, flags); | |
9569dae7 | 217 | } |
9569dae7 | 218 | |
9eac6d0a | 219 | static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin) |
9569dae7 | 220 | { |
9eac6d0a LB |
221 | struct orion_gpio_chip *ochip = |
222 | container_of(chip, struct orion_gpio_chip, chip); | |
9569dae7 | 223 | |
9eac6d0a | 224 | return ochip->secondary_irq_base + pin; |
a8865655 | 225 | } |
9569dae7 | 226 | |
9eac6d0a | 227 | |
9569dae7 LB |
228 | /* |
229 | * Orion-specific GPIO API extensions. | |
230 | */ | |
9eac6d0a LB |
231 | static struct orion_gpio_chip *orion_gpio_chip_find(int pin) |
232 | { | |
233 | int i; | |
234 | ||
235 | for (i = 0; i < orion_gpio_chip_count; i++) { | |
236 | struct orion_gpio_chip *ochip = orion_gpio_chips + i; | |
237 | struct gpio_chip *chip = &ochip->chip; | |
238 | ||
239 | if (pin >= chip->base && pin < chip->base + chip->ngpio) | |
240 | return ochip; | |
241 | } | |
242 | ||
243 | return NULL; | |
244 | } | |
245 | ||
9569dae7 LB |
246 | void __init orion_gpio_set_unused(unsigned pin) |
247 | { | |
9eac6d0a LB |
248 | struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin); |
249 | ||
250 | if (ochip == NULL) | |
251 | return; | |
252 | ||
253 | pin -= ochip->chip.base; | |
254 | ||
a8865655 | 255 | /* Configure as output, drive low. */ |
9eac6d0a LB |
256 | __set_level(ochip, pin, 0); |
257 | __set_direction(ochip, pin, 0); | |
9569dae7 LB |
258 | } |
259 | ||
28d27cf4 | 260 | void __init orion_gpio_set_valid(unsigned pin, int mode) |
9569dae7 | 261 | { |
9eac6d0a LB |
262 | struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin); |
263 | ||
264 | if (ochip == NULL) | |
265 | return; | |
266 | ||
267 | pin -= ochip->chip.base; | |
268 | ||
28d27cf4 NP |
269 | if (mode == 1) |
270 | mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK; | |
9eac6d0a | 271 | |
28d27cf4 | 272 | if (mode & GPIO_INPUT_OK) |
9eac6d0a | 273 | __set_bit(pin, &ochip->valid_input); |
9569dae7 | 274 | else |
9eac6d0a LB |
275 | __clear_bit(pin, &ochip->valid_input); |
276 | ||
28d27cf4 | 277 | if (mode & GPIO_OUTPUT_OK) |
9eac6d0a | 278 | __set_bit(pin, &ochip->valid_output); |
28d27cf4 | 279 | else |
9eac6d0a | 280 | __clear_bit(pin, &ochip->valid_output); |
9569dae7 LB |
281 | } |
282 | ||
283 | void orion_gpio_set_blink(unsigned pin, int blink) | |
284 | { | |
9eac6d0a | 285 | struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin); |
9569dae7 | 286 | unsigned long flags; |
9569dae7 | 287 | |
9eac6d0a LB |
288 | if (ochip == NULL) |
289 | return; | |
9569dae7 | 290 | |
9eac6d0a LB |
291 | spin_lock_irqsave(&ochip->lock, flags); |
292 | __set_level(ochip, pin, 0); | |
293 | __set_blinking(ochip, pin, blink); | |
294 | spin_unlock_irqrestore(&ochip->lock, flags); | |
9569dae7 LB |
295 | } |
296 | EXPORT_SYMBOL(orion_gpio_set_blink); | |
07332318 LB |
297 | |
298 | ||
299 | /***************************************************************************** | |
300 | * Orion GPIO IRQ | |
301 | * | |
302 | * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same | |
303 | * value of the line or the opposite value. | |
304 | * | |
305 | * Level IRQ handlers: DATA_IN is used directly as cause register. | |
306 | * Interrupt are masked by LEVEL_MASK registers. | |
307 | * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. | |
308 | * Interrupt are masked by EDGE_MASK registers. | |
309 | * Both-edge handlers: Similar to regular Edge handlers, but also swaps | |
310 | * the polarity to catch the next line transaction. | |
311 | * This is a race condition that might not perfectly | |
312 | * work on some use cases. | |
313 | * | |
314 | * Every eight GPIO lines are grouped (OR'ed) before going up to main | |
315 | * cause register. | |
316 | * | |
317 | * EDGE cause mask | |
318 | * data-in /--------| |-----| |----\ | |
319 | * -----| |----- ---- to main cause reg | |
320 | * X \----------------| |----/ | |
321 | * polarity LEVEL mask | |
322 | * | |
323 | ****************************************************************************/ | |
3b0c8d40 | 324 | static void gpio_irq_ack(struct irq_data *d) |
07332318 | 325 | { |
9eac6d0a | 326 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); |
e83bbb11 | 327 | int type = irqd_get_trigger_type(d); |
9eac6d0a | 328 | |
fd4b9b36 | 329 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { |
9eac6d0a LB |
330 | int pin = d->irq - ochip->secondary_irq_base; |
331 | ||
332 | writel(~(1 << pin), GPIO_EDGE_CAUSE(ochip)); | |
fd4b9b36 | 333 | } |
07332318 LB |
334 | } |
335 | ||
3b0c8d40 | 336 | static void gpio_irq_mask(struct irq_data *d) |
07332318 | 337 | { |
9eac6d0a | 338 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); |
e83bbb11 | 339 | int type = irqd_get_trigger_type(d); |
9eac6d0a LB |
340 | void __iomem *reg; |
341 | int pin; | |
342 | ||
9eac6d0a LB |
343 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) |
344 | reg = GPIO_EDGE_MASK(ochip); | |
345 | else | |
346 | reg = GPIO_LEVEL_MASK(ochip); | |
347 | ||
348 | pin = d->irq - ochip->secondary_irq_base; | |
349 | ||
350 | writel(readl(reg) & ~(1 << pin), reg); | |
07332318 LB |
351 | } |
352 | ||
3b0c8d40 | 353 | static void gpio_irq_unmask(struct irq_data *d) |
07332318 | 354 | { |
9eac6d0a | 355 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); |
e83bbb11 | 356 | int type = irqd_get_trigger_type(d); |
9eac6d0a LB |
357 | void __iomem *reg; |
358 | int pin; | |
359 | ||
9eac6d0a LB |
360 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) |
361 | reg = GPIO_EDGE_MASK(ochip); | |
362 | else | |
363 | reg = GPIO_LEVEL_MASK(ochip); | |
364 | ||
365 | pin = d->irq - ochip->secondary_irq_base; | |
366 | ||
367 | writel(readl(reg) | (1 << pin), reg); | |
07332318 LB |
368 | } |
369 | ||
3b0c8d40 | 370 | static int gpio_irq_set_type(struct irq_data *d, u32 type) |
07332318 | 371 | { |
9eac6d0a LB |
372 | struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d); |
373 | int pin; | |
07332318 LB |
374 | u32 u; |
375 | ||
9eac6d0a LB |
376 | pin = d->irq - ochip->secondary_irq_base; |
377 | ||
378 | u = readl(GPIO_IO_CONF(ochip)) & (1 << pin); | |
07332318 LB |
379 | if (!u) { |
380 | printk(KERN_ERR "orion gpio_irq_set_type failed " | |
3b0c8d40 | 381 | "(irq %d, pin %d).\n", d->irq, pin); |
07332318 LB |
382 | return -EINVAL; |
383 | } | |
384 | ||
07332318 LB |
385 | /* |
386 | * Set edge/level type. | |
387 | */ | |
388 | if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { | |
e83bbb11 | 389 | __irq_set_handler_locked(d->irq, handle_edge_irq); |
07332318 | 390 | } else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { |
e83bbb11 | 391 | __irq_set_handler_locked(d->irq, handle_level_irq); |
07332318 | 392 | } else { |
9eac6d0a LB |
393 | printk(KERN_ERR "failed to set irq=%d (type=%d)\n", |
394 | d->irq, type); | |
07332318 LB |
395 | return -EINVAL; |
396 | } | |
397 | ||
398 | /* | |
399 | * Configure interrupt polarity. | |
400 | */ | |
401 | if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) { | |
9eac6d0a LB |
402 | u = readl(GPIO_IN_POL(ochip)); |
403 | u &= ~(1 << pin); | |
404 | writel(u, GPIO_IN_POL(ochip)); | |
07332318 | 405 | } else if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW) { |
9eac6d0a LB |
406 | u = readl(GPIO_IN_POL(ochip)); |
407 | u |= 1 << pin; | |
408 | writel(u, GPIO_IN_POL(ochip)); | |
07332318 LB |
409 | } else if (type == IRQ_TYPE_EDGE_BOTH) { |
410 | u32 v; | |
411 | ||
9eac6d0a | 412 | v = readl(GPIO_IN_POL(ochip)) ^ readl(GPIO_DATA_IN(ochip)); |
07332318 LB |
413 | |
414 | /* | |
415 | * set initial polarity based on current input level | |
416 | */ | |
9eac6d0a LB |
417 | u = readl(GPIO_IN_POL(ochip)); |
418 | if (v & (1 << pin)) | |
419 | u |= 1 << pin; /* falling */ | |
07332318 | 420 | else |
9eac6d0a LB |
421 | u &= ~(1 << pin); /* rising */ |
422 | writel(u, GPIO_IN_POL(ochip)); | |
07332318 LB |
423 | } |
424 | ||
07332318 LB |
425 | return 0; |
426 | } | |
427 | ||
fd4b9b36 | 428 | struct irq_chip orion_gpio_irq_chip = { |
a8865655 | 429 | .name = "orion_gpio_irq", |
3b0c8d40 LB |
430 | .irq_ack = gpio_irq_ack, |
431 | .irq_mask = gpio_irq_mask, | |
432 | .irq_unmask = gpio_irq_unmask, | |
433 | .irq_set_type = gpio_irq_set_type, | |
07332318 LB |
434 | }; |
435 | ||
9eac6d0a LB |
436 | void __init orion_gpio_init(int gpio_base, int ngpio, |
437 | u32 base, int mask_offset, int secondary_irq_base) | |
438 | { | |
439 | struct orion_gpio_chip *ochip; | |
440 | int i; | |
441 | ||
442 | if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) | |
443 | return; | |
444 | ||
445 | ochip = orion_gpio_chips + orion_gpio_chip_count; | |
446 | ochip->chip.label = "orion_gpio"; | |
447 | ochip->chip.request = orion_gpio_request; | |
448 | ochip->chip.direction_input = orion_gpio_direction_input; | |
449 | ochip->chip.get = orion_gpio_get; | |
450 | ochip->chip.direction_output = orion_gpio_direction_output; | |
451 | ochip->chip.set = orion_gpio_set; | |
452 | ochip->chip.to_irq = orion_gpio_to_irq; | |
453 | ochip->chip.base = gpio_base; | |
454 | ochip->chip.ngpio = ngpio; | |
455 | ochip->chip.can_sleep = 0; | |
456 | spin_lock_init(&ochip->lock); | |
457 | ochip->base = (void __iomem *)base; | |
458 | ochip->valid_input = 0; | |
459 | ochip->valid_output = 0; | |
460 | ochip->mask_offset = mask_offset; | |
461 | ochip->secondary_irq_base = secondary_irq_base; | |
462 | ||
463 | gpiochip_add(&ochip->chip); | |
464 | ||
465 | orion_gpio_chip_count++; | |
466 | ||
467 | /* | |
468 | * Mask and clear GPIO interrupts. | |
469 | */ | |
470 | writel(0, GPIO_EDGE_CAUSE(ochip)); | |
471 | writel(0, GPIO_EDGE_MASK(ochip)); | |
472 | writel(0, GPIO_LEVEL_MASK(ochip)); | |
473 | ||
474 | for (i = 0; i < ngpio; i++) { | |
475 | unsigned int irq = secondary_irq_base + i; | |
476 | ||
f38c02f3 TG |
477 | irq_set_chip_and_handler(irq, &orion_gpio_irq_chip, |
478 | handle_level_irq); | |
6845664a | 479 | irq_set_chip_data(irq, ochip); |
e83bbb11 | 480 | irq_set_status_flags(irq, IRQ_LEVEL); |
9eac6d0a LB |
481 | set_irq_flags(irq, IRQF_VALID); |
482 | } | |
483 | } | |
484 | ||
07332318 LB |
485 | void orion_gpio_irq_handler(int pinoff) |
486 | { | |
9eac6d0a | 487 | struct orion_gpio_chip *ochip; |
e83bbb11 | 488 | u32 cause, type; |
9eac6d0a | 489 | int i; |
07332318 | 490 | |
9eac6d0a LB |
491 | ochip = orion_gpio_chip_find(pinoff); |
492 | if (ochip == NULL) | |
493 | return; | |
07332318 | 494 | |
9eac6d0a LB |
495 | cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip)); |
496 | cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip)); | |
07332318 | 497 | |
9eac6d0a LB |
498 | for (i = 0; i < ochip->chip.ngpio; i++) { |
499 | int irq; | |
9eac6d0a LB |
500 | |
501 | irq = ochip->secondary_irq_base + i; | |
502 | ||
503 | if (!(cause & (1 << i))) | |
07332318 LB |
504 | continue; |
505 | ||
e83bbb11 TG |
506 | type = irqd_get_trigger_type(irq_get_irq_data(irq)); |
507 | if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { | |
07332318 LB |
508 | /* Swap polarity (race with GPIO line) */ |
509 | u32 polarity; | |
510 | ||
9eac6d0a LB |
511 | polarity = readl(GPIO_IN_POL(ochip)); |
512 | polarity ^= 1 << i; | |
513 | writel(polarity, GPIO_IN_POL(ochip)); | |
07332318 | 514 | } |
e83bbb11 | 515 | generic_handle_irq(irq); |
07332318 LB |
516 | } |
517 | } |