Merge git://git.infradead.org/~dwmw2/mtd-2.6.35
[pandora-kernel.git] / arch / arm / mach-s5pc100 / gpiolib.c
1 /*
2  * arch/arm/plat-s5pc100/gpiolib.c
3  *
4  *  Copyright 2009 Samsung Electronics Co
5  *  Kyungmin Park <kyungmin.park@samsung.com>
6  *
7  * S5PC100 - GPIOlib support
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/irq.h>
16 #include <linux/io.h>
17 #include <linux/gpio.h>
18
19 #include <mach/map.h>
20 #include <mach/regs-gpio.h>
21
22 #include <plat/gpio-core.h>
23 #include <plat/gpio-cfg.h>
24 #include <plat/gpio-cfg-helpers.h>
25
26 /* S5PC100 GPIO bank summary:
27  *
28  * Bank GPIOs   Style   INT Type
29  * A0   8       4Bit    GPIO_INT0
30  * A1   5       4Bit    GPIO_INT1
31  * B    8       4Bit    GPIO_INT2
32  * C    5       4Bit    GPIO_INT3
33  * D    7       4Bit    GPIO_INT4
34  * E0   8       4Bit    GPIO_INT5
35  * E1   6       4Bit    GPIO_INT6
36  * F0   8       4Bit    GPIO_INT7
37  * F1   8       4Bit    GPIO_INT8
38  * F2   8       4Bit    GPIO_INT9
39  * F3   4       4Bit    GPIO_INT10
40  * G0   8       4Bit    GPIO_INT11
41  * G1   3       4Bit    GPIO_INT12
42  * G2   7       4Bit    GPIO_INT13
43  * G3   7       4Bit    GPIO_INT14
44  * H0   8       4Bit    WKUP_INT
45  * H1   8       4Bit    WKUP_INT
46  * H2   8       4Bit    WKUP_INT
47  * H3   8       4Bit    WKUP_INT
48  * I    8       4Bit    GPIO_INT15
49  * J0   8       4Bit    GPIO_INT16
50  * J1   5       4Bit    GPIO_INT17
51  * J2   8       4Bit    GPIO_INT18
52  * J3   8       4Bit    GPIO_INT19
53  * J4   4       4Bit    GPIO_INT20
54  * K0   8       4Bit    None
55  * K1   6       4Bit    None
56  * K2   8       4Bit    None
57  * K3   8       4Bit    None
58  * L0   8       4Bit    None
59  * L1   8       4Bit    None
60  * L2   8       4Bit    None
61  * L3   8       4Bit    None
62  */
63
64 static int s5pc100_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
65 {
66         return S3C_IRQ_GPIO(chip->base + offset);
67 }
68
69 static int s5pc100_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset)
70 {
71         int base;
72
73         base = chip->base - S5PC100_GPH0(0);
74         if (base == 0)
75                 return IRQ_EINT(offset);
76         base = chip->base - S5PC100_GPH1(0);
77         if (base == 0)
78                 return IRQ_EINT(8 + offset);
79         base = chip->base - S5PC100_GPH2(0);
80         if (base == 0)
81                 return IRQ_EINT(16 + offset);
82         base = chip->base - S5PC100_GPH3(0);
83         if (base == 0)
84                 return IRQ_EINT(24 + offset);
85         return -EINVAL;
86 }
87
88 static struct s3c_gpio_cfg gpio_cfg = {
89         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
90         .set_pull       = s3c_gpio_setpull_updown,
91         .get_pull       = s3c_gpio_getpull_updown,
92 };
93
94 static struct s3c_gpio_cfg gpio_cfg_eint = {
95         .cfg_eint       = 0xf,
96         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
97         .set_pull       = s3c_gpio_setpull_updown,
98         .get_pull       = s3c_gpio_getpull_updown,
99 };
100
101 static struct s3c_gpio_cfg gpio_cfg_noint = {
102         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
103         .set_pull       = s3c_gpio_setpull_updown,
104         .get_pull       = s3c_gpio_getpull_updown,
105 };
106
107 static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
108         {
109                 .base   = S5PC100_GPA0_BASE,
110                 .config = &gpio_cfg,
111                 .chip   = {
112                         .base   = S5PC100_GPA0(0),
113                         .ngpio  = S5PC100_GPIO_A0_NR,
114                         .label  = "GPA0",
115                 },
116         }, {
117                 .base   = S5PC100_GPA1_BASE,
118                 .config = &gpio_cfg,
119                 .chip   = {
120                         .base   = S5PC100_GPA1(0),
121                         .ngpio  = S5PC100_GPIO_A1_NR,
122                         .label  = "GPA1",
123                 },
124         }, {
125                 .base   = S5PC100_GPB_BASE,
126                 .config = &gpio_cfg,
127                 .chip   = {
128                         .base   = S5PC100_GPB(0),
129                         .ngpio  = S5PC100_GPIO_B_NR,
130                         .label  = "GPB",
131                 },
132         }, {
133                 .base   = S5PC100_GPC_BASE,
134                 .config = &gpio_cfg,
135                 .chip   = {
136                         .base   = S5PC100_GPC(0),
137                         .ngpio  = S5PC100_GPIO_C_NR,
138                         .label  = "GPC",
139                 },
140         }, {
141                 .base   = S5PC100_GPD_BASE,
142                 .config = &gpio_cfg,
143                 .chip   = {
144                         .base   = S5PC100_GPD(0),
145                         .ngpio  = S5PC100_GPIO_D_NR,
146                         .label  = "GPD",
147                 },
148         }, {
149                 .base   = S5PC100_GPE0_BASE,
150                 .config = &gpio_cfg,
151                 .chip   = {
152                         .base   = S5PC100_GPE0(0),
153                         .ngpio  = S5PC100_GPIO_E0_NR,
154                         .label  = "GPE0",
155                 },
156         }, {
157                 .base   = S5PC100_GPE1_BASE,
158                 .config = &gpio_cfg,
159                 .chip   = {
160                         .base   = S5PC100_GPE1(0),
161                         .ngpio  = S5PC100_GPIO_E1_NR,
162                         .label  = "GPE1",
163                 },
164         }, {
165                 .base   = S5PC100_GPF0_BASE,
166                 .config = &gpio_cfg,
167                 .chip   = {
168                         .base   = S5PC100_GPF0(0),
169                         .ngpio  = S5PC100_GPIO_F0_NR,
170                         .label  = "GPF0",
171                 },
172         }, {
173                 .base   = S5PC100_GPF1_BASE,
174                 .config = &gpio_cfg,
175                 .chip   = {
176                         .base   = S5PC100_GPF1(0),
177                         .ngpio  = S5PC100_GPIO_F1_NR,
178                         .label  = "GPF1",
179                 },
180         }, {
181                 .base   = S5PC100_GPF2_BASE,
182                 .config = &gpio_cfg,
183                 .chip   = {
184                         .base   = S5PC100_GPF2(0),
185                         .ngpio  = S5PC100_GPIO_F2_NR,
186                         .label  = "GPF2",
187                 },
188         }, {
189                 .base   = S5PC100_GPF3_BASE,
190                 .config = &gpio_cfg,
191                 .chip   = {
192                         .base   = S5PC100_GPF3(0),
193                         .ngpio  = S5PC100_GPIO_F3_NR,
194                         .label  = "GPF3",
195                 },
196         }, {
197                 .base   = S5PC100_GPG0_BASE,
198                 .config = &gpio_cfg,
199                 .chip   = {
200                         .base   = S5PC100_GPG0(0),
201                         .ngpio  = S5PC100_GPIO_G0_NR,
202                         .label  = "GPG0",
203                 },
204         }, {
205                 .base   = S5PC100_GPG1_BASE,
206                 .config = &gpio_cfg,
207                 .chip   = {
208                         .base   = S5PC100_GPG1(0),
209                         .ngpio  = S5PC100_GPIO_G1_NR,
210                         .label  = "GPG1",
211                 },
212         }, {
213                 .base   = S5PC100_GPG2_BASE,
214                 .config = &gpio_cfg,
215                 .chip   = {
216                         .base   = S5PC100_GPG2(0),
217                         .ngpio  = S5PC100_GPIO_G2_NR,
218                         .label  = "GPG2",
219                 },
220         }, {
221                 .base   = S5PC100_GPG3_BASE,
222                 .config = &gpio_cfg,
223                 .chip   = {
224                         .base   = S5PC100_GPG3(0),
225                         .ngpio  = S5PC100_GPIO_G3_NR,
226                         .label  = "GPG3",
227                 },
228         }, {
229                 .base   = S5PC100_GPH0_BASE,
230                 .config = &gpio_cfg_eint,
231                 .chip   = {
232                         .base   = S5PC100_GPH0(0),
233                         .ngpio  = S5PC100_GPIO_H0_NR,
234                         .label  = "GPH0",
235                 },
236         }, {
237                 .base   = S5PC100_GPH1_BASE,
238                 .config = &gpio_cfg_eint,
239                 .chip   = {
240                         .base   = S5PC100_GPH1(0),
241                         .ngpio  = S5PC100_GPIO_H1_NR,
242                         .label  = "GPH1",
243                 },
244         }, {
245                 .base   = S5PC100_GPH2_BASE,
246                 .config = &gpio_cfg_eint,
247                 .chip   = {
248                         .base   = S5PC100_GPH2(0),
249                         .ngpio  = S5PC100_GPIO_H2_NR,
250                         .label  = "GPH2",
251                 },
252         }, {
253                 .base   = S5PC100_GPH3_BASE,
254                 .config = &gpio_cfg_eint,
255                 .chip   = {
256                         .base   = S5PC100_GPH3(0),
257                         .ngpio  = S5PC100_GPIO_H3_NR,
258                         .label  = "GPH3",
259                 },
260         }, {
261                 .base   = S5PC100_GPI_BASE,
262                 .config = &gpio_cfg,
263                 .chip   = {
264                         .base   = S5PC100_GPI(0),
265                         .ngpio  = S5PC100_GPIO_I_NR,
266                         .label  = "GPI",
267                 },
268         }, {
269                 .base   = S5PC100_GPJ0_BASE,
270                 .config = &gpio_cfg,
271                 .chip   = {
272                         .base   = S5PC100_GPJ0(0),
273                         .ngpio  = S5PC100_GPIO_J0_NR,
274                         .label  = "GPJ0",
275                 },
276         }, {
277                 .base   = S5PC100_GPJ1_BASE,
278                 .config = &gpio_cfg,
279                 .chip   = {
280                         .base   = S5PC100_GPJ1(0),
281                         .ngpio  = S5PC100_GPIO_J1_NR,
282                         .label  = "GPJ1",
283                 },
284         }, {
285                 .base   = S5PC100_GPJ2_BASE,
286                 .config = &gpio_cfg,
287                 .chip   = {
288                         .base   = S5PC100_GPJ2(0),
289                         .ngpio  = S5PC100_GPIO_J2_NR,
290                         .label  = "GPJ2",
291                 },
292         }, {
293                 .base   = S5PC100_GPJ3_BASE,
294                 .config = &gpio_cfg,
295                 .chip   = {
296                         .base   = S5PC100_GPJ3(0),
297                         .ngpio  = S5PC100_GPIO_J3_NR,
298                         .label  = "GPJ3",
299                 },
300         }, {
301                 .base   = S5PC100_GPJ4_BASE,
302                 .config = &gpio_cfg,
303                 .chip   = {
304                         .base   = S5PC100_GPJ4(0),
305                         .ngpio  = S5PC100_GPIO_J4_NR,
306                         .label  = "GPJ4",
307                 },
308         }, {
309                 .base   = S5PC100_GPK0_BASE,
310                 .config = &gpio_cfg_noint,
311                 .chip   = {
312                         .base   = S5PC100_GPK0(0),
313                         .ngpio  = S5PC100_GPIO_K0_NR,
314                         .label  = "GPK0",
315                 },
316         }, {
317                 .base   = S5PC100_GPK1_BASE,
318                 .config = &gpio_cfg_noint,
319                 .chip   = {
320                         .base   = S5PC100_GPK1(0),
321                         .ngpio  = S5PC100_GPIO_K1_NR,
322                         .label  = "GPK1",
323                 },
324         }, {
325                 .base   = S5PC100_GPK2_BASE,
326                 .config = &gpio_cfg_noint,
327                 .chip   = {
328                         .base   = S5PC100_GPK2(0),
329                         .ngpio  = S5PC100_GPIO_K2_NR,
330                         .label  = "GPK2",
331                 },
332         }, {
333                 .base   = S5PC100_GPK3_BASE,
334                 .config = &gpio_cfg_noint,
335                 .chip   = {
336                         .base   = S5PC100_GPK3(0),
337                         .ngpio  = S5PC100_GPIO_K3_NR,
338                         .label  = "GPK3",
339                 },
340         }, {
341                 .base   = S5PC100_GPL0_BASE,
342                 .config = &gpio_cfg_noint,
343                 .chip   = {
344                         .base   = S5PC100_GPL0(0),
345                         .ngpio  = S5PC100_GPIO_L0_NR,
346                         .label  = "GPL0",
347                 },
348         }, {
349                 .base   = S5PC100_GPL1_BASE,
350                 .config = &gpio_cfg_noint,
351                 .chip   = {
352                         .base   = S5PC100_GPL1(0),
353                         .ngpio  = S5PC100_GPIO_L1_NR,
354                         .label  = "GPL1",
355                 },
356         }, {
357                 .base   = S5PC100_GPL2_BASE,
358                 .config = &gpio_cfg_noint,
359                 .chip   = {
360                         .base   = S5PC100_GPL2(0),
361                         .ngpio  = S5PC100_GPIO_L2_NR,
362                         .label  = "GPL2",
363                 },
364         }, {
365                 .base   = S5PC100_GPL3_BASE,
366                 .config = &gpio_cfg_noint,
367                 .chip   = {
368                         .base   = S5PC100_GPL3(0),
369                         .ngpio  = S5PC100_GPIO_L3_NR,
370                         .label  = "GPL3",
371                 },
372         }, {
373                 .base   = S5PC100_GPL4_BASE,
374                 .config = &gpio_cfg_noint,
375                 .chip   = {
376                         .base   = S5PC100_GPL4(0),
377                         .ngpio  = S5PC100_GPIO_L4_NR,
378                         .label  = "GPL4",
379                 },
380         },
381 };
382
383 /* FIXME move from irq-gpio.c */
384 extern struct irq_chip s5pc100_gpioint;
385 extern void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc);
386
387 static __init void s5pc100_gpiolib_link(struct s3c_gpio_chip *chip)
388 {
389         /* Interrupt */
390         if (chip->config == &gpio_cfg) {
391                 int i, irq;
392
393                 chip->chip.to_irq = s5pc100_gpiolib_to_irq;
394
395                 for (i = 0;  i < chip->chip.ngpio; i++) {
396                         irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i;
397                         set_irq_chip(irq, &s5pc100_gpioint);
398                         set_irq_data(irq, &chip->chip);
399                         set_irq_handler(irq, handle_level_irq);
400                         set_irq_flags(irq, IRQF_VALID);
401                 }
402         } else if (chip->config == &gpio_cfg_eint) {
403                 chip->chip.to_irq = s5pc100_gpiolib_to_eint;
404         }
405 }
406
407 static __init int s5pc100_gpiolib_init(void)
408 {
409         struct s3c_gpio_chip *chip;
410         int nr_chips;
411
412         chip = s5pc100_gpio_chips;
413         nr_chips = ARRAY_SIZE(s5pc100_gpio_chips);
414
415         for (; nr_chips > 0; nr_chips--, chip++)
416                 s5pc100_gpiolib_link(chip);
417
418         samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips,
419                                        ARRAY_SIZE(s5pc100_gpio_chips));
420
421         /* Interrupt */
422         set_irq_chained_handler(IRQ_GPIOINT, s5pc100_irq_gpioint_handler);
423
424         return 0;
425 }
426 core_initcall(s5pc100_gpiolib_init);