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(6, 5)
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 void aic_common_set_priority(int priority
, unsigned *val
)
85 *val
&= ~AT91_AIC_PRIOR
;
89 int aic_common_irq_domain_xlate(struct irq_domain
*d
,
90 struct device_node
*ctrlr
,
93 irq_hw_number_t
*out_hwirq
,
94 unsigned int *out_type
)
96 if (WARN_ON(intsize
< 3))
99 if (WARN_ON((intspec
[2] < AT91_AIC_IRQ_MIN_PRIORITY
) ||
100 (intspec
[2] > AT91_AIC_IRQ_MAX_PRIORITY
)))
103 *out_hwirq
= intspec
[0];
104 *out_type
= intspec
[1] & IRQ_TYPE_SENSE_MASK
;
109 static void __init
aic_common_ext_irq_of_init(struct irq_domain
*domain
)
111 struct device_node
*node
= irq_domain_get_of_node(domain
);
112 struct irq_chip_generic
*gc
;
113 struct aic_chip_data
*aic
;
114 struct property
*prop
;
118 gc
= irq_get_domain_generic_chip(domain
, 0);
123 of_property_for_each_u32(node
, "atmel,external-irqs", prop
, p
, hwirq
) {
124 gc
= irq_get_domain_generic_chip(domain
, hwirq
);
126 pr_warn("AIC: external irq %d >= %d skip it\n",
127 hwirq
, domain
->revmap_size
);
132 aic
->ext_irqs
|= (1 << (hwirq
% 32));
136 #define AT91_RTC_IDR 0x24
137 #define AT91_RTC_IMR 0x28
138 #define AT91_RTC_IRQ_MASK 0x1f
140 void __init
aic_common_rtc_irq_fixup(struct device_node
*root
)
142 struct device_node
*np
;
145 np
= of_find_compatible_node(root
, NULL
, "atmel,at91rm9200-rtc");
147 np
= of_find_compatible_node(root
, NULL
,
148 "atmel,at91sam9x5-rtc");
153 regs
= of_iomap(np
, 0);
159 writel(AT91_RTC_IRQ_MASK
, regs
+ AT91_RTC_IDR
);
164 #define AT91_RTT_MR 0x00 /* Real-time Mode Register */
165 #define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */
166 #define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */
168 void __init
aic_common_rtt_irq_fixup(struct device_node
*root
)
170 struct device_node
*np
;
174 * The at91sam9263 SoC has 2 instances of the RTT block, hence we
175 * iterate over the DT to find each occurrence.
177 for_each_compatible_node(np
, NULL
, "atmel,at91sam9260-rtt") {
178 regs
= of_iomap(np
, 0);
182 writel(readl(regs
+ AT91_RTT_MR
) &
183 ~(AT91_RTT_ALMIEN
| AT91_RTT_RTTINCIEN
),
190 static void __init
aic_common_irq_fixup(const struct of_device_id
*matches
)
192 struct device_node
*root
= of_find_node_by_path("/");
193 const struct of_device_id
*match
;
198 match
= of_match_node(matches
, root
);
202 void (*fixup
)(struct device_node
*) = match
->data
;
209 struct irq_domain
*__init
aic_common_of_init(struct device_node
*node
,
210 const struct irq_domain_ops
*ops
,
211 const char *name
, int nirqs
,
212 const struct of_device_id
*matches
)
214 struct irq_chip_generic
*gc
;
215 struct irq_domain
*domain
;
216 struct aic_chip_data
*aic
;
217 void __iomem
*reg_base
;
222 nchips
= DIV_ROUND_UP(nirqs
, 32);
224 reg_base
= of_iomap(node
, 0);
226 return ERR_PTR(-ENOMEM
);
228 aic
= kcalloc(nchips
, sizeof(*aic
), GFP_KERNEL
);
234 domain
= irq_domain_add_linear(node
, nchips
* 32, ops
, aic
);
240 ret
= irq_alloc_domain_generic_chips(domain
, 32, 1, name
,
242 IRQ_NOREQUEST
| IRQ_NOPROBE
|
245 goto err_domain_remove
;
247 for (i
= 0; i
< nchips
; i
++) {
248 gc
= irq_get_domain_generic_chip(domain
, i
* 32);
250 gc
->reg_base
= reg_base
;
253 gc
->wake_enabled
= ~0;
254 gc
->chip_types
[0].type
= IRQ_TYPE_SENSE_MASK
;
255 gc
->chip_types
[0].chip
.irq_eoi
= irq_gc_eoi
;
256 gc
->chip_types
[0].chip
.irq_set_wake
= irq_gc_set_wake
;
257 gc
->chip_types
[0].chip
.irq_shutdown
= aic_common_shutdown
;
258 gc
->private = &aic
[i
];
261 aic_common_ext_irq_of_init(domain
);
262 aic_common_irq_fixup(matches
);
267 irq_domain_remove(domain
);