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