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