2 * arch/arm/plat-spear/shirq.c
4 * SPEAr platform shared irq layer source file
6 * Copyright (C) 2009 ST Microelectronics
7 * Viresh Kumar <viresh.linux@gmail.com>
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
14 #include <linux/err.h>
16 #include <linux/irq.h>
17 #include <linux/spinlock.h>
18 #include <plat/shirq.h>
20 struct spear_shirq
*shirq
;
21 static DEFINE_SPINLOCK(lock
);
23 static void shirq_irq_mask(struct irq_data
*d
)
25 struct spear_shirq
*shirq
= irq_data_get_irq_chip_data(d
);
26 u32 val
, id
= d
->irq
- shirq
->dev_config
[0].virq
;
29 if ((shirq
->regs
.enb_reg
== -1) || shirq
->dev_config
[id
].enb_mask
== -1)
32 spin_lock_irqsave(&lock
, flags
);
33 val
= readl(shirq
->regs
.base
+ shirq
->regs
.enb_reg
);
34 if (shirq
->regs
.reset_to_enb
)
35 val
|= shirq
->dev_config
[id
].enb_mask
;
37 val
&= ~(shirq
->dev_config
[id
].enb_mask
);
38 writel(val
, shirq
->regs
.base
+ shirq
->regs
.enb_reg
);
39 spin_unlock_irqrestore(&lock
, flags
);
42 static void shirq_irq_unmask(struct irq_data
*d
)
44 struct spear_shirq
*shirq
= irq_data_get_irq_chip_data(d
);
45 u32 val
, id
= d
->irq
- shirq
->dev_config
[0].virq
;
48 if ((shirq
->regs
.enb_reg
== -1) || shirq
->dev_config
[id
].enb_mask
== -1)
51 spin_lock_irqsave(&lock
, flags
);
52 val
= readl(shirq
->regs
.base
+ shirq
->regs
.enb_reg
);
53 if (shirq
->regs
.reset_to_enb
)
54 val
&= ~(shirq
->dev_config
[id
].enb_mask
);
56 val
|= shirq
->dev_config
[id
].enb_mask
;
57 writel(val
, shirq
->regs
.base
+ shirq
->regs
.enb_reg
);
58 spin_unlock_irqrestore(&lock
, flags
);
61 static struct irq_chip shirq_chip
= {
62 .name
= "spear_shirq",
63 .irq_ack
= shirq_irq_mask
,
64 .irq_mask
= shirq_irq_mask
,
65 .irq_unmask
= shirq_irq_unmask
,
68 static void shirq_handler(unsigned irq
, struct irq_desc
*desc
)
71 struct spear_shirq
*shirq
= irq_get_handler_data(irq
);
73 desc
->irq_data
.chip
->irq_ack(&desc
->irq_data
);
74 while ((val
= readl(shirq
->regs
.base
+ shirq
->regs
.status_reg
) &
75 shirq
->regs
.status_reg_mask
)) {
76 for (i
= 0; (i
< shirq
->dev_count
) && val
; i
++) {
77 if (!(shirq
->dev_config
[i
].status_mask
& val
))
80 generic_handle_irq(shirq
->dev_config
[i
].virq
);
83 val
&= ~shirq
->dev_config
[i
].status_mask
;
84 if ((shirq
->regs
.clear_reg
== -1) ||
85 shirq
->dev_config
[i
].clear_mask
== -1)
87 mask
= readl(shirq
->regs
.base
+ shirq
->regs
.clear_reg
);
88 if (shirq
->regs
.reset_to_clear
)
89 mask
&= ~shirq
->dev_config
[i
].clear_mask
;
91 mask
|= shirq
->dev_config
[i
].clear_mask
;
92 writel(mask
, shirq
->regs
.base
+ shirq
->regs
.clear_reg
);
95 desc
->irq_data
.chip
->irq_unmask(&desc
->irq_data
);
98 int spear_shirq_register(struct spear_shirq
*shirq
)
102 if (!shirq
|| !shirq
->dev_config
|| !shirq
->regs
.base
)
105 if (!shirq
->dev_count
)
108 irq_set_chained_handler(shirq
->irq
, shirq_handler
);
109 for (i
= 0; i
< shirq
->dev_count
; i
++) {
110 irq_set_chip_and_handler(shirq
->dev_config
[i
].virq
,
111 &shirq_chip
, handle_simple_irq
);
112 set_irq_flags(shirq
->dev_config
[i
].virq
, IRQF_VALID
);
113 irq_set_chip_data(shirq
->dev_config
[i
].virq
, shirq
);
116 irq_set_handler_data(shirq
->irq
, shirq
);