1 /* linux/arch/arm/plat-s5p/irq-eint.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *		http://www.samsung.com
5  *
6  * S5P - IRQ EINT support
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12 
13 #include <linux/kernel.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/io.h>
17 #include <linux/device.h>
18 #include <linux/gpio.h>
19 
20 #include <asm/hardware/vic.h>
21 
22 #include <plat/regs-irqtype.h>
23 
24 #include <mach/map.h>
25 #include <plat/cpu.h>
26 #include <plat/pm.h>
27 
28 #include <plat/gpio-cfg.h>
29 #include <mach/regs-gpio.h>
30 
s5p_irq_eint_mask(struct irq_data * data)31 static inline void s5p_irq_eint_mask(struct irq_data *data)
32 {
33 	u32 mask;
34 
35 	mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
36 	mask |= eint_irq_to_bit(data->irq);
37 	__raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
38 }
39 
s5p_irq_eint_unmask(struct irq_data * data)40 static void s5p_irq_eint_unmask(struct irq_data *data)
41 {
42 	u32 mask;
43 
44 	mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
45 	mask &= ~(eint_irq_to_bit(data->irq));
46 	__raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
47 }
48 
s5p_irq_eint_ack(struct irq_data * data)49 static inline void s5p_irq_eint_ack(struct irq_data *data)
50 {
51 	__raw_writel(eint_irq_to_bit(data->irq),
52 		     S5P_EINT_PEND(EINT_REG_NR(data->irq)));
53 }
54 
s5p_irq_eint_maskack(struct irq_data * data)55 static void s5p_irq_eint_maskack(struct irq_data *data)
56 {
57 	/* compiler should in-line these */
58 	s5p_irq_eint_mask(data);
59 	s5p_irq_eint_ack(data);
60 }
61 
s5p_irq_eint_set_type(struct irq_data * data,unsigned int type)62 static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type)
63 {
64 	int offs = EINT_OFFSET(data->irq);
65 	int shift;
66 	u32 ctrl, mask;
67 	u32 newvalue = 0;
68 
69 	switch (type) {
70 	case IRQ_TYPE_EDGE_RISING:
71 		newvalue = S5P_IRQ_TYPE_EDGE_RISING;
72 		break;
73 
74 	case IRQ_TYPE_EDGE_FALLING:
75 		newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
76 		break;
77 
78 	case IRQ_TYPE_EDGE_BOTH:
79 		newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
80 		break;
81 
82 	case IRQ_TYPE_LEVEL_LOW:
83 		newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
84 		break;
85 
86 	case IRQ_TYPE_LEVEL_HIGH:
87 		newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
88 		break;
89 
90 	default:
91 		printk(KERN_ERR "No such irq type %d", type);
92 		return -EINVAL;
93 	}
94 
95 	shift = (offs & 0x7) * 4;
96 	mask = 0x7 << shift;
97 
98 	ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
99 	ctrl &= ~mask;
100 	ctrl |= newvalue << shift;
101 	__raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
102 
103 	if ((0 <= offs) && (offs < 8))
104 		s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
105 
106 	else if ((8 <= offs) && (offs < 16))
107 		s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
108 
109 	else if ((16 <= offs) && (offs < 24))
110 		s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
111 
112 	else if ((24 <= offs) && (offs < 32))
113 		s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
114 
115 	else
116 		printk(KERN_ERR "No such irq number %d", offs);
117 
118 	return 0;
119 }
120 
121 static struct irq_chip s5p_irq_eint = {
122 	.name		= "s5p-eint",
123 	.irq_mask	= s5p_irq_eint_mask,
124 	.irq_unmask	= s5p_irq_eint_unmask,
125 	.irq_mask_ack	= s5p_irq_eint_maskack,
126 	.irq_ack	= s5p_irq_eint_ack,
127 	.irq_set_type	= s5p_irq_eint_set_type,
128 #ifdef CONFIG_PM
129 	.irq_set_wake	= s3c_irqext_wake,
130 #endif
131 };
132 
133 /* s5p_irq_demux_eint
134  *
135  * This function demuxes the IRQ from the group0 external interrupts,
136  * from EINTs 16 to 31. It is designed to be inlined into the specific
137  * handler s5p_irq_demux_eintX_Y.
138  *
139  * Each EINT pend/mask registers handle eight of them.
140  */
s5p_irq_demux_eint(unsigned int start)141 static inline void s5p_irq_demux_eint(unsigned int start)
142 {
143 	u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
144 	u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
145 	unsigned int irq;
146 
147 	status &= ~mask;
148 	status &= 0xff;
149 
150 	while (status) {
151 		irq = fls(status) - 1;
152 		generic_handle_irq(irq + start);
153 		status &= ~(1 << irq);
154 	}
155 }
156 
s5p_irq_demux_eint16_31(unsigned int irq,struct irq_desc * desc)157 static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
158 {
159 	s5p_irq_demux_eint(IRQ_EINT(16));
160 	s5p_irq_demux_eint(IRQ_EINT(24));
161 }
162 
s5p_irq_vic_eint_mask(struct irq_data * data)163 static inline void s5p_irq_vic_eint_mask(struct irq_data *data)
164 {
165 	void __iomem *base = irq_data_get_irq_chip_data(data);
166 
167 	s5p_irq_eint_mask(data);
168 	writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR);
169 }
170 
s5p_irq_vic_eint_unmask(struct irq_data * data)171 static void s5p_irq_vic_eint_unmask(struct irq_data *data)
172 {
173 	void __iomem *base = irq_data_get_irq_chip_data(data);
174 
175 	s5p_irq_eint_unmask(data);
176 	writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE);
177 }
178 
s5p_irq_vic_eint_ack(struct irq_data * data)179 static inline void s5p_irq_vic_eint_ack(struct irq_data *data)
180 {
181 	__raw_writel(eint_irq_to_bit(data->irq),
182 		     S5P_EINT_PEND(EINT_REG_NR(data->irq)));
183 }
184 
s5p_irq_vic_eint_maskack(struct irq_data * data)185 static void s5p_irq_vic_eint_maskack(struct irq_data *data)
186 {
187 	s5p_irq_vic_eint_mask(data);
188 	s5p_irq_vic_eint_ack(data);
189 }
190 
191 static struct irq_chip s5p_irq_vic_eint = {
192 	.name		= "s5p_vic_eint",
193 	.irq_mask	= s5p_irq_vic_eint_mask,
194 	.irq_unmask	= s5p_irq_vic_eint_unmask,
195 	.irq_mask_ack	= s5p_irq_vic_eint_maskack,
196 	.irq_ack	= s5p_irq_vic_eint_ack,
197 	.irq_set_type	= s5p_irq_eint_set_type,
198 #ifdef CONFIG_PM
199 	.irq_set_wake	= s3c_irqext_wake,
200 #endif
201 };
202 
s5p_init_irq_eint(void)203 int __init s5p_init_irq_eint(void)
204 {
205 	int irq;
206 
207 	for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
208 		irq_set_chip(irq, &s5p_irq_vic_eint);
209 
210 	for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
211 		irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq);
212 		set_irq_flags(irq, IRQF_VALID);
213 	}
214 
215 	irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
216 	return 0;
217 }
218 
219 arch_initcall(s5p_init_irq_eint);
220