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