2 * SPEAr platform shared irq layer source file
4 * Copyright (C) 2009-2012 ST Microelectronics
5 * Viresh Kumar <viresh.linux@gmail.com>
7 * Copyright (C) 2012 ST Microelectronics
8 * Shiraz Hashim <shiraz.hashim@st.com>
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 #include <linux/err.h>
17 #include <linux/export.h>
18 #include <linux/interrupt.h>
20 #include <linux/irq.h>
21 #include <linux/irqdomain.h>
22 #include <linux/irqchip/spear-shirq.h>
24 #include <linux/of_address.h>
25 #include <linux/of_irq.h>
26 #include <linux/spinlock.h>
30 static DEFINE_SPINLOCK(lock
);
32 /* spear300 shared irq registers offsets and masks */
33 #define SPEAR300_INT_ENB_MASK_REG 0x54
34 #define SPEAR300_INT_STS_MASK_REG 0x58
36 static struct spear_shirq spear300_shirq_ras1
= {
40 .enb_reg
= SPEAR300_INT_ENB_MASK_REG
,
41 .status_reg
= SPEAR300_INT_STS_MASK_REG
,
46 static struct spear_shirq
*spear300_shirq_blocks
[] = {
50 /* spear310 shared irq registers offsets and masks */
51 #define SPEAR310_INT_STS_MASK_REG 0x04
53 static struct spear_shirq spear310_shirq_ras1
= {
58 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
63 static struct spear_shirq spear310_shirq_ras2
= {
68 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
73 static struct spear_shirq spear310_shirq_ras3
= {
78 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
83 static struct spear_shirq spear310_shirq_intrcomm_ras
= {
88 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
93 static struct spear_shirq
*spear310_shirq_blocks
[] = {
97 &spear310_shirq_intrcomm_ras
,
100 /* spear320 shared irq registers offsets and masks */
101 #define SPEAR320_INT_STS_MASK_REG 0x04
102 #define SPEAR320_INT_CLR_MASK_REG 0x04
103 #define SPEAR320_INT_ENB_MASK_REG 0x08
105 static struct spear_shirq spear320_shirq_ras1
= {
110 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
111 .clear_reg
= SPEAR320_INT_CLR_MASK_REG
,
116 static struct spear_shirq spear320_shirq_ras2
= {
121 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
122 .clear_reg
= SPEAR320_INT_CLR_MASK_REG
,
127 static struct spear_shirq spear320_shirq_ras3
= {
132 .enb_reg
= SPEAR320_INT_ENB_MASK_REG
,
134 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
135 .clear_reg
= SPEAR320_INT_CLR_MASK_REG
,
140 static struct spear_shirq spear320_shirq_intrcomm_ras
= {
145 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
146 .clear_reg
= SPEAR320_INT_CLR_MASK_REG
,
151 static struct spear_shirq
*spear320_shirq_blocks
[] = {
152 &spear320_shirq_ras3
,
153 &spear320_shirq_ras1
,
154 &spear320_shirq_ras2
,
155 &spear320_shirq_intrcomm_ras
,
158 static void shirq_irq_mask_unmask(struct irq_data
*d
, bool mask
)
160 struct spear_shirq
*shirq
= irq_data_get_irq_chip_data(d
);
161 u32 val
, offset
= d
->irq
- shirq
->irq_base
;
164 if (shirq
->regs
.enb_reg
== -1)
167 spin_lock_irqsave(&lock
, flags
);
168 val
= readl(shirq
->base
+ shirq
->regs
.enb_reg
);
170 if (mask
^ shirq
->regs
.reset_to_enb
)
171 val
&= ~(0x1 << shirq
->irq_bit_off
<< offset
);
173 val
|= 0x1 << shirq
->irq_bit_off
<< offset
;
175 writel(val
, shirq
->base
+ shirq
->regs
.enb_reg
);
176 spin_unlock_irqrestore(&lock
, flags
);
180 static void shirq_irq_mask(struct irq_data
*d
)
182 shirq_irq_mask_unmask(d
, 1);
185 static void shirq_irq_unmask(struct irq_data
*d
)
187 shirq_irq_mask_unmask(d
, 0);
190 static struct irq_chip shirq_chip
= {
191 .name
= "spear-shirq",
192 .irq_ack
= shirq_irq_mask
,
193 .irq_mask
= shirq_irq_mask
,
194 .irq_unmask
= shirq_irq_unmask
,
197 static void shirq_handler(unsigned irq
, struct irq_desc
*desc
)
199 u32 i
, j
, val
, mask
, tmp
;
200 struct irq_chip
*chip
;
201 struct spear_shirq
*shirq
= irq_get_handler_data(irq
);
203 chip
= irq_get_chip(irq
);
204 chip
->irq_ack(&desc
->irq_data
);
206 mask
= ((0x1 << shirq
->irq_nr
) - 1) << shirq
->irq_bit_off
;
207 while ((val
= readl(shirq
->base
+ shirq
->regs
.status_reg
) &
210 val
>>= shirq
->irq_bit_off
;
211 for (i
= 0, j
= 1; i
< shirq
->irq_nr
; i
++, j
<<= 1) {
216 generic_handle_irq(shirq
->irq_base
+ i
);
218 /* clear interrupt */
219 if (shirq
->regs
.clear_reg
== -1)
222 tmp
= readl(shirq
->base
+ shirq
->regs
.clear_reg
);
223 if (shirq
->regs
.reset_to_clear
)
224 tmp
&= ~(j
<< shirq
->irq_bit_off
);
226 tmp
|= (j
<< shirq
->irq_bit_off
);
227 writel(tmp
, shirq
->base
+ shirq
->regs
.clear_reg
);
230 chip
->irq_unmask(&desc
->irq_data
);
233 static void __init
spear_shirq_register(struct spear_shirq
*shirq
)
237 if (shirq
->invalid_irq
)
240 irq_set_chained_handler(shirq
->irq
, shirq_handler
);
241 for (i
= 0; i
< shirq
->irq_nr
; i
++) {
242 irq_set_chip_and_handler(shirq
->irq_base
+ i
,
243 &shirq_chip
, handle_simple_irq
);
244 set_irq_flags(shirq
->irq_base
+ i
, IRQF_VALID
);
245 irq_set_chip_data(shirq
->irq_base
+ i
, shirq
);
248 irq_set_handler_data(shirq
->irq
, shirq
);
251 static int __init
shirq_init(struct spear_shirq
**shirq_blocks
, int block_nr
,
252 struct device_node
*np
)
254 int i
, irq_base
, hwirq
= 0, irq_nr
= 0;
255 static struct irq_domain
*shirq_domain
;
258 base
= of_iomap(np
, 0);
260 pr_err("%s: failed to map shirq registers\n", __func__
);
264 for (i
= 0; i
< block_nr
; i
++)
265 irq_nr
+= shirq_blocks
[i
]->irq_nr
;
267 irq_base
= irq_alloc_descs(-1, 0, irq_nr
, 0);
268 if (IS_ERR_VALUE(irq_base
)) {
269 pr_err("%s: irq desc alloc failed\n", __func__
);
273 shirq_domain
= irq_domain_add_legacy(np
, irq_nr
, irq_base
, 0,
274 &irq_domain_simple_ops
, NULL
);
275 if (WARN_ON(!shirq_domain
)) {
276 pr_warn("%s: irq domain init failed\n", __func__
);
280 for (i
= 0; i
< block_nr
; i
++) {
281 shirq_blocks
[i
]->base
= base
;
282 shirq_blocks
[i
]->irq_base
= irq_find_mapping(shirq_domain
,
284 shirq_blocks
[i
]->irq
= irq_of_parse_and_map(np
, i
);
286 spear_shirq_register(shirq_blocks
[i
]);
287 hwirq
+= shirq_blocks
[i
]->irq_nr
;
293 irq_free_descs(irq_base
, irq_nr
);
299 int __init
spear300_shirq_of_init(struct device_node
*np
,
300 struct device_node
*parent
)
302 return shirq_init(spear300_shirq_blocks
,
303 ARRAY_SIZE(spear300_shirq_blocks
), np
);
305 IRQCHIP_DECLARE(spear300_shirq
, "st,spear300-shirq", spear300_shirq_of_init
);
307 int __init
spear310_shirq_of_init(struct device_node
*np
,
308 struct device_node
*parent
)
310 return shirq_init(spear310_shirq_blocks
,
311 ARRAY_SIZE(spear310_shirq_blocks
), np
);
313 IRQCHIP_DECLARE(spear310_shirq
, "st,spear310-shirq", spear310_shirq_of_init
);
315 int __init
spear320_shirq_of_init(struct device_node
*np
,
316 struct device_node
*parent
)
318 return shirq_init(spear320_shirq_blocks
,
319 ARRAY_SIZE(spear320_shirq_blocks
), np
);
321 IRQCHIP_DECLARE(spear320_shirq
, "st,spear320-shirq", spear320_shirq_of_init
);