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