2 * SPEAr platform shared irq layer source file
4 * Copyright (C) 2009-2012 ST Microelectronics
5 * Viresh Kumar <vireshk@kernel.org>
7 * Copyright (C) 2012 ST Microelectronics
8 * Shiraz Hashim <shiraz.linux.kernel@gmail.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/irqchip.h>
22 #include <linux/irqdomain.h>
24 #include <linux/of_address.h>
25 #include <linux/of_irq.h>
26 #include <linux/spinlock.h>
29 * struct spear_shirq: shared irq structure
31 * base: Base register address
32 * status_reg: Status register offset for chained interrupt handler
33 * mask_reg: Mask register offset for irq chip
34 * mask: Mask to apply to the status register
35 * virq_base: Base virtual interrupt number
36 * nr_irqs: Number of interrupts handled by this block
37 * offset: Bit offset of the first interrupt
38 * irq_chip: Interrupt controller chip used for this instance,
39 * if NULL group is disabled, but accounted
49 struct irq_chip
*irq_chip
;
52 /* spear300 shared irq registers offsets and masks */
53 #define SPEAR300_INT_ENB_MASK_REG 0x54
54 #define SPEAR300_INT_STS_MASK_REG 0x58
56 static DEFINE_RAW_SPINLOCK(shirq_lock
);
58 static void shirq_irq_mask(struct irq_data
*d
)
60 struct spear_shirq
*shirq
= irq_data_get_irq_chip_data(d
);
61 u32 val
, shift
= d
->irq
- shirq
->virq_base
+ shirq
->offset
;
62 u32 __iomem
*reg
= shirq
->base
+ shirq
->mask_reg
;
64 raw_spin_lock(&shirq_lock
);
65 val
= readl(reg
) & ~(0x1 << shift
);
67 raw_spin_unlock(&shirq_lock
);
70 static void shirq_irq_unmask(struct irq_data
*d
)
72 struct spear_shirq
*shirq
= irq_data_get_irq_chip_data(d
);
73 u32 val
, shift
= d
->irq
- shirq
->virq_base
+ shirq
->offset
;
74 u32 __iomem
*reg
= shirq
->base
+ shirq
->mask_reg
;
76 raw_spin_lock(&shirq_lock
);
77 val
= readl(reg
) | (0x1 << shift
);
79 raw_spin_unlock(&shirq_lock
);
82 static struct irq_chip shirq_chip
= {
83 .name
= "spear-shirq",
84 .irq_mask
= shirq_irq_mask
,
85 .irq_unmask
= shirq_irq_unmask
,
88 static struct spear_shirq spear300_shirq_ras1
= {
91 .mask
= ((0x1 << 9) - 1) << 0,
92 .irq_chip
= &shirq_chip
,
93 .status_reg
= SPEAR300_INT_STS_MASK_REG
,
94 .mask_reg
= SPEAR300_INT_ENB_MASK_REG
,
97 static struct spear_shirq
*spear300_shirq_blocks
[] = {
101 /* spear310 shared irq registers offsets and masks */
102 #define SPEAR310_INT_STS_MASK_REG 0x04
104 static struct spear_shirq spear310_shirq_ras1
= {
107 .mask
= ((0x1 << 8) - 1) << 0,
108 .irq_chip
= &dummy_irq_chip
,
109 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
112 static struct spear_shirq spear310_shirq_ras2
= {
115 .mask
= ((0x1 << 5) - 1) << 8,
116 .irq_chip
= &dummy_irq_chip
,
117 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
120 static struct spear_shirq spear310_shirq_ras3
= {
123 .mask
= ((0x1 << 1) - 1) << 13,
124 .irq_chip
= &dummy_irq_chip
,
125 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
128 static struct spear_shirq spear310_shirq_intrcomm_ras
= {
131 .mask
= ((0x1 << 3) - 1) << 14,
132 .irq_chip
= &dummy_irq_chip
,
133 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
136 static struct spear_shirq
*spear310_shirq_blocks
[] = {
137 &spear310_shirq_ras1
,
138 &spear310_shirq_ras2
,
139 &spear310_shirq_ras3
,
140 &spear310_shirq_intrcomm_ras
,
143 /* spear320 shared irq registers offsets and masks */
144 #define SPEAR320_INT_STS_MASK_REG 0x04
145 #define SPEAR320_INT_CLR_MASK_REG 0x04
146 #define SPEAR320_INT_ENB_MASK_REG 0x08
148 static struct spear_shirq spear320_shirq_ras3
= {
151 .mask
= ((0x1 << 7) - 1) << 0,
154 static struct spear_shirq spear320_shirq_ras1
= {
157 .mask
= ((0x1 << 3) - 1) << 7,
158 .irq_chip
= &dummy_irq_chip
,
159 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
162 static struct spear_shirq spear320_shirq_ras2
= {
165 .mask
= ((0x1 << 1) - 1) << 10,
166 .irq_chip
= &dummy_irq_chip
,
167 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
170 static struct spear_shirq spear320_shirq_intrcomm_ras
= {
173 .mask
= ((0x1 << 11) - 1) << 11,
174 .irq_chip
= &dummy_irq_chip
,
175 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
178 static struct spear_shirq
*spear320_shirq_blocks
[] = {
179 &spear320_shirq_ras3
,
180 &spear320_shirq_ras1
,
181 &spear320_shirq_ras2
,
182 &spear320_shirq_intrcomm_ras
,
185 static void shirq_handler(struct irq_desc
*desc
)
187 struct spear_shirq
*shirq
= irq_desc_get_handler_data(desc
);
190 pend
= readl(shirq
->base
+ shirq
->status_reg
) & shirq
->mask
;
191 pend
>>= shirq
->offset
;
194 int irq
= __ffs(pend
);
196 pend
&= ~(0x1 << irq
);
197 generic_handle_irq(shirq
->virq_base
+ irq
);
201 static void __init
spear_shirq_register(struct spear_shirq
*shirq
,
206 if (!shirq
->irq_chip
)
209 irq_set_chained_handler_and_data(parent_irq
, shirq_handler
, shirq
);
211 for (i
= 0; i
< shirq
->nr_irqs
; i
++) {
212 irq_set_chip_and_handler(shirq
->virq_base
+ i
,
213 shirq
->irq_chip
, handle_simple_irq
);
214 irq_set_chip_data(shirq
->virq_base
+ i
, shirq
);
218 static int __init
shirq_init(struct spear_shirq
**shirq_blocks
, int block_nr
,
219 struct device_node
*np
)
221 int i
, parent_irq
, virq_base
, hwirq
= 0, nr_irqs
= 0;
222 struct irq_domain
*shirq_domain
;
225 base
= of_iomap(np
, 0);
227 pr_err("%s: failed to map shirq registers\n", __func__
);
231 for (i
= 0; i
< block_nr
; i
++)
232 nr_irqs
+= shirq_blocks
[i
]->nr_irqs
;
234 virq_base
= irq_alloc_descs(-1, 0, nr_irqs
, 0);
235 if (IS_ERR_VALUE(virq_base
)) {
236 pr_err("%s: irq desc alloc failed\n", __func__
);
240 shirq_domain
= irq_domain_add_legacy(np
, nr_irqs
, virq_base
, 0,
241 &irq_domain_simple_ops
, NULL
);
242 if (WARN_ON(!shirq_domain
)) {
243 pr_warn("%s: irq domain init failed\n", __func__
);
247 for (i
= 0; i
< block_nr
; i
++) {
248 shirq_blocks
[i
]->base
= base
;
249 shirq_blocks
[i
]->virq_base
= irq_find_mapping(shirq_domain
,
252 parent_irq
= irq_of_parse_and_map(np
, i
);
253 spear_shirq_register(shirq_blocks
[i
], parent_irq
);
254 hwirq
+= shirq_blocks
[i
]->nr_irqs
;
260 irq_free_descs(virq_base
, nr_irqs
);
266 static int __init
spear300_shirq_of_init(struct device_node
*np
,
267 struct device_node
*parent
)
269 return shirq_init(spear300_shirq_blocks
,
270 ARRAY_SIZE(spear300_shirq_blocks
), np
);
272 IRQCHIP_DECLARE(spear300_shirq
, "st,spear300-shirq", spear300_shirq_of_init
);
274 static int __init
spear310_shirq_of_init(struct device_node
*np
,
275 struct device_node
*parent
)
277 return shirq_init(spear310_shirq_blocks
,
278 ARRAY_SIZE(spear310_shirq_blocks
), np
);
280 IRQCHIP_DECLARE(spear310_shirq
, "st,spear310-shirq", spear310_shirq_of_init
);
282 static int __init
spear320_shirq_of_init(struct device_node
*np
,
283 struct device_node
*parent
)
285 return shirq_init(spear320_shirq_blocks
,
286 ARRAY_SIZE(spear320_shirq_blocks
), np
);
288 IRQCHIP_DECLARE(spear320_shirq
, "st,spear320-shirq", spear320_shirq_of_init
);