summaryrefslogtreecommitdiff
path: root/drivers/irqchip
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/Kconfig15
-rw-r--r--drivers/irqchip/Makefile4
-rw-r--r--drivers/irqchip/exynos-combiner.c8
-rw-r--r--drivers/irqchip/irq-gic.c8
-rw-r--r--drivers/irqchip/irq-moxart.c117
-rw-r--r--drivers/irqchip/irq-nvic.c117
-rw-r--r--drivers/irqchip/irq-orion.c192
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c9
-rw-r--r--drivers/irqchip/irq-renesas-irqc.c4
-rw-r--r--drivers/irqchip/irq-sirfsoc.c18
-rw-r--r--drivers/irqchip/irq-sun4i.c2
-rw-r--r--drivers/irqchip/irq-tb10x.c195
-rw-r--r--drivers/irqchip/irq-vt8500.c6
13 files changed, 673 insertions, 22 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4a33351c25dc..1fea003ed33f 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -10,6 +10,11 @@ config ARM_GIC
config GIC_NON_BANKED
bool
+config ARM_NVIC
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config ARM_VIC
bool
select IRQ_DOMAIN
@@ -25,6 +30,11 @@ config ARM_VIC_NR
The maximum number of VICs available in the system, for
power management.
+config ORION_IRQCHIP
+ bool
+ select IRQ_DOMAIN
+ select MULTI_IRQ_HANDLER
+
config RENESAS_INTC_IRQPIN
bool
select IRQ_DOMAIN
@@ -33,6 +43,11 @@ config RENESAS_IRQC
bool
select IRQ_DOMAIN
+config TB10X_IRQC
+ bool
+ select IRQ_DOMAIN
+ select GENERIC_IRQ_CHIP
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cda4cb5f7327..e65c41a7366b 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -7,12 +7,16 @@ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
obj-$(CONFIG_METAG) += irq-metag-ext.o
obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o
+obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o
+obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
+obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index a9d2b2fa4afd..4c6826513901 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -204,10 +204,10 @@ static unsigned int combiner_lookup_irq(int group)
return 0;
}
-void __init combiner_init(void __iomem *combiner_base,
- struct device_node *np,
- unsigned int max_nr,
- int irq_base)
+static void __init combiner_init(void __iomem *combiner_base,
+ struct device_node *np,
+ unsigned int max_nr,
+ int irq_base)
{
int i, irq;
unsigned int nr_irq;
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 19ceaa60e0f4..ee7c50312066 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -414,7 +414,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
writel_relaxed(1, base + GIC_DIST_CTRL);
}
-static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
+static void gic_cpu_init(struct gic_chip_data *gic)
{
void __iomem *dist_base = gic_data_dist_base(gic);
void __iomem *base = gic_data_cpu_base(gic);
@@ -702,8 +702,8 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
}
#ifdef CONFIG_SMP
-static int __cpuinit gic_secondary_init(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static int gic_secondary_init(struct notifier_block *nfb, unsigned long action,
+ void *hcpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
gic_cpu_init(&gic_data[0]);
@@ -714,7 +714,7 @@ static int __cpuinit gic_secondary_init(struct notifier_block *nfb,
* Notifier for enabling the GIC CPU interface. Set an arbitrarily high
* priority because the GIC needs to be up before the ARM generic timers.
*/
-static struct notifier_block __cpuinitdata gic_cpu_notifier = {
+static struct notifier_block gic_cpu_notifier = {
.notifier_call = gic_secondary_init,
.priority = 100,
};
diff --git a/drivers/irqchip/irq-moxart.c b/drivers/irqchip/irq-moxart.c
new file mode 100644
index 000000000000..5552fc2bf28a
--- /dev/null
+++ b/drivers/irqchip/irq-moxart.c
@@ -0,0 +1,117 @@
+/*
+ * MOXA ART SoCs IRQ chip driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define IRQ_SOURCE_REG 0
+#define IRQ_MASK_REG 0x04
+#define IRQ_CLEAR_REG 0x08
+#define IRQ_MODE_REG 0x0c
+#define IRQ_LEVEL_REG 0x10
+#define IRQ_STATUS_REG 0x14
+
+#define FIQ_SOURCE_REG 0x20
+#define FIQ_MASK_REG 0x24
+#define FIQ_CLEAR_REG 0x28
+#define FIQ_MODE_REG 0x2c
+#define FIQ_LEVEL_REG 0x30
+#define FIQ_STATUS_REG 0x34
+
+
+struct moxart_irq_data {
+ void __iomem *base;
+ struct irq_domain *domain;
+ unsigned int interrupt_mask;
+};
+
+static struct moxart_irq_data intc;
+
+static asmlinkage void __exception_irq_entry handle_irq(struct pt_regs *regs)
+{
+ u32 irqstat;
+ int hwirq;
+
+ irqstat = readl(intc.base + IRQ_STATUS_REG);
+
+ while (irqstat) {
+ hwirq = ffs(irqstat) - 1;
+ handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
+ irqstat &= ~(1 << hwirq);
+ }
+}
+
+static int __init moxart_of_intc_init(struct device_node *node,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ int ret;
+ struct irq_chip_generic *gc;
+
+ intc.base = of_iomap(node, 0);
+ if (!intc.base) {
+ pr_err("%s: unable to map IC registers\n",
+ node->full_name);
+ return -EINVAL;
+ }
+
+ intc.domain = irq_domain_add_linear(node, 32, &irq_generic_chip_ops,
+ intc.base);
+ if (!intc.domain) {
+ pr_err("%s: unable to create IRQ domain\n", node->full_name);
+ return -EINVAL;
+ }
+
+ ret = irq_alloc_domain_generic_chips(intc.domain, 32, 1,
+ "MOXARTINTC", handle_edge_irq,
+ clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: could not allocate generic chip\n",
+ node->full_name);
+ irq_domain_remove(intc.domain);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "interrupt-mask",
+ &intc.interrupt_mask);
+ if (ret)
+ pr_err("%s: could not read interrupt-mask DT property\n",
+ node->full_name);
+
+ gc = irq_get_domain_generic_chip(intc.domain, 0);
+
+ gc->reg_base = intc.base;
+ gc->chip_types[0].regs.mask = IRQ_MASK_REG;
+ gc->chip_types[0].regs.ack = IRQ_CLEAR_REG;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ writel(0, intc.base + IRQ_MASK_REG);
+ writel(0xffffffff, intc.base + IRQ_CLEAR_REG);
+
+ writel(intc.interrupt_mask, intc.base + IRQ_MODE_REG);
+ writel(intc.interrupt_mask, intc.base + IRQ_LEVEL_REG);
+
+ set_handle_irq(handle_irq);
+
+ return 0;
+}
+IRQCHIP_DECLARE(moxa_moxart_ic, "moxa,moxart-ic", moxart_of_intc_init);
diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c
new file mode 100644
index 000000000000..70bdf6edb7bb
--- /dev/null
+++ b/drivers/irqchip/irq-nvic.c
@@ -0,0 +1,117 @@
+/*
+ * drivers/irq/irq-nvic.c
+ *
+ * Copyright (C) 2008 ARM Limited, All Rights Reserved.
+ * Copyright (C) 2013 Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Support for the Nested Vectored Interrupt Controller found on the
+ * ARMv7-M CPUs (Cortex-M3/M4)
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+
+#include <asm/v7m.h>
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define NVIC_ISER 0x000
+#define NVIC_ICER 0x080
+#define NVIC_IPR 0x300
+
+#define NVIC_MAX_BANKS 16
+/*
+ * Each bank handles 32 irqs. Only the 16th (= last) bank handles only
+ * 16 irqs.
+ */
+#define NVIC_MAX_IRQ ((NVIC_MAX_BANKS - 1) * 32 + 16)
+
+static struct irq_domain *nvic_irq_domain;
+
+asmlinkage void __exception_irq_entry
+nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs)
+{
+ unsigned int irq = irq_linear_revmap(nvic_irq_domain, hwirq);
+
+ handle_IRQ(irq, regs);
+}
+
+static void nvic_eoi(struct irq_data *d)
+{
+ /*
+ * This is a no-op as end of interrupt is signaled by the exception
+ * return sequence.
+ */
+}
+
+static int __init nvic_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ unsigned int irqs, i, ret, numbanks;
+ void __iomem *nvic_base;
+
+ numbanks = (readl_relaxed(V7M_SCS_ICTR) &
+ V7M_SCS_ICTR_INTLINESNUM_MASK) + 1;
+
+ nvic_base = of_iomap(node, 0);
+ if (!nvic_base) {
+ pr_warn("unable to map nvic registers\n");
+ return -ENOMEM;
+ }
+
+ irqs = numbanks * 32;
+ if (irqs > NVIC_MAX_IRQ)
+ irqs = NVIC_MAX_IRQ;
+
+ nvic_irq_domain =
+ irq_domain_add_linear(node, irqs, &irq_generic_chip_ops, NULL);
+ if (!nvic_irq_domain) {
+ pr_warn("Failed to allocate irq domain\n");
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(nvic_irq_domain, 32, 1,
+ "nvic_irq", handle_fasteoi_irq,
+ clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_warn("Failed to allocate irq chips\n");
+ irq_domain_remove(nvic_irq_domain);
+ return ret;
+ }
+
+ for (i = 0; i < numbanks; ++i) {
+ struct irq_chip_generic *gc;
+
+ gc = irq_get_domain_generic_chip(nvic_irq_domain, 32 * i);
+ gc->reg_base = nvic_base + 4 * i;
+ gc->chip_types[0].regs.enable = NVIC_ISER;
+ gc->chip_types[0].regs.disable = NVIC_ICER;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
+ gc->chip_types[0].chip.irq_eoi = nvic_eoi;
+
+ /* disable interrupts */
+ writel_relaxed(~0, gc->reg_base + NVIC_ICER);
+ }
+
+ /* Set priority on all interrupts */
+ for (i = 0; i < irqs; i += 4)
+ writel_relaxed(0, nvic_base + NVIC_IPR + i);
+
+ return 0;
+}
+IRQCHIP_DECLARE(armv7m_nvic, "arm,armv7m-nvic", nvic_of_init);
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
new file mode 100644
index 000000000000..e51d40031884
--- /dev/null
+++ b/drivers/irqchip/irq-orion.c
@@ -0,0 +1,192 @@
+/*
+ * Marvell Orion SoCs IRQ chip driver.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "irqchip.h"
+
+/*
+ * Orion SoC main interrupt controller
+ */
+#define ORION_IRQS_PER_CHIP 32
+
+#define ORION_IRQ_CAUSE 0x00
+#define ORION_IRQ_MASK 0x04
+#define ORION_IRQ_FIQ_MASK 0x08
+#define ORION_IRQ_ENDP_MASK 0x0c
+
+static struct irq_domain *orion_irq_domain;
+
+static asmlinkage void
+__exception_irq_entry orion_handle_irq(struct pt_regs *regs)
+{
+ struct irq_domain_chip_generic *dgc = orion_irq_domain->gc;
+ int n, base = 0;
+
+ for (n = 0; n < dgc->num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+ struct irq_chip_generic *gc =
+ irq_get_domain_generic_chip(orion_irq_domain, base);
+ u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &
+ gc->mask_cache;
+ while (stat) {
+ u32 hwirq = ffs(stat) - 1;
+ u32 irq = irq_find_mapping(orion_irq_domain,
+ gc->irq_base + hwirq);
+ handle_IRQ(irq, regs);
+ stat &= ~(1 << hwirq);
+ }
+ }
+}
+
+static int __init orion_irq_init(struct device_node *np,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ int n, ret, base, num_chips = 0;
+ struct resource r;
+
+ /* count number of irq chips by valid reg addresses */
+ while (of_address_to_resource(np, num_chips, &r) == 0)
+ num_chips++;
+
+ orion_irq_domain = irq_domain_add_linear(np,
+ num_chips * ORION_IRQS_PER_CHIP,
+ &irq_generic_chip_ops, NULL);
+ if (!orion_irq_domain)
+ panic("%s: unable to add irq domain\n", np->name);
+
+ ret = irq_alloc_domain_generic_chips(orion_irq_domain,
+ ORION_IRQS_PER_CHIP, 1, np->name,
+ handle_level_irq, clr, 0,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret)
+ panic("%s: unable to alloc irq domain gc\n", np->name);
+
+ for (n = 0, base = 0; n < num_chips; n++, base += ORION_IRQS_PER_CHIP) {
+ struct irq_chip_generic *gc =
+ irq_get_domain_generic_chip(orion_irq_domain, base);
+
+ of_address_to_resource(np, n, &r);
+
+ if (!request_mem_region(r.start, resource_size(&r), np->name))
+ panic("%s: unable to request mem region %d",
+ np->name, n);
+
+ gc->reg_base = ioremap(r.start, resource_size(&r));
+ if (!gc->reg_base)
+ panic("%s: unable to map resource %d", np->name, n);
+
+ gc->chip_types[0].regs.mask = ORION_IRQ_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ /* mask all interrupts */
+ writel(0, gc->reg_base + ORION_IRQ_MASK);
+ }
+
+ set_handle_irq(orion_handle_irq);
+ return 0;
+}
+IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
+
+/*
+ * Orion SoC bridge interrupt controller
+ */
+#define ORION_BRIDGE_IRQ_CAUSE 0x00
+#define ORION_BRIDGE_IRQ_MASK 0x04
+
+static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *d = irq_get_handler_data(irq);
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+ u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
+ gc->mask_cache;
+
+ while (stat) {
+ u32 hwirq = ffs(stat) - 1;
+
+ generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
+ stat &= ~(1 << hwirq);
+ }
+}
+
+static int __init orion_bridge_irq_init(struct device_node *np,
+ struct device_node *parent)
+{
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ struct resource r;
+ struct irq_domain *domain;
+ struct irq_chip_generic *gc;
+ int ret, irq, nrirqs = 32;
+
+ /* get optional number of interrupts provided */
+ of_property_read_u32(np, "marvell,#interrupts", &nrirqs);
+
+ domain = irq_domain_add_linear(np, nrirqs,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ pr_err("%s: unable to add irq domain\n", np->name);
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
+ handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: unable to alloc irq domain gc\n", np->name);
+ return ret;
+ }
+
+ ret = of_address_to_resource(np, 0, &r);
+ if (ret) {
+ pr_err("%s: unable to get resource\n", np->name);
+ return ret;
+ }
+
+ if (!request_mem_region(r.start, resource_size(&r), np->name)) {
+ pr_err("%s: unable to request mem region\n", np->name);
+ return -ENOMEM;
+ }
+
+ /* Map the parent interrupt for the chained handler */
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq <= 0) {
+ pr_err("%s: unable to parse irq\n", np->name);
+ return -EINVAL;
+ }
+
+ gc = irq_get_domain_generic_chip(domain, 0);
+ gc->reg_base = ioremap(r.start, resource_size(&r));
+ if (!gc->reg_base) {
+ pr_err("%s: unable to map resource\n", np->name);
+ return -ENOMEM;
+ }
+
+ gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
+ gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+
+ /* mask all interrupts */
+ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, orion_bridge_irq_handler);
+
+ return 0;
+}
+IRQCHIP_DECLARE(orion_bridge_intc,
+ "marvell,orion-bridge-intc", orion_bridge_irq_init);
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 5a68e5accec1..82cec63a9011 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -18,6 +18,7 @@
*/
#include <linux/init.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
@@ -347,8 +348,14 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
/* deal with driver instance configuration */
- if (pdata)
+ if (pdata) {
memcpy(&p->config, pdata, sizeof(*pdata));
+ } else {
+ of_property_read_u32(pdev->dev.of_node, "sense-bitfield-width",
+ &p->config.sense_bitfield_width);
+ p->config.control_parent = of_property_read_bool(pdev->dev.of_node,
+ "control-parent");
+ }
if (!p->config.sense_bitfield_width)
p->config.sense_bitfield_width = 4; /* default to 4 bits */
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c
index 927bff373aac..2f404ba61c6c 100644
--- a/drivers/irqchip/irq-renesas-irqc.c
+++ b/drivers/irqchip/irq-renesas-irqc.c
@@ -248,8 +248,8 @@ static int irqc_probe(struct platform_device *pdev)
return 0;
err3:
- for (; k >= 0; k--)
- free_irq(p->irq[k - 1].requested_irq, &p->irq[k - 1]);
+ while (--k >= 0)
+ free_irq(p->irq[k].requested_irq, &p->irq[k]);
irq_domain_remove(p->irq_domain);
err2:
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 69ea44ebcf61..4851afae38dc 100644
--- a/drivers/irqchip/irq-sirfsoc.c
+++ b/drivers/irqchip/irq-sirfsoc.c
@@ -23,7 +23,7 @@
#define SIRFSOC_INT_RISC_LEVEL1 0x0024
#define SIRFSOC_INIT_IRQ_ID 0x0038
-#define SIRFSOC_NUM_IRQS 128
+#define SIRFSOC_NUM_IRQS 64
static struct irq_domain *sirfsoc_irqdomain;
@@ -32,15 +32,18 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
+ int ret;
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
- gc = irq_alloc_generic_chip("SIRFINTC", 1, irq_start, base, handle_level_irq);
- ct = gc->chip_types;
+ ret = irq_alloc_domain_generic_chips(sirfsoc_irqdomain, num, 1, "irq_sirfsoc",
+ handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+ gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, irq_start);
+ gc->reg_base = base;
+ ct = gc->chip_types;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
-
- irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0);
}
static asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
@@ -60,9 +63,8 @@ static int __init sirfsoc_irq_init(struct device_node *np, struct device_node *p
if (!base)
panic("unable to map intc cpu registers\n");
- /* using legacy because irqchip_generic does not work with linear */
- sirfsoc_irqdomain = irq_domain_add_legacy(np, SIRFSOC_NUM_IRQS, 0, 0,
- &irq_domain_simple_ops, base);
+ sirfsoc_irqdomain = irq_domain_add_linear(np, SIRFSOC_NUM_IRQS,
+ &irq_generic_chip_ops, base);
sirfsoc_alloc_gc(base, 0, 32);
sirfsoc_alloc_gc(base + 4, 32, SIRFSOC_NUM_IRQS - 32);
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index b66d4ae06898..a5438d889245 100644
--- a/drivers/irqchip/irq-sun4i.c
+++ b/drivers/irqchip/irq-sun4i.c
@@ -38,7 +38,7 @@ static struct irq_domain *sun4i_irq_domain;
static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs);
-void sun4i_irq_ack(struct irq_data *irqd)
+static void sun4i_irq_ack(struct irq_data *irqd)
{
unsigned int irq = irqd_to_hwirq(irqd);
unsigned int irq_off = irq % 32;
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
new file mode 100644
index 000000000000..7c44c99bf1f2
--- /dev/null
+++ b/drivers/irqchip/irq-tb10x.c
@@ -0,0 +1,195 @@
+/*
+ * Abilis Systems interrupt controller driver
+ *
+ * Copyright (C) Abilis Systems 2012
+ *
+ * Author: Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include "irqchip.h"
+
+#define AB_IRQCTL_INT_ENABLE 0x00
+#define AB_IRQCTL_INT_STATUS 0x04
+#define AB_IRQCTL_SRC_MODE 0x08
+#define AB_IRQCTL_SRC_POLARITY 0x0C
+#define AB_IRQCTL_INT_MODE 0x10
+#define AB_IRQCTL_INT_POLARITY 0x14
+#define AB_IRQCTL_INT_FORCE 0x18
+
+#define AB_IRQCTL_MAXIRQ 32
+
+static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
+ u32 val)
+{
+ irq_reg_writel(val, gc->reg_base + reg);
+}
+
+static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
+{
+ return irq_reg_readl(gc->reg_base + reg);
+}
+
+static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+ uint32_t im, mod, pol;
+
+ im = data->mask;
+
+ irq_gc_lock(gc);
+
+ mod = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_MODE) | im;
+ pol = ab_irqctl_readreg(gc, AB_IRQCTL_SRC_POLARITY) | im;
+
+ switch (flow_type & IRQF_TRIGGER_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ pol ^= im;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ mod ^= im;
+ break;
+ case IRQ_TYPE_NONE:
+ flow_type = IRQ_TYPE_LEVEL_LOW;
+ case IRQ_TYPE_LEVEL_LOW:
+ mod ^= im;
+ pol ^= im;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ break;
+ default:
+ irq_gc_unlock(gc);
+ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
+ __func__, data->irq);
+ return -EBADR;
+ }
+
+ irqd_set_trigger_type(data, flow_type);
+ irq_setup_alt_chip(data, flow_type);
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_MODE, mod);
+ ab_irqctl_writereg(gc, AB_IRQCTL_SRC_POLARITY, pol);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, im);
+
+ irq_gc_unlock(gc);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain = irq_desc_get_handler_data(desc);
+
+ generic_handle_irq(irq_find_mapping(domain, irq));
+}
+
+static int __init of_tb10x_init_irq(struct device_node *ictl,
+ struct device_node *parent)
+{
+ int i, ret, nrirqs = of_irq_count(ictl);
+ struct resource mem;
+ struct irq_chip_generic *gc;
+ struct irq_domain *domain;
+ void __iomem *reg_base;
+
+ if (of_address_to_resource(ictl, 0, &mem)) {
+ pr_err("%s: No registers declared in DeviceTree.\n",
+ ictl->name);
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, resource_size(&mem),
+ ictl->name)) {
+ pr_err("%s: Request mem region failed.\n", ictl->name);
+ return -EBUSY;
+ }
+
+ reg_base = ioremap(mem.start, resource_size(&mem));
+ if (!reg_base) {
+ ret = -EBUSY;
+ pr_err("%s: ioremap failed.\n", ictl->name);
+ goto ioremap_fail;
+ }
+
+ domain = irq_domain_add_linear(ictl, AB_IRQCTL_MAXIRQ,
+ &irq_generic_chip_ops, NULL);
+ if (!domain) {
+ ret = -ENOMEM;
+ pr_err("%s: Could not register interrupt domain.\n",
+ ictl->name);
+ goto irq_domain_add_fail;
+ }
+
+ ret = irq_alloc_domain_generic_chips(domain, AB_IRQCTL_MAXIRQ,
+ 2, ictl->name, handle_level_irq,
+ IRQ_NOREQUEST, IRQ_NOPROBE,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret) {
+ pr_err("%s: Could not allocate generic interrupt chip.\n",
+ ictl->name);
+ goto gc_alloc_fail;
+ }
+
+ gc = domain->gc->gc[0];
+ gc->reg_base = reg_base;
+
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[0].regs.mask = AB_IRQCTL_INT_ENABLE;
+
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = tb10x_irq_set_type;
+ gc->chip_types[1].regs.ack = AB_IRQCTL_INT_STATUS;
+ gc->chip_types[1].regs.mask = AB_IRQCTL_INT_ENABLE;
+ gc->chip_types[1].handler = handle_edge_irq;
+
+ for (i = 0; i < nrirqs; i++) {
+ unsigned int irq = irq_of_parse_and_map(ictl, i);
+
+ irq_set_handler_data(irq, domain);
+ irq_set_chained_handler(irq, tb10x_irq_cascade);
+ }
+
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_MODE, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_POLARITY, 0);
+ ab_irqctl_writereg(gc, AB_IRQCTL_INT_STATUS, ~0UL);
+
+ return 0;
+
+gc_alloc_fail:
+ irq_domain_remove(domain);
+irq_domain_add_fail:
+ iounmap(reg_base);
+ioremap_fail:
+ release_mem_region(mem.start, resource_size(&mem));
+ return ret;
+}
+IRQCHIP_DECLARE(tb10x_intc, "abilis,tb10x-ictl", of_tb10x_init_irq);
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
index d97059550a2c..1846e7d66681 100644
--- a/drivers/irqchip/irq-vt8500.c
+++ b/drivers/irqchip/irq-vt8500.c
@@ -178,7 +178,8 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
-asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
+static asmlinkage
+void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
{
u32 stat, i;
int irqnr, virq;
@@ -203,7 +204,8 @@ asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
}
}
-int __init vt8500_irq_init(struct device_node *node, struct device_node *parent)
+static int __init vt8500_irq_init(struct device_node *node,
+ struct device_node *parent)
{
int irq, i;
struct device_node *np = node;