Merge branch 'nfs-for-2.6.35' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
[pandora-kernel.git] / arch / arm / mach-s5p6440 / gpio.c
1 /* arch/arm/mach-s5p6440/gpio.c
2  *
3  * Copyright (c) 2009 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * S5P6440 - 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 <mach/map.h>
17 #include <mach/gpio.h>
18 #include <mach/regs-gpio.h>
19 #include <plat/gpio-core.h>
20 #include <plat/gpio-cfg.h>
21 #include <plat/gpio-cfg-helpers.h>
22
23 /* GPIO bank summary:
24 *
25 * Bank  GPIOs   Style   SlpCon  ExtInt Group
26 * A     6       4Bit    Yes     1
27 * B     7       4Bit    Yes     1
28 * C     8       4Bit    Yes     2
29 * F     2       2Bit    Yes     4 [1]
30 * G     7       4Bit    Yes     5
31 * H     10      4Bit[2] Yes     6
32 * I     16      2Bit    Yes     None
33 * J     12      2Bit    Yes     None
34 * N     16      2Bit    No      IRQ_EINT
35 * P     8       2Bit    Yes     8
36 * R     15      4Bit[2] Yes     8
37 *
38 * [1] BANKF pins 14,15 do not form part of the external interrupt sources
39 * [2] BANK has two control registers, GPxCON0 and GPxCON1
40 */
41
42 static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
43                                              unsigned int offset)
44 {
45         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
46         void __iomem *base = ourchip->base;
47         void __iomem *regcon = base;
48         unsigned long con;
49
50         switch (offset) {
51         case 6:
52                 offset += 1;
53         case 0:
54         case 1:
55         case 2:
56         case 3:
57         case 4:
58         case 5:
59                 regcon -= 4;
60                 break;
61         default:
62                 offset -= 7;
63                 break;
64         }
65
66         con = __raw_readl(regcon);
67         con &= ~(0xf << con_4bit_shift(offset));
68         __raw_writel(con, regcon);
69
70         return 0;
71 }
72
73 static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
74                                               unsigned int offset, int value)
75 {
76         struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
77         void __iomem *base = ourchip->base;
78         void __iomem *regcon = base;
79         unsigned long con;
80         unsigned long dat;
81         unsigned con_offset  = offset;
82
83         switch (con_offset) {
84         case 6:
85                 con_offset += 1;
86         case 0:
87         case 1:
88         case 2:
89         case 3:
90         case 4:
91         case 5:
92                 regcon -= 4;
93                 break;
94         default:
95                 con_offset -= 7;
96                 break;
97         }
98
99         con = __raw_readl(regcon);
100         con &= ~(0xf << con_4bit_shift(con_offset));
101         con |= 0x1 << con_4bit_shift(con_offset);
102
103         dat = __raw_readl(base + GPIODAT_OFF);
104         if (value)
105                 dat |= 1 << offset;
106         else
107                 dat &= ~(1 << offset);
108
109         __raw_writel(con, regcon);
110         __raw_writel(dat, base + GPIODAT_OFF);
111
112         return 0;
113 }
114
115 int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
116                                    unsigned int off, unsigned int cfg)
117 {
118         void __iomem *reg = chip->base;
119         unsigned int shift;
120         u32 con;
121
122         switch (off) {
123         case 0:
124         case 1:
125         case 2:
126         case 3:
127         case 4:
128         case 5:
129                 shift = (off & 7) * 4;
130                 reg -= 4;
131                 break;
132         case 6:
133                 shift = ((off + 1) & 7) * 4;
134                 reg -= 4;
135         default:
136                 shift = ((off + 1) & 7) * 4;
137                 break;
138         }
139
140         if (s3c_gpio_is_cfg_special(cfg)) {
141                 cfg &= 0xf;
142                 cfg <<= shift;
143         }
144
145         con = __raw_readl(reg);
146         con &= ~(0xf << shift);
147         con |= cfg;
148         __raw_writel(con, reg);
149
150         return 0;
151 }
152
153 static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = {
154         {
155                 .cfg_eint       = 0,
156         }, {
157                 .cfg_eint       = 7,
158         }, {
159                 .cfg_eint       = 3,
160                 .set_config     = s5p6440_gpio_setcfg_4bit_rbank,
161         }, {
162                 .cfg_eint       = 0,
163                 .set_config     = s3c_gpio_setcfg_s3c24xx,
164                 .get_config     = s3c_gpio_getcfg_s3c24xx,
165         }, {
166                 .cfg_eint       = 2,
167                 .set_config     = s3c_gpio_setcfg_s3c24xx,
168                 .get_config     = s3c_gpio_getcfg_s3c24xx,
169         }, {
170                 .cfg_eint       = 3,
171                 .set_config     = s3c_gpio_setcfg_s3c24xx,
172                 .get_config     = s3c_gpio_getcfg_s3c24xx,
173         },
174 };
175
176 static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
177         {
178                 .base   = S5P6440_GPA_BASE,
179                 .config = &s5p6440_gpio_cfgs[1],
180                 .chip   = {
181                         .base   = S5P6440_GPA(0),
182                         .ngpio  = S5P6440_GPIO_A_NR,
183                         .label  = "GPA",
184                 },
185         }, {
186                 .base   = S5P6440_GPB_BASE,
187                 .config = &s5p6440_gpio_cfgs[1],
188                 .chip   = {
189                         .base   = S5P6440_GPB(0),
190                         .ngpio  = S5P6440_GPIO_B_NR,
191                         .label  = "GPB",
192                 },
193         }, {
194                 .base   = S5P6440_GPC_BASE,
195                 .config = &s5p6440_gpio_cfgs[1],
196                 .chip   = {
197                         .base   = S5P6440_GPC(0),
198                         .ngpio  = S5P6440_GPIO_C_NR,
199                         .label  = "GPC",
200                 },
201         }, {
202                 .base   = S5P6440_GPG_BASE,
203                 .config = &s5p6440_gpio_cfgs[1],
204                 .chip   = {
205                         .base   = S5P6440_GPG(0),
206                         .ngpio  = S5P6440_GPIO_G_NR,
207                         .label  = "GPG",
208                 },
209         },
210 };
211
212 static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
213         {
214                 .base   = S5P6440_GPH_BASE + 0x4,
215                 .config = &s5p6440_gpio_cfgs[1],
216                 .chip   = {
217                         .base   = S5P6440_GPH(0),
218                         .ngpio  = S5P6440_GPIO_H_NR,
219                         .label  = "GPH",
220                 },
221         },
222 };
223
224 static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
225         {
226                 .base   = S5P6440_GPR_BASE + 0x4,
227                 .config = &s5p6440_gpio_cfgs[2],
228                 .chip   = {
229                         .base   = S5P6440_GPR(0),
230                         .ngpio  = S5P6440_GPIO_R_NR,
231                         .label  = "GPR",
232                 },
233         },
234 };
235
236 static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
237         {
238                 .base   = S5P6440_GPF_BASE,
239                 .config = &s5p6440_gpio_cfgs[5],
240                 .chip   = {
241                         .base   = S5P6440_GPF(0),
242                         .ngpio  = S5P6440_GPIO_F_NR,
243                         .label  = "GPF",
244                 },
245         }, {
246                 .base   = S5P6440_GPI_BASE,
247                 .config = &s5p6440_gpio_cfgs[3],
248                 .chip   = {
249                         .base   = S5P6440_GPI(0),
250                         .ngpio  = S5P6440_GPIO_I_NR,
251                         .label  = "GPI",
252                 },
253         }, {
254                 .base   = S5P6440_GPJ_BASE,
255                 .config = &s5p6440_gpio_cfgs[3],
256                 .chip   = {
257                         .base   = S5P6440_GPJ(0),
258                         .ngpio  = S5P6440_GPIO_J_NR,
259                         .label  = "GPJ",
260                 },
261         }, {
262                 .base   = S5P6440_GPN_BASE,
263                 .config = &s5p6440_gpio_cfgs[4],
264                 .chip   = {
265                         .base   = S5P6440_GPN(0),
266                         .ngpio  = S5P6440_GPIO_N_NR,
267                         .label  = "GPN",
268                 },
269         }, {
270                 .base   = S5P6440_GPP_BASE,
271                 .config = &s5p6440_gpio_cfgs[5],
272                 .chip   = {
273                         .base   = S5P6440_GPP(0),
274                         .ngpio  = S5P6440_GPIO_P_NR,
275                         .label  = "GPP",
276                 },
277         },
278 };
279
280 void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
281 {
282         for (; nr_chips > 0; nr_chips--, chipcfg++) {
283                 if (!chipcfg->set_config)
284                         chipcfg->set_config     = s3c_gpio_setcfg_s3c64xx_4bit;
285                 if (!chipcfg->get_config)
286                         chipcfg->get_config     = s3c_gpio_getcfg_s3c64xx_4bit;
287                 if (!chipcfg->set_pull)
288                         chipcfg->set_pull       = s3c_gpio_setpull_updown;
289                 if (!chipcfg->get_pull)
290                         chipcfg->get_pull       = s3c_gpio_getpull_updown;
291         }
292 }
293
294 static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
295                                                 int nr_chips)
296 {
297         for (; nr_chips > 0; nr_chips--, chip++) {
298                 chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input;
299                 chip->chip.direction_output =
300                                         s5p6440_gpiolib_rbank_4bit2_output;
301                 s3c_gpiolib_add(chip);
302         }
303 }
304
305 static int __init s5p6440_gpiolib_init(void)
306 {
307         struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
308         int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
309
310         s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs,
311                                 ARRAY_SIZE(s5p6440_gpio_cfgs));
312
313         for (; nr_chips > 0; nr_chips--, chips++)
314                 s3c_gpiolib_add(chips);
315
316         samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
317                                 ARRAY_SIZE(s5p6440_gpio_4bit));
318
319         samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
320                                 ARRAY_SIZE(s5p6440_gpio_4bit2));
321
322         s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2,
323                                 ARRAY_SIZE(gpio_rbank_4bit2));
324
325         return 0;
326 }
327 arch_initcall(s5p6440_gpiolib_init);