aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5p64x0/gpiolib.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s5p64x0/gpiolib.c')
-rw-r--r--arch/arm/mach-s5p64x0/gpiolib.c511
1 files changed, 511 insertions, 0 deletions
diff --git a/arch/arm/mach-s5p64x0/gpiolib.c b/arch/arm/mach-s5p64x0/gpiolib.c
new file mode 100644
index 000000000000..e7fb3b004e77
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/gpiolib.c
@@ -0,0 +1,511 @@
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
65static 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
101static 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
148int 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
186static 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
209static 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
245static 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
257static 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
269static 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
313static 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
357static 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
377static 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
389static 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
449void __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
463static 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
474static 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}
511core_initcall(s5p64x0_gpiolib_init);