uboot/drivers/gpio/mxs_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Freescale i.MX28 GPIO control code
   4 *
   5 * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
   6 * on behalf of DENX Software Engineering GmbH
   7 */
   8
   9#include <common.h>
  10#include <log.h>
  11#include <malloc.h>
  12#include <asm/global_data.h>
  13#include <linux/bitops.h>
  14#include <linux/errno.h>
  15#include <asm/io.h>
  16#include <asm/arch/iomux.h>
  17#include <asm/arch/imx-regs.h>
  18
  19#if     defined(CONFIG_MX23)
  20#define PINCTRL_BANKS           3
  21#define PINCTRL_DOUT(n)         (0x0500 + ((n) * 0x10))
  22#define PINCTRL_DIN(n)          (0x0600 + ((n) * 0x10))
  23#define PINCTRL_DOE(n)          (0x0700 + ((n) * 0x10))
  24#define PINCTRL_PIN2IRQ(n)      (0x0800 + ((n) * 0x10))
  25#define PINCTRL_IRQEN(n)        (0x0900 + ((n) * 0x10))
  26#define PINCTRL_IRQSTAT(n)      (0x0c00 + ((n) * 0x10))
  27#elif   defined(CONFIG_MX28)
  28#define PINCTRL_BANKS           5
  29#define PINCTRL_DOUT(n)         (0x0700 + ((n) * 0x10))
  30#define PINCTRL_DIN(n)          (0x0900 + ((n) * 0x10))
  31#define PINCTRL_DOE(n)          (0x0b00 + ((n) * 0x10))
  32#define PINCTRL_PIN2IRQ(n)      (0x1000 + ((n) * 0x10))
  33#define PINCTRL_IRQEN(n)        (0x1100 + ((n) * 0x10))
  34#define PINCTRL_IRQSTAT(n)      (0x1400 + ((n) * 0x10))
  35#else
  36#error "Please select CONFIG_MX23 or CONFIG_MX28"
  37#endif
  38
  39#define GPIO_INT_FALL_EDGE      0x0
  40#define GPIO_INT_LOW_LEV        0x1
  41#define GPIO_INT_RISE_EDGE      0x2
  42#define GPIO_INT_HIGH_LEV       0x3
  43#define GPIO_INT_LEV_MASK       (1 << 0)
  44#define GPIO_INT_POL_MASK       (1 << 1)
  45
  46void mxs_gpio_init(void)
  47{
  48        int i;
  49
  50        for (i = 0; i < PINCTRL_BANKS; i++) {
  51                writel(0, MXS_PINCTRL_BASE + PINCTRL_PIN2IRQ(i));
  52                writel(0, MXS_PINCTRL_BASE + PINCTRL_IRQEN(i));
  53                /* Use SCT address here to clear the IRQSTAT bits */
  54                writel(0xffffffff, MXS_PINCTRL_BASE + PINCTRL_IRQSTAT(i) + 8);
  55        }
  56}
  57
  58#if !CONFIG_IS_ENABLED(DM_GPIO)
  59int gpio_get_value(unsigned gpio)
  60{
  61        uint32_t bank = PAD_BANK(gpio);
  62        uint32_t offset = PINCTRL_DIN(bank);
  63        struct mxs_register_32 *reg =
  64                (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
  65
  66        return (readl(&reg->reg) >> PAD_PIN(gpio)) & 1;
  67}
  68
  69void gpio_set_value(unsigned gpio, int value)
  70{
  71        uint32_t bank = PAD_BANK(gpio);
  72        uint32_t offset = PINCTRL_DOUT(bank);
  73        struct mxs_register_32 *reg =
  74                (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
  75
  76        if (value)
  77                writel(1 << PAD_PIN(gpio), &reg->reg_set);
  78        else
  79                writel(1 << PAD_PIN(gpio), &reg->reg_clr);
  80}
  81
  82int gpio_direction_input(unsigned gpio)
  83{
  84        uint32_t bank = PAD_BANK(gpio);
  85        uint32_t offset = PINCTRL_DOE(bank);
  86        struct mxs_register_32 *reg =
  87                (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
  88
  89        writel(1 << PAD_PIN(gpio), &reg->reg_clr);
  90
  91        return 0;
  92}
  93
  94int gpio_direction_output(unsigned gpio, int value)
  95{
  96        uint32_t bank = PAD_BANK(gpio);
  97        uint32_t offset = PINCTRL_DOE(bank);
  98        struct mxs_register_32 *reg =
  99                (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset);
 100
 101        gpio_set_value(gpio, value);
 102
 103        writel(1 << PAD_PIN(gpio), &reg->reg_set);
 104
 105        return 0;
 106}
 107
 108int gpio_request(unsigned gpio, const char *label)
 109{
 110        if (PAD_BANK(gpio) >= PINCTRL_BANKS)
 111                return -1;
 112
 113        return 0;
 114}
 115
 116int gpio_free(unsigned gpio)
 117{
 118        return 0;
 119}
 120
 121int name_to_gpio(const char *name)
 122{
 123        unsigned bank, pin;
 124        char *end;
 125
 126        bank = simple_strtoul(name, &end, 10);
 127
 128        if (!*end || *end != ':')
 129                return bank;
 130
 131        pin = simple_strtoul(end + 1, NULL, 10);
 132
 133        return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT);
 134}
 135#else /* DM_GPIO */
 136#include <dm.h>
 137#include <asm/gpio.h>
 138#include <dt-structs.h>
 139#include <asm/arch/gpio.h>
 140#define MXS_MAX_GPIO_PER_BANK           32
 141
 142DECLARE_GLOBAL_DATA_PTR;
 143/*
 144 * According to i.MX28 Reference Manual:
 145 * 'i.MX28 Applications Processor Reference Manual, Rev. 1, 2010'
 146 * The i.MX28 has following number of GPIOs available:
 147 * Bank 0: 0-28 -> 29 PINS
 148 * Bank 1: 0-31 -> 32 PINS
 149 * Bank 2: 0-27 -> 28 PINS
 150 * Bank 3: 0-30 -> 31 PINS
 151 * Bank 4: 0-20 -> 21 PINS
 152 */
 153
 154struct mxs_gpio_plat {
 155#if CONFIG_IS_ENABLED(OF_PLATDATA)
 156        struct dtd_fsl_imx23_gpio dtplat;
 157#endif
 158        unsigned int bank;
 159        int gpio_ranges;
 160};
 161
 162struct mxs_gpio_priv {
 163        unsigned int bank;
 164};
 165
 166static int mxs_gpio_get_value(struct udevice *dev, unsigned offset)
 167{
 168        struct mxs_gpio_priv *priv = dev_get_priv(dev);
 169        struct mxs_register_32 *reg =
 170                (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
 171                                           PINCTRL_DIN(priv->bank));
 172
 173        return (readl(&reg->reg) >> offset) & 1;
 174}
 175
 176static int mxs_gpio_set_value(struct udevice *dev, unsigned offset,
 177                              int value)
 178{
 179        struct mxs_gpio_priv *priv = dev_get_priv(dev);
 180        struct mxs_register_32 *reg =
 181                (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
 182                                           PINCTRL_DOUT(priv->bank));
 183        if (value)
 184                writel(BIT(offset), &reg->reg_set);
 185        else
 186                writel(BIT(offset), &reg->reg_clr);
 187
 188        return 0;
 189}
 190
 191static int mxs_gpio_direction_input(struct udevice *dev, unsigned offset)
 192{
 193        struct mxs_gpio_priv *priv = dev_get_priv(dev);
 194        struct mxs_register_32 *reg =
 195                (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
 196                                           PINCTRL_DOE(priv->bank));
 197
 198        writel(BIT(offset), &reg->reg_clr);
 199
 200        return 0;
 201}
 202
 203static int mxs_gpio_direction_output(struct udevice *dev, unsigned offset,
 204                                     int value)
 205{
 206        struct mxs_gpio_priv *priv = dev_get_priv(dev);
 207        struct mxs_register_32 *reg =
 208                (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
 209                                           PINCTRL_DOE(priv->bank));
 210
 211        mxs_gpio_set_value(dev, offset, value);
 212
 213        writel(BIT(offset), &reg->reg_set);
 214
 215        return 0;
 216}
 217
 218static int mxs_gpio_get_function(struct udevice *dev, unsigned offset)
 219{
 220        struct mxs_gpio_priv *priv = dev_get_priv(dev);
 221        struct mxs_register_32 *reg =
 222                (struct mxs_register_32 *)(MXS_PINCTRL_BASE +
 223                                           PINCTRL_DOE(priv->bank));
 224        bool is_output = !!(readl(&reg->reg) >> offset);
 225
 226        return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
 227}
 228
 229static const struct dm_gpio_ops gpio_mxs_ops = {
 230        .direction_input        = mxs_gpio_direction_input,
 231        .direction_output       = mxs_gpio_direction_output,
 232        .get_value              = mxs_gpio_get_value,
 233        .set_value              = mxs_gpio_set_value,
 234        .get_function           = mxs_gpio_get_function,
 235};
 236
 237static int mxs_gpio_probe(struct udevice *dev)
 238{
 239        struct mxs_gpio_plat *plat = dev_get_plat(dev);
 240        struct mxs_gpio_priv *priv = dev_get_priv(dev);
 241        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 242        char name[16], *str;
 243
 244#if CONFIG_IS_ENABLED(OF_PLATDATA)
 245        struct dtd_fsl_imx23_gpio *dtplat = &plat->dtplat;
 246        priv->bank = (unsigned int)dtplat->reg[0];
 247        uc_priv->gpio_count = dtplat->gpio_ranges[3];
 248#else
 249        priv->bank = (unsigned int)plat->bank;
 250        uc_priv->gpio_count = plat->gpio_ranges;
 251#endif
 252        snprintf(name, sizeof(name), "GPIO%d_", priv->bank);
 253        str = strdup(name);
 254        if (!str)
 255                return -ENOMEM;
 256
 257        uc_priv->bank_name = str;
 258
 259        debug("%s: %s: %d pins base: 0x%x\n", __func__, uc_priv->bank_name,
 260              uc_priv->gpio_count, priv->bank);
 261
 262        return 0;
 263}
 264
 265#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 266static int mxs_of_to_plat(struct udevice *dev)
 267{
 268        struct mxs_gpio_plat *plat = dev_get_plat(dev);
 269        struct fdtdec_phandle_args args;
 270        int node = dev_of_offset(dev);
 271        int ret;
 272
 273        plat->bank = dev_read_addr(dev);
 274        if (plat->bank == FDT_ADDR_T_NONE) {
 275                printf("%s: No 'reg' property defined!\n", __func__);
 276                return -EINVAL;
 277        }
 278
 279        ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges",
 280                                             NULL, 3, 0, &args);
 281        if (ret)
 282                printf("%s: 'gpio-ranges' not defined - using default!\n",
 283                       __func__);
 284
 285        plat->gpio_ranges = ret == 0 ? args.args[2] : MXS_MAX_GPIO_PER_BANK;
 286
 287        return 0;
 288}
 289
 290static const struct udevice_id mxs_gpio_ids[] = {
 291        { .compatible = "fsl,imx23-gpio" },
 292        { .compatible = "fsl,imx28-gpio" },
 293        { }
 294};
 295#endif
 296
 297U_BOOT_DRIVER(fsl_imx23_gpio) = {
 298        .name = "fsl_imx23_gpio",
 299        .id     = UCLASS_GPIO,
 300        .ops    = &gpio_mxs_ops,
 301        .probe  = mxs_gpio_probe,
 302        .priv_auto      = sizeof(struct mxs_gpio_priv),
 303        .plat_auto      = sizeof(struct mxs_gpio_plat),
 304#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 305        .of_match = mxs_gpio_ids,
 306        .of_to_plat = mxs_of_to_plat,
 307#endif
 308};
 309
 310DM_DRIVER_ALIAS(fsl_imx23_gpio, fsl_imx28_gpio)
 311#endif /* DM_GPIO */
 312