]>
Commit | Line | Data |
---|---|---|
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/export.h> | |
14 | #include <linux/fs.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/irq.h> | |
17 | ||
18 | #include <asm/gpio.h> | |
19 | #include <asm/io.h> | |
20 | ||
21 | #include <mach/portmux.h> | |
22 | ||
23 | #include "pio.h" | |
24 | ||
25 | #define MAX_NR_PIO_DEVICES 8 | |
26 | ||
27 | struct pio_device { | |
28 | struct gpio_chip chip; | |
29 | void __iomem *regs; | |
30 | const struct platform_device *pdev; | |
31 | struct clk *clk; | |
32 | u32 pinmux_mask; | |
33 | char name[8]; | |
34 | }; | |
35 | ||
36 | static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; | |
37 | ||
38 | static struct pio_device *gpio_to_pio(unsigned int gpio) | |
39 | { | |
40 | struct pio_device *pio; | |
41 | unsigned int index; | |
42 | ||
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; | |
49 | ||
50 | return pio; | |
51 | } | |
52 | ||
53 | /* Pin multiplexing API */ | |
54 | static DEFINE_SPINLOCK(pio_lock); | |
55 | ||
56 | void __init at32_select_periph(unsigned int port, u32 pin_mask, | |
57 | unsigned int periph, unsigned long flags) | |
58 | { | |
59 | struct pio_device *pio; | |
60 | ||
61 | /* assign and verify pio */ | |
62 | pio = gpio_to_pio(port); | |
63 | if (unlikely(!pio)) { | |
64 | printk(KERN_WARNING "pio: invalid port %u\n", port); | |
65 | goto fail; | |
66 | } | |
67 | ||
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); | |
74 | goto fail; | |
75 | } | |
76 | ||
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 */ | |
83 | if (periph) | |
84 | pio_writel(pio, BSR, pin_mask); | |
85 | else | |
86 | pio_writel(pio, ASR, pin_mask); | |
87 | ||
88 | /* enable peripheral control */ | |
89 | pio_writel(pio, PDR, pin_mask); | |
90 | ||
91 | /* Disable pull ups if not requested. */ | |
92 | if (!(flags & AT32_GPIOF_PULLUP)) | |
93 | pio_writel(pio, PUDR, pin_mask); | |
94 | ||
95 | spin_unlock(&pio_lock); | |
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 | ||
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); | |
125 | if (flags & AT32_GPIOF_MULTIDRV) | |
126 | pio_writel(pio, MDER, mask); | |
127 | else | |
128 | pio_writel(pio, MDDR, mask); | |
129 | pio_writel(pio, PUDR, mask); | |
130 | pio_writel(pio, OER, mask); | |
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); | |
140 | pio_writel(pio, ODR, mask); | |
141 | } | |
142 | ||
143 | pio_writel(pio, PER, mask); | |
144 | ||
145 | return; | |
146 | ||
147 | fail: | |
148 | dump_stack(); | |
149 | } | |
150 | ||
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 | ||
170 | /* Reserve a pin, preventing anyone else from changing its configuration. */ | |
171 | void __init at32_reserve_pin(unsigned int port, u32 pin_mask) | |
172 | { | |
173 | struct pio_device *pio; | |
174 | ||
175 | /* assign and verify pio */ | |
176 | pio = gpio_to_pio(port); | |
177 | if (unlikely(!pio)) { | |
178 | printk(KERN_WARNING "pio: invalid port %u\n", port); | |
179 | goto fail; | |
180 | } | |
181 | ||
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); | |
188 | goto fail; | |
189 | } | |
190 | ||
191 | /* Reserve pins */ | |
192 | pio->pinmux_mask |= pin_mask; | |
193 | spin_unlock(&pio_lock); | |
194 | return; | |
195 | ||
196 | fail: | |
197 | dump_stack(); | |
198 | } | |
199 | ||
200 | /*--------------------------------------------------------------------------*/ | |
201 | ||
202 | /* GPIO API */ | |
203 | ||
204 | static int direction_input(struct gpio_chip *chip, unsigned offset) | |
205 | { | |
206 | struct pio_device *pio = container_of(chip, struct pio_device, chip); | |
207 | u32 mask = 1 << offset; | |
208 | ||
209 | if (!(pio_readl(pio, PSR) & mask)) | |
210 | return -EINVAL; | |
211 | ||
212 | pio_writel(pio, ODR, mask); | |
213 | return 0; | |
214 | } | |
215 | ||
216 | static int gpio_get(struct gpio_chip *chip, unsigned offset) | |
217 | { | |
218 | struct pio_device *pio = container_of(chip, struct pio_device, chip); | |
219 | ||
220 | return (pio_readl(pio, PDSR) >> offset) & 1; | |
221 | } | |
222 | ||
223 | static void gpio_set(struct gpio_chip *chip, unsigned offset, int value); | |
224 | ||
225 | static int direction_output(struct gpio_chip *chip, unsigned offset, int value) | |
226 | { | |
227 | struct pio_device *pio = container_of(chip, struct pio_device, chip); | |
228 | u32 mask = 1 << offset; | |
229 | ||
230 | if (!(pio_readl(pio, PSR) & mask)) | |
231 | return -EINVAL; | |
232 | ||
233 | gpio_set(chip, offset, value); | |
234 | pio_writel(pio, OER, mask); | |
235 | return 0; | |
236 | } | |
237 | ||
238 | static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |
239 | { | |
240 | struct pio_device *pio = container_of(chip, struct pio_device, chip); | |
241 | u32 mask = 1 << offset; | |
242 | ||
243 | if (value) | |
244 | pio_writel(pio, SODR, mask); | |
245 | else | |
246 | pio_writel(pio, CODR, mask); | |
247 | } | |
248 | ||
249 | /*--------------------------------------------------------------------------*/ | |
250 | ||
251 | /* GPIO IRQ support */ | |
252 | ||
253 | static void gpio_irq_mask(struct irq_data *d) | |
254 | { | |
255 | unsigned gpio = irq_to_gpio(d->irq); | |
256 | struct pio_device *pio = &pio_dev[gpio >> 5]; | |
257 | ||
258 | pio_writel(pio, IDR, 1 << (gpio & 0x1f)); | |
259 | } | |
260 | ||
261 | static void gpio_irq_unmask(struct irq_data *d) | |
262 | { | |
263 | unsigned gpio = irq_to_gpio(d->irq); | |
264 | struct pio_device *pio = &pio_dev[gpio >> 5]; | |
265 | ||
266 | pio_writel(pio, IER, 1 << (gpio & 0x1f)); | |
267 | } | |
268 | ||
269 | static int gpio_irq_type(struct irq_data *d, unsigned type) | |
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", | |
279 | .irq_mask = gpio_irq_mask, | |
280 | .irq_unmask = gpio_irq_unmask, | |
281 | .irq_set_type = gpio_irq_type, | |
282 | }; | |
283 | ||
284 | static void gpio_irq_handler(struct irq_desc *desc) | |
285 | { | |
286 | struct pio_device *pio = irq_desc_get_chip_data(desc); | |
287 | unsigned gpio_irq; | |
288 | ||
289 | gpio_irq = (unsigned) irq_desc_get_handler_data(desc); | |
290 | for (;;) { | |
291 | u32 isr; | |
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; | |
304 | generic_handle_irq(i); | |
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 | ||
314 | irq_set_chip_data(irq, pio); | |
315 | ||
316 | for (i = 0; i < 32; i++, gpio_irq++) { | |
317 | irq_set_chip_data(gpio_irq, pio); | |
318 | irq_set_chip_and_handler(gpio_irq, &gpio_irqchip, | |
319 | handle_simple_irq); | |
320 | } | |
321 | ||
322 | irq_set_chained_handler_and_data(irq, gpio_irq_handler, | |
323 | (void *)gpio_irq); | |
324 | } | |
325 | ||
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); | |
358 | if (!label && (imr & mask)) | |
359 | label = "[irq]"; | |
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 | ||
385 | /*--------------------------------------------------------------------------*/ | |
386 | ||
387 | static int __init pio_probe(struct platform_device *pdev) | |
388 | { | |
389 | struct pio_device *pio = NULL; | |
390 | int irq = platform_get_irq(pdev, 0); | |
391 | int gpio_irq_base = GPIO_IRQ_BASE + pdev->id * 32; | |
392 | ||
393 | BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES); | |
394 | pio = &pio_dev[pdev->id]; | |
395 | BUG_ON(!pio->regs); | |
396 | ||
397 | pio->chip.label = pio->name; | |
398 | pio->chip.base = pdev->id * 32; | |
399 | pio->chip.ngpio = 32; | |
400 | pio->chip.parent = &pdev->dev; | |
401 | pio->chip.owner = THIS_MODULE; | |
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 | ||
411 | gpio_irq_setup(pio, irq, gpio_irq_base); | |
412 | ||
413 | platform_set_drvdata(pdev, pio); | |
414 | ||
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); | |
417 | ||
418 | return 0; | |
419 | } | |
420 | ||
421 | static struct platform_driver pio_driver = { | |
422 | .driver = { | |
423 | .name = "pio", | |
424 | }, | |
425 | }; | |
426 | ||
427 | static int __init pio_init(void) | |
428 | { | |
429 | return platform_driver_probe(&pio_driver, pio_probe); | |
430 | } | |
431 | postcore_initcall(pio_init); | |
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; | |
465 | pio->regs = ioremap(regs->start, resource_size(regs)); | |
466 | ||
467 | /* start with irqs disabled and acked */ | |
468 | pio_writel(pio, IDR, ~0UL); | |
469 | (void) pio_readl(pio, ISR); | |
470 | } |