uboot/drivers/gpio/s5p_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2009 Samsung Electronics
   4 * Minkyu Kang <mk7.kang@samsung.com>
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <errno.h>
  10#include <fdtdec.h>
  11#include <malloc.h>
  12#include <asm/io.h>
  13#include <asm/gpio.h>
  14#include <dm/device-internal.h>
  15
  16DECLARE_GLOBAL_DATA_PTR;
  17
  18#define S5P_GPIO_GET_PIN(x)     (x % GPIO_PER_BANK)
  19
  20#define CON_MASK(val)                   (0xf << ((val) << 2))
  21#define CON_SFR(gpio, cfg)              ((cfg) << ((gpio) << 2))
  22#define CON_SFR_UNSHIFT(val, gpio)      ((val) >> ((gpio) << 2))
  23
  24#define DAT_MASK(gpio)                  (0x1 << (gpio))
  25#define DAT_SET(gpio)                   (0x1 << (gpio))
  26
  27#define PULL_MASK(gpio)         (0x3 << ((gpio) << 1))
  28#define PULL_MODE(gpio, pull)           ((pull) << ((gpio) << 1))
  29
  30#define DRV_MASK(gpio)                  (0x3 << ((gpio) << 1))
  31#define DRV_SET(gpio, mode)             ((mode) << ((gpio) << 1))
  32#define RATE_MASK(gpio)         (0x1 << (gpio + 16))
  33#define RATE_SET(gpio)                  (0x1 << (gpio + 16))
  34
  35/* Platform data for each bank */
  36struct exynos_gpio_platdata {
  37        struct s5p_gpio_bank *bank;
  38        const char *bank_name;  /* Name of port, e.g. 'gpa0" */
  39};
  40
  41/* Information about each bank at run-time */
  42struct exynos_bank_info {
  43        struct s5p_gpio_bank *bank;
  44};
  45
  46static struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio)
  47{
  48        const struct gpio_info *data;
  49        unsigned int upto;
  50        int i, count;
  51
  52        data = get_gpio_data();
  53        count = get_bank_num();
  54        upto = 0;
  55
  56        for (i = 0; i < count; i++) {
  57                debug("i=%d, upto=%d\n", i, upto);
  58                if (gpio < data->max_gpio) {
  59                        struct s5p_gpio_bank *bank;
  60                        bank = (struct s5p_gpio_bank *)data->reg_addr;
  61                        bank += (gpio - upto) / GPIO_PER_BANK;
  62                        debug("gpio=%d, bank=%p\n", gpio, bank);
  63                        return bank;
  64                }
  65
  66                upto = data->max_gpio;
  67                data++;
  68        }
  69
  70        return NULL;
  71}
  72
  73static void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg)
  74{
  75        unsigned int value;
  76
  77        value = readl(&bank->con);
  78        value &= ~CON_MASK(gpio);
  79        value |= CON_SFR(gpio, cfg);
  80        writel(value, &bank->con);
  81}
  82
  83static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en)
  84{
  85        unsigned int value;
  86
  87        value = readl(&bank->dat);
  88        value &= ~DAT_MASK(gpio);
  89        if (en)
  90                value |= DAT_SET(gpio);
  91        writel(value, &bank->dat);
  92}
  93
  94#ifdef CONFIG_SPL_BUILD
  95/* Common GPIO API - SPL does not support driver model yet */
  96int gpio_set_value(unsigned gpio, int value)
  97{
  98        s5p_gpio_set_value(s5p_gpio_get_bank(gpio),
  99                           s5p_gpio_get_pin(gpio), value);
 100
 101        return 0;
 102}
 103#else
 104static int s5p_gpio_get_cfg_pin(struct s5p_gpio_bank *bank, int gpio)
 105{
 106        unsigned int value;
 107
 108        value = readl(&bank->con);
 109        value &= CON_MASK(gpio);
 110        return CON_SFR_UNSHIFT(value, gpio);
 111}
 112
 113static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio)
 114{
 115        unsigned int value;
 116
 117        value = readl(&bank->dat);
 118        return !!(value & DAT_MASK(gpio));
 119}
 120#endif /* CONFIG_SPL_BUILD */
 121
 122static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode)
 123{
 124        unsigned int value;
 125
 126        value = readl(&bank->pull);
 127        value &= ~PULL_MASK(gpio);
 128
 129        switch (mode) {
 130        case S5P_GPIO_PULL_DOWN:
 131        case S5P_GPIO_PULL_UP:
 132                value |= PULL_MODE(gpio, mode);
 133                break;
 134        default:
 135                break;
 136        }
 137
 138        writel(value, &bank->pull);
 139}
 140
 141static void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode)
 142{
 143        unsigned int value;
 144
 145        value = readl(&bank->drv);
 146        value &= ~DRV_MASK(gpio);
 147
 148        switch (mode) {
 149        case S5P_GPIO_DRV_1X:
 150        case S5P_GPIO_DRV_2X:
 151        case S5P_GPIO_DRV_3X:
 152        case S5P_GPIO_DRV_4X:
 153                value |= DRV_SET(gpio, mode);
 154                break;
 155        default:
 156                return;
 157        }
 158
 159        writel(value, &bank->drv);
 160}
 161
 162static void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode)
 163{
 164        unsigned int value;
 165
 166        value = readl(&bank->drv);
 167        value &= ~RATE_MASK(gpio);
 168
 169        switch (mode) {
 170        case S5P_GPIO_DRV_FAST:
 171        case S5P_GPIO_DRV_SLOW:
 172                value |= RATE_SET(gpio);
 173                break;
 174        default:
 175                return;
 176        }
 177
 178        writel(value, &bank->drv);
 179}
 180
 181int s5p_gpio_get_pin(unsigned gpio)
 182{
 183        return S5P_GPIO_GET_PIN(gpio);
 184}
 185
 186/* Driver model interface */
 187#ifndef CONFIG_SPL_BUILD
 188/* set GPIO pin 'gpio' as an input */
 189static int exynos_gpio_direction_input(struct udevice *dev, unsigned offset)
 190{
 191        struct exynos_bank_info *state = dev_get_priv(dev);
 192
 193        /* Configure GPIO direction as input. */
 194        s5p_gpio_cfg_pin(state->bank, offset, S5P_GPIO_INPUT);
 195
 196        return 0;
 197}
 198
 199/* set GPIO pin 'gpio' as an output, with polarity 'value' */
 200static int exynos_gpio_direction_output(struct udevice *dev, unsigned offset,
 201                                       int value)
 202{
 203        struct exynos_bank_info *state = dev_get_priv(dev);
 204
 205        /* Configure GPIO output value. */
 206        s5p_gpio_set_value(state->bank, offset, value);
 207
 208        /* Configure GPIO direction as output. */
 209        s5p_gpio_cfg_pin(state->bank, offset, S5P_GPIO_OUTPUT);
 210
 211        return 0;
 212}
 213
 214/* read GPIO IN value of pin 'gpio' */
 215static int exynos_gpio_get_value(struct udevice *dev, unsigned offset)
 216{
 217        struct exynos_bank_info *state = dev_get_priv(dev);
 218
 219        return s5p_gpio_get_value(state->bank, offset);
 220}
 221
 222/* write GPIO OUT value to pin 'gpio' */
 223static int exynos_gpio_set_value(struct udevice *dev, unsigned offset,
 224                                 int value)
 225{
 226        struct exynos_bank_info *state = dev_get_priv(dev);
 227
 228        s5p_gpio_set_value(state->bank, offset, value);
 229
 230        return 0;
 231}
 232#endif /* nCONFIG_SPL_BUILD */
 233
 234/*
 235 * There is no common GPIO API for pull, drv, pin, rate (yet). These
 236 * functions are kept here to preserve function ordering for review.
 237 */
 238void gpio_set_pull(int gpio, int mode)
 239{
 240        s5p_gpio_set_pull(s5p_gpio_get_bank(gpio),
 241                          s5p_gpio_get_pin(gpio), mode);
 242}
 243
 244void gpio_set_drv(int gpio, int mode)
 245{
 246        s5p_gpio_set_drv(s5p_gpio_get_bank(gpio),
 247                         s5p_gpio_get_pin(gpio), mode);
 248}
 249
 250void gpio_cfg_pin(int gpio, int cfg)
 251{
 252        s5p_gpio_cfg_pin(s5p_gpio_get_bank(gpio),
 253                         s5p_gpio_get_pin(gpio), cfg);
 254}
 255
 256void gpio_set_rate(int gpio, int mode)
 257{
 258        s5p_gpio_set_rate(s5p_gpio_get_bank(gpio),
 259                          s5p_gpio_get_pin(gpio), mode);
 260}
 261
 262#ifndef CONFIG_SPL_BUILD
 263static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)
 264{
 265        struct exynos_bank_info *state = dev_get_priv(dev);
 266        int cfg;
 267
 268        cfg = s5p_gpio_get_cfg_pin(state->bank, offset);
 269        if (cfg == S5P_GPIO_OUTPUT)
 270                return GPIOF_OUTPUT;
 271        else if (cfg == S5P_GPIO_INPUT)
 272                return GPIOF_INPUT;
 273        else
 274                return GPIOF_FUNC;
 275}
 276
 277static const struct dm_gpio_ops gpio_exynos_ops = {
 278        .direction_input        = exynos_gpio_direction_input,
 279        .direction_output       = exynos_gpio_direction_output,
 280        .get_value              = exynos_gpio_get_value,
 281        .set_value              = exynos_gpio_set_value,
 282        .get_function           = exynos_gpio_get_function,
 283};
 284
 285static int gpio_exynos_probe(struct udevice *dev)
 286{
 287        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 288        struct exynos_bank_info *priv = dev->priv;
 289        struct exynos_gpio_platdata *plat = dev->platdata;
 290
 291        /* Only child devices have ports */
 292        if (!plat)
 293                return 0;
 294
 295        priv->bank = plat->bank;
 296
 297        uc_priv->gpio_count = GPIO_PER_BANK;
 298        uc_priv->bank_name = plat->bank_name;
 299
 300        return 0;
 301}
 302
 303/**
 304 * We have a top-level GPIO device with no actual GPIOs. It has a child
 305 * device for each Exynos GPIO bank.
 306 */
 307static int gpio_exynos_bind(struct udevice *parent)
 308{
 309        struct exynos_gpio_platdata *plat = parent->platdata;
 310        struct s5p_gpio_bank *bank, *base;
 311        const void *blob = gd->fdt_blob;
 312        int node;
 313
 314        /* If this is a child device, there is nothing to do here */
 315        if (plat)
 316                return 0;
 317
 318        base = (struct s5p_gpio_bank *)devfdt_get_addr(parent);
 319        for (node = fdt_first_subnode(blob, dev_of_offset(parent)), bank = base;
 320             node > 0;
 321             node = fdt_next_subnode(blob, node), bank++) {
 322                struct exynos_gpio_platdata *plat;
 323                struct udevice *dev;
 324                fdt_addr_t reg;
 325                int ret;
 326
 327                if (!fdtdec_get_bool(blob, node, "gpio-controller"))
 328                        continue;
 329                plat = calloc(1, sizeof(*plat));
 330                if (!plat)
 331                        return -ENOMEM;
 332
 333                plat->bank_name = fdt_get_name(blob, node, NULL);
 334                ret = device_bind(parent, parent->driver,
 335                                  plat->bank_name, plat, -1, &dev);
 336                if (ret)
 337                        return ret;
 338
 339                dev_set_of_offset(dev, node);
 340
 341                reg = devfdt_get_addr(dev);
 342                if (reg != FDT_ADDR_T_NONE)
 343                        bank = (struct s5p_gpio_bank *)((ulong)base + reg);
 344
 345                plat->bank = bank;
 346
 347                debug("dev at %p: %s\n", bank, plat->bank_name);
 348        }
 349
 350        return 0;
 351}
 352
 353static const struct udevice_id exynos_gpio_ids[] = {
 354        { .compatible = "samsung,s5pc100-pinctrl" },
 355        { .compatible = "samsung,s5pc110-pinctrl" },
 356        { .compatible = "samsung,exynos4210-pinctrl" },
 357        { .compatible = "samsung,exynos4x12-pinctrl" },
 358        { .compatible = "samsung,exynos5250-pinctrl" },
 359        { .compatible = "samsung,exynos5420-pinctrl" },
 360        { }
 361};
 362
 363U_BOOT_DRIVER(gpio_exynos) = {
 364        .name   = "gpio_exynos",
 365        .id     = UCLASS_GPIO,
 366        .of_match = exynos_gpio_ids,
 367        .bind   = gpio_exynos_bind,
 368        .probe = gpio_exynos_probe,
 369        .priv_auto_alloc_size = sizeof(struct exynos_bank_info),
 370        .ops    = &gpio_exynos_ops,
 371};
 372#endif
 373