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