upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / irq-gpio.c
1 /*
2  * linux/arch/arm/plat-samsung/irq-gpio.c
3  *
4  * Copyright (C) 2009-2010 Samsung Electronics Co.Ltd
5  * Author: Kyungmin Park <kyungmin.park@samsung.com>
6  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
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/init.h>
15 #include <linux/irq.h>
16 #include <linux/gpio.h>
17 #include <linux/slab.h>
18 #include <linux/io.h>
19
20 #include <plat/gpio-core.h>
21
22 #define GPIO_BASE(chip)         (((unsigned long)(chip)->base) & ~(SZ_4K - 1))
23
24 #define CON_OFFSET                      0x700
25 #define MASK_OFFSET                     0x900
26 #define PEND_OFFSET                     0xA00
27 #define REG_OFFSET(x)                   ((x) << 2)
28
29 #define SAMSUNG_IRQ_GPIO_LEVEL_LOW      0x0
30 #define SAMSUNG_IRQ_GPIO_LEVEL_HIGH     0x1
31 #define SAMSUNG_IRQ_GPIO_EDGE_FALLING   0x2
32 #define SAMSUNG_IRQ_GPIO_EDGE_RISING    0x3
33 #define SAMSUNG_IRQ_GPIO_EDGE_BOTH      0x4
34
35 #define IRQ_GPIO_GROUP(x)               (IRQ_GPIO_BASE + ((x) * 8))
36
37 static inline int samsung_irq_gpio_get_bit(unsigned int irq, int group)
38 {
39         return irq - (IRQ_GPIO_GROUP(group));
40 }
41
42 static void samsung_irq_gpio_ack(unsigned int irq)
43 {
44         struct s3c_gpio_chip *chip = get_irq_chip_data(irq);
45         int group, localgroup, n, offset, value;
46
47         group = chip->group;
48         localgroup = chip->localgroup;
49         n = samsung_irq_gpio_get_bit(irq, group);
50
51         offset = REG_OFFSET(localgroup);        /* 4 bytes offset */
52
53         value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + offset);
54         value |= BIT(n);
55         __raw_writel(value, GPIO_BASE(chip) + PEND_OFFSET + offset);
56 }
57
58 static void samsung_irq_gpio_mask(unsigned int irq)
59 {
60         struct s3c_gpio_chip *chip = get_irq_chip_data(irq);
61         int group, localgroup, n, offset, value;
62
63         group = chip->group;
64         localgroup = chip->localgroup;
65         n = samsung_irq_gpio_get_bit(irq, group);
66
67         offset = REG_OFFSET(localgroup);        /* 4 bytes offset */
68
69         value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + offset);
70         value |= BIT(n);
71         __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + offset);
72 }
73
74 static void samsung_irq_gpio_mask_ack(unsigned int irq)
75 {
76         samsung_irq_gpio_mask(irq);
77         samsung_irq_gpio_ack(irq);
78 }
79
80 static void samsung_irq_gpio_unmask(unsigned int irq)
81 {
82         struct s3c_gpio_chip *chip = get_irq_chip_data(irq);
83         int group, localgroup, n, offset, value;
84
85         group = chip->group;
86         localgroup = chip->localgroup;
87         n = samsung_irq_gpio_get_bit(irq, group);
88
89         offset = REG_OFFSET(localgroup);        /* 4 bytes offset */
90
91         value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + offset);
92         value &= ~BIT(n);
93         __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + offset);
94 }
95
96 static int samsung_irq_gpio_set_type(unsigned int irq, unsigned int type)
97 {
98         struct s3c_gpio_chip *chip = get_irq_chip_data(irq);
99         int group, localgroup, bit, offset, value;
100         struct irq_desc *desc = irq_to_desc(irq);
101
102         group = chip->group;
103         localgroup = chip->localgroup;
104         bit = samsung_irq_gpio_get_bit(irq, group);
105
106         switch (type) {
107         case IRQ_TYPE_EDGE_RISING:
108                 type = SAMSUNG_IRQ_GPIO_EDGE_RISING;
109                 break;
110         case IRQ_TYPE_EDGE_FALLING:
111                 type = SAMSUNG_IRQ_GPIO_EDGE_FALLING;
112                 break;
113         case IRQ_TYPE_EDGE_BOTH:
114                 type = SAMSUNG_IRQ_GPIO_EDGE_BOTH;
115                 break;
116         case IRQ_TYPE_LEVEL_HIGH:
117                 type = SAMSUNG_IRQ_GPIO_LEVEL_HIGH;
118                 break;
119         case IRQ_TYPE_LEVEL_LOW:
120                 type = SAMSUNG_IRQ_GPIO_LEVEL_LOW;
121                 break;
122         case IRQ_TYPE_NONE:
123                 printk(KERN_WARNING "No irq type\n");
124         default:
125                 return -EINVAL;
126         }
127
128         offset = REG_OFFSET(localgroup);        /* 4 bytes offset */
129         bit = bit << 2;                 /* 4 bits offset */
130
131         value = __raw_readl(GPIO_BASE(chip) + CON_OFFSET + offset);
132         value &= ~(0xf << bit);
133         value |= (type << bit);
134         __raw_writel(value, GPIO_BASE(chip) + CON_OFFSET + offset);
135
136         if (type & IRQ_TYPE_EDGE_BOTH)
137                 desc->handle_irq = handle_edge_irq;
138         else
139                 desc->handle_irq = handle_level_irq;
140
141         return 0;
142 }
143
144 static struct irq_chip samsung_irq_gpio = {
145         .name           = "GPIO",
146         .ack            = samsung_irq_gpio_ack,
147         .mask           = samsung_irq_gpio_mask,
148         .mask_ack       = samsung_irq_gpio_mask_ack,
149         .unmask         = samsung_irq_gpio_unmask,
150         .set_type       = samsung_irq_gpio_set_type,
151 };
152
153 static int samsung_irq_gpio_to_irq(struct gpio_chip *gpio, unsigned int offset)
154 {
155         struct s3c_gpio_chip *chip = to_s3c_gpio(gpio);
156
157         return IRQ_GPIO_GROUP(chip->group) + offset;
158 }
159
160 void __init samsung_irq_gpio_add(struct s3c_gpio_chip *chip)
161 {
162         int irq, i;
163
164         chip->chip.to_irq = samsung_irq_gpio_to_irq;
165
166         for (i = 0; i < chip->chip.ngpio; i++) {
167                 irq = IRQ_GPIO_GROUP(chip->group) + i;
168                 set_irq_chip(irq, &samsung_irq_gpio);
169                 set_irq_chip_data(irq, chip);
170                 set_irq_handler(irq, handle_level_irq);
171                 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
172         }
173 }
174
175 /*
176  * Note that this 'irq' is the real repesentative irq for GPIO
177  *
178  * To reduce the register access, use the valid group cache.
179  * first check the valid groups. if failed, scan all groups fully.
180  */
181 static void samsung_irq_gpio_handler(unsigned int irq, struct irq_desc *desc)
182 {
183         struct samsung_irq_gpio *gpio;
184         int group, n, offset;
185         int start, end, pend, mask, handled = 0;
186         struct irq_chip *chip = get_irq_chip(irq);
187
188         gpio = get_irq_data(irq);
189         start = gpio->start;
190         end = gpio->nr_groups;
191
192         /* primary controller ack'ing */
193         if (chip->ack)
194                 chip->ack(irq);
195
196         /* Check the valid group first */
197         for (group = 0; group <= end; group++) {
198                 if (!test_bit(group, &gpio->valid_groups))
199                         continue;
200
201                 offset = REG_OFFSET(group);     /* 4 bytes offset */
202                 pend = __raw_readl(gpio->base + PEND_OFFSET + offset);
203                 if (!pend)
204                         continue;
205
206                 mask = __raw_readl(gpio->base + MASK_OFFSET + offset);
207                 pend &= ~mask;
208                 if (!pend)
209                         continue;
210
211                 while (pend) {
212                         n = fls(pend) - 1;
213                         generic_handle_irq(IRQ_GPIO_GROUP(start + group) + n);
214                         pend &= ~BIT(n);
215                 }
216
217                 handled = 1;
218         }
219
220         if (handled)
221                 goto out;
222
223         /* Okay we can't find a proper handler. Scan fully */
224         for (group = 0; group <= end; group++) {
225                 offset = REG_OFFSET(group);     /* 4 bytes offset */
226                 pend = __raw_readl(gpio->base + PEND_OFFSET + offset);
227                 if (!pend)
228                         continue;
229
230                 mask = __raw_readl(gpio->base + MASK_OFFSET + offset);
231                 pend &= ~mask;
232                 if (!pend)
233                         continue;
234
235                 while (pend) {
236                         n = fls(pend) - 1;
237                         generic_handle_irq(IRQ_GPIO_GROUP(start + group) + n);
238                         pend &= ~BIT(n);
239                 }
240
241                 /* It found the valid group */
242                 set_bit(group, &gpio->valid_groups);
243         }
244
245 out:
246         /* primary controller unmasking */
247         chip->unmask(irq);
248 }
249
250 void __init samsung_irq_gpio_register(struct samsung_irq_gpio_info *gpios, int num)
251 {
252         struct samsung_irq_gpio_info *gpio = gpios;
253         struct samsung_irq_gpio *sig;
254         int i;
255
256         for (i = 0; i < num; i++, gpio++) {
257                 sig = kmemdup(&gpio->sig, sizeof(gpio->sig), GFP_KERNEL);
258                 if (!sig)
259                         continue;
260
261                 sig->valid_groups = 0;
262                 /* Use the default irq gpio handler, if no handler is defined */
263                 if (!gpio->handler)
264                         gpio->handler = samsung_irq_gpio_handler;
265
266                 set_irq_chained_handler(gpio->irq, gpio->handler);
267                 set_irq_data(gpio->irq, sig);
268         }
269 }