linux/arch/arm/plat-s3c64xx/gpiolib.c
<<
>>
Prefs
   1/* arch/arm/plat-s3c64xx/gpiolib.c
   2 *
   3 * Copyright 2008 Openmoko, Inc.
   4 * Copyright 2008 Simtec Electronics
   5 *      Ben Dooks <ben@simtec.co.uk>
   6 *      http://armlinux.simtec.co.uk/
   7 *
   8 * S3C64XX - GPIOlib support 
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/irq.h>
  17#include <linux/io.h>
  18
  19#include <mach/map.h>
  20#include <mach/gpio.h>
  21#include <mach/gpio-core.h>
  22
  23#include <plat/gpio-cfg.h>
  24#include <plat/gpio-cfg-helpers.h>
  25#include <plat/regs-gpio.h>
  26
  27/* GPIO bank summary:
  28 *
  29 * Bank GPIOs   Style   SlpCon  ExtInt Group
  30 * A    8       4Bit    Yes     1
  31 * B    7       4Bit    Yes     1
  32 * C    8       4Bit    Yes     2
  33 * D    5       4Bit    Yes     3
  34 * E    5       4Bit    Yes     None
  35 * F    16      2Bit    Yes     4 [1]
  36 * G    7       4Bit    Yes     5
  37 * H    10      4Bit[2] Yes     6
  38 * I    16      2Bit    Yes     None
  39 * J    12      2Bit    Yes     None
  40 * K    16      4Bit[2] No      None
  41 * L    15      4Bit[2] No      None
  42 * M    6       4Bit    No      IRQ_EINT
  43 * N    16      2Bit    No      IRQ_EINT
  44 * O    16      2Bit    Yes     7
  45 * P    15      2Bit    Yes     8
  46 * Q    9       2Bit    Yes     9
  47 *
  48 * [1] BANKF pins 14,15 do not form part of the external interrupt sources
  49 * [2] BANK has two control registers, GPxCON0 and GPxCON1
  50 */
  51
  52#define OFF_GPCON       (0x00)
  53#define OFF_GPDAT       (0x04)
  54
  55#define con_4bit_shift(__off) ((__off) * 4)
  56
  57#if 1
  58#define gpio_dbg(x...) do { } while(0)
  59#else
  60#define gpio_dbg(x...) printk(KERN_DEBUG x)
  61#endif
  62
  63/* The s3c64xx_gpiolib_4bit routines are to control the gpio banks where
  64 * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
  65 * following example:
  66 *
  67 * base + 0x00: Control register, 4 bits per gpio
  68 *              gpio n: 4 bits starting at (4*n)
  69 *              0000 = input, 0001 = output, others mean special-function
  70 * base + 0x04: Data register, 1 bit per gpio
  71 *              bit n: data bit n
  72 *
  73 * Note, since the data register is one bit per gpio and is at base + 0x4
  74 * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
  75 * the output.
  76*/
  77
  78static int s3c64xx_gpiolib_4bit_input(struct gpio_chip *chip, unsigned offset)
  79{
  80        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
  81        void __iomem *base = ourchip->base;
  82        unsigned long con;
  83
  84        con = __raw_readl(base + OFF_GPCON);
  85        con &= ~(0xf << con_4bit_shift(offset));
  86        __raw_writel(con, base + OFF_GPCON);
  87
  88        gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
  89
  90        return 0;
  91}
  92
  93static int s3c64xx_gpiolib_4bit_output(struct gpio_chip *chip,
  94                                       unsigned offset, int value)
  95{
  96        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
  97        void __iomem *base = ourchip->base;
  98        unsigned long con;
  99        unsigned long dat;
 100
 101        con = __raw_readl(base + OFF_GPCON);
 102        con &= ~(0xf << con_4bit_shift(offset));
 103        con |= 0x1 << con_4bit_shift(offset);
 104
 105        dat = __raw_readl(base + OFF_GPDAT);
 106        if (value)
 107                dat |= 1 << offset;
 108        else
 109                dat &= ~(1 << offset);
 110
 111        __raw_writel(dat, base + OFF_GPDAT);
 112        __raw_writel(con, base + OFF_GPCON);
 113        __raw_writel(dat, base + OFF_GPDAT);
 114
 115        gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
 116
 117        return 0;
 118}
 119
 120/* The next set of routines are for the case where the GPIO configuration
 121 * registers are 4 bits per GPIO but there is more than one register (the
 122 * bank has more than 8 GPIOs.
 123 *
 124 * This case is the similar to the 4 bit case, but the registers are as
 125 * follows:
 126 *
 127 * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
 128 *              gpio n: 4 bits starting at (4*n)
 129 *              0000 = input, 0001 = output, others mean special-function
 130 * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
 131 *              gpio n: 4 bits starting at (4*n)
 132 *              0000 = input, 0001 = output, others mean special-function
 133 * base + 0x08: Data register, 1 bit per gpio
 134 *              bit n: data bit n
 135 *
 136 * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
 137 * store the 'base + 0x4' address so that these routines see the data
 138 * register at ourchip->base + 0x04.
 139*/
 140
 141static int s3c64xx_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned offset)
 142{
 143        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
 144        void __iomem *base = ourchip->base;
 145        void __iomem *regcon = base;
 146        unsigned long con;
 147
 148        if (offset > 7)
 149                offset -= 8;
 150        else
 151                regcon -= 4;
 152
 153        con = __raw_readl(regcon);
 154        con &= ~(0xf << con_4bit_shift(offset));
 155        __raw_writel(con, regcon);
 156
 157        gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
 158
 159        return 0;
 160
 161}
 162
 163static int s3c64xx_gpiolib_4bit2_output(struct gpio_chip *chip,
 164                                       unsigned offset, int value)
 165{
 166        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
 167        void __iomem *base = ourchip->base;
 168        void __iomem *regcon = base;
 169        unsigned long con;
 170        unsigned long dat;
 171
 172        if (offset > 7)
 173                offset -= 8;
 174        else
 175                regcon -= 4;
 176
 177        con = __raw_readl(regcon);
 178        con &= ~(0xf << con_4bit_shift(offset));
 179        con |= 0x1 << con_4bit_shift(offset);
 180
 181        dat = __raw_readl(base + OFF_GPDAT);
 182        if (value)
 183                dat |= 1 << offset;
 184        else
 185                dat &= ~(1 << offset);
 186
 187        __raw_writel(dat, base + OFF_GPDAT);
 188        __raw_writel(con, regcon);
 189        __raw_writel(dat, base + OFF_GPDAT);
 190
 191        gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
 192
 193        return 0;
 194}
 195
 196static struct s3c_gpio_cfg gpio_4bit_cfg_noint = {
 197        .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
 198        .set_pull       = s3c_gpio_setpull_updown,
 199        .get_pull       = s3c_gpio_getpull_updown,
 200};
 201
 202static struct s3c_gpio_cfg gpio_4bit_cfg_eint0111 = {
 203        .cfg_eint       = 7,
 204        .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
 205        .set_pull       = s3c_gpio_setpull_updown,
 206        .get_pull       = s3c_gpio_getpull_updown,
 207};
 208
 209static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
 210        .cfg_eint       = 3,
 211        .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
 212        .set_pull       = s3c_gpio_setpull_updown,
 213        .get_pull       = s3c_gpio_getpull_updown,
 214};
 215
 216static struct s3c_gpio_chip gpio_4bit[] = {
 217        {
 218                .base   = S3C64XX_GPA_BASE,
 219                .config = &gpio_4bit_cfg_eint0111,
 220                .chip   = {
 221                        .base   = S3C64XX_GPA(0),
 222                        .ngpio  = S3C64XX_GPIO_A_NR,
 223                        .label  = "GPA",
 224                },
 225        }, {
 226                .base   = S3C64XX_GPB_BASE,
 227                .config = &gpio_4bit_cfg_eint0111,
 228                .chip   = {
 229                        .base   = S3C64XX_GPB(0),
 230                        .ngpio  = S3C64XX_GPIO_B_NR,
 231                        .label  = "GPB",
 232                },
 233        }, {
 234                .base   = S3C64XX_GPC_BASE,
 235                .config = &gpio_4bit_cfg_eint0111,
 236                .chip   = {
 237                        .base   = S3C64XX_GPC(0),
 238                        .ngpio  = S3C64XX_GPIO_C_NR,
 239                        .label  = "GPC",
 240                },
 241        }, {
 242                .base   = S3C64XX_GPD_BASE,
 243                .config = &gpio_4bit_cfg_eint0111,
 244                .chip   = {
 245                        .base   = S3C64XX_GPD(0),
 246                        .ngpio  = S3C64XX_GPIO_D_NR,
 247                        .label  = "GPD",
 248                },
 249        }, {
 250                .base   = S3C64XX_GPE_BASE,
 251                .config = &gpio_4bit_cfg_noint,
 252                .chip   = {
 253                        .base   = S3C64XX_GPE(0),
 254                        .ngpio  = S3C64XX_GPIO_E_NR,
 255                        .label  = "GPE",
 256                },
 257        }, {
 258                .base   = S3C64XX_GPG_BASE,
 259                .config = &gpio_4bit_cfg_eint0111,
 260                .chip   = {
 261                        .base   = S3C64XX_GPG(0),
 262                        .ngpio  = S3C64XX_GPIO_G_NR,
 263                        .label  = "GPG",
 264                },
 265        }, {
 266                .base   = S3C64XX_GPM_BASE,
 267                .config = &gpio_4bit_cfg_eint0011,
 268                .chip   = {
 269                        .base   = S3C64XX_GPM(0),
 270                        .ngpio  = S3C64XX_GPIO_M_NR,
 271                        .label  = "GPM",
 272                },
 273        },
 274};
 275
 276static struct s3c_gpio_chip gpio_4bit2[] = {
 277        {
 278                .base   = S3C64XX_GPH_BASE + 0x4,
 279                .config = &gpio_4bit_cfg_eint0111,
 280                .chip   = {
 281                        .base   = S3C64XX_GPH(0),
 282                        .ngpio  = S3C64XX_GPIO_H_NR,
 283                        .label  = "GPH",
 284                },
 285        }, {
 286                .base   = S3C64XX_GPK_BASE + 0x4,
 287                .config = &gpio_4bit_cfg_noint,
 288                .chip   = {
 289                        .base   = S3C64XX_GPK(0),
 290                        .ngpio  = S3C64XX_GPIO_K_NR,
 291                        .label  = "GPK",
 292                },
 293        }, {
 294                .base   = S3C64XX_GPL_BASE + 0x4,
 295                .config = &gpio_4bit_cfg_eint0011,
 296                .chip   = {
 297                        .base   = S3C64XX_GPL(0),
 298                        .ngpio  = S3C64XX_GPIO_L_NR,
 299                        .label  = "GPL",
 300                },
 301        },
 302};
 303
 304static struct s3c_gpio_cfg gpio_2bit_cfg_noint = {
 305        .set_config     = s3c_gpio_setcfg_s3c24xx,
 306        .set_pull       = s3c_gpio_setpull_updown,
 307        .get_pull       = s3c_gpio_getpull_updown,
 308};
 309
 310static struct s3c_gpio_cfg gpio_2bit_cfg_eint10 = {
 311        .cfg_eint       = 2,
 312        .set_config     = s3c_gpio_setcfg_s3c24xx,
 313        .set_pull       = s3c_gpio_setpull_updown,
 314        .get_pull       = s3c_gpio_getpull_updown,
 315};
 316
 317static struct s3c_gpio_cfg gpio_2bit_cfg_eint11 = {
 318        .cfg_eint       = 3,
 319        .set_config     = s3c_gpio_setcfg_s3c24xx,
 320        .set_pull       = s3c_gpio_setpull_updown,
 321        .get_pull       = s3c_gpio_getpull_updown,
 322};
 323
 324int s3c64xx_gpio2int_gpn(struct gpio_chip *chip, unsigned pin)
 325{
 326        return IRQ_EINT(0) + pin;
 327}
 328
 329static struct s3c_gpio_chip gpio_2bit[] = {
 330        {
 331                .base   = S3C64XX_GPF_BASE,
 332                .config = &gpio_2bit_cfg_eint11,
 333                .chip   = {
 334                        .base   = S3C64XX_GPF(0),
 335                        .ngpio  = S3C64XX_GPIO_F_NR,
 336                        .label  = "GPF",
 337                },
 338        }, {
 339                .base   = S3C64XX_GPI_BASE,
 340                .config = &gpio_2bit_cfg_noint,
 341                .chip   = {
 342                        .base   = S3C64XX_GPI(0),
 343                        .ngpio  = S3C64XX_GPIO_I_NR,
 344                        .label  = "GPI",
 345                },
 346        }, {
 347                .base   = S3C64XX_GPJ_BASE,
 348                .config = &gpio_2bit_cfg_noint,
 349                .chip   = {
 350                        .base   = S3C64XX_GPJ(0),
 351                        .ngpio  = S3C64XX_GPIO_J_NR,
 352                        .label  = "GPJ",
 353                },
 354        }, {
 355                .base   = S3C64XX_GPN_BASE,
 356                .config = &gpio_2bit_cfg_eint10,
 357                .chip   = {
 358                        .base   = S3C64XX_GPN(0),
 359                        .ngpio  = S3C64XX_GPIO_N_NR,
 360                        .label  = "GPN",
 361                        .to_irq = s3c64xx_gpio2int_gpn,
 362                },
 363        }, {
 364                .base   = S3C64XX_GPO_BASE,
 365                .config = &gpio_2bit_cfg_eint11,
 366                .chip   = {
 367                        .base   = S3C64XX_GPO(0),
 368                        .ngpio  = S3C64XX_GPIO_O_NR,
 369                        .label  = "GPO",
 370                },
 371        }, {
 372                .base   = S3C64XX_GPP_BASE,
 373                .config = &gpio_2bit_cfg_eint11,
 374                .chip   = {
 375                        .base   = S3C64XX_GPP(0),
 376                        .ngpio  = S3C64XX_GPIO_P_NR,
 377                        .label  = "GPP",
 378                },
 379        }, {
 380                .base   = S3C64XX_GPQ_BASE,
 381                .config = &gpio_2bit_cfg_eint11,
 382                .chip   = {
 383                        .base   = S3C64XX_GPQ(0),
 384                        .ngpio  = S3C64XX_GPIO_Q_NR,
 385                        .label  = "GPQ",
 386                },
 387        },
 388};
 389
 390static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
 391{
 392        chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
 393        chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
 394        chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
 395}
 396
 397static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
 398{
 399        chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
 400        chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
 401        chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
 402}
 403
 404static __init void s3c64xx_gpiolib_add_2bit(struct s3c_gpio_chip *chip)
 405{
 406        chip->pm = __gpio_pm(&s3c_gpio_pm_2bit);
 407}
 408
 409static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
 410                                       int nr_chips,
 411                                       void (*fn)(struct s3c_gpio_chip *))
 412{
 413        for (; nr_chips > 0; nr_chips--, chips++) {
 414                if (fn)
 415                        (fn)(chips);
 416                s3c_gpiolib_add(chips);
 417        }
 418}
 419
 420static __init int s3c64xx_gpiolib_init(void)
 421{
 422        s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
 423                            s3c64xx_gpiolib_add_4bit);
 424
 425        s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
 426                            s3c64xx_gpiolib_add_4bit2);
 427
 428        s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit),
 429                            s3c64xx_gpiolib_add_2bit);
 430
 431        return 0;
 432}
 433
 434core_initcall(s3c64xx_gpiolib_init);
 435
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.