1 /* linux/arch/arm/mach-s5pv310/gpiolib.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * S5PV310 - GPIOlib support
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.
13 #include <linux/kernel.h>
14 #include <linux/irq.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>
22 static int s5pc210_gpio_setcfg_pdn(struct s3c_gpio_chip *chip,
23 unsigned int off, s3c_gpio_pdncfg_t to)
25 void __iomem *reg = chip->base + 0x10;
29 pup = __raw_readl(reg);
32 __raw_writel(pup, reg);
37 static int s5pc210_gpio_setpull_pdn(struct s3c_gpio_chip *chip,
38 unsigned int off, s3c_gpio_pull_t pull)
40 void __iomem *reg = chip->base + 0x14;
44 pup = __raw_readl(reg);
47 __raw_writel(pup, reg);
52 #ifdef CONFIG_DEBUG_GPIO
53 static int s5pc210_gpio_setcfg_4bit(struct s3c_gpio_chip *chip,
54 unsigned int off, unsigned int cfg)
56 void __iomem *reg = chip->base;
57 unsigned int shift = (off & 7) * 4;
60 if (s3c_gpio_is_cfg_special(cfg)) {
65 con = __raw_readl(reg);
66 con = (con >> shift) & 0xf;
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),
73 return s3c_gpio_setcfg_s3c64xx_4bit(chip, off, cfg);
76 static int s5pc210_gpio_setpull_updown(struct s3c_gpio_chip *chip,
77 unsigned int off, s3c_gpio_pull_t pull)
79 void __iomem *reg = chip->base + 0x08;
83 pup = __raw_readl(reg);
84 pup = (pup >> shift) & 0x3;
86 printk(KERN_WARNING "%s(%d) PUP is changed from 0x%x to 0x%x\n",
87 chip->chip.label, off, pup, pull);
89 return s3c_gpio_setpull_updown(chip, off, pull);
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,
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,
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,
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,
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,
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,
137 static int s5pv310_gpio2int(struct gpio_chip *chip, unsigned pin)
140 int base = chip->base;
143 case S5PV310_GPX0(0):
144 ret = IRQ_EINT(0) + pin;
147 case S5PV310_GPX1(0):
148 ret = IRQ_EINT(8) + pin;
151 case S5PV310_GPX2(0):
152 ret = IRQ_EINT(16) + pin;
155 case S5PV310_GPX3(0):
156 ret = IRQ_EINT(24) + pin;
163 /* GPIO bank's base address given the index of the bank in the
164 * list of all gpio banks.
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))
171 * Following are the gpio banks in v310.
173 * The 'config' member when left to NULL, is initialized to the default
174 * structure gpio_cfg in the init function below.
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.
180 static struct s3c_gpio_chip s5pv310_gpio_part1_4bit[] = {
183 .base = S5PV310_GPA0(0),
184 .ngpio = S5PV310_GPIO_A0_NR,
189 .base = S5PV310_GPA1(0),
190 .ngpio = S5PV310_GPIO_A1_NR,
195 .base = S5PV310_GPB(0),
196 .ngpio = S5PV310_GPIO_B_NR,
201 .base = S5PV310_GPC0(0),
202 .ngpio = S5PV310_GPIO_C0_NR,
207 .base = S5PV310_GPC1(0),
208 .ngpio = S5PV310_GPIO_C1_NR,
213 .base = S5PV310_GPD0(0),
214 .ngpio = S5PV310_GPIO_D0_NR,
219 .base = S5PV310_GPD1(0),
220 .ngpio = S5PV310_GPIO_D1_NR,
225 .base = S5PV310_GPE0(0),
226 .ngpio = S5PV310_GPIO_E0_NR,
231 .base = S5PV310_GPE1(0),
232 .ngpio = S5PV310_GPIO_E1_NR,
237 .base = S5PV310_GPE2(0),
238 .ngpio = S5PV310_GPIO_E2_NR,
243 .base = S5PV310_GPE3(0),
244 .ngpio = S5PV310_GPIO_E3_NR,
249 .base = S5PV310_GPE4(0),
250 .ngpio = S5PV310_GPIO_E4_NR,
255 .base = S5PV310_GPF0(0),
256 .ngpio = S5PV310_GPIO_F0_NR,
261 .base = S5PV310_GPF1(0),
262 .ngpio = S5PV310_GPIO_F1_NR,
267 .base = S5PV310_GPF2(0),
268 .ngpio = S5PV310_GPIO_F2_NR,
273 .base = S5PV310_GPF3(0),
274 .ngpio = S5PV310_GPIO_F3_NR,
280 static struct s3c_gpio_chip s5pv310_gpio_part2_4bit[] = {
283 .base = S5PV310_GPJ0(0),
284 .ngpio = S5PV310_GPIO_J0_NR,
289 .base = S5PV310_GPJ1(0),
290 .ngpio = S5PV310_GPIO_J1_NR,
295 .base = S5PV310_GPK0(0),
296 .ngpio = S5PV310_GPIO_K0_NR,
301 .base = S5PV310_GPK1(0),
302 .ngpio = S5PV310_GPIO_K1_NR,
307 .base = S5PV310_GPK2(0),
308 .ngpio = S5PV310_GPIO_K2_NR,
313 .base = S5PV310_GPK3(0),
314 .ngpio = S5PV310_GPIO_K3_NR,
319 .base = S5PV310_GPL0(0),
320 .ngpio = S5PV310_GPIO_L0_NR,
325 .base = S5PV310_GPL1(0),
326 .ngpio = S5PV310_GPIO_L1_NR,
331 .base = S5PV310_GPL2(0),
332 .ngpio = S5PV310_GPIO_L2_NR,
336 .config = &gpio_cfg_noint,
338 .base = S5PV310_GPY0(0),
339 .ngpio = S5PV310_GPIO_Y0_NR,
343 .config = &gpio_cfg_noint,
345 .base = S5PV310_GPY1(0),
346 .ngpio = S5PV310_GPIO_Y1_NR,
350 .config = &gpio_cfg_noint,
352 .base = S5PV310_GPY2(0),
353 .ngpio = S5PV310_GPIO_Y2_NR,
357 .config = &gpio_cfg_noint,
359 .base = S5PV310_GPY3(0),
360 .ngpio = S5PV310_GPIO_Y3_NR,
364 .config = &gpio_cfg_noint,
366 .base = S5PV310_GPY4(0),
367 .ngpio = S5PV310_GPIO_Y4_NR,
371 .config = &gpio_cfg_noint,
373 .base = S5PV310_GPY5(0),
374 .ngpio = S5PV310_GPIO_Y5_NR,
378 .config = &gpio_cfg_noint,
380 .base = S5PV310_GPY6(0),
381 .ngpio = S5PV310_GPIO_Y6_NR,
385 .base = (S5P_VA_GPIO2 + 0xC00),
386 .config = &gpio_cfg_extint,
388 .base = S5PV310_GPX0(0),
389 .ngpio = S5PV310_GPIO_X0_NR,
391 .to_irq = s5pv310_gpio2int,
394 .base = (S5P_VA_GPIO2 + 0xC20),
395 .config = &gpio_cfg_extint,
397 .base = S5PV310_GPX1(0),
398 .ngpio = S5PV310_GPIO_X1_NR,
400 .to_irq = s5pv310_gpio2int,
403 .base = (S5P_VA_GPIO2 + 0xC40),
404 .config = &gpio_cfg_extint,
406 .base = S5PV310_GPX2(0),
407 .ngpio = S5PV310_GPIO_X2_NR,
409 .to_irq = s5pv310_gpio2int,
412 .base = (S5P_VA_GPIO2 + 0xC60),
413 .config = &gpio_cfg_extint,
415 .base = S5PV310_GPX3(0),
416 .ngpio = S5PV310_GPIO_X3_NR,
418 .to_irq = s5pv310_gpio2int,
423 static struct s3c_gpio_chip s5pv310_gpio_part3_4bit[] = {
425 .config = &gpio_cfg_noint,
427 .base = S5PV310_GPZ(0),
428 .ngpio = S5PV310_GPIO_Z_NR,
434 static int s5pc210_extint_to_irq(struct gpio_chip *gpio, unsigned int offset)
436 struct s3c_gpio_chip *chip = to_s3c_gpio(gpio);
439 irq = (chip->group * 8) + offset;
440 return IRQ_EINT(irq);
443 static __init int s5pv310_gpiolib_init(void)
445 struct samsung_irq_gpio_info gpio[2];
446 struct s3c_gpio_chip *chip;
449 int group = 0, extint = 0;
451 chip = s5pv310_gpio_part1_4bit;
452 nr_chips = ARRAY_SIZE(s5pv310_gpio_part1_4bit);
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);
462 if (chip->base == NULL)
463 chip->base = S5PV310_BANK_BASE1(i);
466 samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part1_4bit, nr_chips);
468 chip = s5pv310_gpio_part2_4bit;
469 nr_chips = ARRAY_SIZE(s5pv310_gpio_part2_4bit);
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);
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;
484 if (chip->base == NULL)
485 chip->base = S5PV310_BANK_BASE2(i);
488 samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part2_4bit, nr_chips);
490 chip = s5pv310_gpio_part3_4bit;
491 nr_chips = ARRAY_SIZE(s5pv310_gpio_part3_4bit);
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);
501 if (chip->base == NULL)
502 chip->base = S5PV310_BANK_BASE3(i);
505 samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part3_4bit, nr_chips);
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));
522 core_initcall(s5pv310_gpiolib_init);