diff options
| -rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt | 18 | ||||
| -rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
| -rw-r--r-- | drivers/irqchip/irq-zevio.c | 127 |
3 files changed, 146 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt new file mode 100644 index 000000000000..aee38e7c13e7 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | TI-NSPIRE interrupt controller | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Compatible property value should be "lsi,zevio-intc". | ||
| 5 | |||
| 6 | - reg: Physical base address of the controller and length of memory mapped | ||
| 7 | region. | ||
| 8 | |||
| 9 | - interrupt-controller : Identifies the node as an interrupt controller | ||
| 10 | |||
| 11 | Example: | ||
| 12 | |||
| 13 | interrupt-controller { | ||
| 14 | compatible = "lsi,zevio-intc"; | ||
| 15 | interrupt-controller; | ||
| 16 | reg = <0xDC000000 0x1000>; | ||
| 17 | #interrupt-cells = <1>; | ||
| 18 | }; | ||
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c60b9010b152..292b10645fd8 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
| @@ -20,5 +20,6 @@ obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o | |||
| 20 | obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o | 20 | obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o |
| 21 | obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o | 21 | obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o |
| 22 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o | 22 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o |
| 23 | obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o | ||
| 23 | obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o | 24 | obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o |
| 24 | obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o | 25 | obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o |
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c new file mode 100644 index 000000000000..8ed04c4a43ee --- /dev/null +++ b/drivers/irqchip/irq-zevio.c | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/irqchip/irq-zevio.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> | ||
| 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 | |||
| 12 | #include <linux/io.h> | ||
| 13 | #include <linux/irq.h> | ||
| 14 | #include <linux/of.h> | ||
| 15 | #include <linux/of_address.h> | ||
| 16 | #include <linux/of_irq.h> | ||
| 17 | |||
| 18 | #include <asm/mach/irq.h> | ||
| 19 | #include <asm/exception.h> | ||
| 20 | |||
| 21 | #include "irqchip.h" | ||
| 22 | |||
| 23 | #define IO_STATUS 0x000 | ||
| 24 | #define IO_RAW_STATUS 0x004 | ||
| 25 | #define IO_ENABLE 0x008 | ||
| 26 | #define IO_DISABLE 0x00C | ||
| 27 | #define IO_CURRENT 0x020 | ||
| 28 | #define IO_RESET 0x028 | ||
| 29 | #define IO_MAX_PRIOTY 0x02C | ||
| 30 | |||
| 31 | #define IO_IRQ_BASE 0x000 | ||
| 32 | #define IO_FIQ_BASE 0x100 | ||
| 33 | |||
| 34 | #define IO_INVERT_SEL 0x200 | ||
| 35 | #define IO_STICKY_SEL 0x204 | ||
| 36 | #define IO_PRIORITY_SEL 0x300 | ||
| 37 | |||
| 38 | #define MAX_INTRS 32 | ||
| 39 | #define FIQ_START MAX_INTRS | ||
| 40 | |||
| 41 | static struct irq_domain *zevio_irq_domain; | ||
| 42 | static void __iomem *zevio_irq_io; | ||
| 43 | |||
| 44 | static void zevio_irq_ack(struct irq_data *irqd) | ||
| 45 | { | ||
| 46 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(irqd); | ||
| 47 | struct irq_chip_regs *regs = | ||
| 48 | &container_of(irqd->chip, struct irq_chip_type, chip)->regs; | ||
| 49 | |||
| 50 | readl(gc->reg_base + regs->ack); | ||
| 51 | } | ||
| 52 | |||
| 53 | static asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs) | ||
| 54 | { | ||
| 55 | int irqnr; | ||
| 56 | |||
| 57 | while (readl(zevio_irq_io + IO_STATUS)) { | ||
| 58 | irqnr = readl(zevio_irq_io + IO_CURRENT); | ||
| 59 | irqnr = irq_find_mapping(zevio_irq_domain, irqnr); | ||
| 60 | handle_IRQ(irqnr, regs); | ||
| 61 | }; | ||
| 62 | } | ||
| 63 | |||
| 64 | static void __init zevio_init_irq_base(void __iomem *base) | ||
| 65 | { | ||
| 66 | /* Disable all interrupts */ | ||
| 67 | writel(~0, base + IO_DISABLE); | ||
| 68 | |||
| 69 | /* Accept interrupts of all priorities */ | ||
| 70 | writel(0xF, base + IO_MAX_PRIOTY); | ||
| 71 | |||
| 72 | /* Reset existing interrupts */ | ||
| 73 | readl(base + IO_RESET); | ||
| 74 | } | ||
| 75 | |||
| 76 | static int __init zevio_of_init(struct device_node *node, | ||
| 77 | struct device_node *parent) | ||
| 78 | { | ||
| 79 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
| 80 | struct irq_chip_generic *gc; | ||
| 81 | int ret; | ||
| 82 | |||
| 83 | if (WARN_ON(zevio_irq_io || zevio_irq_domain)) | ||
| 84 | return -EBUSY; | ||
| 85 | |||
| 86 | zevio_irq_io = of_iomap(node, 0); | ||
| 87 | BUG_ON(!zevio_irq_io); | ||
| 88 | |||
| 89 | /* Do not invert interrupt status bits */ | ||
| 90 | writel(~0, zevio_irq_io + IO_INVERT_SEL); | ||
| 91 | |||
| 92 | /* Disable sticky interrupts */ | ||
| 93 | writel(0, zevio_irq_io + IO_STICKY_SEL); | ||
| 94 | |||
| 95 | /* We don't use IRQ priorities. Set each IRQ to highest priority. */ | ||
| 96 | memset_io(zevio_irq_io + IO_PRIORITY_SEL, 0, MAX_INTRS * sizeof(u32)); | ||
| 97 | |||
| 98 | /* Init IRQ and FIQ */ | ||
| 99 | zevio_init_irq_base(zevio_irq_io + IO_IRQ_BASE); | ||
| 100 | zevio_init_irq_base(zevio_irq_io + IO_FIQ_BASE); | ||
| 101 | |||
| 102 | zevio_irq_domain = irq_domain_add_linear(node, MAX_INTRS, | ||
| 103 | &irq_generic_chip_ops, NULL); | ||
| 104 | BUG_ON(!zevio_irq_domain); | ||
| 105 | |||
| 106 | ret = irq_alloc_domain_generic_chips(zevio_irq_domain, MAX_INTRS, 1, | ||
| 107 | "zevio_intc", handle_level_irq, | ||
| 108 | clr, 0, IRQ_GC_INIT_MASK_CACHE); | ||
| 109 | BUG_ON(ret); | ||
| 110 | |||
| 111 | gc = irq_get_domain_generic_chip(zevio_irq_domain, 0); | ||
| 112 | gc->reg_base = zevio_irq_io; | ||
| 113 | gc->chip_types[0].chip.irq_ack = zevio_irq_ack; | ||
| 114 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; | ||
| 115 | gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; | ||
| 116 | gc->chip_types[0].regs.mask = IO_IRQ_BASE + IO_ENABLE; | ||
| 117 | gc->chip_types[0].regs.enable = IO_IRQ_BASE + IO_ENABLE; | ||
| 118 | gc->chip_types[0].regs.disable = IO_IRQ_BASE + IO_DISABLE; | ||
| 119 | gc->chip_types[0].regs.ack = IO_IRQ_BASE + IO_RESET; | ||
| 120 | |||
| 121 | set_handle_irq(zevio_handle_irq); | ||
| 122 | |||
| 123 | pr_info("TI-NSPIRE classic IRQ controller\n"); | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | IRQCHIP_DECLARE(zevio_irq, "lsi,zevio-intc", zevio_of_init); | ||
