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