aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-vt8500/irq.c
diff options
context:
space:
mode:
authorTony Prisk <linux@prisktech.co.nz>2012-10-10 03:59:32 -0400
committerTony Prisk <linux@prisktech.co.nz>2012-10-25 23:45:11 -0400
commit0c464d588b6911ca84851ce4762695201d866c7c (patch)
tree794563933d34573f72c43609b8cb357c9f11e6c7 /arch/arm/mach-vt8500/irq.c
parentddffeb8c4d0331609ef2581d84de4d763607bd37 (diff)
arm: vt8500: Convert irq.c for multiplatform integration
This patch converts arch-vt8500/irq.c to MULTI_IRQ_HANDLER and SPARSE_IRQ. IRQ domain is changed from legacy to linear. Also, remove legacy code in include/mach/entry-macro.S and include/mach/irq.h to prepare for multiplatform. Signed-off-by: Tony Prisk <linux@prisktech.co.nz> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arm/mach-vt8500/irq.c')
-rw-r--r--arch/arm/mach-vt8500/irq.c108
1 files changed, 70 insertions, 38 deletions
diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c
index f8f9ab9bc56e..b9cf5ce9efbb 100644
--- a/arch/arm/mach-vt8500/irq.c
+++ b/arch/arm/mach-vt8500/irq.c
@@ -36,7 +36,7 @@
36#include <linux/of_address.h> 36#include <linux/of_address.h>
37 37
38#include <asm/irq.h> 38#include <asm/irq.h>
39 39#include <asm/exception.h>
40 40
41#define VT8500_ICPC_IRQ 0x20 41#define VT8500_ICPC_IRQ 0x20
42#define VT8500_ICPC_FIQ 0x24 42#define VT8500_ICPC_FIQ 0x24
@@ -66,30 +66,34 @@
66#define VT8500_EDGE ( VT8500_TRIGGER_RISING \ 66#define VT8500_EDGE ( VT8500_TRIGGER_RISING \
67 | VT8500_TRIGGER_FALLING) 67 | VT8500_TRIGGER_FALLING)
68 68
69static int irq_cnt; 69/* vt8500 has 1 intc, wm8505 and wm8650 have 2 */
70#define VT8500_INTC_MAX 2
70 71
71struct vt8500_irq_priv { 72struct vt8500_irq_data {
72 void __iomem *base; 73 void __iomem *base; /* IO Memory base address */
74 struct irq_domain *domain; /* Domain for this controller */
73}; 75};
74 76
77/* Global variable for accessing io-mem addresses */
78static struct vt8500_irq_data intc[VT8500_INTC_MAX];
79static u32 active_cnt = 0;
80
75static void vt8500_irq_mask(struct irq_data *d) 81static void vt8500_irq_mask(struct irq_data *d)
76{ 82{
77 struct vt8500_irq_priv *priv = 83 struct vt8500_irq_data *priv = d->domain->host_data;
78 (struct vt8500_irq_priv *)(d->domain->host_data);
79 void __iomem *base = priv->base; 84 void __iomem *base = priv->base;
80 u8 edge; 85 void __iomem *stat_reg = base + VT8500_ICIS + (d->hwirq < 32 ? 0 : 4);
86 u8 edge, dctr;
87 u32 status;
81 88
82 edge = readb(base + VT8500_ICDC + d->hwirq) & VT8500_EDGE; 89 edge = readb(base + VT8500_ICDC + d->hwirq) & VT8500_EDGE;
83 if (edge) { 90 if (edge) {
84 void __iomem *stat_reg = base + VT8500_ICIS 91 status = readl(stat_reg);
85 + (d->hwirq < 32 ? 0 : 4);
86 unsigned status = readl(stat_reg);
87 92
88 status |= (1 << (d->hwirq & 0x1f)); 93 status |= (1 << (d->hwirq & 0x1f));
89 writel(status, stat_reg); 94 writel(status, stat_reg);
90 } else { 95 } else {
91 u8 dctr = readb(base + VT8500_ICDC + d->hwirq); 96 dctr = readb(base + VT8500_ICDC + d->hwirq);
92
93 dctr &= ~VT8500_INT_ENABLE; 97 dctr &= ~VT8500_INT_ENABLE;
94 writeb(dctr, base + VT8500_ICDC + d->hwirq); 98 writeb(dctr, base + VT8500_ICDC + d->hwirq);
95 } 99 }
@@ -97,8 +101,7 @@ static void vt8500_irq_mask(struct irq_data *d)
97 101
98static void vt8500_irq_unmask(struct irq_data *d) 102static void vt8500_irq_unmask(struct irq_data *d)
99{ 103{
100 struct vt8500_irq_priv *priv = 104 struct vt8500_irq_data *priv = d->domain->host_data;
101 (struct vt8500_irq_priv *)(d->domain->host_data);
102 void __iomem *base = priv->base; 105 void __iomem *base = priv->base;
103 u8 dctr; 106 u8 dctr;
104 107
@@ -109,8 +112,7 @@ static void vt8500_irq_unmask(struct irq_data *d)
109 112
110static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) 113static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type)
111{ 114{
112 struct vt8500_irq_priv *priv = 115 struct vt8500_irq_data *priv = d->domain->host_data;
113 (struct vt8500_irq_priv *)(d->domain->host_data);
114 void __iomem *base = priv->base; 116 void __iomem *base = priv->base;
115 u8 dctr; 117 u8 dctr;
116 118
@@ -148,17 +150,15 @@ static struct irq_chip vt8500_irq_chip = {
148 150
149static void __init vt8500_init_irq_hw(void __iomem *base) 151static void __init vt8500_init_irq_hw(void __iomem *base)
150{ 152{
151 unsigned int i; 153 u32 i;
152 154
153 /* Enable rotating priority for IRQ */ 155 /* Enable rotating priority for IRQ */
154 writel(ICPC_ROTATE, base + VT8500_ICPC_IRQ); 156 writel(ICPC_ROTATE, base + VT8500_ICPC_IRQ);
155 writel(0x00, base + VT8500_ICPC_FIQ); 157 writel(0x00, base + VT8500_ICPC_FIQ);
156 158
157 for (i = 0; i < 64; i++) { 159 /* Disable all interrupts and route them to IRQ */
158 /* Disable all interrupts and route them to IRQ */ 160 for (i = 0; i < 64; i++)
159 writeb(VT8500_INT_DISABLE | ICDC_IRQ, 161 writeb(VT8500_INT_DISABLE | ICDC_IRQ, base + VT8500_ICDC + i);
160 base + VT8500_ICDC + i);
161 }
162} 162}
163 163
164static int vt8500_irq_map(struct irq_domain *h, unsigned int virq, 164static int vt8500_irq_map(struct irq_domain *h, unsigned int virq,
@@ -175,33 +175,67 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
175 .xlate = irq_domain_xlate_onecell, 175 .xlate = irq_domain_xlate_onecell,
176}; 176};
177 177
178asmlinkage void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
179{
180 u32 stat, i;
181 int irqnr, virq;
182 void __iomem *base;
183
184 /* Loop through each active controller */
185 for (i=0; i<active_cnt; i++) {
186 base = intc[i].base;
187 irqnr = readl_relaxed(base) & 0x3F;
188 /*
189 Highest Priority register default = 63, so check that this
190 is a real interrupt by checking the status register
191 */
192 if (irqnr == 63) {
193 stat = readl_relaxed(base + VT8500_ICIS + 4);
194 if (!(stat & BIT(31)))
195 continue;
196 }
197
198 virq = irq_find_mapping(intc[i].domain, irqnr);
199 handle_IRQ(virq, regs);
200 }
201}
202
178int __init vt8500_irq_init(struct device_node *node, struct device_node *parent) 203int __init vt8500_irq_init(struct device_node *node, struct device_node *parent)
179{ 204{
180 struct irq_domain *vt8500_irq_domain;
181 struct vt8500_irq_priv *priv;
182 int irq, i; 205 int irq, i;
183 struct device_node *np = node; 206 struct device_node *np = node;
184 207
185 priv = kzalloc(sizeof(struct vt8500_irq_priv), GFP_KERNEL); 208 if (active_cnt == VT8500_INTC_MAX) {
186 priv->base = of_iomap(np, 0); 209 pr_err("%s: Interrupt controllers > VT8500_INTC_MAX\n",
210 __func__);
211 goto out;
212 }
213
214 intc[active_cnt].base = of_iomap(np, 0);
215 intc[active_cnt].domain = irq_domain_add_linear(node, 64,
216 &vt8500_irq_domain_ops, &intc[active_cnt]);
187 217
188 vt8500_irq_domain = irq_domain_add_legacy(node, 64, irq_cnt, 0, 218 if (!intc[active_cnt].base) {
189 &vt8500_irq_domain_ops, priv); 219 pr_err("%s: Unable to map IO memory\n", __func__);
190 if (!vt8500_irq_domain) 220 goto out;
191 pr_err("%s: Unable to add wmt irq domain!\n", __func__); 221 }
222
223 if (!intc[active_cnt].domain) {
224 pr_err("%s: Unable to add irq domain!\n", __func__);
225 goto out;
226 }
192 227
193 irq_set_default_host(vt8500_irq_domain); 228 vt8500_init_irq_hw(intc[active_cnt].base);
194 229
195 vt8500_init_irq_hw(priv->base); 230 pr_info("vt8500-irq: Added interrupt controller\n");
196 231
197 pr_info("Added IRQ Controller @ %x [virq_base = %d]\n", 232 active_cnt++;
198 (u32)(priv->base), irq_cnt);
199 233
200 /* check if this is a slaved controller */ 234 /* check if this is a slaved controller */
201 if (of_irq_count(np) != 0) { 235 if (of_irq_count(np) != 0) {
202 /* check that we have the correct number of interrupts */ 236 /* check that we have the correct number of interrupts */
203 if (of_irq_count(np) != 8) { 237 if (of_irq_count(np) != 8) {
204 pr_err("%s: Incorrect IRQ map for slave controller\n", 238 pr_err("%s: Incorrect IRQ map for slaved controller\n",
205 __func__); 239 __func__);
206 return -EINVAL; 240 return -EINVAL;
207 } 241 }
@@ -213,9 +247,7 @@ int __init vt8500_irq_init(struct device_node *node, struct device_node *parent)
213 247
214 pr_info("vt8500-irq: Enabled slave->parent interrupts\n"); 248 pr_info("vt8500-irq: Enabled slave->parent interrupts\n");
215 } 249 }
216 250out:
217 irq_cnt += 64;
218
219 return 0; 251 return 0;
220} 252}
221 253