linux/arch/arm/plat-samsung/gpiolib.c
<<
>>
Prefs
   1/* arch/arm/plat-samsung/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 * Copyright (c) 2009 Samsung Electronics Co., Ltd.
   9 *              http://www.samsung.com/
  10 *
  11 * SAMSUNG - GPIOlib support
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License version 2 as
  15 * published by the Free Software Foundation.
  16 */
  17
  18#include <linux/kernel.h>
  19#include <linux/irq.h>
  20#include <linux/io.h>
  21#include <linux/gpio.h>
  22#include <plat/gpio-core.h>
  23#include <plat/gpio-cfg.h>
  24#include <plat/gpio-cfg-helpers.h>
  25
  26#ifndef DEBUG_GPIO
  27#define gpio_dbg(x...) do { } while (0)
  28#else
  29#define gpio_dbg(x...) printk(KERN_DEBUG x)
  30#endif
  31
  32/* The samsung_gpiolib_4bit routines are to control the gpio banks where
  33 * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
  34 * following example:
  35 *
  36 * base + 0x00: Control register, 4 bits per gpio
  37 *              gpio n: 4 bits starting at (4*n)
  38 *              0000 = input, 0001 = output, others mean special-function
  39 * base + 0x04: Data register, 1 bit per gpio
  40 *              bit n: data bit n
  41 *
  42 * Note, since the data register is one bit per gpio and is at base + 0x4
  43 * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
  44 * the output.
  45*/
  46
  47static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,
  48                                      unsigned int offset)
  49{
  50        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
  51        void __iomem *base = ourchip->base;
  52        unsigned long con;
  53
  54        con = __raw_readl(base + GPIOCON_OFF);
  55        con &= ~(0xf << con_4bit_shift(offset));
  56        __raw_writel(con, base + GPIOCON_OFF);
  57
  58        gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
  59
  60        return 0;
  61}
  62
  63static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
  64                                       unsigned int offset, int value)
  65{
  66        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
  67        void __iomem *base = ourchip->base;
  68        unsigned long con;
  69        unsigned long dat;
  70
  71        con = __raw_readl(base + GPIOCON_OFF);
  72        con &= ~(0xf << con_4bit_shift(offset));
  73        con |= 0x1 << con_4bit_shift(offset);
  74
  75        dat = __raw_readl(base + GPIODAT_OFF);
  76
  77        if (value)
  78                dat |= 1 << offset;
  79        else
  80                dat &= ~(1 << offset);
  81
  82        __raw_writel(dat, base + GPIODAT_OFF);
  83        __raw_writel(con, base + GPIOCON_OFF);
  84        __raw_writel(dat, base + GPIODAT_OFF);
  85
  86        gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
  87
  88        return 0;
  89}
  90
  91/* The next set of routines are for the case where the GPIO configuration
  92 * registers are 4 bits per GPIO but there is more than one register (the
  93 * bank has more than 8 GPIOs.
  94 *
  95 * This case is the similar to the 4 bit case, but the registers are as
  96 * follows:
  97 *
  98 * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
  99 *              gpio n: 4 bits starting at (4*n)
 100 *              0000 = input, 0001 = output, others mean special-function
 101 * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
 102 *              gpio n: 4 bits starting at (4*n)
 103 *              0000 = input, 0001 = output, others mean special-function
 104 * base + 0x08: Data register, 1 bit per gpio
 105 *              bit n: data bit n
 106 *
 107 * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
 108 * store the 'base + 0x4' address so that these routines see the data
 109 * register at ourchip->base + 0x04.
 110 */
 111
 112static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip,
 113                                       unsigned int offset)
 114{
 115        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
 116        void __iomem *base = ourchip->base;
 117        void __iomem *regcon = base;
 118        unsigned long con;
 119
 120        if (offset > 7)
 121                offset -= 8;
 122        else
 123                regcon -= 4;
 124
 125        con = __raw_readl(regcon);
 126        con &= ~(0xf << con_4bit_shift(offset));
 127        __raw_writel(con, regcon);
 128
 129        gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
 130
 131        return 0;
 132}
 133
 134static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip,
 135                                        unsigned int offset, int value)
 136{
 137        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
 138        void __iomem *base = ourchip->base;
 139        void __iomem *regcon = base;
 140        unsigned long con;
 141        unsigned long dat;
 142        unsigned con_offset = offset;
 143
 144        if (con_offset > 7)
 145                con_offset -= 8;
 146        else
 147                regcon -= 4;
 148
 149        con = __raw_readl(regcon);
 150        con &= ~(0xf << con_4bit_shift(con_offset));
 151        con |= 0x1 << con_4bit_shift(con_offset);
 152
 153        dat = __raw_readl(base + GPIODAT_OFF);
 154
 155        if (value)
 156                dat |= 1 << offset;
 157        else
 158                dat &= ~(1 << offset);
 159
 160        __raw_writel(dat, base + GPIODAT_OFF);
 161        __raw_writel(con, regcon);
 162        __raw_writel(dat, base + GPIODAT_OFF);
 163
 164        gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
 165
 166        return 0;
 167}
 168
 169void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
 170{
 171        chip->chip.direction_input = samsung_gpiolib_4bit_input;
 172        chip->chip.direction_output = samsung_gpiolib_4bit_output;
 173        chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
 174}
 175
 176void __init samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
 177{
 178        chip->chip.direction_input = samsung_gpiolib_4bit2_input;
 179        chip->chip.direction_output = samsung_gpiolib_4bit2_output;
 180        chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
 181}
 182
 183void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
 184                                           int nr_chips)
 185{
 186        for (; nr_chips > 0; nr_chips--, chip++) {
 187                samsung_gpiolib_add_4bit(chip);
 188                s3c_gpiolib_add(chip);
 189        }
 190}
 191
 192void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip,
 193                                            int nr_chips)
 194{
 195        for (; nr_chips > 0; nr_chips--, chip++) {
 196                samsung_gpiolib_add_4bit2(chip);
 197                s3c_gpiolib_add(chip);
 198        }
 199}
 200
 201void __init samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip,
 202                                           int nr_chips)
 203{
 204        for (; nr_chips > 0; nr_chips--, chip++)
 205                s3c_gpiolib_add(chip);
 206}
 207