upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / gpiolib.c
1 /* linux/arch/arm/mach-s5pv310/gpiolib.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * S5PV310 - 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 #include <plat/gpio-core.h>
18 #include <plat/gpio-cfg.h>
19 #include <plat/gpio-cfg-helpers.h>
20 #include <mach/map.h>
21
22 static int s5pc210_gpio_setcfg_pdn(struct s3c_gpio_chip *chip,
23                 unsigned int off, s3c_gpio_pdncfg_t to)
24 {
25         void __iomem *reg = chip->base + 0x10;
26         int shift = off * 2;
27         u32 pup;
28
29         pup = __raw_readl(reg);
30         pup &= ~(3 << shift);
31         pup |= to << shift;
32         __raw_writel(pup, reg);
33
34         return 0;
35 }
36
37 static int s5pc210_gpio_setpull_pdn(struct s3c_gpio_chip *chip,
38                 unsigned int off, s3c_gpio_pull_t pull)
39 {
40         void __iomem *reg = chip->base + 0x14;
41         int shift = off * 2;
42         u32 pup;
43
44         pup = __raw_readl(reg);
45         pup &= ~(3 << shift);
46         pup |= pull << shift;
47         __raw_writel(pup, reg);
48
49         return 0;
50 }
51
52 #ifdef CONFIG_DEBUG_GPIO
53 static int s5pc210_gpio_setcfg_4bit(struct s3c_gpio_chip *chip,
54                                  unsigned int off, unsigned int cfg)
55 {
56         void __iomem *reg = chip->base;
57         unsigned int shift = (off & 7) * 4;
58         u32 con;
59
60         if (s3c_gpio_is_cfg_special(cfg)) {
61                 cfg &= 0xf;
62                 cfg <<= shift;
63         }
64
65         con = __raw_readl(reg);
66         con = (con >> shift) & 0xf;
67
68         if (con != (cfg >> shift))
69                 printk(KERN_WARNING ">>> %s(%d) CON is changed from 0x%x to 0x%x (0x%08x)\n",
70                         chip->chip.label, off, con, (cfg >> shift),
71                         __raw_readl(reg));
72
73         return s3c_gpio_setcfg_s3c64xx_4bit(chip, off, cfg);
74 }
75
76 static int s5pc210_gpio_setpull_updown(struct s3c_gpio_chip *chip,
77                             unsigned int off, s3c_gpio_pull_t pull)
78 {
79         void __iomem *reg = chip->base + 0x08;
80         int shift = off * 2;
81         u32 pup;
82
83         pup = __raw_readl(reg);
84         pup = (pup >> shift) & 0x3;
85         if (pup != pull)
86                 printk(KERN_WARNING "%s(%d) PUP is changed from 0x%x to 0x%x\n",
87                         chip->chip.label, off, pup, pull);
88
89         return s3c_gpio_setpull_updown(chip, off, pull);
90 }
91
92 static struct s3c_gpio_cfg gpio_cfg = {
93         .set_config     = s5pc210_gpio_setcfg_4bit,
94         .set_pull       = s5pc210_gpio_setpull_updown,
95         .get_pull       = s3c_gpio_getpull_updown,
96         .set_pdn_config = s5pc210_gpio_setcfg_pdn,
97         .set_pdn_pull   = s5pc210_gpio_setpull_pdn,
98 };
99
100 static struct s3c_gpio_cfg gpio_cfg_noint = {
101         .set_config     = s5pc210_gpio_setcfg_4bit,
102         .set_pull       = s5pc210_gpio_setpull_updown,
103         .get_pull       = s3c_gpio_getpull_updown,
104         .set_pdn_config = s5pc210_gpio_setcfg_pdn,
105         .set_pdn_pull   = s5pc210_gpio_setpull_pdn,
106 };
107
108 static struct s3c_gpio_cfg gpio_cfg_extint = {
109         .set_config     = s5pc210_gpio_setcfg_4bit,
110         .set_pull       = s5pc210_gpio_setpull_updown,
111         .get_pull       = s3c_gpio_getpull_updown,
112 };
113 #else
114 static struct s3c_gpio_cfg gpio_cfg = {
115         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
116         .set_pull       = s3c_gpio_setpull_updown,
117         .get_pull       = s3c_gpio_getpull_updown,
118         .set_pdn_config = s5pc210_gpio_setcfg_pdn,
119         .set_pdn_pull   = s5pc210_gpio_setpull_pdn,
120 };
121
122 static struct s3c_gpio_cfg gpio_cfg_noint = {
123         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
124         .set_pull       = s3c_gpio_setpull_updown,
125         .get_pull       = s3c_gpio_getpull_updown,
126         .set_pdn_config = s5pc210_gpio_setcfg_pdn,
127         .set_pdn_pull   = s5pc210_gpio_setpull_pdn,
128 };
129
130 static struct s3c_gpio_cfg gpio_cfg_extint = {
131         .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
132         .set_pull       = s3c_gpio_setpull_updown,
133         .get_pull       = s3c_gpio_getpull_updown,
134 };
135 #endif
136
137 static int s5pv310_gpio2int(struct gpio_chip *chip, unsigned pin)
138 {
139         int ret = 0;
140         int base = chip->base;
141
142         switch (base) {
143         case S5PV310_GPX0(0):
144                 ret = IRQ_EINT(0) + pin;
145                 break;
146
147         case S5PV310_GPX1(0):
148                 ret = IRQ_EINT(8) + pin;
149                 break;
150
151         case S5PV310_GPX2(0):
152                 ret = IRQ_EINT(16) + pin;
153                 break;
154
155         case S5PV310_GPX3(0):
156                 ret = IRQ_EINT(24) + pin;
157                 break;
158         }
159
160         return ret;
161 }
162
163 /* GPIO bank's base address given the index of the bank in the
164  * list of all gpio banks.
165  */
166 #define S5PV310_BANK_BASE1(bank_nr)     (S5P_VA_GPIO + ((bank_nr) * 0x20))
167 #define S5PV310_BANK_BASE2(bank_nr)     (S5P_VA_GPIO2 + ((bank_nr) * 0x20))
168 #define S5PV310_BANK_BASE3(bank_nr)     (S5P_VA_GPIO3 + ((bank_nr) * 0x20))
169
170 /*
171  * Following are the gpio banks in v310.
172  *
173  * The 'config' member when left to NULL, is initialized to the default
174  * structure gpio_cfg in the init function below.
175  *
176  * The 'base' member is also initialized in the init function below.
177  * Note: The initialization of 'base' member of s3c_gpio_chip structure
178  * uses the above macro and depends on the banks being listed in order here.
179  */
180 static struct s3c_gpio_chip s5pv310_gpio_part1_4bit[] = {
181         {
182                 .chip   = {
183                         .base   = S5PV310_GPA0(0),
184                         .ngpio  = S5PV310_GPIO_A0_NR,
185                         .label  = "GPA0",
186                 },
187         }, {
188                 .chip   = {
189                         .base   = S5PV310_GPA1(0),
190                         .ngpio  = S5PV310_GPIO_A1_NR,
191                         .label  = "GPA1",
192                 },
193         }, {
194                 .chip   = {
195                         .base   = S5PV310_GPB(0),
196                         .ngpio  = S5PV310_GPIO_B_NR,
197                         .label  = "GPB",
198                 },
199         }, {
200                 .chip   = {
201                         .base   = S5PV310_GPC0(0),
202                         .ngpio  = S5PV310_GPIO_C0_NR,
203                         .label  = "GPC0",
204                 },
205         }, {
206                 .chip   = {
207                         .base   = S5PV310_GPC1(0),
208                         .ngpio  = S5PV310_GPIO_C1_NR,
209                         .label  = "GPC1",
210                 },
211         }, {
212                 .chip   = {
213                         .base   = S5PV310_GPD0(0),
214                         .ngpio  = S5PV310_GPIO_D0_NR,
215                         .label  = "GPD0",
216                 },
217         }, {
218                 .chip   = {
219                         .base   = S5PV310_GPD1(0),
220                         .ngpio  = S5PV310_GPIO_D1_NR,
221                         .label  = "GPD1",
222                 },
223         }, {
224                 .chip   = {
225                         .base   = S5PV310_GPE0(0),
226                         .ngpio  = S5PV310_GPIO_E0_NR,
227                         .label  = "GPE0",
228                 },
229         }, {
230                 .chip   = {
231                         .base   = S5PV310_GPE1(0),
232                         .ngpio  = S5PV310_GPIO_E1_NR,
233                         .label  = "GPE1",
234                 },
235         }, {
236                 .chip   = {
237                         .base   = S5PV310_GPE2(0),
238                         .ngpio  = S5PV310_GPIO_E2_NR,
239                         .label  = "GPE2",
240                 },
241         }, {
242                 .chip   = {
243                         .base   = S5PV310_GPE3(0),
244                         .ngpio  = S5PV310_GPIO_E3_NR,
245                         .label  = "GPE3",
246                 },
247         }, {
248                 .chip   = {
249                         .base   = S5PV310_GPE4(0),
250                         .ngpio  = S5PV310_GPIO_E4_NR,
251                         .label  = "GPE4",
252                 },
253         }, {
254                 .chip   = {
255                         .base   = S5PV310_GPF0(0),
256                         .ngpio  = S5PV310_GPIO_F0_NR,
257                         .label  = "GPF0",
258                 },
259         }, {
260                 .chip   = {
261                         .base   = S5PV310_GPF1(0),
262                         .ngpio  = S5PV310_GPIO_F1_NR,
263                         .label  = "GPF1",
264                 },
265         }, {
266                 .chip   = {
267                         .base   = S5PV310_GPF2(0),
268                         .ngpio  = S5PV310_GPIO_F2_NR,
269                         .label  = "GPF2",
270                 },
271         }, {
272                 .chip   = {
273                         .base   = S5PV310_GPF3(0),
274                         .ngpio  = S5PV310_GPIO_F3_NR,
275                         .label  = "GPF3",
276                 },
277         },
278 };
279
280 static struct s3c_gpio_chip s5pv310_gpio_part2_4bit[] = {
281         {
282                 .chip   = {
283                         .base   = S5PV310_GPJ0(0),
284                         .ngpio  = S5PV310_GPIO_J0_NR,
285                         .label  = "GPJ0",
286                 },
287         }, {
288                 .chip   = {
289                         .base   = S5PV310_GPJ1(0),
290                         .ngpio  = S5PV310_GPIO_J1_NR,
291                         .label  = "GPJ1",
292                 },
293         }, {
294                 .chip   = {
295                         .base   = S5PV310_GPK0(0),
296                         .ngpio  = S5PV310_GPIO_K0_NR,
297                         .label  = "GPK0",
298                 },
299         }, {
300                 .chip   = {
301                         .base   = S5PV310_GPK1(0),
302                         .ngpio  = S5PV310_GPIO_K1_NR,
303                         .label  = "GPK1",
304                 },
305         }, {
306                 .chip   = {
307                         .base   = S5PV310_GPK2(0),
308                         .ngpio  = S5PV310_GPIO_K2_NR,
309                         .label  = "GPK2",
310                 },
311         }, {
312                 .chip   = {
313                         .base   = S5PV310_GPK3(0),
314                         .ngpio  = S5PV310_GPIO_K3_NR,
315                         .label  = "GPK3",
316                 },
317         }, {
318                 .chip   = {
319                         .base   = S5PV310_GPL0(0),
320                         .ngpio  = S5PV310_GPIO_L0_NR,
321                         .label  = "GPL0",
322                 },
323         }, {
324                 .chip   = {
325                         .base   = S5PV310_GPL1(0),
326                         .ngpio  = S5PV310_GPIO_L1_NR,
327                         .label  = "GPL1",
328                 },
329         }, {
330                 .chip   = {
331                         .base   = S5PV310_GPL2(0),
332                         .ngpio  = S5PV310_GPIO_L2_NR,
333                         .label  = "GPL2",
334                 },
335         }, {
336                 .config = &gpio_cfg_noint,
337                 .chip   = {
338                         .base   = S5PV310_GPY0(0),
339                         .ngpio  = S5PV310_GPIO_Y0_NR,
340                         .label  = "GPY0",
341                 },
342         }, {
343                 .config = &gpio_cfg_noint,
344                 .chip   = {
345                         .base   = S5PV310_GPY1(0),
346                         .ngpio  = S5PV310_GPIO_Y1_NR,
347                         .label  = "GPY1",
348                 },
349         }, {
350                 .config = &gpio_cfg_noint,
351                 .chip   = {
352                         .base   = S5PV310_GPY2(0),
353                         .ngpio  = S5PV310_GPIO_Y2_NR,
354                         .label  = "GPY2",
355                 },
356         }, {
357                 .config = &gpio_cfg_noint,
358                 .chip   = {
359                         .base   = S5PV310_GPY3(0),
360                         .ngpio  = S5PV310_GPIO_Y3_NR,
361                         .label  = "GPY3",
362                 },
363         }, {
364                 .config = &gpio_cfg_noint,
365                 .chip   = {
366                         .base   = S5PV310_GPY4(0),
367                         .ngpio  = S5PV310_GPIO_Y4_NR,
368                         .label  = "GPY4",
369                 },
370         }, {
371                 .config = &gpio_cfg_noint,
372                 .chip   = {
373                         .base   = S5PV310_GPY5(0),
374                         .ngpio  = S5PV310_GPIO_Y5_NR,
375                         .label  = "GPY5",
376                 },
377         }, {
378                 .config = &gpio_cfg_noint,
379                 .chip   = {
380                         .base   = S5PV310_GPY6(0),
381                         .ngpio  = S5PV310_GPIO_Y6_NR,
382                         .label  = "GPY6",
383                 },
384         }, {
385                 .base   = (S5P_VA_GPIO2 + 0xC00),
386                 .config = &gpio_cfg_extint,
387                 .chip   = {
388                         .base   = S5PV310_GPX0(0),
389                         .ngpio  = S5PV310_GPIO_X0_NR,
390                         .label  = "GPX0",
391                         .to_irq = s5pv310_gpio2int,
392                 },
393         }, {
394                 .base   = (S5P_VA_GPIO2 + 0xC20),
395                 .config = &gpio_cfg_extint,
396                 .chip   = {
397                         .base   = S5PV310_GPX1(0),
398                         .ngpio  = S5PV310_GPIO_X1_NR,
399                         .label  = "GPX1",
400                         .to_irq = s5pv310_gpio2int,
401                 },
402         }, {
403                 .base   = (S5P_VA_GPIO2 + 0xC40),
404                 .config = &gpio_cfg_extint,
405                 .chip   = {
406                         .base   = S5PV310_GPX2(0),
407                         .ngpio  = S5PV310_GPIO_X2_NR,
408                         .label  = "GPX2",
409                         .to_irq = s5pv310_gpio2int,
410                 },
411         }, {
412                 .base   = (S5P_VA_GPIO2 + 0xC60),
413                 .config = &gpio_cfg_extint,
414                 .chip   = {
415                         .base   = S5PV310_GPX3(0),
416                         .ngpio  = S5PV310_GPIO_X3_NR,
417                         .label  = "GPX3",
418                         .to_irq = s5pv310_gpio2int,
419                 },
420         },
421 };
422
423 static struct s3c_gpio_chip s5pv310_gpio_part3_4bit[] = {
424         {
425                 .config = &gpio_cfg_noint,
426                 .chip   = {
427                         .base   = S5PV310_GPZ(0),
428                         .ngpio  = S5PV310_GPIO_Z_NR,
429                         .label  = "GPZ",
430                 },
431         },
432 };
433
434 static int s5pc210_extint_to_irq(struct gpio_chip *gpio, unsigned int offset)
435 {
436         struct s3c_gpio_chip *chip = to_s3c_gpio(gpio);
437         int irq;
438
439         irq = (chip->group * 8) + offset;
440         return IRQ_EINT(irq);
441 }
442
443 static __init int s5pv310_gpiolib_init(void)
444 {
445         struct samsung_irq_gpio_info gpio[2];
446         struct s3c_gpio_chip *chip;
447         int i;
448         int nr_chips;
449         int group = 0, extint = 0;
450
451         chip = s5pv310_gpio_part1_4bit;
452         nr_chips = ARRAY_SIZE(s5pv310_gpio_part1_4bit);
453
454         for (i = 0; i < nr_chips; i++, chip++) {
455                 if (chip->config == NULL) {
456                         chip->config = &gpio_cfg;
457                         /* Assign the GPIO interrupt group */
458                         chip->group = group++;
459                         chip->localgroup = chip->group;
460                         samsung_irq_gpio_add(chip);
461                 }
462                 if (chip->base == NULL)
463                         chip->base = S5PV310_BANK_BASE1(i);
464         }
465
466         samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part1_4bit, nr_chips);
467
468         chip = s5pv310_gpio_part2_4bit;
469         nr_chips = ARRAY_SIZE(s5pv310_gpio_part2_4bit);
470
471         for (i = 0; i < nr_chips; i++, chip++) {
472                 if (chip->config == NULL) {
473                         chip->config = &gpio_cfg;
474                         /* Assign the GPIO interrupt group */
475                         chip->group = group++;
476                         chip->localgroup = (chip->group - IRQ_GPIO1_NR_GROUPS);
477                         samsung_irq_gpio_add(chip);
478                 }
479                 if (chip->config == &gpio_cfg_extint) {
480                         /* Assign the External GPIO interrupt group */
481                         chip->group = extint++;
482                         chip->chip.to_irq = s5pc210_extint_to_irq;
483                 }
484                 if (chip->base == NULL)
485                         chip->base = S5PV310_BANK_BASE2(i);
486         }
487
488         samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part2_4bit, nr_chips);
489
490         chip = s5pv310_gpio_part3_4bit;
491         nr_chips = ARRAY_SIZE(s5pv310_gpio_part3_4bit);
492
493         for (i = 0; i < nr_chips; i++, chip++) {
494                 if (chip->config == NULL) {
495                         chip->config = &gpio_cfg;
496                         /* Assign the GPIO interrupt group */
497                         chip->group = group++;
498                         chip->localgroup = (chip->group - IRQ_GPIO1_NR_GROUPS - IRQ_GPIO2_NR_GROUPS);
499                         samsung_irq_gpio_add(chip);
500                 }
501                 if (chip->base == NULL)
502                         chip->base = S5PV310_BANK_BASE3(i);
503         }
504
505         samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part3_4bit, nr_chips);
506
507         /* Register two GPIO IRQ */
508         gpio[0].irq = IRQ_GPIO_XA;
509         gpio[0].sig.start = 0;
510         gpio[0].sig.nr_groups = IRQ_GPIO1_NR_GROUPS;
511         gpio[0].sig.base = S5P_VA_GPIO;
512         gpio[0].handler = NULL;
513         gpio[1].irq = IRQ_GPIO_XB;
514         gpio[1].sig.start = IRQ_GPIO1_NR_GROUPS;
515         gpio[1].sig.nr_groups = IRQ_GPIO2_NR_GROUPS;
516         gpio[1].sig.base = S5P_VA_GPIO2;
517         gpio[1].handler = NULL;
518         samsung_irq_gpio_register(gpio, ARRAY_SIZE(gpio));
519
520         return 0;
521 }
522 core_initcall(s5pv310_gpiolib_init);