2 * arch/arm/mach-vt8500/irq.c
4 * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/irq.h>
23 #include <linux/interrupt.h>
29 #define VT8500_IC_DCTR 0x40 /* Destination control
31 #define VT8500_INT_ENABLE (1 << 3)
32 #define VT8500_TRIGGER_HIGH (0 << 4)
33 #define VT8500_TRIGGER_RISING (1 << 4)
34 #define VT8500_TRIGGER_FALLING (2 << 4)
35 #define VT8500_EDGE ( VT8500_TRIGGER_RISING \
36 | VT8500_TRIGGER_FALLING)
37 #define VT8500_IC_STATUS 0x80 /* Interrupt status, 2*u32 */
39 static void __iomem
*ic_regbase
;
40 static void __iomem
*sic_regbase
;
42 static void vt8500_irq_mask(struct irq_data
*d
)
44 void __iomem
*base
= ic_regbase
;
45 unsigned irq
= d
->irq
;
52 edge
= readb(base
+ VT8500_IC_DCTR
+ irq
) & VT8500_EDGE
;
54 void __iomem
*stat_reg
= base
+ VT8500_IC_STATUS
56 unsigned status
= readl(stat_reg
);
58 status
|= (1 << (irq
& 0x1f));
59 writel(status
, stat_reg
);
61 u8 dctr
= readb(base
+ VT8500_IC_DCTR
+ irq
);
63 dctr
&= ~VT8500_INT_ENABLE
;
64 writeb(dctr
, base
+ VT8500_IC_DCTR
+ irq
);
68 static void vt8500_irq_unmask(struct irq_data
*d
)
70 void __iomem
*base
= ic_regbase
;
71 unsigned irq
= d
->irq
;
78 dctr
= readb(base
+ VT8500_IC_DCTR
+ irq
);
79 dctr
|= VT8500_INT_ENABLE
;
80 writeb(dctr
, base
+ VT8500_IC_DCTR
+ irq
);
83 static int vt8500_irq_set_type(struct irq_data
*d
, unsigned int flow_type
)
85 void __iomem
*base
= ic_regbase
;
86 unsigned irq
= d
->irq
;
87 unsigned orig_irq
= irq
;
95 dctr
= readb(base
+ VT8500_IC_DCTR
+ irq
);
99 case IRQF_TRIGGER_LOW
:
101 case IRQF_TRIGGER_HIGH
:
102 dctr
|= VT8500_TRIGGER_HIGH
;
103 __irq_set_handler_locked(orig_irq
, handle_level_irq
);
105 case IRQF_TRIGGER_FALLING
:
106 dctr
|= VT8500_TRIGGER_FALLING
;
107 __irq_set_handler_locked(orig_irq
, handle_edge_irq
);
109 case IRQF_TRIGGER_RISING
:
110 dctr
|= VT8500_TRIGGER_RISING
;
111 __irq_set_handler_locked(orig_irq
, handle_edge_irq
);
114 writeb(dctr
, base
+ VT8500_IC_DCTR
+ irq
);
119 static struct irq_chip vt8500_irq_chip
= {
121 .irq_ack
= vt8500_irq_mask
,
122 .irq_mask
= vt8500_irq_mask
,
123 .irq_unmask
= vt8500_irq_unmask
,
124 .irq_set_type
= vt8500_irq_set_type
,
127 void __init
vt8500_init_irq(void)
131 ic_regbase
= ioremap(wmt_ic_base
, SZ_64K
);
134 /* Enable rotating priority for IRQ */
135 writel((1 << 6), ic_regbase
+ 0x20);
136 writel(0, ic_regbase
+ 0x24);
138 for (i
= 0; i
< wmt_nr_irqs
; i
++) {
139 /* Disable all interrupts and route them to IRQ */
140 writeb(0x00, ic_regbase
+ VT8500_IC_DCTR
+ i
);
142 irq_set_chip_and_handler(i
, &vt8500_irq_chip
,
144 set_irq_flags(i
, IRQF_VALID
);
147 printk(KERN_ERR
"Unable to remap the Interrupt Controller registers, not enabling IRQs!\n");
151 void __init
wm8505_init_irq(void)
155 ic_regbase
= ioremap(wmt_ic_base
, SZ_64K
);
156 sic_regbase
= ioremap(wmt_sic_base
, SZ_64K
);
158 if (ic_regbase
&& sic_regbase
) {
159 /* Enable rotating priority for IRQ */
160 writel((1 << 6), ic_regbase
+ 0x20);
161 writel(0, ic_regbase
+ 0x24);
162 writel((1 << 6), sic_regbase
+ 0x20);
163 writel(0, sic_regbase
+ 0x24);
165 for (i
= 0; i
< wmt_nr_irqs
; i
++) {
166 /* Disable all interrupts and route them to IRQ */
168 writeb(0x00, ic_regbase
+ VT8500_IC_DCTR
+ i
);
170 writeb(0x00, sic_regbase
+ VT8500_IC_DCTR
173 irq_set_chip_and_handler(i
, &vt8500_irq_chip
,
175 set_irq_flags(i
, IRQF_VALID
);
178 printk(KERN_ERR
"Unable to remap the Interrupt Controller registers, not enabling IRQs!\n");