2 * Atmel AT91 common AIC (Advanced Interrupt Controller) code shared by
3 * irq-atmel-aic and irq-atmel-aic5 drivers
5 * Copyright (C) 2004 SAN People
6 * Copyright (C) 2004 ATMEL
7 * Copyright (C) Rick Bronson
8 * Copyright (C) 2014 Free Electrons
10 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
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.
17 #include <linux/errno.h>
19 #include <linux/irq.h>
20 #include <linux/irqdomain.h>
22 #include <linux/of_address.h>
23 #include <linux/slab.h>
25 #include "irq-atmel-aic-common.h"
27 #define AT91_AIC_PRIOR GENMASK(2, 0)
28 #define AT91_AIC_IRQ_MIN_PRIORITY 0
29 #define AT91_AIC_IRQ_MAX_PRIORITY 7
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)
37 struct aic_chip_data
{
41 static void aic_common_shutdown(struct irq_data
*d
)
43 struct irq_chip_type
*ct
= irq_data_get_chip_type(d
);
48 int aic_common_set_type(struct irq_data
*d
, unsigned type
, unsigned *val
)
50 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
51 struct aic_chip_data
*aic
= gc
->private;
55 case IRQ_TYPE_LEVEL_HIGH
:
56 aic_type
= AT91_AIC_SRCTYPE_HIGH
;
58 case IRQ_TYPE_EDGE_RISING
:
59 aic_type
= AT91_AIC_SRCTYPE_RISING
;
61 case IRQ_TYPE_LEVEL_LOW
:
62 if (!(d
->mask
& aic
->ext_irqs
))
65 aic_type
= AT91_AIC_SRCTYPE_LOW
;
67 case IRQ_TYPE_EDGE_FALLING
:
68 if (!(d
->mask
& aic
->ext_irqs
))
71 aic_type
= AT91_AIC_SRCTYPE_FALLING
;
77 *val
&= AT91_AIC_SRCTYPE
;
83 int aic_common_set_priority(int priority
, unsigned *val
)
85 if (priority
< AT91_AIC_IRQ_MIN_PRIORITY
||
86 priority
> AT91_AIC_IRQ_MAX_PRIORITY
)
89 *val
&= AT91_AIC_PRIOR
;
95 int aic_common_irq_domain_xlate(struct irq_domain
*d
,
96 struct device_node
*ctrlr
,
99 irq_hw_number_t
*out_hwirq
,
100 unsigned int *out_type
)
102 if (WARN_ON(intsize
< 3))
105 if (WARN_ON((intspec
[2] < AT91_AIC_IRQ_MIN_PRIORITY
) ||
106 (intspec
[2] > AT91_AIC_IRQ_MAX_PRIORITY
)))
109 *out_hwirq
= intspec
[0];
110 *out_type
= intspec
[1] & IRQ_TYPE_SENSE_MASK
;
115 static void __init
aic_common_ext_irq_of_init(struct irq_domain
*domain
)
117 struct device_node
*node
= domain
->of_node
;
118 struct irq_chip_generic
*gc
;
119 struct aic_chip_data
*aic
;
120 struct property
*prop
;
124 gc
= irq_get_domain_generic_chip(domain
, 0);
129 of_property_for_each_u32(node
, "atmel,external-irqs", prop
, p
, hwirq
) {
130 gc
= irq_get_domain_generic_chip(domain
, hwirq
);
132 pr_warn("AIC: external irq %d >= %d skip it\n",
133 hwirq
, domain
->revmap_size
);
138 aic
->ext_irqs
|= (1 << (hwirq
% 32));
142 #define AT91_RTC_IDR 0x24
143 #define AT91_RTC_IMR 0x28
144 #define AT91_RTC_IRQ_MASK 0x1f
146 void __init
aic_common_rtc_irq_fixup(struct device_node
*root
)
148 struct device_node
*np
;
151 np
= of_find_compatible_node(root
, NULL
, "atmel,at91rm9200-rtc");
153 np
= of_find_compatible_node(root
, NULL
,
154 "atmel,at91sam9x5-rtc");
159 regs
= of_iomap(np
, 0);
165 writel(AT91_RTC_IRQ_MASK
, regs
+ AT91_RTC_IDR
);
170 void __init
aic_common_irq_fixup(const struct of_device_id
*matches
)
172 struct device_node
*root
= of_find_node_by_path("/");
173 const struct of_device_id
*match
;
178 match
= of_match_node(matches
, root
);
182 void (*fixup
)(struct device_node
*) = match
->data
;
189 struct irq_domain
*__init
aic_common_of_init(struct device_node
*node
,
190 const struct irq_domain_ops
*ops
,
191 const char *name
, int nirqs
)
193 struct irq_chip_generic
*gc
;
194 struct irq_domain
*domain
;
195 struct aic_chip_data
*aic
;
196 void __iomem
*reg_base
;
201 nchips
= DIV_ROUND_UP(nirqs
, 32);
203 reg_base
= of_iomap(node
, 0);
205 return ERR_PTR(-ENOMEM
);
207 aic
= kcalloc(nchips
, sizeof(*aic
), GFP_KERNEL
);
213 domain
= irq_domain_add_linear(node
, nchips
* 32, ops
, aic
);
219 ret
= irq_alloc_domain_generic_chips(domain
, 32, 1, name
,
220 handle_level_irq
, 0, 0,
221 IRQCHIP_SKIP_SET_WAKE
);
223 goto err_domain_remove
;
225 for (i
= 0; i
< nchips
; i
++) {
226 gc
= irq_get_domain_generic_chip(domain
, i
* 32);
228 gc
->reg_base
= reg_base
;
231 gc
->wake_enabled
= ~0;
232 gc
->chip_types
[0].type
= IRQ_TYPE_SENSE_MASK
;
233 gc
->chip_types
[0].handler
= handle_fasteoi_irq
;
234 gc
->chip_types
[0].chip
.irq_eoi
= irq_gc_eoi
;
235 gc
->chip_types
[0].chip
.irq_set_wake
= irq_gc_set_wake
;
236 gc
->chip_types
[0].chip
.irq_shutdown
= aic_common_shutdown
;
237 gc
->private = &aic
[i
];
240 aic_common_ext_irq_of_init(domain
);
245 irq_domain_remove(domain
);