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