]>
Commit | Line | Data |
---|---|---|
1c44f5f1 | 1 | /* |
38f539a6 | 2 | * linux/arch/arm/plat-pxa/gpio.c |
1c44f5f1 PZ |
3 | * |
4 | * Generic PXA GPIO handling | |
5 | * | |
6 | * Author: Nicolas Pitre | |
7 | * Created: Jun 15, 2001 | |
8 | * Copyright: MontaVista Software Inc. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
2f8163ba | 14 | #include <linux/gpio.h> |
1c44f5f1 | 15 | #include <linux/init.h> |
e3630db1 | 16 | #include <linux/irq.h> |
fced80c7 | 17 | #include <linux/io.h> |
2eaa03b5 | 18 | #include <linux/syscore_ops.h> |
4aa78264 | 19 | #include <linux/slab.h> |
1c44f5f1 | 20 | |
f55be1bf | 21 | #include <mach/gpio-pxa.h> |
1c44f5f1 | 22 | |
3b8e285c EM |
23 | int pxa_last_gpio; |
24 | ||
1c44f5f1 PZ |
25 | struct pxa_gpio_chip { |
26 | struct gpio_chip chip; | |
0807da59 EM |
27 | void __iomem *regbase; |
28 | char label[10]; | |
29 | ||
30 | unsigned long irq_mask; | |
31 | unsigned long irq_edge_rise; | |
32 | unsigned long irq_edge_fall; | |
33 | ||
34 | #ifdef CONFIG_PM | |
35 | unsigned long saved_gplr; | |
36 | unsigned long saved_gpdr; | |
37 | unsigned long saved_grer; | |
38 | unsigned long saved_gfer; | |
39 | #endif | |
1c44f5f1 PZ |
40 | }; |
41 | ||
4929f5a8 HZ |
42 | enum { |
43 | PXA25X_GPIO = 0, | |
44 | PXA26X_GPIO, | |
45 | PXA27X_GPIO, | |
46 | PXA3XX_GPIO, | |
47 | PXA93X_GPIO, | |
48 | MMP_GPIO = 0x10, | |
49 | MMP2_GPIO, | |
50 | }; | |
51 | ||
0807da59 EM |
52 | static DEFINE_SPINLOCK(gpio_lock); |
53 | static struct pxa_gpio_chip *pxa_gpio_chips; | |
4929f5a8 | 54 | static int gpio_type; |
0807da59 EM |
55 | |
56 | #define for_each_gpio_chip(i, c) \ | |
57 | for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) | |
58 | ||
59 | static inline void __iomem *gpio_chip_base(struct gpio_chip *c) | |
60 | { | |
61 | return container_of(c, struct pxa_gpio_chip, chip)->regbase; | |
62 | } | |
63 | ||
a065685d | 64 | static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio) |
0807da59 EM |
65 | { |
66 | return &pxa_gpio_chips[gpio_to_bank(gpio)]; | |
67 | } | |
68 | ||
4929f5a8 HZ |
69 | static inline int gpio_is_pxa_type(int type) |
70 | { | |
71 | return (type & MMP_GPIO) == 0; | |
72 | } | |
73 | ||
74 | static inline int gpio_is_mmp_type(int type) | |
75 | { | |
76 | return (type & MMP_GPIO) != 0; | |
77 | } | |
78 | ||
79 | #ifdef CONFIG_ARCH_PXA | |
80 | static inline int __pxa_gpio_to_irq(int gpio) | |
81 | { | |
82 | if (gpio_is_pxa_type(gpio_type)) | |
83 | return PXA_GPIO_TO_IRQ(gpio); | |
84 | return -1; | |
85 | } | |
86 | ||
87 | static inline int __pxa_irq_to_gpio(int irq) | |
88 | { | |
89 | if (gpio_is_pxa_type(gpio_type)) | |
90 | return irq - PXA_GPIO_TO_IRQ(0); | |
91 | return -1; | |
92 | } | |
93 | #else | |
94 | static inline int __pxa_gpio_to_irq(int gpio) { return -1; } | |
95 | static inline int __pxa_irq_to_gpio(int irq) { return -1; } | |
96 | #endif | |
97 | ||
98 | #ifdef CONFIG_ARCH_MMP | |
99 | static inline int __mmp_gpio_to_irq(int gpio) | |
100 | { | |
101 | if (gpio_is_mmp_type(gpio_type)) | |
102 | return MMP_GPIO_TO_IRQ(gpio); | |
103 | return -1; | |
104 | } | |
105 | ||
106 | static inline int __mmp_irq_to_gpio(int irq) | |
107 | { | |
108 | if (gpio_is_mmp_type(gpio_type)) | |
109 | return irq - MMP_GPIO_TO_IRQ(0); | |
110 | return -1; | |
111 | } | |
112 | #else | |
113 | static inline int __mmp_gpio_to_irq(int gpio) { return -1; } | |
114 | static inline int __mmp_irq_to_gpio(int irq) { return -1; } | |
115 | #endif | |
116 | ||
117 | static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | |
118 | { | |
119 | int gpio, ret; | |
120 | ||
121 | gpio = chip->base + offset; | |
122 | ret = __pxa_gpio_to_irq(gpio); | |
123 | if (ret >= 0) | |
124 | return ret; | |
125 | return __mmp_gpio_to_irq(gpio); | |
126 | } | |
127 | ||
128 | int pxa_irq_to_gpio(int irq) | |
129 | { | |
130 | int ret; | |
131 | ||
132 | ret = __pxa_irq_to_gpio(irq); | |
133 | if (ret >= 0) | |
134 | return ret; | |
135 | return __mmp_irq_to_gpio(irq); | |
136 | } | |
137 | ||
1c44f5f1 PZ |
138 | static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) |
139 | { | |
0807da59 EM |
140 | void __iomem *base = gpio_chip_base(chip); |
141 | uint32_t value, mask = 1 << offset; | |
142 | unsigned long flags; | |
143 | ||
144 | spin_lock_irqsave(&gpio_lock, flags); | |
145 | ||
146 | value = __raw_readl(base + GPDR_OFFSET); | |
067455aa EM |
147 | if (__gpio_is_inverted(chip->base + offset)) |
148 | value |= mask; | |
149 | else | |
150 | value &= ~mask; | |
0807da59 | 151 | __raw_writel(value, base + GPDR_OFFSET); |
1c44f5f1 | 152 | |
0807da59 | 153 | spin_unlock_irqrestore(&gpio_lock, flags); |
1c44f5f1 PZ |
154 | return 0; |
155 | } | |
156 | ||
157 | static int pxa_gpio_direction_output(struct gpio_chip *chip, | |
0807da59 | 158 | unsigned offset, int value) |
1c44f5f1 | 159 | { |
0807da59 EM |
160 | void __iomem *base = gpio_chip_base(chip); |
161 | uint32_t tmp, mask = 1 << offset; | |
162 | unsigned long flags; | |
163 | ||
164 | __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); | |
165 | ||
166 | spin_lock_irqsave(&gpio_lock, flags); | |
167 | ||
168 | tmp = __raw_readl(base + GPDR_OFFSET); | |
067455aa EM |
169 | if (__gpio_is_inverted(chip->base + offset)) |
170 | tmp &= ~mask; | |
171 | else | |
172 | tmp |= mask; | |
0807da59 | 173 | __raw_writel(tmp, base + GPDR_OFFSET); |
1c44f5f1 | 174 | |
0807da59 | 175 | spin_unlock_irqrestore(&gpio_lock, flags); |
1c44f5f1 PZ |
176 | return 0; |
177 | } | |
178 | ||
1c44f5f1 PZ |
179 | static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) |
180 | { | |
0807da59 | 181 | return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); |
1c44f5f1 PZ |
182 | } |
183 | ||
1c44f5f1 PZ |
184 | static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
185 | { | |
0807da59 EM |
186 | __raw_writel(1 << offset, gpio_chip_base(chip) + |
187 | (value ? GPSR_OFFSET : GPCR_OFFSET)); | |
1c44f5f1 PZ |
188 | } |
189 | ||
0807da59 | 190 | static int __init pxa_init_gpio_chip(int gpio_end) |
a58fbcd8 | 191 | { |
0807da59 EM |
192 | int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; |
193 | struct pxa_gpio_chip *chips; | |
a58fbcd8 | 194 | |
4aa78264 | 195 | chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL); |
0807da59 EM |
196 | if (chips == NULL) { |
197 | pr_err("%s: failed to allocate GPIO chips\n", __func__); | |
198 | return -ENOMEM; | |
a58fbcd8 | 199 | } |
a58fbcd8 | 200 | |
0807da59 EM |
201 | for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { |
202 | struct gpio_chip *c = &chips[i].chip; | |
e3630db1 | 203 | |
0807da59 | 204 | sprintf(chips[i].label, "gpio-%d", i); |
97b09da4 | 205 | chips[i].regbase = GPIO_BANK(i); |
0807da59 EM |
206 | |
207 | c->base = gpio; | |
208 | c->label = chips[i].label; | |
209 | ||
210 | c->direction_input = pxa_gpio_direction_input; | |
211 | c->direction_output = pxa_gpio_direction_output; | |
212 | c->get = pxa_gpio_get; | |
213 | c->set = pxa_gpio_set; | |
4929f5a8 | 214 | c->to_irq = pxa_gpio_to_irq; |
0807da59 EM |
215 | |
216 | /* number of GPIOs on last bank may be less than 32 */ | |
217 | c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32; | |
218 | gpiochip_add(c); | |
219 | } | |
220 | pxa_gpio_chips = chips; | |
221 | return 0; | |
222 | } | |
e3630db1 | 223 | |
a8f6faeb EM |
224 | /* Update only those GRERx and GFERx edge detection register bits if those |
225 | * bits are set in c->irq_mask | |
226 | */ | |
227 | static inline void update_edge_detect(struct pxa_gpio_chip *c) | |
228 | { | |
229 | uint32_t grer, gfer; | |
230 | ||
231 | grer = __raw_readl(c->regbase + GRER_OFFSET) & ~c->irq_mask; | |
232 | gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~c->irq_mask; | |
233 | grer |= c->irq_edge_rise & c->irq_mask; | |
234 | gfer |= c->irq_edge_fall & c->irq_mask; | |
235 | __raw_writel(grer, c->regbase + GRER_OFFSET); | |
236 | __raw_writel(gfer, c->regbase + GFER_OFFSET); | |
237 | } | |
238 | ||
a3f4c927 | 239 | static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) |
e3630db1 | 240 | { |
0807da59 | 241 | struct pxa_gpio_chip *c; |
4929f5a8 | 242 | int gpio = pxa_irq_to_gpio(d->irq); |
0807da59 | 243 | unsigned long gpdr, mask = GPIO_bit(gpio); |
e3630db1 | 244 | |
a065685d | 245 | c = gpio_to_pxachip(gpio); |
e3630db1 | 246 | |
247 | if (type == IRQ_TYPE_PROBE) { | |
248 | /* Don't mess with enabled GPIOs using preconfigured edges or | |
249 | * GPIOs set to alternate function or to output during probe | |
250 | */ | |
0807da59 | 251 | if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio)) |
e3630db1 | 252 | return 0; |
689c04a3 | 253 | |
254 | if (__gpio_is_occupied(gpio)) | |
e3630db1 | 255 | return 0; |
689c04a3 | 256 | |
e3630db1 | 257 | type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; |
258 | } | |
259 | ||
0807da59 EM |
260 | gpdr = __raw_readl(c->regbase + GPDR_OFFSET); |
261 | ||
067455aa | 262 | if (__gpio_is_inverted(gpio)) |
0807da59 | 263 | __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET); |
067455aa | 264 | else |
0807da59 | 265 | __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET); |
e3630db1 | 266 | |
267 | if (type & IRQ_TYPE_EDGE_RISING) | |
0807da59 | 268 | c->irq_edge_rise |= mask; |
e3630db1 | 269 | else |
0807da59 | 270 | c->irq_edge_rise &= ~mask; |
e3630db1 | 271 | |
272 | if (type & IRQ_TYPE_EDGE_FALLING) | |
0807da59 | 273 | c->irq_edge_fall |= mask; |
e3630db1 | 274 | else |
0807da59 | 275 | c->irq_edge_fall &= ~mask; |
e3630db1 | 276 | |
a8f6faeb | 277 | update_edge_detect(c); |
e3630db1 | 278 | |
a3f4c927 | 279 | pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio, |
e3630db1 | 280 | ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""), |
281 | ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : "")); | |
282 | return 0; | |
283 | } | |
284 | ||
e3630db1 | 285 | static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) |
286 | { | |
0807da59 EM |
287 | struct pxa_gpio_chip *c; |
288 | int loop, gpio, gpio_base, n; | |
289 | unsigned long gedr; | |
e3630db1 | 290 | |
291 | do { | |
e3630db1 | 292 | loop = 0; |
0807da59 EM |
293 | for_each_gpio_chip(gpio, c) { |
294 | gpio_base = c->chip.base; | |
295 | ||
296 | gedr = __raw_readl(c->regbase + GEDR_OFFSET); | |
297 | gedr = gedr & c->irq_mask; | |
298 | __raw_writel(gedr, c->regbase + GEDR_OFFSET); | |
e3630db1 | 299 | |
0807da59 EM |
300 | n = find_first_bit(&gedr, BITS_PER_LONG); |
301 | while (n < BITS_PER_LONG) { | |
302 | loop = 1; | |
e3630db1 | 303 | |
0807da59 EM |
304 | generic_handle_irq(gpio_to_irq(gpio_base + n)); |
305 | n = find_next_bit(&gedr, BITS_PER_LONG, n + 1); | |
306 | } | |
e3630db1 | 307 | } |
308 | } while (loop); | |
309 | } | |
310 | ||
a3f4c927 | 311 | static void pxa_ack_muxed_gpio(struct irq_data *d) |
e3630db1 | 312 | { |
4929f5a8 | 313 | int gpio = pxa_irq_to_gpio(d->irq); |
a065685d | 314 | struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); |
0807da59 EM |
315 | |
316 | __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); | |
e3630db1 | 317 | } |
318 | ||
a3f4c927 | 319 | static void pxa_mask_muxed_gpio(struct irq_data *d) |
e3630db1 | 320 | { |
4929f5a8 | 321 | int gpio = pxa_irq_to_gpio(d->irq); |
a065685d | 322 | struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); |
0807da59 EM |
323 | uint32_t grer, gfer; |
324 | ||
325 | c->irq_mask &= ~GPIO_bit(gpio); | |
326 | ||
327 | grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio); | |
328 | gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio); | |
329 | __raw_writel(grer, c->regbase + GRER_OFFSET); | |
330 | __raw_writel(gfer, c->regbase + GFER_OFFSET); | |
e3630db1 | 331 | } |
332 | ||
a3f4c927 | 333 | static void pxa_unmask_muxed_gpio(struct irq_data *d) |
e3630db1 | 334 | { |
4929f5a8 | 335 | int gpio = pxa_irq_to_gpio(d->irq); |
a065685d | 336 | struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); |
0807da59 EM |
337 | |
338 | c->irq_mask |= GPIO_bit(gpio); | |
a8f6faeb | 339 | update_edge_detect(c); |
e3630db1 | 340 | } |
341 | ||
342 | static struct irq_chip pxa_muxed_gpio_chip = { | |
343 | .name = "GPIO", | |
a3f4c927 LB |
344 | .irq_ack = pxa_ack_muxed_gpio, |
345 | .irq_mask = pxa_mask_muxed_gpio, | |
346 | .irq_unmask = pxa_unmask_muxed_gpio, | |
347 | .irq_set_type = pxa_gpio_irq_type, | |
e3630db1 | 348 | }; |
349 | ||
a58fbcd8 | 350 | void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) |
e3630db1 | 351 | { |
0807da59 EM |
352 | struct pxa_gpio_chip *c; |
353 | int gpio, irq; | |
e3630db1 | 354 | |
a58fbcd8 | 355 | pxa_last_gpio = end; |
e3630db1 | 356 | |
0807da59 EM |
357 | /* Initialize GPIO chips */ |
358 | pxa_init_gpio_chip(end); | |
359 | ||
e3630db1 | 360 | /* clear all GPIO edge detects */ |
0807da59 EM |
361 | for_each_gpio_chip(gpio, c) { |
362 | __raw_writel(0, c->regbase + GFER_OFFSET); | |
363 | __raw_writel(0, c->regbase + GRER_OFFSET); | |
364 | __raw_writel(~0,c->regbase + GEDR_OFFSET); | |
e3630db1 | 365 | } |
366 | ||
87c49e20 HZ |
367 | #ifdef CONFIG_ARCH_PXA |
368 | irq = gpio_to_irq(0); | |
369 | irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, | |
370 | handle_edge_irq); | |
371 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | |
372 | irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler); | |
373 | ||
374 | irq = gpio_to_irq(1); | |
375 | irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, | |
376 | handle_edge_irq); | |
377 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | |
378 | irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler); | |
379 | #endif | |
380 | ||
a58fbcd8 | 381 | for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) { |
f38c02f3 TG |
382 | irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, |
383 | handle_edge_irq); | |
e3630db1 | 384 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
385 | } | |
386 | ||
387 | /* Install handler for GPIO>=2 edge detect interrupts */ | |
6845664a | 388 | irq_set_chained_handler(mux_irq, pxa_gpio_demux_handler); |
a3f4c927 | 389 | pxa_muxed_gpio_chip.irq_set_wake = fn; |
e3630db1 | 390 | } |
663707c1 | 391 | |
392 | #ifdef CONFIG_PM | |
2eaa03b5 | 393 | static int pxa_gpio_suspend(void) |
663707c1 | 394 | { |
0807da59 EM |
395 | struct pxa_gpio_chip *c; |
396 | int gpio; | |
663707c1 | 397 | |
0807da59 EM |
398 | for_each_gpio_chip(gpio, c) { |
399 | c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET); | |
400 | c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET); | |
401 | c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET); | |
402 | c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET); | |
663707c1 | 403 | |
404 | /* Clear GPIO transition detect bits */ | |
0807da59 | 405 | __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET); |
663707c1 | 406 | } |
407 | return 0; | |
408 | } | |
409 | ||
2eaa03b5 | 410 | static void pxa_gpio_resume(void) |
663707c1 | 411 | { |
0807da59 EM |
412 | struct pxa_gpio_chip *c; |
413 | int gpio; | |
663707c1 | 414 | |
0807da59 | 415 | for_each_gpio_chip(gpio, c) { |
663707c1 | 416 | /* restore level with set/clear */ |
0807da59 EM |
417 | __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET); |
418 | __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET); | |
663707c1 | 419 | |
0807da59 EM |
420 | __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET); |
421 | __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); | |
422 | __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); | |
663707c1 | 423 | } |
663707c1 | 424 | } |
425 | #else | |
426 | #define pxa_gpio_suspend NULL | |
427 | #define pxa_gpio_resume NULL | |
428 | #endif | |
429 | ||
2eaa03b5 | 430 | struct syscore_ops pxa_gpio_syscore_ops = { |
663707c1 | 431 | .suspend = pxa_gpio_suspend, |
432 | .resume = pxa_gpio_resume, | |
433 | }; |