[AVR32] extint: Set initial irq type to low level
[deliverable/linux.git] / arch / avr32 / mach-at32ap / extint.c
CommitLineData
5f97f7f9
HS
1/*
2 * External interrupt handling for AT32AP CPUs
3 *
4 * Copyright (C) 2006 Atmel Corporation
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#include <linux/errno.h>
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/platform_device.h>
16#include <linux/random.h>
17
18#include <asm/io.h>
19
7a5b8059
HS
20/* EIC register offsets */
21#define EIC_IER 0x0000
22#define EIC_IDR 0x0004
23#define EIC_IMR 0x0008
24#define EIC_ISR 0x000c
25#define EIC_ICR 0x0010
26#define EIC_MODE 0x0014
27#define EIC_EDGE 0x0018
28#define EIC_LEVEL 0x001c
7a5b8059
HS
29#define EIC_NMIC 0x0024
30
7a5b8059 31/* Bitfields in NMIC */
e7ba176b 32#define EIC_NMIC_ENABLE (1 << 0)
7a5b8059
HS
33
34/* Bit manipulation macros */
35#define EIC_BIT(name) \
36 (1 << EIC_##name##_OFFSET)
37#define EIC_BF(name,value) \
38 (((value) & ((1 << EIC_##name##_SIZE) - 1)) \
39 << EIC_##name##_OFFSET)
40#define EIC_BFEXT(name,value) \
41 (((value) >> EIC_##name##_OFFSET) \
42 & ((1 << EIC_##name##_SIZE) - 1))
43#define EIC_BFINS(name,value,old) \
44 (((old) & ~(((1 << EIC_##name##_SIZE) - 1) \
45 << EIC_##name##_OFFSET)) \
46 | EIC_BF(name,value))
47
48/* Register access macros */
49#define eic_readl(port,reg) \
50 __raw_readl((port)->regs + EIC_##reg)
51#define eic_writel(port,reg,value) \
52 __raw_writel((value), (port)->regs + EIC_##reg)
53
54struct eic {
55 void __iomem *regs;
56 struct irq_chip *chip;
57 unsigned int first_irq;
58};
5f97f7f9 59
e7ba176b
HS
60static struct eic *nmi_eic;
61static bool nmi_enabled;
62
7a5b8059 63static void eic_ack_irq(unsigned int irq)
5f97f7f9 64{
7a5b8059
HS
65 struct eic *eic = get_irq_chip_data(irq);
66 eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
5f97f7f9
HS
67}
68
7a5b8059 69static void eic_mask_irq(unsigned int irq)
5f97f7f9 70{
7a5b8059
HS
71 struct eic *eic = get_irq_chip_data(irq);
72 eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
5f97f7f9
HS
73}
74
7a5b8059 75static void eic_mask_ack_irq(unsigned int irq)
5f97f7f9 76{
7a5b8059
HS
77 struct eic *eic = get_irq_chip_data(irq);
78 eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
79 eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
5f97f7f9
HS
80}
81
7a5b8059 82static void eic_unmask_irq(unsigned int irq)
5f97f7f9 83{
7a5b8059
HS
84 struct eic *eic = get_irq_chip_data(irq);
85 eic_writel(eic, IER, 1 << (irq - eic->first_irq));
5f97f7f9
HS
86}
87
7a5b8059 88static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
5f97f7f9 89{
7a5b8059 90 struct eic *eic = get_irq_chip_data(irq);
01cb087e 91 struct irq_desc *desc;
7a5b8059 92 unsigned int i = irq - eic->first_irq;
5f97f7f9 93 u32 mode, edge, level;
5f97f7f9
HS
94 int ret = 0;
95
58febc0b 96 flow_type &= IRQ_TYPE_SENSE_MASK;
01cb087e
HS
97 if (flow_type == IRQ_TYPE_NONE)
98 flow_type = IRQ_TYPE_LEVEL_LOW;
99
100 desc = &irq_desc[irq];
5f97f7f9 101
7a5b8059
HS
102 mode = eic_readl(eic, MODE);
103 edge = eic_readl(eic, EDGE);
104 level = eic_readl(eic, LEVEL);
5f97f7f9
HS
105
106 switch (flow_type) {
107 case IRQ_TYPE_LEVEL_LOW:
108 mode |= 1 << i;
109 level &= ~(1 << i);
110 break;
111 case IRQ_TYPE_LEVEL_HIGH:
112 mode |= 1 << i;
113 level |= 1 << i;
114 break;
115 case IRQ_TYPE_EDGE_RISING:
116 mode &= ~(1 << i);
117 edge |= 1 << i;
118 break;
119 case IRQ_TYPE_EDGE_FALLING:
120 mode &= ~(1 << i);
121 edge &= ~(1 << i);
122 break;
123 default:
124 ret = -EINVAL;
125 break;
126 }
127
58febc0b 128 if (ret == 0) {
7a5b8059
HS
129 eic_writel(eic, MODE, mode);
130 eic_writel(eic, EDGE, edge);
131 eic_writel(eic, LEVEL, level);
58febc0b 132
e4f586f2 133 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
58febc0b 134 flow_type |= IRQ_LEVEL;
e4f586f2
DB
135 __set_irq_handler_unlocked(irq, handle_level_irq);
136 } else
137 __set_irq_handler_unlocked(irq, handle_edge_irq);
58febc0b
DB
138 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
139 desc->status |= flow_type;
140 }
5f97f7f9 141
5f97f7f9
HS
142 return ret;
143}
144
86298962 145static struct irq_chip eic_chip = {
7a5b8059
HS
146 .name = "eic",
147 .ack = eic_ack_irq,
148 .mask = eic_mask_irq,
149 .mask_ack = eic_mask_ack_irq,
150 .unmask = eic_unmask_irq,
151 .set_type = eic_set_irq_type,
5f97f7f9
HS
152};
153
7a5b8059 154static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
5f97f7f9 155{
7a5b8059 156 struct eic *eic = desc->handler_data;
5f97f7f9 157 unsigned long status, pending;
e4f586f2 158 unsigned int i;
5f97f7f9 159
7a5b8059
HS
160 status = eic_readl(eic, ISR);
161 pending = status & eic_readl(eic, IMR);
5f97f7f9
HS
162
163 while (pending) {
164 i = fls(pending) - 1;
165 pending &= ~(1 << i);
166
e4f586f2 167 generic_handle_irq(i + eic->first_irq);
5f97f7f9 168 }
5f97f7f9
HS
169}
170
e7ba176b
HS
171int nmi_enable(void)
172{
173 nmi_enabled = true;
174
175 if (nmi_eic)
176 eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
177
178 return 0;
179}
180
181void nmi_disable(void)
182{
183 if (nmi_eic)
184 eic_writel(nmi_eic, NMIC, 0);
185
186 nmi_enabled = false;
187}
188
7a5b8059 189static int __init eic_probe(struct platform_device *pdev)
5f97f7f9 190{
7a5b8059
HS
191 struct eic *eic;
192 struct resource *regs;
5f97f7f9
HS
193 unsigned int i;
194 unsigned int nr_irqs;
195 unsigned int int_irq;
7a5b8059 196 int ret;
5f97f7f9
HS
197 u32 pattern;
198
7a5b8059
HS
199 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
200 int_irq = platform_get_irq(pdev, 0);
201 if (!regs || !int_irq) {
202 dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
203 return -ENXIO;
204 }
205
206 ret = -ENOMEM;
207 eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
208 if (!eic) {
209 dev_dbg(&pdev->dev, "no memory for eic structure\n");
210 goto err_kzalloc;
211 }
212
213 eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
214 eic->regs = ioremap(regs->start, regs->end - regs->start + 1);
215 if (!eic->regs) {
216 dev_dbg(&pdev->dev, "failed to map regs\n");
217 goto err_ioremap;
218 }
5f97f7f9
HS
219
220 /*
221 * Find out how many interrupt lines that are actually
222 * implemented in hardware.
223 */
7a5b8059
HS
224 eic_writel(eic, IDR, ~0UL);
225 eic_writel(eic, MODE, ~0UL);
226 pattern = eic_readl(eic, MODE);
5f97f7f9
HS
227 nr_irqs = fls(pattern);
228
d6c49a7a 229 /* Trigger on low level unless overridden by driver */
7a5b8059 230 eic_writel(eic, EDGE, 0UL);
d6c49a7a 231 eic_writel(eic, LEVEL, 0UL);
01cb087e 232
7a5b8059 233 eic->chip = &eic_chip;
5f97f7f9
HS
234
235 for (i = 0; i < nr_irqs; i++) {
7a5b8059 236 set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
d6c49a7a 237 handle_level_irq);
7a5b8059 238 set_irq_chip_data(eic->first_irq + i, eic);
5f97f7f9
HS
239 }
240
7a5b8059
HS
241 set_irq_chained_handler(int_irq, demux_eic_irq);
242 set_irq_data(int_irq, eic);
5f97f7f9 243
e7ba176b
HS
244 if (pdev->id == 0) {
245 nmi_eic = eic;
246 if (nmi_enabled)
247 /*
248 * Someone tried to enable NMI before we were
249 * ready. Do it now.
250 */
251 nmi_enable();
252 }
253
7a5b8059
HS
254 dev_info(&pdev->dev,
255 "External Interrupt Controller at 0x%p, IRQ %u\n",
256 eic->regs, int_irq);
257 dev_info(&pdev->dev,
258 "Handling %u external IRQs, starting with IRQ %u\n",
259 nr_irqs, eic->first_irq);
5f97f7f9
HS
260
261 return 0;
7a5b8059
HS
262
263err_ioremap:
264 kfree(eic);
265err_kzalloc:
266 return ret;
267}
268
269static struct platform_driver eic_driver = {
270 .driver = {
271 .name = "at32_eic",
272 },
273};
274
275static int __init eic_init(void)
276{
277 return platform_driver_probe(&eic_driver, eic_probe);
5f97f7f9 278}
7a5b8059 279arch_initcall(eic_init);
This page took 0.191398 seconds and 5 git commands to generate.