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