Skip to content

Commit b1479eb

Browse files
Boris BREZILLONJason Cooper
authored andcommitted
irqchip: atmel-aic: Add atmel AIC/AIC5 drivers
Add AIC (Advanced Interrupt Controller) and AIC5 (AIC5 is an evolution of the AIC block) drivers. Put common code in irq-atmel-aic-common.c/.h so that both driver can access shared functions (this will ease maintenance). These drivers are only compatible with dt enabled board and replace the old implementation found in arch/arm/mach-at91/irq.c. Signed-off-by: Boris BREZILLON <[email protected]> Acked-by: Nicolas Ferre <[email protected]> Link: https://lkml.kernel.org/r/1405012462-766-4-git-send-email-boris.brezillon@free-electrons.com Signed-off-by: Jason Cooper <[email protected]>
1 parent e9a0caa commit b1479eb

File tree

6 files changed

+846
-0
lines changed

6 files changed

+846
-0
lines changed

drivers/irqchip/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ config ARM_VIC_NR
3030
The maximum number of VICs available in the system, for
3131
power management.
3232

33+
config ATMEL_AIC_IRQ
34+
bool
35+
select GENERIC_IRQ_CHIP
36+
select IRQ_DOMAIN
37+
select MULTI_IRQ_HANDLER
38+
select SPARSE_IRQ
39+
40+
config ATMEL_AIC5_IRQ
41+
bool
42+
select GENERIC_IRQ_CHIP
43+
select IRQ_DOMAIN
44+
select MULTI_IRQ_HANDLER
45+
select SPARSE_IRQ
46+
3347
config BRCMSTB_L2_IRQ
3448
bool
3549
depends on ARM

