firmware: only allow EDD on x86
[linux-2.6/kvm.git] / arch / arm / plat-s5pc1xx / irq-eint.c
blob373122f57d56c42fd8623fe604021d2fcd660a0d
1 /*
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>
20 #include <linux/io.h>
21 #include <linux/sysdev.h>
22 #include <linux/pm.h>
23 #include <linux/gpio.h>
25 #include <asm/hardware/vic.h>
27 #include <mach/map.h>
29 #include <plat/gpio-cfg.h>
30 #include <plat/gpio-ext.h>
31 #include <plat/pm.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)
45 int real;
47 if (irq < IRQ_EINT16_31)
48 real = (irq - IRQ_EINT0);
49 else
50 real = (irq - S3C_IRQ_EINT_BASE) + IRQ_EINT16_31 - IRQ_EINT0;
52 return real;
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)
62 int real, bit;
64 real = s3c_get_eint(irq);
65 bit = 1 << (real & (8 - 1));
67 return bit;
70 static inline void s3c_irq_eint_mask(unsigned int irq)
72 u32 mask;
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)
82 u32 mask;
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;
109 u32 ctrl, con = 0;
111 switch (type) {
112 case IRQ_TYPE_NONE:
113 printk(KERN_WARNING "No edge setting!\n");
114 break;
116 case IRQ_TYPE_EDGE_RISING:
117 con = S5PC1XX_WKUP_INT_RISEEDGE;
118 break;
120 case IRQ_TYPE_EDGE_FALLING:
121 con = S5PC1XX_WKUP_INT_FALLEDGE;
122 break;
124 case IRQ_TYPE_EDGE_BOTH:
125 con = S5PC1XX_WKUP_INT_BOTHEDGE;
126 break;
128 case IRQ_TYPE_LEVEL_LOW:
129 con = S5PC1XX_WKUP_INT_LOWLEV;
130 break;
132 case IRQ_TYPE_LEVEL_HIGH:
133 con = S5PC1XX_WKUP_INT_HILEV;
134 break;
136 default:
137 printk(KERN_ERR "No such irq type %d", type);
138 return -EINVAL;
141 gpio = real & (8 - 1);
142 shift = gpio << 2;
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));
149 switch (real) {
150 case 0 ... 7:
151 gpio = S5PC100_GPH0(gpio);
152 break;
153 case 8 ... 15:
154 gpio = S5PC100_GPH1(gpio);
155 break;
156 case 16 ... 23:
157 gpio = S5PC100_GPH2(gpio);
158 break;
159 case 24 ... 31:
160 gpio = S5PC100_GPH3(gpio);
161 break;
162 default:
163 return -EINVAL;
166 sfn = S3C_GPIO_SFN(0x2);
167 s3c_gpio_cfgpin(gpio, sfn);
169 return 0;
172 static struct irq_chip s3c_irq_eint = {
173 .name = "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)));
192 unsigned int irq;
194 status &= ~mask;
195 status &= (1 << (end - start + 1)) - 1;
197 for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
198 if (status & 1)
199 generic_handle_irq(irq);
201 status >>= 1;
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);
217 unsigned int real;
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);
227 unsigned int real;
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)
236 u32 bit;
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 = {
251 .name = "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)
262 int irq;
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);
278 return 0;
281 arch_initcall(s5pc1xx_init_irq_eint);