linux/arch/mips/ar7/gpio.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
   3 * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
   4 * Copyright (C) 2009-2010 Florian Fainelli <florian@openwrt.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  19 */
  20
  21#include <linux/init.h>
  22#include <linux/export.h>
  23#include <linux/gpio.h>
  24
  25#include <asm/mach-ar7/ar7.h>
  26
  27#define AR7_GPIO_MAX 32
  28#define TITAN_GPIO_MAX 51
  29
  30struct ar7_gpio_chip {
  31        void __iomem            *regs;
  32        struct gpio_chip        chip;
  33};
  34
  35static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
  36{
  37        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
  38        void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT;
  39
  40        return !!(readl(gpio_in) & (1 << gpio));
  41}
  42
  43static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
  44{
  45        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
  46        void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0;
  47        void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1;
  48
  49        return readl(gpio >> 5 ? gpio_in1 : gpio_in0) & (1 << (gpio & 0x1f));
  50}
  51
  52static void ar7_gpio_set_value(struct gpio_chip *chip,
  53                                unsigned gpio, int value)
  54{
  55        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
  56        void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT;
  57        unsigned tmp;
  58
  59        tmp = readl(gpio_out) & ~(1 << gpio);
  60        if (value)
  61                tmp |= 1 << gpio;
  62        writel(tmp, gpio_out);
  63}
  64
  65static void titan_gpio_set_value(struct gpio_chip *chip,
  66                                unsigned gpio, int value)
  67{
  68        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
  69        void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0;
  70        void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1;
  71        unsigned tmp;
  72
  73        tmp = readl(gpio >> 5 ? gpio_out1 : gpio_out0) & ~(1 << (gpio & 0x1f));
  74        if (value)
  75                tmp |= 1 << (gpio & 0x1f);
  76        writel(tmp, gpio >> 5 ? gpio_out1 : gpio_out0);
  77}
  78
  79static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
  80{
  81        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
  82        void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR;
  83
  84        writel(readl(gpio_dir) | (1 << gpio), gpio_dir);
  85
  86        return 0;
  87}
  88
  89static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
  90{
  91        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
  92        void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
  93        void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
  94
  95        if (gpio >= TITAN_GPIO_MAX)
  96                return -EINVAL;
  97
  98        writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) | (1 << (gpio & 0x1f)),
  99                        gpio >> 5 ? gpio_dir1 : gpio_dir0);
 100        return 0;
 101}
 102
 103static int ar7_gpio_direction_output(struct gpio_chip *chip,
 104                                        unsigned gpio, int value)
 105{
 106        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
 107        void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR;
 108
 109        ar7_gpio_set_value(chip, gpio, value);
 110        writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir);
 111
 112        return 0;
 113}
 114
 115static int titan_gpio_direction_output(struct gpio_chip *chip,
 116                                        unsigned gpio, int value)
 117{
 118        struct ar7_gpio_chip *gpch = gpiochip_get_data(chip);
 119        void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
 120        void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
 121
 122        if (gpio >= TITAN_GPIO_MAX)
 123                return -EINVAL;
 124
 125        titan_gpio_set_value(chip, gpio, value);
 126        writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) & ~(1 <<
 127                (gpio & 0x1f)), gpio >> 5 ? gpio_dir1 : gpio_dir0);
 128
 129        return 0;
 130}
 131
 132static struct ar7_gpio_chip ar7_gpio_chip = {
 133        .chip = {
 134                .label                  = "ar7-gpio",
 135                .direction_input        = ar7_gpio_direction_input,
 136                .direction_output       = ar7_gpio_direction_output,
 137                .set                    = ar7_gpio_set_value,
 138                .get                    = ar7_gpio_get_value,
 139                .base                   = 0,
 140                .ngpio                  = AR7_GPIO_MAX,
 141        }
 142};
 143
 144static struct ar7_gpio_chip titan_gpio_chip = {
 145        .chip = {
 146                .label                  = "titan-gpio",
 147                .direction_input        = titan_gpio_direction_input,
 148                .direction_output       = titan_gpio_direction_output,
 149                .set                    = titan_gpio_set_value,
 150                .get                    = titan_gpio_get_value,
 151                .base                   = 0,
 152                .ngpio                  = TITAN_GPIO_MAX,
 153        }
 154};
 155
 156static inline int ar7_gpio_enable_ar7(unsigned gpio)
 157{
 158        void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE;
 159
 160        writel(readl(gpio_en) | (1 << gpio), gpio_en);
 161
 162        return 0;
 163}
 164
 165static inline int ar7_gpio_enable_titan(unsigned gpio)
 166{
 167        void __iomem *gpio_en0 = titan_gpio_chip.regs  + TITAN_GPIO_ENBL_0;
 168        void __iomem *gpio_en1 = titan_gpio_chip.regs  + TITAN_GPIO_ENBL_1;
 169
 170        writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) | (1 << (gpio & 0x1f)),
 171                gpio >> 5 ? gpio_en1 : gpio_en0);
 172
 173        return 0;
 174}
 175
 176int ar7_gpio_enable(unsigned gpio)
 177{
 178        return ar7_is_titan() ? ar7_gpio_enable_titan(gpio) :
 179                                ar7_gpio_enable_ar7(gpio);
 180}
 181EXPORT_SYMBOL(ar7_gpio_enable);
 182
 183static inline int ar7_gpio_disable_ar7(unsigned gpio)
 184{
 185        void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE;
 186
 187        writel(readl(gpio_en) & ~(1 << gpio), gpio_en);
 188
 189        return 0;
 190}
 191
 192static inline int ar7_gpio_disable_titan(unsigned gpio)
 193{
 194        void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0;
 195        void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1;
 196
 197        writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) & ~(1 << (gpio & 0x1f)),
 198                        gpio >> 5 ? gpio_en1 : gpio_en0);
 199
 200        return 0;
 201}
 202
 203int ar7_gpio_disable(unsigned gpio)
 204{
 205        return ar7_is_titan() ? ar7_gpio_disable_titan(gpio) :
 206                                ar7_gpio_disable_ar7(gpio);
 207}
 208EXPORT_SYMBOL(ar7_gpio_disable);
 209
 210struct titan_gpio_cfg {
 211        u32 reg;
 212        u32 shift;
 213        u32 func;
 214};
 215
 216static const struct titan_gpio_cfg titan_gpio_table[] = {
 217        /* reg, start bit, mux value */
 218        {4, 24, 1},
 219        {4, 26, 1},
 220        {4, 28, 1},
 221        {4, 30, 1},
 222        {5, 6, 1},
 223        {5, 8, 1},
 224        {5, 10, 1},
 225        {5, 12, 1},
 226        {7, 14, 3},
 227        {7, 16, 3},
 228        {7, 18, 3},
 229        {7, 20, 3},
 230        {7, 22, 3},
 231        {7, 26, 3},
 232        {7, 28, 3},
 233        {7, 30, 3},
 234        {8, 0, 3},
 235        {8, 2, 3},
 236        {8, 4, 3},
 237        {8, 10, 3},
 238        {8, 14, 3},
 239        {8, 16, 3},
 240        {8, 18, 3},
 241        {8, 20, 3},
 242        {9, 8, 3},
 243        {9, 10, 3},
 244        {9, 12, 3},
 245        {9, 14, 3},
 246        {9, 18, 3},
 247        {9, 20, 3},
 248        {9, 24, 3},
 249        {9, 26, 3},
 250        {9, 28, 3},
 251        {9, 30, 3},
 252        {10, 0, 3},
 253        {10, 2, 3},
 254        {10, 8, 3},
 255        {10, 10, 3},
 256        {10, 12, 3},
 257        {10, 14, 3},
 258        {13, 12, 3},
 259        {13, 14, 3},
 260        {13, 16, 3},
 261        {13, 18, 3},
 262        {13, 24, 3},
 263        {13, 26, 3},
 264        {13, 28, 3},
 265        {13, 30, 3},
 266        {14, 2, 3},
 267        {14, 6, 3},
 268        {14, 8, 3},
 269        {14, 12, 3}
 270};
 271
 272static int titan_gpio_pinsel(unsigned gpio)
 273{
 274        struct titan_gpio_cfg gpio_cfg;
 275        u32 mux_status, pin_sel_reg, tmp;
 276        void __iomem *pin_sel = (void __iomem *)KSEG1ADDR(AR7_REGS_PINSEL);
 277
 278        if (gpio >= ARRAY_SIZE(titan_gpio_table))
 279                return -EINVAL;
 280
 281        gpio_cfg = titan_gpio_table[gpio];
 282        pin_sel_reg = gpio_cfg.reg - 1;
 283
 284        mux_status = (readl(pin_sel + pin_sel_reg) >> gpio_cfg.shift) & 0x3;
 285
 286        /* Check the mux status */
 287        if (!((mux_status == 0) || (mux_status == gpio_cfg.func)))
 288                return 0;
 289
 290        /* Set the pin sel value */
 291        tmp = readl(pin_sel + pin_sel_reg);
 292        tmp |= ((gpio_cfg.func & 0x3) << gpio_cfg.shift);
 293        writel(tmp, pin_sel + pin_sel_reg);
 294
 295        return 0;
 296}
 297
 298/* Perform minimal Titan GPIO configuration */
 299static void titan_gpio_init(void)
 300{
 301        unsigned i;
 302
 303        for (i = 44; i < 48; i++) {
 304                titan_gpio_pinsel(i);
 305                ar7_gpio_enable_titan(i);
 306                titan_gpio_direction_input(&titan_gpio_chip.chip, i);
 307        }
 308}
 309
 310int __init ar7_gpio_init(void)
 311{
 312        int ret;
 313        struct ar7_gpio_chip *gpch;
 314        unsigned size;
 315
 316        if (!ar7_is_titan()) {
 317                gpch = &ar7_gpio_chip;
 318                size = 0x10;
 319        } else {
 320                gpch = &titan_gpio_chip;
 321                size = 0x1f;
 322        }
 323
 324        gpch->regs = ioremap_nocache(AR7_REGS_GPIO, size);
 325        if (!gpch->regs) {
 326                printk(KERN_ERR "%s: failed to ioremap regs\n",
 327                                        gpch->chip.label);
 328                return -ENOMEM;
 329        }
 330
 331        ret = gpiochip_add_data(&gpch->chip, gpch);
 332        if (ret) {
 333                printk(KERN_ERR "%s: failed to add gpiochip\n",
 334                                        gpch->chip.label);
 335                return ret;
 336        }
 337        printk(KERN_INFO "%s: registered %d GPIOs\n",
 338                                gpch->chip.label, gpch->chip.ngpio);
 339
 340        if (ar7_is_titan())
 341                titan_gpio_init();
 342
 343        return ret;
 344}
 345