Merge branch 'x86-pat-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[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         }, {
165                 .cfg_eint       = 2,
166                 .set_config     = s3c_gpio_setcfg_s3c24xx,
167         }, {
168                 .cfg_eint       = 3,
169                 .set_config     = s3c_gpio_setcfg_s3c24xx,
170         },
171 };
172
173 static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
174         {
175                 .base   = S5P6440_GPA_BASE,
176                 .config = &s5p6440_gpio_cfgs[1],
177                 .chip   = {
178                         .base   = S5P6440_GPA(0),
179                         .ngpio  = S5P6440_GPIO_A_NR,
180                         .label  = "GPA",
181                 },
182         }, {
183                 .base   = S5P6440_GPB_BASE,
184                 .config = &s5p6440_gpio_cfgs[1],
185                 .chip   = {
186                         .base   = S5P6440_GPB(0),
187                         .ngpio  = S5P6440_GPIO_B_NR,
188                         .label  = "GPB",
189                 },
190         }, {
191                 .base   = S5P6440_GPC_BASE,
192                 .config = &s5p6440_gpio_cfgs[1],
193                 .chip   = {
194                         .base   = S5P6440_GPC(0),
195                         .ngpio  = S5P6440_GPIO_C_NR,
196                         .label  = "GPC",
197                 },
198         }, {
199                 .base   = S5P6440_GPG_BASE,
200                 .config = &s5p6440_gpio_cfgs[1],
201                 .chip   = {
202                         .base   = S5P6440_GPG(0),
203                         .ngpio  = S5P6440_GPIO_G_NR,
204                         .label  = "GPG",
205                 },
206         },
207 };
208
209 static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
210         {
211                 .base   = S5P6440_GPH_BASE + 0x4,
212                 .config = &s5p6440_gpio_cfgs[1],
213                 .chip   = {
214                         .base   = S5P6440_GPH(0),
215                         .ngpio  = S5P6440_GPIO_H_NR,
216                         .label  = "GPH",
217                 },
218         },
219 };
220
221 static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
222         {
223                 .base   = S5P6440_GPR_BASE + 0x4,
224                 .config = &s5p6440_gpio_cfgs[2],
225                 .chip   = {
226                         .base   = S5P6440_GPR(0),
227                         .ngpio  = S5P6440_GPIO_R_NR,
228                         .label  = "GPR",
229                 },
230         },
231 };
232
233 static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
234         {
235                 .base   = S5P6440_GPF_BASE,
236                 .config = &s5p6440_gpio_cfgs[5],
237                 .chip   = {
238                         .base   = S5P6440_GPF(0),
239                         .ngpio  = S5P6440_GPIO_F_NR,
240                         .label  = "GPF",
241                 },
242         }, {
243                 .base   = S5P6440_GPI_BASE,
244                 .config = &s5p6440_gpio_cfgs[3],
245                 .chip   = {
246                         .base   = S5P6440_GPI(0),
247                         .ngpio  = S5P6440_GPIO_I_NR,
248                         .label  = "GPI",
249                 },
250         }, {
251                 .base   = S5P6440_GPJ_BASE,
252                 .config = &s5p6440_gpio_cfgs[3],
253                 .chip   = {
254                         .base   = S5P6440_GPJ(0),
255                         .ngpio  = S5P6440_GPIO_J_NR,
256                         .label  = "GPJ",
257                 },
258         }, {
259                 .base   = S5P6440_GPN_BASE,
260                 .config = &s5p6440_gpio_cfgs[4],
261                 .chip   = {
262                         .base   = S5P6440_GPN(0),
263                         .ngpio  = S5P6440_GPIO_N_NR,
264                         .label  = "GPN",
265                 },
266         }, {
267                 .base   = S5P6440_GPP_BASE,
268                 .config = &s5p6440_gpio_cfgs[5],
269                 .chip   = {
270                         .base   = S5P6440_GPP(0),
271                         .ngpio  = S5P6440_GPIO_P_NR,
272                         .label  = "GPP",
273                 },
274         },
275 };
276
277 void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
278 {
279         for (; nr_chips > 0; nr_chips--, chipcfg++) {
280                 if (!chipcfg->set_config)
281                         chipcfg->set_config     = s3c_gpio_setcfg_s3c64xx_4bit;
282                 if (!chipcfg->set_pull)
283                         chipcfg->set_pull       = s3c_gpio_setpull_updown;
284                 if (!chipcfg->get_pull)
285                         chipcfg->get_pull       = s3c_gpio_getpull_updown;
286         }
287 }
288
289 static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
290                                                 int nr_chips)
291 {
292         for (; nr_chips > 0; nr_chips--, chip++) {
293                 chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input;
294                 chip->chip.direction_output =
295                                         s5p6440_gpiolib_rbank_4bit2_output;
296                 s3c_gpiolib_add(chip);
297         }
298 }
299
300 static int __init s5p6440_gpiolib_init(void)
301 {
302         struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
303         int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
304
305         s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs,
306                                 ARRAY_SIZE(s5p6440_gpio_cfgs));
307
308         for (; nr_chips > 0; nr_chips--, chips++)
309                 s3c_gpiolib_add(chips);
310
311         samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
312                                 ARRAY_SIZE(s5p6440_gpio_4bit));
313
314         samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
315                                 ARRAY_SIZE(s5p6440_gpio_4bit2));
316
317         s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2,
318                                 ARRAY_SIZE(gpio_rbank_4bit2));
319
320         return 0;
321 }
322 arch_initcall(s5p6440_gpiolib_init);