ARM: S5P6440: Add S5P6440 GPIO support
authorKukjin Kim <kgene.kim@samsung.com>
Tue, 19 Jan 2010 06:31:17 +0000 (15:31 +0900)
committerBen Dooks <ben-linux@fluff.org>
Tue, 19 Jan 2010 09:37:18 +0000 (18:37 +0900)
This patch adds Samsung's S5P6440 GPIO support.

Signed-off-by: Adityapratap Sharma <aditya.ps@samsung.com>
Signed-off-by: Atul Dahiya <atul.dahiya@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
arch/arm/mach-s5p6440/Makefile
arch/arm/mach-s5p6440/include/mach/regs-gpio.h [new file with mode: 0644]
arch/arm/mach-s5p6440/s5p6440-gpio.c [new file with mode: 0644]
arch/arm/plat-s5p/Kconfig

index a3ffda96e87b1d7189f3137970a19d26b6a0b296..a79b13011edc17707612934d5afcebbbae4565db 100644 (file)
@@ -12,7 +12,7 @@ obj-                          :=
 
 # Core support for S5P6440 system
 
-obj-$(CONFIG_CPU_S5P6440)      += cpu.o
+obj-$(CONFIG_CPU_S5P6440)      += cpu.o s5p6440-gpio.o
 
 # machine support
 
