summaryrefslogtreecommitdiff
path: root/packages/linux/linux-2.6.18/pio-interrupt-controller.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-2.6.18/pio-interrupt-controller.patch')
-rw-r--r--packages/linux/linux-2.6.18/pio-interrupt-controller.patch108
1 files changed, 108 insertions, 0 deletions
diff --git a/packages/linux/linux-2.6.18/pio-interrupt-controller.patch b/packages/linux/linux-2.6.18/pio-interrupt-controller.patch
new file mode 100644
index 0000000000..b4f15c4931
--- /dev/null
+++ b/packages/linux/linux-2.6.18/pio-interrupt-controller.patch
@@ -0,0 +1,108 @@
+---
+ arch/avr32/mach-at32ap/pio.c | 73 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 72 insertions(+), 1 deletion(-)
+
+Index: linux-2.6.18-avr32/arch/avr32/mach-at32ap/pio.c
+===================================================================
+--- linux-2.6.18-avr32.orig/arch/avr32/mach-at32ap/pio.c 2006-11-29 18:17:15.000000000 +0100
++++ linux-2.6.18-avr32/arch/avr32/mach-at32ap/pio.c 2006-11-30 11:50:27.000000000 +0100
+@@ -11,6 +11,7 @@
+ #include <linux/clk.h>
+ #include <linux/debugfs.h>
+ #include <linux/fs.h>
++#include <linux/irq.h>
+ #include <linux/platform_device.h>
+
+ #include <asm/gpio.h>
+@@ -709,20 +710,90 @@ err_class_create:
+ late_initcall(pio_init_dev);
+ #endif /* CONFIG_PIO_DEV */
+
++/* Interrupt controller implementation */
++static void pio_mask_irq(unsigned int irq)
++{
++ struct pio_device *pio = get_irq_chip_data(irq);
++
++ pio_writel(pio, IDR, 1 << (irq & 0x1f));
++}
++
++static void pio_unmask_irq(unsigned int irq)
++{
++ struct pio_device *pio = get_irq_chip_data(irq);
++
++ pio_writel(pio, IER, 1 << (irq & 0x1f));
++}
++
++static int pio_set_irq_type(unsigned int irq, unsigned int flow_type)
++{
++ if (flow_type != IRQ_TYPE_NONE && flow_type != IRQ_TYPE_EDGE_BOTH)
++ return -EINVAL;
++
++ return 0;
++}
++
++static struct irq_chip pio_irq_chip = {
++ .name = "pio",
++ .mask = pio_mask_irq,
++ .unmask = pio_unmask_irq,
++ .set_type = pio_set_irq_type,
++};
++
++static void demux_pio_irq(unsigned int irq, struct irq_desc *desc,
++ struct pt_regs *regs)
++{
++ struct pio_device *pio = desc->handler_data;
++ struct irq_desc *ext_desc;
++ u32 status, pending;
++ unsigned int ext_irq;
++ unsigned int i;
++
++ status = pio_readl(pio, ISR);
++ pending = status & pio_readl(pio, IMR);
++
++ while (pending) {
++ i = fls(pending) - 1;
++ pending &= ~(1 << i);
++
++ ext_irq = gpio_to_irq(32 * pio_id(pio) + i);
++ ext_desc = irq_desc + ext_irq;
++ ext_desc->handle_irq(ext_irq, ext_desc, regs);
++ }
++}
++
+ static int __init pio_probe(struct platform_device *pdev)
+ {
+ struct pio_device *pio = NULL;
++ unsigned int i;
++ int int_irq, ext_irq;
+
+ BUG_ON(pdev->id >= MAX_NR_PIO_DEVICES);
+ pio = &pio_dev[pdev->id];
+ BUG_ON(!pio->regs);
+
+- /* TODO: Interrupts */
++ /* Set up interrupts */
++ pio_writel(pio, IDR, ~0UL);
++ pio_readl(pio, ISR);
++
++ ext_irq = gpio_to_irq(32 * pdev->id);
++ for (i = 0; i < 32; i++, ext_irq++) {
++ set_irq_chip_and_handler(ext_irq, &pio_irq_chip,
++ handle_simple_irq);
++ set_irq_chip_data(ext_irq, pio);
++ }
++
++ int_irq = platform_get_irq(pdev, 0);
++ set_irq_chained_handler(int_irq, demux_pio_irq);
++ set_irq_data(int_irq, pio);
+
+ platform_set_drvdata(pdev, pio);
+
+ printk(KERN_INFO "%s: Atmel Port Multiplexer at 0x%p (irq %d)\n",
+ pio->name, pio->regs, platform_get_irq(pdev, 0));
++ printk(KERN_INFO
++ "%s: Handling 32 external IRQs, starting with IRQ %d\n",
++ pio->name, ext_irq - 32);
+
+ return 0;
+ }