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.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/irqdomain.h>
23 #include <linux/of_address.h>
24 #include <linux/of_irq.h>
25 #include <linux/spinlock.h>
30 * struct spear_shirq: shared irq structure
32 * base: Base register address
33 * status_reg: Status register offset for chained interrupt handler
34 * mask_reg: Mask register offset for irq chip
35 * mask: Mask to apply to the status register
36 * virq_base: Base virtual interrupt number
37 * nr_irqs: Number of interrupts handled by this block
38 * offset: Bit offset of the first interrupt
39 * irq_chip: Interrupt controller chip used for this instance,
40 * if NULL group is disabled, but accounted
50 struct irq_chip
*irq_chip
;
53 /* spear300 shared irq registers offsets and masks */
54 #define SPEAR300_INT_ENB_MASK_REG 0x54
55 #define SPEAR300_INT_STS_MASK_REG 0x58
57 static DEFINE_RAW_SPINLOCK(shirq_lock
);
59 static void shirq_irq_mask(struct irq_data
*d
)
61 struct spear_shirq
*shirq
= irq_data_get_irq_chip_data(d
);
62 u32 val
, shift
= d
->irq
- shirq
->virq_base
+ shirq
->offset
;
63 u32 __iomem
*reg
= shirq
->base
+ shirq
->mask_reg
;
65 raw_spin_lock(&shirq_lock
);
66 val
= readl(reg
) & ~(0x1 << shift
);
68 raw_spin_unlock(&shirq_lock
);
71 static void shirq_irq_unmask(struct irq_data
*d
)
73 struct spear_shirq
*shirq
= irq_data_get_irq_chip_data(d
);
74 u32 val
, shift
= d
->irq
- shirq
->virq_base
+ shirq
->offset
;
75 u32 __iomem
*reg
= shirq
->base
+ shirq
->mask_reg
;
77 raw_spin_lock(&shirq_lock
);
78 val
= readl(reg
) | (0x1 << shift
);
80 raw_spin_unlock(&shirq_lock
);
83 static struct irq_chip shirq_chip
= {
84 .name
= "spear-shirq",
85 .irq_mask
= shirq_irq_mask
,
86 .irq_unmask
= shirq_irq_unmask
,
89 static struct spear_shirq spear300_shirq_ras1
= {
92 .mask
= ((0x1 << 9) - 1) << 0,
93 .irq_chip
= &shirq_chip
,
94 .status_reg
= SPEAR300_INT_STS_MASK_REG
,
95 .mask_reg
= SPEAR300_INT_ENB_MASK_REG
,
98 static struct spear_shirq
*spear300_shirq_blocks
[] = {
102 /* spear310 shared irq registers offsets and masks */
103 #define SPEAR310_INT_STS_MASK_REG 0x04
105 static struct spear_shirq spear310_shirq_ras1
= {
108 .mask
= ((0x1 << 8) - 1) << 0,
109 .irq_chip
= &dummy_irq_chip
,
110 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
113 static struct spear_shirq spear310_shirq_ras2
= {
116 .mask
= ((0x1 << 5) - 1) << 8,
117 .irq_chip
= &dummy_irq_chip
,
118 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
121 static struct spear_shirq spear310_shirq_ras3
= {
124 .mask
= ((0x1 << 1) - 1) << 13,
125 .irq_chip
= &dummy_irq_chip
,
126 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
129 static struct spear_shirq spear310_shirq_intrcomm_ras
= {
132 .mask
= ((0x1 << 3) - 1) << 14,
133 .irq_chip
= &dummy_irq_chip
,
134 .status_reg
= SPEAR310_INT_STS_MASK_REG
,
137 static struct spear_shirq
*spear310_shirq_blocks
[] = {
138 &spear310_shirq_ras1
,
139 &spear310_shirq_ras2
,
140 &spear310_shirq_ras3
,
141 &spear310_shirq_intrcomm_ras
,
144 /* spear320 shared irq registers offsets and masks */
145 #define SPEAR320_INT_STS_MASK_REG 0x04
146 #define SPEAR320_INT_CLR_MASK_REG 0x04
147 #define SPEAR320_INT_ENB_MASK_REG 0x08
149 static struct spear_shirq spear320_shirq_ras3
= {
152 .mask
= ((0x1 << 7) - 1) << 0,
155 static struct spear_shirq spear320_shirq_ras1
= {
158 .mask
= ((0x1 << 3) - 1) << 7,
159 .irq_chip
= &dummy_irq_chip
,
160 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
163 static struct spear_shirq spear320_shirq_ras2
= {
166 .mask
= ((0x1 << 1) - 1) << 10,
167 .irq_chip
= &dummy_irq_chip
,
168 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
171 static struct spear_shirq spear320_shirq_intrcomm_ras
= {
174 .mask
= ((0x1 << 11) - 1) << 11,
175 .irq_chip
= &dummy_irq_chip
,
176 .status_reg
= SPEAR320_INT_STS_MASK_REG
,
179 static struct spear_shirq
*spear320_shirq_blocks
[] = {
180 &spear320_shirq_ras3
,
181 &spear320_shirq_ras1
,
182 &spear320_shirq_ras2
,
183 &spear320_shirq_intrcomm_ras
,
186 static void shirq_handler(unsigned irq
, struct irq_desc
*desc
)
188 struct spear_shirq
*shirq
= irq_get_handler_data(irq
);
191 pend
= readl(shirq
->base
+ shirq
->status_reg
) & shirq
->mask
;
192 pend
>>= shirq
->offset
;
195 int irq
= __ffs(pend
);
197 pend
&= ~(0x1 << irq
);
198 generic_handle_irq(shirq
->virq_base
+ irq
);
202 static void __init
spear_shirq_register(struct spear_shirq
*shirq
,
207 if (!shirq
->irq_chip
)
210 irq_set_chained_handler_and_data(parent_irq
, shirq_handler
, shirq
);
212 for (i
= 0; i
< shirq
->nr_irqs
; i
++) {
213 irq_set_chip_and_handler(shirq
->virq_base
+ i
,
214 shirq
->irq_chip
, handle_simple_irq
);
215 set_irq_flags(shirq
->virq_base
+ i
, IRQF_VALID
);
216 irq_set_chip_data(shirq
->virq_base
+ i
, shirq
);
220 static int __init
shirq_init(struct spear_shirq
**shirq_blocks
, int block_nr
,
221 struct device_node
*np
)
223 int i
, parent_irq
, virq_base
, hwirq
= 0, nr_irqs
= 0;
224 struct irq_domain
*shirq_domain
;
227 base
= of_iomap(np
, 0);
229 pr_err("%s: failed to map shirq registers\n", __func__
);
233 for (i
= 0; i
< block_nr
; i
++)
234 nr_irqs
+= shirq_blocks
[i
]->nr_irqs
;
236 virq_base
= irq_alloc_descs(-1, 0, nr_irqs
, 0);
237 if (IS_ERR_VALUE(virq_base
)) {
238 pr_err("%s: irq desc alloc failed\n", __func__
);
242 shirq_domain
= irq_domain_add_legacy(np
, nr_irqs
, virq_base
, 0,
243 &irq_domain_simple_ops
, NULL
);
244 if (WARN_ON(!shirq_domain
)) {
245 pr_warn("%s: irq domain init failed\n", __func__
);
249 for (i
= 0; i
< block_nr
; i
++) {
250 shirq_blocks
[i
]->base
= base
;
251 shirq_blocks
[i
]->virq_base
= irq_find_mapping(shirq_domain
,
254 parent_irq
= irq_of_parse_and_map(np
, i
);
255 spear_shirq_register(shirq_blocks
[i
], parent_irq
);
256 hwirq
+= shirq_blocks
[i
]->nr_irqs
;
262 irq_free_descs(virq_base
, nr_irqs
);
268 static int __init
spear300_shirq_of_init(struct device_node
*np
,
269 struct device_node
*parent
)
271 return shirq_init(spear300_shirq_blocks
,
272 ARRAY_SIZE(spear300_shirq_blocks
), np
);
274 IRQCHIP_DECLARE(spear300_shirq
, "st,spear300-shirq", spear300_shirq_of_init
);
276 static int __init
spear310_shirq_of_init(struct device_node
*np
,
277 struct device_node
*parent
)
279 return shirq_init(spear310_shirq_blocks
,
280 ARRAY_SIZE(spear310_shirq_blocks
), np
);
282 IRQCHIP_DECLARE(spear310_shirq
, "st,spear310-shirq", spear310_shirq_of_init
);
284 static int __init
spear320_shirq_of_init(struct device_node
*np
,
285 struct device_node
*parent
)
287 return shirq_init(spear320_shirq_blocks
,
288 ARRAY_SIZE(spear320_shirq_blocks
), np
);
290 IRQCHIP_DECLARE(spear320_shirq
, "st,spear320-shirq", spear320_shirq_of_init
);