]>
Commit | Line | Data |
---|---|---|
5f97f7f9 HS |
1 | /* |
2 | * Atmel PIO2 Port Multiplexer support | |
3 | * | |
4 | * Copyright (C) 2004-2006 Atmel Corporation | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
10 | ||
11 | #include <linux/clk.h> | |
12 | #include <linux/debugfs.h> | |
09cf6a29 | 13 | #include <linux/export.h> |
5f97f7f9 HS |
14 | #include <linux/fs.h> |
15 | #include <linux/platform_device.h> | |
6a4e5227 | 16 | #include <linux/irq.h> |
5f97f7f9 | 17 | |
6a4e5227 | 18 | #include <asm/gpio.h> |
5f97f7f9 HS |
19 | #include <asm/io.h> |
20 | ||
3663b736 | 21 | #include <mach/portmux.h> |
5f97f7f9 HS |
22 | |
23 | #include "pio.h" | |
24 | ||
25 | #define MAX_NR_PIO_DEVICES 8 | |
26 | ||
27 | struct pio_device { | |
b98348bd | 28 | struct gpio_chip chip; |
5f97f7f9 HS |
29 | void __iomem *regs; |
30 | const struct platform_device *pdev; | |
31 | struct clk *clk; | |
c3e2a79c | 32 | u32 pinmux_mask; |
6a4e5227 | 33 | char name[8]; |
5f97f7f9 HS |
34 | }; |
35 | ||
36 | static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; | |
37 | ||
c3e2a79c | 38 | static struct pio_device *gpio_to_pio(unsigned int gpio) |
5f97f7f9 HS |
39 | { |
40 | struct pio_device *pio; | |
c3e2a79c | 41 | unsigned int index; |
5f97f7f9 | 42 | |
c3e2a79c HS |
43 | index = gpio >> 5; |
44 | if (index >= MAX_NR_PIO_DEVICES) | |
45 | return NULL; | |
46 | pio = &pio_dev[index]; | |
47 | if (!pio->regs) | |
48 | return NULL; | |
5f97f7f9 | 49 | |
c3e2a79c HS |
50 | return pio; |
51 | } | |
52 | ||
53 | /* Pin multiplexing API */ | |
caf18f19 | 54 | static DEFINE_SPINLOCK(pio_lock); |
5f97f7f9 | 55 | |
caf18f19 JM |
56 | void __init at32_select_periph(unsigned int port, u32 pin_mask, |
57 | unsigned int periph, unsigned long flags) | |
c3e2a79c HS |
58 | { |
59 | struct pio_device *pio; | |
c3e2a79c | 60 | |
caf18f19 JM |
61 | /* assign and verify pio */ |
62 | pio = gpio_to_pio(port); | |
c3e2a79c | 63 | if (unlikely(!pio)) { |
caf18f19 | 64 | printk(KERN_WARNING "pio: invalid port %u\n", port); |
c3e2a79c HS |
65 | goto fail; |
66 | } | |
67 | ||
caf18f19 JM |
68 | /* Test if any of the requested pins is already muxed */ |
69 | spin_lock(&pio_lock); | |
70 | if (unlikely(pio->pinmux_mask & pin_mask)) { | |
71 | printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n", | |
72 | pio->name, pin_mask, pio->pinmux_mask & pin_mask); | |
73 | spin_unlock(&pio_lock); | |
c3e2a79c HS |
74 | goto fail; |
75 | } | |
76 | ||
caf18f19 JM |
77 | pio->pinmux_mask |= pin_mask; |
78 | ||
79 | /* enable pull ups */ | |
80 | pio_writel(pio, PUER, pin_mask); | |
81 | ||
82 | /* select either peripheral A or B */ | |
c3e2a79c | 83 | if (periph) |
caf18f19 | 84 | pio_writel(pio, BSR, pin_mask); |
5f97f7f9 | 85 | else |
caf18f19 JM |
86 | pio_writel(pio, ASR, pin_mask); |
87 | ||
88 | /* enable peripheral control */ | |
89 | pio_writel(pio, PDR, pin_mask); | |
c3e2a79c | 90 | |
caf18f19 | 91 | /* Disable pull ups if not requested. */ |
c3e2a79c | 92 | if (!(flags & AT32_GPIOF_PULLUP)) |
caf18f19 JM |
93 | pio_writel(pio, PUDR, pin_mask); |
94 | ||
95 | spin_unlock(&pio_lock); | |
c3e2a79c HS |
96 | |
97 | return; | |
98 | ||
99 | fail: | |
100 | dump_stack(); | |
101 | } | |
102 | ||
103 | void __init at32_select_gpio(unsigned int pin, unsigned long flags) | |
104 | { | |
105 | struct pio_device *pio; | |
106 | unsigned int pin_index = pin & 0x1f; | |
107 | u32 mask = 1 << pin_index; | |
108 | ||
109 | pio = gpio_to_pio(pin); | |
110 | if (unlikely(!pio)) { | |
111 | printk("pio: invalid pin %u\n", pin); | |
112 | goto fail; | |
113 | } | |
114 | ||
115 | if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { | |
116 | printk("%s: pin %u is busy\n", pio->name, pin_index); | |
117 | goto fail; | |
118 | } | |
119 | ||
6a4e5227 HS |
120 | if (flags & AT32_GPIOF_OUTPUT) { |
121 | if (flags & AT32_GPIOF_HIGH) | |
122 | pio_writel(pio, SODR, mask); | |
123 | else | |
124 | pio_writel(pio, CODR, mask); | |
7808fa48 MV |
125 | if (flags & AT32_GPIOF_MULTIDRV) |
126 | pio_writel(pio, MDER, mask); | |
127 | else | |
128 | pio_writel(pio, MDDR, mask); | |
6a4e5227 | 129 | pio_writel(pio, PUDR, mask); |
c3e2a79c | 130 | pio_writel(pio, OER, mask); |
6a4e5227 HS |
131 | } else { |
132 | if (flags & AT32_GPIOF_PULLUP) | |
133 | pio_writel(pio, PUER, mask); | |
134 | else | |
135 | pio_writel(pio, PUDR, mask); | |
136 | if (flags & AT32_GPIOF_DEGLITCH) | |
137 | pio_writel(pio, IFER, mask); | |
138 | else | |
139 | pio_writel(pio, IFDR, mask); | |
c3e2a79c | 140 | pio_writel(pio, ODR, mask); |
6a4e5227 | 141 | } |
c3e2a79c HS |
142 | |
143 | pio_writel(pio, PER, mask); | |
6a4e5227 | 144 | |
c3e2a79c HS |
145 | return; |
146 | ||
147 | fail: | |
148 | dump_stack(); | |
5f97f7f9 HS |
149 | } |
150 | ||
ece2678c HS |
151 | /* |
152 | * Undo a previous pin reservation. Will not affect the hardware | |
153 | * configuration. | |
154 | */ | |
155 | void at32_deselect_pin(unsigned int pin) | |
156 | { | |
157 | struct pio_device *pio; | |
158 | unsigned int pin_index = pin & 0x1f; | |
159 | ||
160 | pio = gpio_to_pio(pin); | |
161 | if (unlikely(!pio)) { | |
162 | printk("pio: invalid pin %u\n", pin); | |
163 | dump_stack(); | |
164 | return; | |
165 | } | |
166 | ||
167 | clear_bit(pin_index, &pio->pinmux_mask); | |
168 | } | |
169 | ||
e7f70b8c | 170 | /* Reserve a pin, preventing anyone else from changing its configuration. */ |
adde42b5 | 171 | void __init at32_reserve_pin(unsigned int port, u32 pin_mask) |
e7f70b8c HS |
172 | { |
173 | struct pio_device *pio; | |
e7f70b8c | 174 | |
adde42b5 AR |
175 | /* assign and verify pio */ |
176 | pio = gpio_to_pio(port); | |
e7f70b8c | 177 | if (unlikely(!pio)) { |
adde42b5 | 178 | printk(KERN_WARNING "pio: invalid port %u\n", port); |
e7f70b8c HS |
179 | goto fail; |
180 | } | |
181 | ||
adde42b5 AR |
182 | /* Test if any of the requested pins is already muxed */ |
183 | spin_lock(&pio_lock); | |
184 | if (unlikely(pio->pinmux_mask & pin_mask)) { | |
185 | printk(KERN_WARNING "%s: pin(s) busy (req. 0x%x, busy 0x%x)\n", | |
186 | pio->name, pin_mask, pio->pinmux_mask & pin_mask); | |
187 | spin_unlock(&pio_lock); | |
e7f70b8c HS |
188 | goto fail; |
189 | } | |
190 | ||
adde42b5 AR |
191 | /* Reserve pins */ |
192 | pio->pinmux_mask |= pin_mask; | |
193 | spin_unlock(&pio_lock); | |
e7f70b8c HS |
194 | return; |
195 | ||
196 | fail: | |
197 | dump_stack(); | |
198 | } | |
6a4e5227 HS |
199 | |
200 | /*--------------------------------------------------------------------------*/ | |
201 | ||
202 | /* GPIO API */ | |
203 | ||
b98348bd | 204 | static int direction_input(struct gpio_chip *chip, unsigned offset) |
6a4e5227 | 205 | { |
b98348bd DB |
206 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
207 | u32 mask = 1 << offset; | |
6a4e5227 | 208 | |
b98348bd DB |
209 | if (!(pio_readl(pio, PSR) & mask)) |
210 | return -EINVAL; | |
6a4e5227 | 211 | |
b98348bd | 212 | pio_writel(pio, ODR, mask); |
6a4e5227 HS |
213 | return 0; |
214 | } | |
6a4e5227 | 215 | |
b98348bd | 216 | static int gpio_get(struct gpio_chip *chip, unsigned offset) |
6a4e5227 | 217 | { |
b98348bd | 218 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
6a4e5227 | 219 | |
b98348bd | 220 | return (pio_readl(pio, PDSR) >> offset) & 1; |
6a4e5227 | 221 | } |
6a4e5227 | 222 | |
b98348bd | 223 | static void gpio_set(struct gpio_chip *chip, unsigned offset, int value); |
6a4e5227 | 224 | |
b98348bd | 225 | static int direction_output(struct gpio_chip *chip, unsigned offset, int value) |
6a4e5227 | 226 | { |
b98348bd DB |
227 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
228 | u32 mask = 1 << offset; | |
6a4e5227 | 229 | |
b98348bd DB |
230 | if (!(pio_readl(pio, PSR) & mask)) |
231 | return -EINVAL; | |
6a4e5227 | 232 | |
b98348bd DB |
233 | gpio_set(chip, offset, value); |
234 | pio_writel(pio, OER, mask); | |
6a4e5227 HS |
235 | return 0; |
236 | } | |
6a4e5227 | 237 | |
b98348bd | 238 | static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
6a4e5227 | 239 | { |
b98348bd DB |
240 | struct pio_device *pio = container_of(chip, struct pio_device, chip); |
241 | u32 mask = 1 << offset; | |
6a4e5227 | 242 | |
6a4e5227 HS |
243 | if (value) |
244 | pio_writel(pio, SODR, mask); | |
245 | else | |
246 | pio_writel(pio, CODR, mask); | |
247 | } | |
6a4e5227 HS |
248 | |
249 | /*--------------------------------------------------------------------------*/ | |
250 | ||
251 | /* GPIO IRQ support */ | |
252 | ||
f2f9c650 | 253 | static void gpio_irq_mask(struct irq_data *d) |
6a4e5227 | 254 | { |
f2f9c650 | 255 | unsigned gpio = irq_to_gpio(d->irq); |
6a4e5227 HS |
256 | struct pio_device *pio = &pio_dev[gpio >> 5]; |
257 | ||
258 | pio_writel(pio, IDR, 1 << (gpio & 0x1f)); | |
259 | } | |
260 | ||
024b3f29 | 261 | static void gpio_irq_unmask(struct irq_data *d) |
6a4e5227 | 262 | { |
f2f9c650 | 263 | unsigned gpio = irq_to_gpio(d->irq); |
6a4e5227 HS |
264 | struct pio_device *pio = &pio_dev[gpio >> 5]; |
265 | ||
266 | pio_writel(pio, IER, 1 << (gpio & 0x1f)); | |
267 | } | |
268 | ||
f2f9c650 | 269 | static int gpio_irq_type(struct irq_data *d, unsigned type) |
6a4e5227 HS |
270 | { |
271 | if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE) | |
272 | return -EINVAL; | |
273 | ||
274 | return 0; | |
275 | } | |
276 | ||
277 | static struct irq_chip gpio_irqchip = { | |
278 | .name = "gpio", | |
f2f9c650 TG |
279 | .irq_mask = gpio_irq_mask, |
280 | .irq_unmask = gpio_irq_unmask, | |
281 | .irq_set_type = gpio_irq_type, | |
6a4e5227 HS |
282 | }; |
283 | ||
bd0b9ac4 | 284 | static void gpio_irq_handler(struct irq_desc *desc) |
6a4e5227 | 285 | { |
dd8ea6af | 286 | struct pio_device *pio = irq_desc_get_chip_data(desc); |
6a4e5227 HS |
287 | unsigned gpio_irq; |
288 | ||
df6e23ae | 289 | gpio_irq = (unsigned) irq_desc_get_handler_data(desc); |
6a4e5227 HS |
290 | for (;;) { |
291 | u32 isr; | |
6a4e5227 HS |
292 | |
293 | /* ack pending GPIO interrupts */ | |
294 | isr = pio_readl(pio, ISR) & pio_readl(pio, IMR); | |
295 | if (!isr) | |
296 | break; | |
297 | do { | |
298 | int i; | |
299 | ||
300 | i = ffs(isr) - 1; | |
301 | isr &= ~(1 << i); | |
302 | ||
303 | i += gpio_irq; | |
f2f9c650 | 304 | generic_handle_irq(i); |
6a4e5227 HS |
305 | } while (isr); |
306 | } | |
307 | } | |
308 | ||
309 | static void __init | |
310 | gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) | |
311 | { | |
312 | unsigned i; | |
313 | ||
d75f1bfd | 314 | irq_set_chip_data(irq, pio); |
6a4e5227 HS |
315 | |
316 | for (i = 0; i < 32; i++, gpio_irq++) { | |
d75f1bfd TG |
317 | irq_set_chip_data(gpio_irq, pio); |
318 | irq_set_chip_and_handler(gpio_irq, &gpio_irqchip, | |
319 | handle_simple_irq); | |
6a4e5227 HS |
320 | } |
321 | ||
4365160d TG |
322 | irq_set_chained_handler_and_data(irq, gpio_irq_handler, |
323 | (void *)gpio_irq); | |
6a4e5227 HS |
324 | } |
325 | ||
b98348bd DB |
326 | /*--------------------------------------------------------------------------*/ |
327 | ||
328 | #ifdef CONFIG_DEBUG_FS | |
329 | ||
330 | #include <linux/seq_file.h> | |
331 | ||
332 | /* | |
333 | * This shows more info than the generic gpio dump code: | |
334 | * pullups, deglitching, open drain drive. | |
335 | */ | |
336 | static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip) | |
337 | { | |
338 | struct pio_device *pio = container_of(chip, struct pio_device, chip); | |
339 | u32 psr, osr, imr, pdsr, pusr, ifsr, mdsr; | |
340 | unsigned i; | |
341 | u32 mask; | |
342 | char bank; | |
343 | ||
344 | psr = pio_readl(pio, PSR); | |
345 | osr = pio_readl(pio, OSR); | |
346 | imr = pio_readl(pio, IMR); | |
347 | pdsr = pio_readl(pio, PDSR); | |
348 | pusr = pio_readl(pio, PUSR); | |
349 | ifsr = pio_readl(pio, IFSR); | |
350 | mdsr = pio_readl(pio, MDSR); | |
351 | ||
352 | bank = 'A' + pio->pdev->id; | |
353 | ||
354 | for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { | |
355 | const char *label; | |
356 | ||
357 | label = gpiochip_is_requested(chip, i); | |
aafafddb DB |
358 | if (!label && (imr & mask)) |
359 | label = "[irq]"; | |
b98348bd DB |
360 | if (!label) |
361 | continue; | |
362 | ||
363 | seq_printf(s, " gpio-%-3d P%c%-2d (%-12s) %s %s %s", | |
364 | chip->base + i, bank, i, | |
365 | label, | |
366 | (osr & mask) ? "out" : "in ", | |
367 | (mask & pdsr) ? "hi" : "lo", | |
368 | (mask & pusr) ? " " : "up"); | |
369 | if (ifsr & mask) | |
370 | seq_printf(s, " deglitch"); | |
371 | if ((osr & mdsr) & mask) | |
372 | seq_printf(s, " open-drain"); | |
373 | if (imr & mask) | |
374 | seq_printf(s, " irq-%d edge-both", | |
375 | gpio_to_irq(chip->base + i)); | |
376 | seq_printf(s, "\n"); | |
377 | } | |
378 | } | |
379 | ||
380 | #else | |
381 | #define pio_bank_show NULL | |
382 | #endif | |
383 | ||
384 | ||
6a4e5227 HS |
385 | /*--------------------------------------------------------------------------*/ |
386 | ||
5f97f7f9 HS |
387 | static int __init pio_probe(struct platform_device *pdev) |
388 | { | |
389 | struct pio_device *pio = NULL; | |
6a4e5227 HS |
390 | int irq = platform_get_irq(pdev, 0); |
391 | int gpio_irq_base = GPIO_IRQ_BASE + pdev->id * 32; | |
5f97f7f9 HS |
392 | |
393 | BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES); | |
394 | pio = &pio_dev[pdev->id]; | |
395 | BUG_ON(!pio->regs); | |
396 | ||
b98348bd DB |
397 | pio->chip.label = pio->name; |
398 | pio->chip.base = pdev->id * 32; | |
399 | pio->chip.ngpio = 32; | |
d8f388d8 DB |
400 | pio->chip.dev = &pdev->dev; |
401 | pio->chip.owner = THIS_MODULE; | |
b98348bd DB |
402 | |
403 | pio->chip.direction_input = direction_input; | |
404 | pio->chip.get = gpio_get; | |
405 | pio->chip.direction_output = direction_output; | |
406 | pio->chip.set = gpio_set; | |
407 | pio->chip.dbg_show = pio_bank_show; | |
408 | ||
409 | gpiochip_add(&pio->chip); | |
410 | ||
6a4e5227 | 411 | gpio_irq_setup(pio, irq, gpio_irq_base); |
5f97f7f9 HS |
412 | |
413 | platform_set_drvdata(pdev, pio); | |
414 | ||
6a4e5227 HS |
415 | printk(KERN_DEBUG "%s: base 0x%p, irq %d chains %d..%d\n", |
416 | pio->name, pio->regs, irq, gpio_irq_base, gpio_irq_base + 31); | |
5f97f7f9 HS |
417 | |
418 | return 0; | |
419 | } | |
420 | ||
421 | static struct platform_driver pio_driver = { | |
5f97f7f9 HS |
422 | .driver = { |
423 | .name = "pio", | |
424 | }, | |
425 | }; | |
426 | ||
427 | static int __init pio_init(void) | |
428 | { | |
d6634db8 | 429 | return platform_driver_probe(&pio_driver, pio_probe); |
5f97f7f9 | 430 | } |
6a4e5227 | 431 | postcore_initcall(pio_init); |
5f97f7f9 HS |
432 | |
433 | void __init at32_init_pio(struct platform_device *pdev) | |
434 | { | |
435 | struct resource *regs; | |
436 | struct pio_device *pio; | |
437 | ||
438 | if (pdev->id > MAX_NR_PIO_DEVICES) { | |
439 | dev_err(&pdev->dev, "only %d PIO devices supported\n", | |
440 | MAX_NR_PIO_DEVICES); | |
441 | return; | |
442 | } | |
443 | ||
444 | pio = &pio_dev[pdev->id]; | |
445 | snprintf(pio->name, sizeof(pio->name), "pio%d", pdev->id); | |
446 | ||
447 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
448 | if (!regs) { | |
449 | dev_err(&pdev->dev, "no mmio resource defined\n"); | |
450 | return; | |
451 | } | |
452 | ||
453 | pio->clk = clk_get(&pdev->dev, "mck"); | |
454 | if (IS_ERR(pio->clk)) | |
455 | /* | |
456 | * This is a fatal error, but if we continue we might | |
457 | * be so lucky that we manage to initialize the | |
458 | * console and display this message... | |
459 | */ | |
460 | dev_err(&pdev->dev, "no mck clock defined\n"); | |
461 | else | |
462 | clk_enable(pio->clk); | |
463 | ||
464 | pio->pdev = pdev; | |
28f65c11 | 465 | pio->regs = ioremap(regs->start, resource_size(regs)); |
5f97f7f9 | 466 | |
6a4e5227 HS |
467 | /* start with irqs disabled and acked */ |
468 | pio_writel(pio, IDR, ~0UL); | |
469 | (void) pio_readl(pio, ISR); | |
5f97f7f9 | 470 | } |