Commit 4de563ae821b1935b3c467a4606e5738b0b0df87
Committed by
Thomas Gleixner
1 parent
002fca5df1
Exists in
master
and in
20 other branches
irqchip: Add support for MOXA ART SoCs
This patch adds an irqchip driver for the main interrupt controller found on MOXA ART SoCs. Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com> Cc: grant.likely@secretlab.ca Cc: thomas.petazzoni@free-electrons.com Cc: arnd@arndb.de Cc: u.kleine-koenig@pengutronix.de Cc: linux@arm.linux.org.uk Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1372941531-6393-1-git-send-email-jonas.jensen@gmail.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Showing 2 changed files with 118 additions and 0 deletions Side-by-side Diff
drivers/irqchip/Makefile
... | ... | @@ -7,6 +7,7 @@ |
7 | 7 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o |
8 | 8 | obj-$(CONFIG_METAG) += irq-metag-ext.o |
9 | 9 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o |
10 | +obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o | |
10 | 11 | obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o |
11 | 12 | obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o |
12 | 13 | obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o |
drivers/irqchip/irq-moxart.c
1 | +/* | |
2 | + * MOXA ART SoCs IRQ chip driver. | |
3 | + * | |
4 | + * Copyright (C) 2013 Jonas Jensen | |
5 | + * | |
6 | + * Jonas Jensen <jonas.jensen@gmail.com> | |
7 | + * | |
8 | + * This file is licensed under the terms of the GNU General Public | |
9 | + * License version 2. This program is licensed "as is" without any | |
10 | + * warranty of any kind, whether express or implied. | |
11 | + */ | |
12 | + | |
13 | +#include <linux/io.h> | |
14 | +#include <linux/irq.h> | |
15 | +#include <linux/of.h> | |
16 | +#include <linux/of_address.h> | |
17 | +#include <linux/of_irq.h> | |
18 | +#include <linux/irqdomain.h> | |
19 | + | |
20 | +#include <asm/exception.h> | |
21 | + | |
22 | +#include "irqchip.h" | |
23 | + | |
24 | +#define IRQ_SOURCE_REG 0 | |
25 | +#define IRQ_MASK_REG 0x04 | |
26 | +#define IRQ_CLEAR_REG 0x08 | |
27 | +#define IRQ_MODE_REG 0x0c | |
28 | +#define IRQ_LEVEL_REG 0x10 | |
29 | +#define IRQ_STATUS_REG 0x14 | |
30 | + | |
31 | +#define FIQ_SOURCE_REG 0x20 | |
32 | +#define FIQ_MASK_REG 0x24 | |
33 | +#define FIQ_CLEAR_REG 0x28 | |
34 | +#define FIQ_MODE_REG 0x2c | |
35 | +#define FIQ_LEVEL_REG 0x30 | |
36 | +#define FIQ_STATUS_REG 0x34 | |
37 | + | |
38 | + | |
39 | +struct moxart_irq_data { | |
40 | + void __iomem *base; | |
41 | + struct irq_domain *domain; | |
42 | + unsigned int interrupt_mask; | |
43 | +}; | |
44 | + | |
45 | +static struct moxart_irq_data intc; | |
46 | + | |
47 | +static asmlinkage void __exception_irq_entry handle_irq(struct pt_regs *regs) | |
48 | +{ | |
49 | + u32 irqstat; | |
50 | + int hwirq; | |
51 | + | |
52 | + irqstat = readl(intc.base + IRQ_STATUS_REG); | |
53 | + | |
54 | + while (irqstat) { | |
55 | + hwirq = ffs(irqstat) - 1; | |
56 | + handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); | |
57 | + irqstat &= ~(1 << hwirq); | |
58 | + } | |
59 | +} | |
60 | + | |
61 | +static int __init moxart_of_intc_init(struct device_node *node, | |
62 | + struct device_node *parent) | |
63 | +{ | |
64 | + unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | |
65 | + int ret; | |
66 | + struct irq_chip_generic *gc; | |
67 | + | |
68 | + intc.base = of_iomap(node, 0); | |
69 | + if (!intc.base) { | |
70 | + pr_err("%s: unable to map IC registers\n", | |
71 | + node->full_name); | |
72 | + return -EINVAL; | |
73 | + } | |
74 | + | |
75 | + intc.domain = irq_domain_add_linear(node, 32, &irq_generic_chip_ops, | |
76 | + intc.base); | |
77 | + if (!intc.domain) { | |
78 | + pr_err("%s: unable to create IRQ domain\n", node->full_name); | |
79 | + return -EINVAL; | |
80 | + } | |
81 | + | |
82 | + ret = irq_alloc_domain_generic_chips(intc.domain, 32, 1, | |
83 | + "MOXARTINTC", handle_edge_irq, | |
84 | + clr, 0, IRQ_GC_INIT_MASK_CACHE); | |
85 | + if (ret) { | |
86 | + pr_err("%s: could not allocate generic chip\n", | |
87 | + node->full_name); | |
88 | + irq_domain_remove(intc.domain); | |
89 | + return -EINVAL; | |
90 | + } | |
91 | + | |
92 | + ret = of_property_read_u32(node, "interrupt-mask", | |
93 | + &intc.interrupt_mask); | |
94 | + if (ret) | |
95 | + pr_err("%s: could not read interrupt-mask DT property\n", | |
96 | + node->full_name); | |
97 | + | |
98 | + gc = irq_get_domain_generic_chip(intc.domain, 0); | |
99 | + | |
100 | + gc->reg_base = intc.base; | |
101 | + gc->chip_types[0].regs.mask = IRQ_MASK_REG; | |
102 | + gc->chip_types[0].regs.ack = IRQ_CLEAR_REG; | |
103 | + gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; | |
104 | + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; | |
105 | + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; | |
106 | + | |
107 | + writel(0, intc.base + IRQ_MASK_REG); | |
108 | + writel(0xffffffff, intc.base + IRQ_CLEAR_REG); | |
109 | + | |
110 | + writel(intc.interrupt_mask, intc.base + IRQ_MODE_REG); | |
111 | + writel(intc.interrupt_mask, intc.base + IRQ_LEVEL_REG); | |
112 | + | |
113 | + set_handle_irq(handle_irq); | |
114 | + | |
115 | + return 0; | |
116 | +} | |
117 | +IRQCHIP_DECLARE(moxa_moxart_ic, "moxa,moxart-ic", moxart_of_intc_init); |