drivers/irqchip/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
1818
obj-$(CONFIG_ARM_GIC) += irq-gic.o
1919
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
2020
obj-$(CONFIG_ARM_VIC) += irq-vic.o
21+
obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o
22+
obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o
2123
obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o
2224
obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o
2325
obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Atmel AT91 common AIC (Advanced Interrupt Controller) code shared by
3+
* irq-atmel-aic and irq-atmel-aic5 drivers
4+
*
5+
* Copyright (C) 2004 SAN People
6+
* Copyright (C) 2004 ATMEL
7+
* Copyright (C) Rick Bronson
8+
* Copyright (C) 2014 Free Electrons
9+
*
10+
* Author: Boris BREZILLON <[email protected]>
11+
*
12+
* This file is licensed under the terms of the GNU General Public
13+
* License version 2. This program is licensed "as is" without any
14+
* warranty of any kind, whether express or implied.
15+
*/
16+
17+
#include <linux/errno.h>
18+
#include <linux/io.h>
19+
#include <linux/irq.h>
20+
#include <linux/irqdomain.h>
21+
#include <linux/of.h>
22+
#include <linux/of_address.h>
23+
#include <linux/slab.h>
24+
25+
#include "irq-atmel-aic-common.h"
26+
27+
#define AT91_AIC_PRIOR GENMASK(2, 0)
28+
#define AT91_AIC_IRQ_MIN_PRIORITY 0
29+
#define AT91_AIC_IRQ_MAX_PRIORITY 7
30+
31+
#define AT91_AIC_SRCTYPE GENMASK(7, 6)
32+
#define AT91_AIC_SRCTYPE_LOW (0 << 5)
33+
#define AT91_AIC_SRCTYPE_FALLING (1 << 5)
34+
#define AT91_AIC_SRCTYPE_HIGH (2 << 5)
35+
#define AT91_AIC_SRCTYPE_RISING (3 << 5)
36+
37+
struct aic_chip_data {
38+
u32 ext_irqs;
39+
};
40+
41+
static void aic_common_shutdown(struct irq_data *d)
42+
{
43+
struct irq_chip_type *ct = irq_data_get_chip_type(d);
44+
45+
ct->chip.irq_mask(d);
46+
}
47+
48+
int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val)
49+
{
50+
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
51+
struct aic_chip_data *aic = gc->private;
52+
unsigned aic_type;
53+
54+
switch (type) {
55+
case IRQ_TYPE_LEVEL_HIGH:
56+
aic_type = AT91_AIC_SRCTYPE_HIGH;
57+
break;
58+
case IRQ_TYPE_EDGE_RISING:
59+
aic_type = AT91_AIC_SRCTYPE_RISING;
60+
break;
61+
case IRQ_TYPE_LEVEL_LOW:
62+
if (!(d->mask & aic->ext_irqs))
63+
return -EINVAL;
64+
65+
aic_type = AT91_AIC_SRCTYPE_LOW;
66+
break;
67+
case IRQ_TYPE_EDGE_FALLING:
68+
if (!(d->mask & aic->ext_irqs))
69+
return -EINVAL;
70+
71+
aic_type = AT91_AIC_SRCTYPE_FALLING;
72+
break;
73+
default:
74+
return -EINVAL;
75+
}
76+
77+
*val &= AT91_AIC_SRCTYPE;
78+
*val |= aic_type;
79+
80+
return 0;
81+
}
82+
83+
int aic_common_set_priority(int priority, unsigned *val)
84+
{
85+
if (priority < AT91_AIC_IRQ_MIN_PRIORITY ||
86+
priority > AT91_AIC_IRQ_MAX_PRIORITY)
87+
return -EINVAL;
88+
89+
*val &= AT91_AIC_PRIOR;
90+
*val |= priority;
91+
92+
return 0;
93+
}
94+
95+
int aic_common_irq_domain_xlate(struct irq_domain *d,
96+
struct device_node *ctrlr,
97+
const u32 *intspec,
98+
unsigned int intsize,
99+
irq_hw_number_t *out_hwirq,
100+
unsigned int *out_type)
101+
{
102+
if (WARN_ON(intsize < 3))
103+
return -EINVAL;
104+
105+
if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY) ||
106+
(intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
107+
return -EINVAL;
108+
109+
*out_hwirq = intspec[0];
110+
*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
111+
112+
return 0;
113+
}
114+
115+
static void __init aic_common_ext_irq_of_init(struct irq_domain *domain)
116+
{
117+
struct device_node *node = domain->of_node;
118+
struct irq_chip_generic *gc;
119+
struct aic_chip_data *aic;
120+
struct property *prop;
121+
const __be32 *p;
122+
u32 hwirq;
123+
124+
gc = irq_get_domain_generic_chip(domain, 0);
125+
126+
aic = gc->private;
127+
aic->ext_irqs |= 1;
128+
129+
of_property_for_each_u32(node, "atmel,external-irqs", prop, p, hwirq) {
130+
gc = irq_get_domain_generic_chip(domain, hwirq);
131+
if (!gc) {
132+
pr_warn("AIC: external irq %d >= %d skip it\n",
133+
hwirq, domain->revmap_size);
134+
continue;
135+
}
136+
137+
aic = gc->private;
138+
aic->ext_irqs |= (1 << (hwirq % 32));
139+
}
140+
}
141+
142+
struct irq_domain *__init aic_common_of_init(struct device_node *node,
143+
const struct irq_domain_ops *ops,
144+
const char *name, int nirqs)
145+
{
146+
struct irq_chip_generic *gc;
147+
struct irq_domain *domain;
148+
struct aic_chip_data *aic;
149+
void __iomem *reg_base;
150+
int nchips;
151+
int ret;
152+
int i;
153+
154+
nchips = DIV_ROUND_UP(nirqs, 32);
155+
156+
reg_base = of_iomap(node, 0);
157+
if (!reg_base)
158+
return ERR_PTR(-ENOMEM);
159+
160+
aic = kcalloc(nchips, sizeof(*aic), GFP_KERNEL);
161+
if (!aic) {
162+
ret = -ENOMEM;
163+
goto err_iounmap;
164+
}
165+
166+
domain = irq_domain_add_linear(node, nchips * 32, ops, aic);
167+
if (!domain) {
168+
ret = -ENOMEM;
169+
goto err_free_aic;
170+
}
171+
172+
ret = irq_alloc_domain_generic_chips(domain, 32, 1, name,
173+
handle_level_irq, 0, 0,
174+
IRQCHIP_SKIP_SET_WAKE);
175+
if (ret)
176+
goto err_domain_remove;
177+
178+
for (i = 0; i < nchips; i++) {
179+
gc = irq_get_domain_generic_chip(domain, i * 32);
180+
181+
gc->reg_base = reg_base;
182+
183+
gc->unused = 0;
184+
gc->wake_enabled = ~0;
185+
gc->chip_types[0].type = IRQ_TYPE_SENSE_MASK;
186+
gc->chip_types[0].handler = handle_fasteoi_irq;
187+
gc->chip_types[0].chip.irq_eoi = irq_gc_eoi;
188+
gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
189+
gc->chip_types[0].chip.irq_shutdown = aic_common_shutdown;
190+
gc->private = &aic[i];
191+
}
192+
193+
aic_common_ext_irq_of_init(domain);
194+
195+
return domain;
196+
197+
err_domain_remove:
198+
irq_domain_remove(domain);
199+
200+
err_free_aic:
201+
kfree(aic);
202+
203+
err_iounmap:
204+
iounmap(reg_base);
205+
206+
return ERR_PTR(ret);
207+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Atmel AT91 common AIC (Advanced Interrupt Controller) header file
3+
*
4+
* Copyright (C) 2004 SAN People
5+
* Copyright (C) 2004 ATMEL
6+
* Copyright (C) Rick Bronson
7+
* Copyright (C) 2014 Free Electrons
8+
*
9+
* Author: Boris BREZILLON <[email protected]>
10+
*
11+
* This file is licensed under the terms of the GNU General Public
12+
* License version 2. This program is licensed "as is" without any
13+
* warranty of any kind, whether express or implied.
14+
*/
15+
16+
#ifndef __IRQ_ATMEL_AIC_COMMON_H
17+
#define __IRQ_ATMEL_AIC_COMMON_H
18+
19+
20+
int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val);
21+
22+
int aic_common_set_priority(int priority, unsigned *val);
23+
24+
int aic_common_irq_domain_xlate(struct irq_domain *d,
25+
struct device_node *ctrlr,
26+
const u32 *intspec,
27+
unsigned int intsize,
28+
irq_hw_number_t *out_hwirq,
29+
unsigned int *out_type);
30+
31+
struct irq_domain *__init aic_common_of_init(struct device_node *node,
32+
const struct irq_domain_ops *ops,
33+
const char *name, int nirqs);
34+
35+
#endif /* __IRQ_ATMEL_AIC_COMMON_H */

0 commit comments

Comments
 (0)