diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/pio.c')
-rw-r--r-- | arch/avr32/mach-at32ap/pio.c | 255 |
1 files changed, 239 insertions, 16 deletions
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index f1280ed8ed6d..9ba5654cde11 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c | |||
@@ -12,7 +12,9 @@ | |||
12 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/irq.h> | ||
15 | 16 | ||
17 | #include <asm/gpio.h> | ||
16 | #include <asm/io.h> | 18 | #include <asm/io.h> |
17 | 19 | ||
18 | #include <asm/arch/portmux.h> | 20 | #include <asm/arch/portmux.h> |
@@ -26,7 +28,8 @@ struct pio_device { | |||
26 | const struct platform_device *pdev; | 28 | const struct platform_device *pdev; |
27 | struct clk *clk; | 29 | struct clk *clk; |
28 | u32 pinmux_mask; | 30 | u32 pinmux_mask; |
29 | char name[32]; | 31 | u32 gpio_mask; |
32 | char name[8]; | ||
30 | }; | 33 | }; |
31 | 34 | ||
32 | static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; | 35 | static struct pio_device pio_dev[MAX_NR_PIO_DEVICES]; |
@@ -76,6 +79,9 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph, | |||
76 | if (!(flags & AT32_GPIOF_PULLUP)) | 79 | if (!(flags & AT32_GPIOF_PULLUP)) |
77 | pio_writel(pio, PUDR, mask); | 80 | pio_writel(pio, PUDR, mask); |
78 | 81 | ||
82 | /* gpio_request NOT allowed */ | ||
83 | set_bit(pin_index, &pio->gpio_mask); | ||
84 | |||
79 | return; | 85 | return; |
80 | 86 | ||
81 | fail: | 87 | fail: |
@@ -99,19 +105,52 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags) | |||
99 | goto fail; | 105 | goto fail; |
100 | } | 106 | } |
101 | 107 | ||
102 | pio_writel(pio, PUER, mask); | 108 | if (flags & AT32_GPIOF_OUTPUT) { |
103 | if (flags & AT32_GPIOF_HIGH) | 109 | if (flags & AT32_GPIOF_HIGH) |
104 | pio_writel(pio, SODR, mask); | 110 | pio_writel(pio, SODR, mask); |
105 | else | 111 | else |
106 | pio_writel(pio, CODR, mask); | 112 | pio_writel(pio, CODR, mask); |
107 | if (flags & AT32_GPIOF_OUTPUT) | 113 | pio_writel(pio, PUDR, mask); |
108 | pio_writel(pio, OER, mask); | 114 | pio_writel(pio, OER, mask); |
109 | else | 115 | } else { |
116 | if (flags & AT32_GPIOF_PULLUP) | ||
117 | pio_writel(pio, PUER, mask); | ||
118 | else | ||
119 | pio_writel(pio, PUDR, mask); | ||
120 | if (flags & AT32_GPIOF_DEGLITCH) | ||
121 | pio_writel(pio, IFER, mask); | ||
122 | else | ||
123 | pio_writel(pio, IFDR, mask); | ||
110 | pio_writel(pio, ODR, mask); | 124 | pio_writel(pio, ODR, mask); |
125 | } | ||
111 | 126 | ||
112 | pio_writel(pio, PER, mask); | 127 | pio_writel(pio, PER, mask); |
113 | if (!(flags & AT32_GPIOF_PULLUP)) | 128 | |
114 | pio_writel(pio, PUDR, mask); | 129 | /* gpio_request now allowed */ |
130 | clear_bit(pin_index, &pio->gpio_mask); | ||
131 | |||
132 | return; | ||
133 | |||
134 | fail: | ||
135 | dump_stack(); | ||
136 | } | ||
137 | |||
138 | /* Reserve a pin, preventing anyone else from changing its configuration. */ | ||
139 | void __init at32_reserve_pin(unsigned int pin) | ||
140 | { | ||
141 | struct pio_device *pio; | ||
142 | unsigned int pin_index = pin & 0x1f; | ||
143 | |||
144 | pio = gpio_to_pio(pin); | ||
145 | if (unlikely(!pio)) { | ||
146 | printk("pio: invalid pin %u\n", pin); | ||
147 | goto fail; | ||
148 | } | ||
149 | |||
150 | if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { | ||
151 | printk("%s: pin %u is busy\n", pio->name, pin_index); | ||
152 | goto fail; | ||
153 | } | ||
115 | 154 | ||
116 | return; | 155 | return; |
117 | 156 | ||
@@ -119,20 +158,197 @@ fail: | |||
119 | dump_stack(); | 158 | dump_stack(); |
120 | } | 159 | } |
121 | 160 | ||
161 | /*--------------------------------------------------------------------------*/ | ||
162 | |||
163 | /* GPIO API */ | ||
164 | |||
165 | int gpio_request(unsigned int gpio, const char *label) | ||
166 | { | ||
167 | struct pio_device *pio; | ||
168 | unsigned int pin; | ||
169 | |||
170 | pio = gpio_to_pio(gpio); | ||
171 | if (!pio) | ||
172 | return -ENODEV; | ||
173 | |||
174 | pin = gpio & 0x1f; | ||
175 | if (test_and_set_bit(pin, &pio->gpio_mask)) | ||
176 | return -EBUSY; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | EXPORT_SYMBOL(gpio_request); | ||
181 | |||
182 | void gpio_free(unsigned int gpio) | ||
183 | { | ||
184 | struct pio_device *pio; | ||
185 | unsigned int pin; | ||
186 | |||
187 | pio = gpio_to_pio(gpio); | ||
188 | if (!pio) { | ||
189 | printk(KERN_ERR | ||
190 | "gpio: attempted to free invalid pin %u\n", gpio); | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | pin = gpio & 0x1f; | ||
195 | if (!test_and_clear_bit(pin, &pio->gpio_mask)) | ||
196 | printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n", | ||
197 | pio->name, pin); | ||
198 | } | ||
199 | EXPORT_SYMBOL(gpio_free); | ||
200 | |||
201 | int gpio_direction_input(unsigned int gpio) | ||
202 | { | ||
203 | struct pio_device *pio; | ||
204 | unsigned int pin; | ||
205 | |||
206 | pio = gpio_to_pio(gpio); | ||
207 | if (!pio) | ||
208 | return -ENODEV; | ||
209 | |||
210 | pin = gpio & 0x1f; | ||
211 | pio_writel(pio, ODR, 1 << pin); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | EXPORT_SYMBOL(gpio_direction_input); | ||
216 | |||
217 | int gpio_direction_output(unsigned int gpio) | ||
218 | { | ||
219 | struct pio_device *pio; | ||
220 | unsigned int pin; | ||
221 | |||
222 | pio = gpio_to_pio(gpio); | ||
223 | if (!pio) | ||
224 | return -ENODEV; | ||
225 | |||
226 | pin = gpio & 0x1f; | ||
227 | pio_writel(pio, OER, 1 << pin); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | EXPORT_SYMBOL(gpio_direction_output); | ||
232 | |||
233 | int gpio_get_value(unsigned int gpio) | ||
234 | { | ||
235 | struct pio_device *pio = &pio_dev[gpio >> 5]; | ||
236 | |||
237 | return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1; | ||
238 | } | ||
239 | EXPORT_SYMBOL(gpio_get_value); | ||
240 | |||
241 | void gpio_set_value(unsigned int gpio, int value) | ||
242 | { | ||
243 | struct pio_device *pio = &pio_dev[gpio >> 5]; | ||
244 | u32 mask; | ||
245 | |||
246 | mask = 1 << (gpio & 0x1f); | ||
247 | if (value) | ||
248 | pio_writel(pio, SODR, mask); | ||
249 | else | ||
250 | pio_writel(pio, CODR, mask); | ||
251 | } | ||
252 | EXPORT_SYMBOL(gpio_set_value); | ||
253 | |||
254 | /*--------------------------------------------------------------------------*/ | ||
255 | |||
256 | /* GPIO IRQ support */ | ||
257 | |||
258 | static void gpio_irq_mask(unsigned irq) | ||
259 | { | ||
260 | unsigned gpio = irq_to_gpio(irq); | ||
261 | struct pio_device *pio = &pio_dev[gpio >> 5]; | ||
262 | |||
263 | pio_writel(pio, IDR, 1 << (gpio & 0x1f)); | ||
264 | } | ||
265 | |||
266 | static void gpio_irq_unmask(unsigned irq) | ||
267 | { | ||
268 | unsigned gpio = irq_to_gpio(irq); | ||
269 | struct pio_device *pio = &pio_dev[gpio >> 5]; | ||
270 | |||
271 | pio_writel(pio, IER, 1 << (gpio & 0x1f)); | ||
272 | } | ||
273 | |||
274 | static int gpio_irq_type(unsigned irq, unsigned type) | ||
275 | { | ||
276 | if (type != IRQ_TYPE_EDGE_BOTH && type != IRQ_TYPE_NONE) | ||
277 | return -EINVAL; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static struct irq_chip gpio_irqchip = { | ||
283 | .name = "gpio", | ||
284 | .mask = gpio_irq_mask, | ||
285 | .unmask = gpio_irq_unmask, | ||
286 | .set_type = gpio_irq_type, | ||
287 | }; | ||
288 | |||
289 | static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) | ||
290 | { | ||
291 | struct pio_device *pio = get_irq_chip_data(irq); | ||
292 | unsigned gpio_irq; | ||
293 | |||
294 | gpio_irq = (unsigned) get_irq_data(irq); | ||
295 | for (;;) { | ||
296 | u32 isr; | ||
297 | struct irq_desc *d; | ||
298 | |||
299 | /* ack pending GPIO interrupts */ | ||
300 | isr = pio_readl(pio, ISR) & pio_readl(pio, IMR); | ||
301 | if (!isr) | ||
302 | break; | ||
303 | do { | ||
304 | int i; | ||
305 | |||
306 | i = ffs(isr) - 1; | ||
307 | isr &= ~(1 << i); | ||
308 | |||
309 | i += gpio_irq; | ||
310 | d = &irq_desc[i]; | ||
311 | |||
312 | d->handle_irq(i, d); | ||
313 | } while (isr); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | static void __init | ||
318 | gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) | ||
319 | { | ||
320 | unsigned i; | ||
321 | |||
322 | set_irq_chip_data(irq, pio); | ||
323 | set_irq_data(irq, (void *) gpio_irq); | ||
324 | |||
325 | for (i = 0; i < 32; i++, gpio_irq++) { | ||
326 | set_irq_chip_data(gpio_irq, pio); | ||
327 | set_irq_chip_and_handler(gpio_irq, &gpio_irqchip, | ||
328 | handle_simple_irq); | ||
329 | } | ||
330 | |||
331 | set_irq_chained_handler(irq, gpio_irq_handler); | ||
332 | } | ||
333 | |||
334 | /*--------------------------------------------------------------------------*/ | ||
335 | |||
122 | static int __init pio_probe(struct platform_device *pdev) | 336 | static int __init pio_probe(struct platform_device *pdev) |
123 | { | 337 | { |
124 | struct pio_device *pio = NULL; | 338 | struct pio_device *pio = NULL; |
339 | int irq = platform_get_irq(pdev, 0); | ||
340 | int gpio_irq_base = GPIO_IRQ_BASE + pdev->id * 32; | ||
125 | 341 | ||
126 | BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES); | 342 | BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES); |
127 | pio = &pio_dev[pdev->id]; | 343 | pio = &pio_dev[pdev->id]; |
128 | BUG_ON(!pio->regs); | 344 | BUG_ON(!pio->regs); |
129 | 345 | ||
130 | /* TODO: Interrupts */ | 346 | gpio_irq_setup(pio, irq, gpio_irq_base); |
131 | 347 | ||
132 | platform_set_drvdata(pdev, pio); | 348 | platform_set_drvdata(pdev, pio); |
133 | 349 | ||
134 | printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n", | 350 | printk(KERN_DEBUG "%s: base 0x%p, irq %d chains %d..%d\n", |
135 | pio->name, pio->regs, platform_get_irq(pdev, 0)); | 351 | pio->name, pio->regs, irq, gpio_irq_base, gpio_irq_base + 31); |
136 | 352 | ||
137 | return 0; | 353 | return 0; |
138 | } | 354 | } |
@@ -148,7 +364,7 @@ static int __init pio_init(void) | |||
148 | { | 364 | { |
149 | return platform_driver_register(&pio_driver); | 365 | return platform_driver_register(&pio_driver); |
150 | } | 366 | } |
151 | subsys_initcall(pio_init); | 367 | postcore_initcall(pio_init); |
152 | 368 | ||
153 | void __init at32_init_pio(struct platform_device *pdev) | 369 | void __init at32_init_pio(struct platform_device *pdev) |
154 | { | 370 | { |
@@ -184,6 +400,13 @@ void __init at32_init_pio(struct platform_device *pdev) | |||
184 | pio->pdev = pdev; | 400 | pio->pdev = pdev; |
185 | pio->regs = ioremap(regs->start, regs->end - regs->start + 1); | 401 | pio->regs = ioremap(regs->start, regs->end - regs->start + 1); |
186 | 402 | ||
187 | pio_writel(pio, ODR, ~0UL); | 403 | /* |
188 | pio_writel(pio, PER, ~0UL); | 404 | * request_gpio() is only valid for pins that have been |
405 | * explicitly configured as GPIO and not previously requested | ||
406 | */ | ||
407 | pio->gpio_mask = ~0UL; | ||
408 | |||
409 | /* start with irqs disabled and acked */ | ||
410 | pio_writel(pio, IDR, ~0UL); | ||
411 | (void) pio_readl(pio, ISR); | ||
189 | } | 412 | } |