2 * linux/arch/arm/plat-s5pc1xx/irq-eint.c
4 * Copyright 2009 Samsung Electronics Co.
5 * Byungho Min <bhmin@samsung.com>
6 * Kyungin Park <kyungmin.park@samsung.com>
8 * Based on plat-s3c64xx/irq-eint.c
10 * S5PC1XX - Interrupt handling for IRQ_EINT(x)
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
17 #include <linux/kernel.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
21 #include <linux/sysdev.h>
23 #include <linux/gpio.h>
25 #include <asm/hardware/vic.h>
29 #include <plat/gpio-cfg.h>
30 #include <plat/gpio-ext.h>
32 #include <plat/regs-gpio.h>
33 #include <plat/regs-irqtype.h>
36 * bank is a group of external interrupt
37 * bank0 means EINT0 ... EINT7
38 * bank1 means EINT8 ... EINT15
39 * bank2 means EINT16 ... EINT23
40 * bank3 means EINT24 ... EINT31
43 static inline int s3c_get_eint(unsigned int irq
)
47 if (irq
< IRQ_EINT16_31
)
48 real
= (irq
- IRQ_EINT0
);
50 real
= (irq
- S3C_IRQ_EINT_BASE
) + IRQ_EINT16_31
- IRQ_EINT0
;
55 static inline int s3c_get_bank(unsigned int irq
)
57 return s3c_get_eint(irq
) >> 3;
60 static inline int s3c_eint_to_bit(unsigned int irq
)
64 real
= s3c_get_eint(irq
);
65 bit
= 1 << (real
& (8 - 1));
70 static inline void s3c_irq_eint_mask(unsigned int irq
)
73 u32 bank
= s3c_get_bank(irq
);
75 mask
= __raw_readl(S5PC1XX_WKUP_INT_MASK(bank
));
76 mask
|= s3c_eint_to_bit(irq
);
77 __raw_writel(mask
, S5PC1XX_WKUP_INT_MASK(bank
));
80 static void s3c_irq_eint_unmask(unsigned int irq
)
83 u32 bank
= s3c_get_bank(irq
);
85 mask
= __raw_readl(S5PC1XX_WKUP_INT_MASK(bank
));
86 mask
&= ~(s3c_eint_to_bit(irq
));
87 __raw_writel(mask
, S5PC1XX_WKUP_INT_MASK(bank
));
90 static inline void s3c_irq_eint_ack(unsigned int irq
)
92 u32 bank
= s3c_get_bank(irq
);
94 __raw_writel(s3c_eint_to_bit(irq
), S5PC1XX_WKUP_INT_PEND(bank
));
97 static void s3c_irq_eint_maskack(unsigned int irq
)
99 /* compiler should in-line these */
100 s3c_irq_eint_mask(irq
);
101 s3c_irq_eint_ack(irq
);
104 static int s3c_irq_eint_set_type(unsigned int irq
, unsigned int type
)
106 u32 bank
= s3c_get_bank(irq
);
107 int real
= s3c_get_eint(irq
);
108 int gpio
, shift
, sfn
;
113 printk(KERN_WARNING
"No edge setting!\n");
116 case IRQ_TYPE_EDGE_RISING
:
117 con
= S5PC1XX_WKUP_INT_RISEEDGE
;
120 case IRQ_TYPE_EDGE_FALLING
:
121 con
= S5PC1XX_WKUP_INT_FALLEDGE
;
124 case IRQ_TYPE_EDGE_BOTH
:
125 con
= S5PC1XX_WKUP_INT_BOTHEDGE
;
128 case IRQ_TYPE_LEVEL_LOW
:
129 con
= S5PC1XX_WKUP_INT_LOWLEV
;
132 case IRQ_TYPE_LEVEL_HIGH
:
133 con
= S5PC1XX_WKUP_INT_HILEV
;
137 printk(KERN_ERR
"No such irq type %d", type
);
141 gpio
= real
& (8 - 1);
144 ctrl
= __raw_readl(S5PC1XX_WKUP_INT_CON(bank
));
145 ctrl
&= ~(0x7 << shift
);
146 ctrl
|= con
<< shift
;
147 __raw_writel(ctrl
, S5PC1XX_WKUP_INT_CON(bank
));
151 gpio
= S5PC100_GPH0(gpio
);
154 gpio
= S5PC100_GPH1(gpio
);
157 gpio
= S5PC100_GPH2(gpio
);
160 gpio
= S5PC100_GPH3(gpio
);
166 sfn
= S3C_GPIO_SFN(0x2);
167 s3c_gpio_cfgpin(gpio
, sfn
);
172 static struct irq_chip s3c_irq_eint
= {
174 .mask
= s3c_irq_eint_mask
,
175 .unmask
= s3c_irq_eint_unmask
,
176 .mask_ack
= s3c_irq_eint_maskack
,
177 .ack
= s3c_irq_eint_ack
,
178 .set_type
= s3c_irq_eint_set_type
,
179 .set_wake
= s3c_irqext_wake
,
182 /* s3c_irq_demux_eint
184 * This function demuxes the IRQ from external interrupts,
185 * from IRQ_EINT(16) to IRQ_EINT(31). It is designed to be inlined into
186 * the specific handlers s3c_irq_demux_eintX_Y.
188 static inline void s3c_irq_demux_eint(unsigned int start
, unsigned int end
)
190 u32 status
= __raw_readl(S5PC1XX_WKUP_INT_PEND((start
>> 3)));
191 u32 mask
= __raw_readl(S5PC1XX_WKUP_INT_MASK((start
>> 3)));
195 status
&= (1 << (end
- start
+ 1)) - 1;
197 for (irq
= IRQ_EINT(start
); irq
<= IRQ_EINT(end
); irq
++) {
199 generic_handle_irq(irq
);
205 static void s3c_irq_demux_eint16_31(unsigned int irq
, struct irq_desc
*desc
)
207 s3c_irq_demux_eint(16, 23);
208 s3c_irq_demux_eint(24, 31);
212 * Handle EINT0 ... EINT15 at VIC directly
214 static void s3c_irq_vic_eint_mask(unsigned int irq
)
216 void __iomem
*base
= get_irq_chip_data(irq
);
219 s3c_irq_eint_mask(irq
);
220 real
= s3c_get_eint(irq
);
221 writel(1 << real
, base
+ VIC_INT_ENABLE_CLEAR
);
224 static void s3c_irq_vic_eint_unmask(unsigned int irq
)
226 void __iomem
*base
= get_irq_chip_data(irq
);
229 s3c_irq_eint_unmask(irq
);
230 real
= s3c_get_eint(irq
);
231 writel(1 << real
, base
+ VIC_INT_ENABLE
);
234 static inline void s3c_irq_vic_eint_ack(unsigned int irq
)
237 u32 bank
= s3c_get_bank(irq
);
239 bit
= s3c_eint_to_bit(irq
);
240 __raw_writel(bit
, S5PC1XX_WKUP_INT_PEND(bank
));
243 static void s3c_irq_vic_eint_maskack(unsigned int irq
)
245 /* compiler should in-line these */
246 s3c_irq_vic_eint_mask(irq
);
247 s3c_irq_vic_eint_ack(irq
);
250 static struct irq_chip s3c_irq_vic_eint
= {
252 .mask
= s3c_irq_vic_eint_mask
,
253 .unmask
= s3c_irq_vic_eint_unmask
,
254 .mask_ack
= s3c_irq_vic_eint_maskack
,
255 .ack
= s3c_irq_vic_eint_ack
,
256 .set_type
= s3c_irq_eint_set_type
,
257 .set_wake
= s3c_irqext_wake
,
260 static int __init
s5pc1xx_init_irq_eint(void)
264 for (irq
= IRQ_EINT0
; irq
<= IRQ_EINT15
; irq
++) {
265 set_irq_chip(irq
, &s3c_irq_vic_eint
);
266 set_irq_handler(irq
, handle_level_irq
);
267 set_irq_flags(irq
, IRQF_VALID
);
270 for (irq
= IRQ_EINT(16); irq
<= IRQ_EINT(31); irq
++) {
271 set_irq_chip(irq
, &s3c_irq_eint
);
272 set_irq_handler(irq
, handle_level_irq
);
273 set_irq_flags(irq
, IRQF_VALID
);
276 set_irq_chained_handler(IRQ_EINT16_31
, s3c_irq_demux_eint16_31
);
281 arch_initcall(s5pc1xx_init_irq_eint
);