diff --git a/arch/arm/mach-s5p6440/include/mach/regs-gpio.h b/arch/arm/mach-s5p6440/include/mach/regs-gpio.h
new file mode 100644 (file)
index 0000000..82ff753
--- /dev/null
@@ -0,0 +1,54 @@
+/* linux/arch/arm/mach-s5p6440/include/mach/regs-gpio.h
+ *
+ * Copyright (c) 2009 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * S5P6440 - GPIO register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_REGS_GPIO_H
+#define __ASM_ARCH_REGS_GPIO_H __FILE__
+
+#include <mach/map.h>
+
+/* Base addresses for each of the banks */
+#define S5P6440_GPA_BASE               (S5P_VA_GPIO + 0x0000)
+#define S5P6440_GPB_BASE               (S5P_VA_GPIO + 0x0020)
+#define S5P6440_GPC_BASE               (S5P_VA_GPIO + 0x0040)
+#define S5P6440_GPF_BASE               (S5P_VA_GPIO + 0x00A0)
+#define S5P6440_GPG_BASE               (S5P_VA_GPIO + 0x00C0)
+#define S5P6440_GPH_BASE               (S5P_VA_GPIO + 0x00E0)
+#define S5P6440_GPI_BASE               (S5P_VA_GPIO + 0x0100)
+#define S5P6440_GPJ_BASE               (S5P_VA_GPIO + 0x0120)
+#define S5P6440_GPN_BASE               (S5P_VA_GPIO + 0x0830)
+#define S5P6440_GPP_BASE               (S5P_VA_GPIO + 0x0160)
+#define S5P6440_GPR_BASE               (S5P_VA_GPIO + 0x0290)
+#define S5P6440_EINT0CON0              (S5P_VA_GPIO + 0x900)
+#define S5P6440_EINT0FLTCON0           (S5P_VA_GPIO + 0x910)
+#define S5P6440_EINT0FLTCON1           (S5P_VA_GPIO + 0x914)
+#define S5P6440_EINT0MASK              (S5P_VA_GPIO + 0x920)
+#define S5P6440_EINT0PEND              (S5P_VA_GPIO + 0x924)
+
+/* for LCD */
+#define S5P6440_SPCON_LCD_SEL_RGB      (1 << 0)
+#define S5P6440_SPCON_LCD_SEL_MASK     (3 << 0)
+
+/* These set of macros are not really useful for the
+ * GPF/GPI/GPJ/GPN/GPP,
+ * useful for others set of GPIO's (4 bit)
+ */
+#define S5P6440_GPIO_CONMASK(__gpio)   (0xf << ((__gpio) * 4))
+#define S5P6440_GPIO_INPUT(__gpio)     (0x0 << ((__gpio) * 4))
+#define S5P6440_GPIO_OUTPUT(__gpio)    (0x1 << ((__gpio) * 4))
+
+/* Use these macros for GPF/GPI/GPJ/GPN/GPP set of GPIO (2 bit)
+ * */
+#define S5P6440_GPIO2_CONMASK(__gpio)  (0x3 << ((__gpio) * 2))
+#define S5P6440_GPIO2_INPUT(__gpio)    (0x0 << ((__gpio) * 2))
+#define S5P6440_GPIO2_OUTPUT(__gpio)   (0x1 << ((__gpio) * 2))
+
+#endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/arch/arm/mach-s5p6440/s5p6440-gpio.c b/arch/arm/mach-s5p6440/s5p6440-gpio.c
new file mode 100644 (file)
index 0000000..742264c
--- /dev/null
@@ -0,0 +1,322 @@
+/* arch/arm/mach-s5p6440/s5p6440-gpio.c
+ *
+ * Copyright (c) 2009 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * S5P6440 - GPIOlib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <mach/map.h>
+#include <mach/gpio.h>
+#include <mach/regs-gpio.h>
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+/* GPIO bank summary:
+*
+* Bank GPIOs   Style   SlpCon  ExtInt Group
+* A    6       4Bit    Yes     1
+* B    7       4Bit    Yes     1
+* C    8       4Bit    Yes     2
+* F    2       2Bit    Yes     4 [1]
+* G    7       4Bit    Yes     5
+* H    10      4Bit[2] Yes     6
+* I    16      2Bit    Yes     None
+* J    12      2Bit    Yes     None
+* N    16      2Bit    No      IRQ_EINT
+* P    8       2Bit    Yes     8
+* R    15      4Bit[2] Yes     8
+*
+* [1] BANKF pins 14,15 do not form part of the external interrupt sources
+* [2] BANK has two control registers, GPxCON0 and GPxCON1
+*/
+
+static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
+                                            unsigned int offset)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       void __iomem *regcon = base;
+       unsigned long con;
+
+       switch (offset) {
+       case 6:
+               offset += 1;
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+               regcon -= 4;
+               break;
+       default:
+               offset -= 7;
+               break;
+       }
+
+       con = __raw_readl(regcon);
+       con &= ~(0xf << con_4bit_shift(offset));
+       __raw_writel(con, regcon);
+
+       return 0;
+}
+
+static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
+                                             unsigned int offset, int value)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       void __iomem *regcon = base;
+       unsigned long con;
+       unsigned long dat;
+       unsigned con_offset  = offset;
+
+       switch (con_offset) {
+       case 6:
+               con_offset += 1;
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+               regcon -= 4;
+               break;
+       default:
+               con_offset -= 7;
+               break;
+       }
+
+       con = __raw_readl(regcon);
+       con &= ~(0xf << con_4bit_shift(con_offset));
+       con |= 0x1 << con_4bit_shift(con_offset);
+
+       dat = __raw_readl(base + GPIODAT_OFF);
+       if (value)
+               dat |= 1 << offset;
+       else
+               dat &= ~(1 << offset);
+
+       __raw_writel(con, regcon);
+       __raw_writel(dat, base + GPIODAT_OFF);
+
+       return 0;
+}
+
+int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
+                                  unsigned int off, unsigned int cfg)
+{
+       void __iomem *reg = chip->base;
+       unsigned int shift;
+       u32 con;
+
+       switch (off) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+               shift = (off & 7) * 4;
+               reg -= 4;
+               break;
+       case 6:
+               shift = ((off + 1) & 7) * 4;
+               reg -= 4;
+       default:
+               shift = ((off + 1) & 7) * 4;
+               break;
+       }
+
+       if (s3c_gpio_is_cfg_special(cfg)) {
+               cfg &= 0xf;
+               cfg <<= shift;
+       }
+
+       con = __raw_readl(reg);
+       con &= ~(0xf << shift);
+       con |= cfg;
+       __raw_writel(con, reg);
+
+       return 0;
+}
+
+static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = {
+       {
+               .cfg_eint       = 0,
+       }, {
+               .cfg_eint       = 7,
+       }, {
+               .cfg_eint       = 3,
+               .set_config     = s5p6440_gpio_setcfg_4bit_rbank,
+       }, {
+               .cfg_eint       = 0,
+               .set_config     = s3c_gpio_setcfg_s3c24xx,
+       }, {
+               .cfg_eint       = 2,
+               .set_config     = s3c_gpio_setcfg_s3c24xx,
+       }, {
+               .cfg_eint       = 3,
+               .set_config     = s3c_gpio_setcfg_s3c24xx,
+       },
+};
+
+static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
+       {
+               .base   = S5P6440_GPA_BASE,
+               .config = &s5p6440_gpio_cfgs[1],
+               .chip   = {
+                       .base   = S5P6440_GPA(0),
+                       .ngpio  = S5P6440_GPIO_A_NR,
+                       .label  = "GPA",
+               },
+       }, {
+               .base   = S5P6440_GPB_BASE,
+               .config = &s5p6440_gpio_cfgs[1],
+               .chip   = {
+                       .base   = S5P6440_GPB(0),
+                       .ngpio  = S5P6440_GPIO_B_NR,
+                       .label  = "GPB",
+               },
+       }, {
+               .base   = S5P6440_GPC_BASE,
+               .config = &s5p6440_gpio_cfgs[1],
+               .chip   = {
+                       .base   = S5P6440_GPC(0),
+                       .ngpio  = S5P6440_GPIO_C_NR,
+                       .label  = "GPC",
+               },
+       }, {
+               .base   = S5P6440_GPG_BASE,
+               .config = &s5p6440_gpio_cfgs[1],
+               .chip   = {
+                       .base   = S5P6440_GPG(0),
+                       .ngpio  = S5P6440_GPIO_G_NR,
+                       .label  = "GPG",
+               },
+       },
+};
+
+static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
+       {
+               .base   = S5P6440_GPH_BASE + 0x4,
+               .config = &s5p6440_gpio_cfgs[1],
+               .chip   = {
+                       .base   = S5P6440_GPH(0),
+                       .ngpio  = S5P6440_GPIO_H_NR,
+                       .label  = "GPH",
+               },
+       },
+};
+
+static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
+       {
+               .base   = S5P6440_GPR_BASE + 0x4,
+               .config = &s5p6440_gpio_cfgs[2],
+               .chip   = {
+                       .base   = S5P6440_GPR(0),
+                       .ngpio  = S5P6440_GPIO_R_NR,
+                       .label  = "GPR",
+               },
+       },
+};
+
+static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
+       {
+               .base   = S5P6440_GPF_BASE,
+               .config = &s5p6440_gpio_cfgs[5],
+               .chip   = {
+                       .base   = S5P6440_GPF(0),
+                       .ngpio  = S5P6440_GPIO_F_NR,
+                       .label  = "GPF",
+               },
+       }, {
+               .base   = S5P6440_GPI_BASE,
+               .config = &s5p6440_gpio_cfgs[3],
+               .chip   = {
+                       .base   = S5P6440_GPI(0),
+                       .ngpio  = S5P6440_GPIO_I_NR,
+                       .label  = "GPI",
+               },
+       }, {
+               .base   = S5P6440_GPJ_BASE,
+               .config = &s5p6440_gpio_cfgs[3],
+               .chip   = {
+                       .base   = S5P6440_GPJ(0),
+                       .ngpio  = S5P6440_GPIO_J_NR,
+                       .label  = "GPJ",
+               },
+       }, {
+               .base   = S5P6440_GPN_BASE,
+               .config = &s5p6440_gpio_cfgs[4],
+               .chip   = {
+                       .base   = S5P6440_GPN(0),
+                       .ngpio  = S5P6440_GPIO_N_NR,
+                       .label  = "GPN",
+               },
+       }, {
+               .base   = S5P6440_GPP_BASE,
+               .config = &s5p6440_gpio_cfgs[5],
+               .chip   = {
+                       .base   = S5P6440_GPP(0),
+                       .ngpio  = S5P6440_GPIO_P_NR,
+                       .label  = "GPP",
+               },
+       },
+};
+
+void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
+{
+       for (; nr_chips > 0; nr_chips--, chipcfg++) {
+               if (!chipcfg->set_config)
+                       chipcfg->set_config     = s3c_gpio_setcfg_s3c64xx_4bit;
+               if (!chipcfg->set_pull)
+                       chipcfg->set_pull       = s3c_gpio_setpull_updown;
+               if (!chipcfg->get_pull)
+                       chipcfg->get_pull       = s3c_gpio_getpull_updown;
+       }
+}
+
+static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
+                                               int nr_chips)
+{
+       for (; nr_chips > 0; nr_chips--, chip++) {
+               chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input;
+               chip->chip.direction_output =
+                                       s5p6440_gpiolib_rbank_4bit2_output;
+               s3c_gpiolib_add(chip);
+       }
+}
+
+static int __init s5p6440_gpiolib_init(void)
+{
+       struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
+       int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
+
+       s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs,
+                               ARRAY_SIZE(s5p6440_gpio_cfgs));
+
+       for (; nr_chips > 0; nr_chips--, chips++)
+               s3c_gpiolib_add(chips);
+
+       samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
+                               ARRAY_SIZE(s5p6440_gpio_4bit));
+
+       samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
+                               ARRAY_SIZE(s5p6440_gpio_4bit2));
+
+       s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2,
+                               ARRAY_SIZE(gpio_rbank_4bit2));
+
+       return 0;
+}
+arch_initcall(s5p6440_gpiolib_init);
index 7e08b4064414334219f678a6fbfd40b69d9244af..e7c31e7060e583b361183de3cd72050a7ae4aaa9 100644 (file)
@@ -14,6 +14,10 @@ config PLAT_S5P
        select NO_IOPORT
        select ARCH_REQUIRE_GPIOLIB
        select S3C_GPIO_TRACK
+       select SAMSUNG_GPIOLIB_4BIT
+       select S3C_GPIO_CFG_S3C64XX
+       select S3C_GPIO_PULL_UPDOWN
+       select S3C_GPIO_CFG_S3C24XX
        select PLAT_SAMSUNG
        select SAMSUNG_CLKSRC
        select SAMSUNG_IRQ_VIC_TIMER