Merge branch 'prcm_scm_misc_fixes_3.2' of git://git.pwsan.com/linux-2.6 into fixes
[pandora-kernel.git] / arch / arm / mach-s5p64x0 / gpiolib.c
1 /* linux/arch/arm/mach-s5p64x0/gpiolib.c
2  *
3  * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * S5P64X0 - GPIOlib 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/irq.h>
15 #include <linux/io.h>
16 #include <linux/gpio.h>
17
18 #include <mach/map.h>
19 #include <mach/regs-gpio.h>
20 #include <mach/regs-clock.h>
21
22 #include <plat/cpu.h>
23 #include <plat/gpio-core.h>
24 #include <plat/gpio-cfg.h>
25 #include <plat/gpio-cfg-helpers.h>
26
27 /*
28  * S5P6440 GPIO bank summary:
29  *
30  * Bank GPIOs   Style   SlpCon  ExtInt Group
31  * A    6       4Bit    Yes     1
32  * B    7       4Bit    Yes     1
33  * C    8       4Bit    Yes     2
34  * F    2       2Bit    Yes     4 [1]
35  * G    7       4Bit    Yes     5
36  * H    10      4Bit[2] Yes     6
37  * I    16      2Bit    Yes     None
38  * J    12      2Bit    Yes     None
39  * N    16      2Bit    No      IRQ_EINT
40  * P    8       2Bit    Yes     8
41  * R    15      4Bit[2] Yes     8
42  *
43  * S5P6450 GPIO bank summary:
44  *
45  * Bank GPIOs   Style   SlpCon  ExtInt Group
46  * A    6       4Bit    Yes     1
47  * B    7       4Bit    Yes     1
48  * C    8       4Bit    Yes     2
49  * D    8       4Bit    Yes     None
50  * F    2       2Bit    Yes     None
51  * G    14      4Bit[2] Yes     5
52  * H    10      4Bit[2] Yes     6
53  * I    16      2Bit    Yes     None
54  * J    12      2Bit    Yes     None
55  * K    5       4Bit    Yes     None
56  * N    16      2Bit    No      IRQ_EINT
57  * P    11      2Bit    Yes     8
58  * Q    14      2Bit    Yes     None
59  * R    15      4Bit[2] Yes     None
60  * S    8       2Bit    Yes     None
61  *
62  * [1] BANKF pins 14,15 do not form part of the external interrupt sources
63  * [2] BANK has two control registers, GPxCON0 and GPxCON1
64  */
65
66 static int s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
67                                              unsigned int offset)
68 {
69         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
70         void __iomem *base = ourchip->base;
71         void __iomem *regcon = base;
72         unsigned long con;
73         unsigned long flags;
74
75         switch (offset) {
76         case 6:
77                 offset += 1;
78         case 0:
79         case 1:
80         case 2:
81         case 3:
82         case 4:
83         case 5:
84                 regcon -= 4;
85                 break;
86         default:
87                 offset -= 7;
88                 break;
89         }
90
91         s3c_gpio_lock(ourchip, flags);
92
93         con = __raw_readl(regcon);
94         con &= ~(0xf << con_4bit_shift(offset));
95         __raw_writel(con, regcon);
96
97         s3c_gpio_unlock(ourchip, flags);
98
99         return 0;
100 }
101
102 static int s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
103                                               unsigned int offset, int value)
104 {
105         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
106         void __iomem *base = ourchip->base;
107         void __iomem *regcon = base;
108         unsigned long con;
109         unsigned long dat;
110         unsigned long flags;
111         unsigned con_offset  = offset;
112
113         switch (con_offset) {
114         case 6:
115                 con_offset += 1;
116         case 0:
117         case 1:
118         case 2:
119         case 3:
120         case 4:
121         case 5:
122                 regcon -= 4;
123                 break;
124         default:
125                 con_offset -= 7;
126                 break;
127         }
128
129         s3c_gpio_lock(ourchip, flags);
130
131         con = __raw_readl(regcon);
132         con &= ~(0xf << con_4bit_shift(con_offset));
133         con |= 0x1 << con_4bit_shift(con_offset);
134
135         dat = __raw_readl(base + GPIODAT_OFF);
136         if (value)
137                 dat |= 1 << offset;
138         else
139                 dat &= ~(1 << offset);
140
141         __raw_writel(con, regcon);
142         __raw_writel(dat, base + GPIODAT_OFF);
143
144         s3c_gpio_unlock(ourchip, flags);
145
146         return 0;
147 }
148
149 int s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
150                                    unsigned int off, unsigned int cfg)
151 {
152         void __iomem *reg = chip->base;
153         unsigned int shift;
154         u32 con;
155
156         switch (off) {
157         case 0:
158         case 1:
159         case 2:
160         case 3:
161         case 4:
162         case 5:
163                 shift = (off & 7) * 4;
164                 reg -= 4;
165                 break;
166         case 6:
167                 shift = ((off + 1) & 7) * 4;
168                 reg -= 4;
169         default:
170                 shift = ((off + 1) & 7) * 4;
171                 break;
172         }
173
174         if (s3c_gpio_is_cfg_special(cfg)) {
175                 cfg &= 0xf;
176                 cfg <<= shift;
177         }
178
179         con = __raw_readl(reg);
180         con &= ~(0xf << shift);
181         con |= cfg;
182         __raw_writel(con, reg);
183
184         return 0;
185 }
186
187 static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = {
188         {
189                 .cfg_eint       = 0,
190         }, {
191                 .cfg_eint       = 7,
192         }, {
193                 .cfg_eint       = 3,
194                 .set_config     = s5p64x0_gpio_setcfg_4bit_rbank,
195         }, {
196                 .cfg_eint       = 0,
197                 .set_config     = s3c_gpio_setcfg_s3c24xx,
198                 .get_config     = s3c_gpio_getcfg_s3c24xx,
199         }, {
200                 .cfg_eint       = 2,
201                 .set_config     = s3c_gpio_setcfg_s3c24xx,
202                 .get_config     = s3c_gpio_getcfg_s3c24xx,
203         }, {
204                 .cfg_eint       = 3,
205                 .set_config     = s3c_gpio_setcfg_s3c24xx,
206                 .get_config     = s3c_gpio_getcfg_s3c24xx,
207         },
208 };
209
210 static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
211         {
212                 .base   = S5P64X0_GPA_BASE,
213                 .config = &s5p64x0_gpio_cfgs[1],
214                 .chip   = {
215                         .base   = S5P6440_GPA(0),
216                         .ngpio  = S5P6440_GPIO_A_NR,
217                         .label  = "GPA",
218                 },
219         }, {
220                 .base   = S5P64X0_GPB_BASE,
221                 .config = &s5p64x0_gpio_cfgs[1],
222                 .chip   = {
223                         .base   = S5P6440_GPB(0),
224                         .ngpio  = S5P6440_GPIO_B_NR,
225                         .label  = "GPB",
226                 },
227         }, {
228                 .base   = S5P64X0_GPC_BASE,
229                 .config = &s5p64x0_gpio_cfgs[1],
230                 .chip   = {
231                         .base   = S5P6440_GPC(0),
232                         .ngpio  = S5P6440_GPIO_C_NR,
233                         .label  = "GPC",
234                 },
235         }, {
236                 .base   = S5P64X0_GPG_BASE,
237                 .config = &s5p64x0_gpio_cfgs[1],
238                 .chip   = {
239                         .base   = S5P6440_GPG(0),
240                         .ngpio  = S5P6440_GPIO_G_NR,
241                         .label  = "GPG",
242                 },
243         },
244 };
245
246 static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
247         {
248                 .base   = S5P64X0_GPH_BASE + 0x4,
249                 .config = &s5p64x0_gpio_cfgs[1],
250                 .chip   = {
251                         .base   = S5P6440_GPH(0),
252                         .ngpio  = S5P6440_GPIO_H_NR,
253                         .label  = "GPH",
254                 },
255         },
256 };
257
258 static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
259         {
260                 .base   = S5P64X0_GPR_BASE + 0x4,
261                 .config = &s5p64x0_gpio_cfgs[2],
262                 .chip   = {
263                         .base   = S5P6440_GPR(0),
264                         .ngpio  = S5P6440_GPIO_R_NR,
265                         .label  = "GPR",
266                 },
267         },
268 };
269
270 static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
271         {
272                 .base   = S5P64X0_GPF_BASE,
273                 .config = &s5p64x0_gpio_cfgs[5],
274                 .chip   = {
275                         .base   = S5P6440_GPF(0),
276                         .ngpio  = S5P6440_GPIO_F_NR,
277                         .label  = "GPF",
278                 },
279         }, {
280                 .base   = S5P64X0_GPI_BASE,
281                 .config = &s5p64x0_gpio_cfgs[3],
282                 .chip   = {
283                         .base   = S5P6440_GPI(0),
284                         .ngpio  = S5P6440_GPIO_I_NR,
285                         .label  = "GPI",
286                 },
287         }, {
288                 .base   = S5P64X0_GPJ_BASE,
289                 .config = &s5p64x0_gpio_cfgs[3],
290                 .chip   = {
291                         .base   = S5P6440_GPJ(0),
292                         .ngpio  = S5P6440_GPIO_J_NR,
293                         .label  = "GPJ",
294                 },
295         }, {
296                 .base   = S5P64X0_GPN_BASE,
297                 .config = &s5p64x0_gpio_cfgs[4],
298                 .chip   = {
299                         .base   = S5P6440_GPN(0),
300                         .ngpio  = S5P6440_GPIO_N_NR,
301                         .label  = "GPN",
302                 },
303         }, {
304                 .base   = S5P64X0_GPP_BASE,
305                 .config = &s5p64x0_gpio_cfgs[5],
306                 .chip   = {
307                         .base   = S5P6440_GPP(0),
308                         .ngpio  = S5P6440_GPIO_P_NR,
309                         .label  = "GPP",
310                 },
311         },
312 };
313
314 static struct s3c_gpio_chip s5p6450_gpio_4bit[] = {
315         {
316                 .base   = S5P64X0_GPA_BASE,
317                 .config = &s5p64x0_gpio_cfgs[1],
318                 .chip   = {
319                         .base   = S5P6450_GPA(0),
320                         .ngpio  = S5P6450_GPIO_A_NR,
321                         .label  = "GPA",
322                 },
323         }, {
324                 .base   = S5P64X0_GPB_BASE,
325                 .config = &s5p64x0_gpio_cfgs[1],
326                 .chip   = {
327                         .base   = S5P6450_GPB(0),
328                         .ngpio  = S5P6450_GPIO_B_NR,
329                         .label  = "GPB",
330                 },
331         }, {
332                 .base   = S5P64X0_GPC_BASE,
333                 .config = &s5p64x0_gpio_cfgs[1],
334                 .chip   = {
335                         .base   = S5P6450_GPC(0),
336                         .ngpio  = S5P6450_GPIO_C_NR,
337                         .label  = "GPC",
338                 },
339         }, {
340                 .base   = S5P6450_GPD_BASE,
341                 .config = &s5p64x0_gpio_cfgs[1],
342                 .chip   = {
343                         .base   = S5P6450_GPD(0),
344                         .ngpio  = S5P6450_GPIO_D_NR,
345                         .label  = "GPD",
346                 },
347         }, {
348                 .base   = S5P6450_GPK_BASE,
349                 .config = &s5p64x0_gpio_cfgs[1],
350                 .chip   = {
351                         .base   = S5P6450_GPK(0),
352                         .ngpio  = S5P6450_GPIO_K_NR,
353                         .label  = "GPK",
354                 },
355         },
356 };
357
358 static struct s3c_gpio_chip s5p6450_gpio_4bit2[] = {
359         {
360                 .base   = S5P64X0_GPG_BASE + 0x4,
361                 .config = &s5p64x0_gpio_cfgs[1],
362                 .chip   = {
363                         .base   = S5P6450_GPG(0),
364                         .ngpio  = S5P6450_GPIO_G_NR,
365                         .label  = "GPG",
366                 },
367         }, {
368                 .base   = S5P64X0_GPH_BASE + 0x4,
369                 .config = &s5p64x0_gpio_cfgs[1],
370                 .chip   = {
371                         .base   = S5P6450_GPH(0),
372                         .ngpio  = S5P6450_GPIO_H_NR,
373                         .label  = "GPH",
374                 },
375         },
376 };
377
378 static struct s3c_gpio_chip s5p6450_gpio_rbank_4bit2[] = {
379         {
380                 .base   = S5P64X0_GPR_BASE + 0x4,
381                 .config = &s5p64x0_gpio_cfgs[2],
382                 .chip   = {
383                         .base   = S5P6450_GPR(0),
384                         .ngpio  = S5P6450_GPIO_R_NR,
385                         .label  = "GPR",
386                 },
387         },
388 };
389
390 static struct s3c_gpio_chip s5p6450_gpio_2bit[] = {
391         {
392                 .base   = S5P64X0_GPF_BASE,
393                 .config = &s5p64x0_gpio_cfgs[5],
394                 .chip   = {
395                         .base   = S5P6450_GPF(0),
396                         .ngpio  = S5P6450_GPIO_F_NR,
397                         .label  = "GPF",
398                 },
399         }, {
400                 .base   = S5P64X0_GPI_BASE,
401                 .config = &s5p64x0_gpio_cfgs[3],
402                 .chip   = {
403                         .base   = S5P6450_GPI(0),
404                         .ngpio  = S5P6450_GPIO_I_NR,
405                         .label  = "GPI",
406                 },
407         }, {
408                 .base   = S5P64X0_GPJ_BASE,
409                 .config = &s5p64x0_gpio_cfgs[3],
410                 .chip   = {
411                         .base   = S5P6450_GPJ(0),
412                         .ngpio  = S5P6450_GPIO_J_NR,
413                         .label  = "GPJ",
414                 },
415         }, {
416                 .base   = S5P64X0_GPN_BASE,
417                 .config = &s5p64x0_gpio_cfgs[4],
418                 .chip   = {
419                         .base   = S5P6450_GPN(0),
420                         .ngpio  = S5P6450_GPIO_N_NR,
421                         .label  = "GPN",
422                 },
423         }, {
424                 .base   = S5P64X0_GPP_BASE,
425                 .config = &s5p64x0_gpio_cfgs[5],
426                 .chip   = {
427                         .base   = S5P6450_GPP(0),
428                         .ngpio  = S5P6450_GPIO_P_NR,
429                         .label  = "GPP",
430                 },
431         }, {
432                 .base   = S5P6450_GPQ_BASE,
433                 .config = &s5p64x0_gpio_cfgs[4],
434                 .chip   = {
435                         .base   = S5P6450_GPQ(0),
436                         .ngpio  = S5P6450_GPIO_Q_NR,
437                         .label  = "GPQ",
438                 },
439         }, {
440                 .base   = S5P6450_GPS_BASE,
441                 .config = &s5p64x0_gpio_cfgs[5],
442                 .chip   = {
443                         .base   = S5P6450_GPS(0),
444                         .ngpio  = S5P6450_GPIO_S_NR,
445                         .label  = "GPS",
446                 },
447         },
448 };
449
450 void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
451 {
452         for (; nr_chips > 0; nr_chips--, chipcfg++) {
453                 if (!chipcfg->set_config)
454                         chipcfg->set_config     = s3c_gpio_setcfg_s3c64xx_4bit;
455                 if (!chipcfg->get_config)
456                         chipcfg->get_config     = s3c_gpio_getcfg_s3c64xx_4bit;
457                 if (!chipcfg->set_pull)
458                         chipcfg->set_pull       = s3c_gpio_setpull_updown;
459                 if (!chipcfg->get_pull)
460                         chipcfg->get_pull       = s3c_gpio_getpull_updown;
461         }
462 }
463
464 static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
465                                                 int nr_chips)
466 {
467         for (; nr_chips > 0; nr_chips--, chip++) {
468                 chip->chip.direction_input = s5p64x0_gpiolib_rbank_4bit2_input;
469                 chip->chip.direction_output =
470                                         s5p64x0_gpiolib_rbank_4bit2_output;
471                 s3c_gpiolib_add(chip);
472         }
473 }
474
475 static int __init s5p64x0_gpiolib_init(void)
476 {
477         s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs,
478                                 ARRAY_SIZE(s5p64x0_gpio_cfgs));
479
480         if (soc_is_s5p6450()) {
481                 samsung_gpiolib_add_2bit_chips(s5p6450_gpio_2bit,
482                                         ARRAY_SIZE(s5p6450_gpio_2bit));
483
484                 samsung_gpiolib_add_4bit_chips(s5p6450_gpio_4bit,
485                                         ARRAY_SIZE(s5p6450_gpio_4bit));
486
487                 samsung_gpiolib_add_4bit2_chips(s5p6450_gpio_4bit2,
488                                         ARRAY_SIZE(s5p6450_gpio_4bit2));
489
490                 s5p64x0_gpio_add_rbank_4bit2(s5p6450_gpio_rbank_4bit2,
491                                         ARRAY_SIZE(s5p6450_gpio_rbank_4bit2));
492         } else {
493                 samsung_gpiolib_add_2bit_chips(s5p6440_gpio_2bit,
494                                         ARRAY_SIZE(s5p6440_gpio_2bit));
495
496                 samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
497                                         ARRAY_SIZE(s5p6440_gpio_4bit));
498
499                 samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
500                                         ARRAY_SIZE(s5p6440_gpio_4bit2));
501
502                 s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
503                                         ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
504         }
505
506         return 0;
507 }
508 core_initcall(s5p64x0_gpiolib_init);