uboot/drivers/gpio/omap_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2009 Wind River Systems, Inc.
   4 * Tom Rix <Tom.Rix@windriver.com>
   5 *
   6 * This work is derived from the linux 2.6.27 kernel source
   7 * To fetch, use the kernel repository
   8 * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
   9 * Use the v2.6.27 tag.
  10 *
  11 * Below is the original's header including its copyright
  12 *
  13 *  linux/arch/arm/plat-omap/gpio.c
  14 *
  15 * Support functions for OMAP GPIO
  16 *
  17 * Copyright (C) 2003-2005 Nokia Corporation
  18 * Written by Juha Yrjölä <juha.yrjola@nokia.com>
  19 */
  20#include <common.h>
  21#include <dm.h>
  22#include <fdtdec.h>
  23#include <asm/global_data.h>
  24#include <asm/gpio.h>
  25#include <asm/io.h>
  26#include <dm/device-internal.h>
  27#include <linux/errno.h>
  28#include <malloc.h>
  29
  30DECLARE_GLOBAL_DATA_PTR;
  31
  32#define OMAP_GPIO_DIR_OUT       0
  33#define OMAP_GPIO_DIR_IN        1
  34
  35#if CONFIG_IS_ENABLED(DM_GPIO)
  36
  37#define GPIO_PER_BANK                   32
  38
  39struct gpio_bank {
  40        /* TODO(sjg@chromium.org): Can we use a struct here? */
  41        void *base;     /* address of registers in physical memory */
  42};
  43
  44#endif
  45
  46int gpio_is_valid(int gpio)
  47{
  48        return (gpio >= 0) && (gpio < OMAP_MAX_GPIO);
  49}
  50
  51static void _set_gpio_direction(const struct gpio_bank *bank, int gpio,
  52                                int is_input)
  53{
  54        void *reg = bank->base;
  55        u32 l;
  56
  57        reg += OMAP_GPIO_OE;
  58
  59        l = __raw_readl(reg);
  60        if (is_input)
  61                l |= 1 << gpio;
  62        else
  63                l &= ~(1 << gpio);
  64        __raw_writel(l, reg);
  65}
  66
  67/**
  68 * Get the direction of the GPIO by reading the GPIO_OE register
  69 * corresponding to the specified bank.
  70 */
  71static int _get_gpio_direction(const struct gpio_bank *bank, int gpio)
  72{
  73        void *reg = bank->base;
  74        u32 v;
  75
  76        reg += OMAP_GPIO_OE;
  77
  78        v = __raw_readl(reg);
  79
  80        if (v & (1 << gpio))
  81                return OMAP_GPIO_DIR_IN;
  82        else
  83                return OMAP_GPIO_DIR_OUT;
  84}
  85
  86static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio,
  87                                int enable)
  88{
  89        void *reg = bank->base;
  90        u32 l = 0;
  91
  92        if (enable)
  93                reg += OMAP_GPIO_SETDATAOUT;
  94        else
  95                reg += OMAP_GPIO_CLEARDATAOUT;
  96
  97        l = 1 << gpio;
  98        __raw_writel(l, reg);
  99}
 100
 101static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
 102{
 103        void *reg = bank->base;
 104        int input;
 105
 106        input = _get_gpio_direction(bank, gpio);
 107        switch (input) {
 108        case OMAP_GPIO_DIR_IN:
 109                reg += OMAP_GPIO_DATAIN;
 110                break;
 111        case OMAP_GPIO_DIR_OUT:
 112                reg += OMAP_GPIO_DATAOUT;
 113                break;
 114        default:
 115                return -1;
 116        }
 117
 118        return (__raw_readl(reg) & (1 << gpio)) != 0;
 119}
 120
 121#if !CONFIG_IS_ENABLED(DM_GPIO)
 122static inline int get_gpio_index(int gpio)
 123{
 124        return gpio & 0x1f;
 125}
 126
 127static inline const struct gpio_bank *get_gpio_bank(int gpio)
 128{
 129        return &omap_gpio_bank[gpio >> 5];
 130}
 131
 132static int check_gpio(int gpio)
 133{
 134        if (!gpio_is_valid(gpio)) {
 135                printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
 136                return -1;
 137        }
 138        return 0;
 139}
 140
 141/**
 142 * Set value of the specified gpio
 143 */
 144int gpio_set_value(unsigned gpio, int value)
 145{
 146        const struct gpio_bank *bank;
 147
 148        if (check_gpio(gpio) < 0)
 149                return -1;
 150        bank = get_gpio_bank(gpio);
 151        _set_gpio_dataout(bank, get_gpio_index(gpio), value);
 152
 153        return 0;
 154}
 155
 156/**
 157 * Get value of the specified gpio
 158 */
 159int gpio_get_value(unsigned gpio)
 160{
 161        const struct gpio_bank *bank;
 162
 163        if (check_gpio(gpio) < 0)
 164                return -1;
 165        bank = get_gpio_bank(gpio);
 166
 167        return _get_gpio_value(bank, get_gpio_index(gpio));
 168}
 169
 170/**
 171 * Set gpio direction as input
 172 */
 173int gpio_direction_input(unsigned gpio)
 174{
 175        const struct gpio_bank *bank;
 176
 177        if (check_gpio(gpio) < 0)
 178                return -1;
 179
 180        bank = get_gpio_bank(gpio);
 181        _set_gpio_direction(bank, get_gpio_index(gpio), 1);
 182
 183        return 0;
 184}
 185
 186/**
 187 * Set gpio direction as output
 188 */
 189int gpio_direction_output(unsigned gpio, int value)
 190{
 191        const struct gpio_bank *bank;
 192
 193        if (check_gpio(gpio) < 0)
 194                return -1;
 195
 196        bank = get_gpio_bank(gpio);
 197        _set_gpio_dataout(bank, get_gpio_index(gpio), value);
 198        _set_gpio_direction(bank, get_gpio_index(gpio), 0);
 199
 200        return 0;
 201}
 202
 203/**
 204 * Request a gpio before using it.
 205 *
 206 * NOTE: Argument 'label' is unused.
 207 */
 208int gpio_request(unsigned gpio, const char *label)
 209{
 210        if (check_gpio(gpio) < 0)
 211                return -1;
 212
 213        return 0;
 214}
 215
 216/**
 217 * Reset and free the gpio after using it.
 218 */
 219int gpio_free(unsigned gpio)
 220{
 221        return 0;
 222}
 223
 224#else /* new driver model interface CONFIG_DM_GPIO */
 225
 226/* set GPIO pin 'gpio' as an input */
 227static int omap_gpio_direction_input(struct udevice *dev, unsigned offset)
 228{
 229        struct gpio_bank *bank = dev_get_priv(dev);
 230
 231        /* Configure GPIO direction as input. */
 232        _set_gpio_direction(bank, offset, 1);
 233
 234        return 0;
 235}
 236
 237/* set GPIO pin 'gpio' as an output, with polarity 'value' */
 238static int omap_gpio_direction_output(struct udevice *dev, unsigned offset,
 239                                       int value)
 240{
 241        struct gpio_bank *bank = dev_get_priv(dev);
 242
 243        _set_gpio_dataout(bank, offset, value);
 244        _set_gpio_direction(bank, offset, 0);
 245
 246        return 0;
 247}
 248
 249/* read GPIO IN value of pin 'gpio' */
 250static int omap_gpio_get_value(struct udevice *dev, unsigned offset)
 251{
 252        struct gpio_bank *bank = dev_get_priv(dev);
 253
 254        return _get_gpio_value(bank, offset);
 255}
 256
 257/* write GPIO OUT value to pin 'gpio' */
 258static int omap_gpio_set_value(struct udevice *dev, unsigned offset,
 259                                 int value)
 260{
 261        struct gpio_bank *bank = dev_get_priv(dev);
 262
 263        _set_gpio_dataout(bank, offset, value);
 264
 265        return 0;
 266}
 267
 268static int omap_gpio_get_function(struct udevice *dev, unsigned offset)
 269{
 270        struct gpio_bank *bank = dev_get_priv(dev);
 271
 272        /* GPIOF_FUNC is not implemented yet */
 273        if (_get_gpio_direction(bank, offset) == OMAP_GPIO_DIR_OUT)
 274                return GPIOF_OUTPUT;
 275        else
 276                return GPIOF_INPUT;
 277}
 278
 279static const struct dm_gpio_ops gpio_omap_ops = {
 280        .direction_input        = omap_gpio_direction_input,
 281        .direction_output       = omap_gpio_direction_output,
 282        .get_value              = omap_gpio_get_value,
 283        .set_value              = omap_gpio_set_value,
 284        .get_function           = omap_gpio_get_function,
 285};
 286
 287static int omap_gpio_probe(struct udevice *dev)
 288{
 289        struct gpio_bank *bank = dev_get_priv(dev);
 290        struct omap_gpio_plat *plat = dev_get_plat(dev);
 291        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 292        char name[18], *str;
 293
 294        sprintf(name, "gpio@%4x_", (unsigned int)plat->base);
 295        str = strdup(name);
 296        if (!str)
 297                return -ENOMEM;
 298        uc_priv->bank_name = str;
 299        uc_priv->gpio_count = GPIO_PER_BANK;
 300        bank->base = (void *)plat->base;
 301        return 0;
 302}
 303
 304#if !CONFIG_IS_ENABLED(OF_CONTROL)
 305static int omap_gpio_bind(struct udevice *dev)
 306{
 307        struct omap_gpio_plat *plat = dev_get_plat(dev);
 308        fdt_addr_t base_addr;
 309
 310        if (plat)
 311                return 0;
 312
 313        base_addr = dev_read_addr(dev);
 314        if (base_addr == FDT_ADDR_T_NONE)
 315                return -EINVAL;
 316
 317        /*
 318        * TODO:
 319        * When every board is converted to driver model and DT is
 320        * supported, this can be done by auto-alloc feature, but
 321        * not using calloc to alloc memory for plat.
 322        *
 323        * For example am33xx_gpio uses platform data rather than device tree.
 324        *
 325        * NOTE: DO NOT COPY this code if you are using device tree.
 326        */
 327        plat = calloc(1, sizeof(*plat));
 328        if (!plat)
 329                return -ENOMEM;
 330
 331        plat->base = base_addr;
 332        plat->port_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL);
 333        dev_set_plat(dev, plat);
 334
 335        return 0;
 336}
 337#endif
 338
 339#if CONFIG_IS_ENABLED(OF_REAL)
 340static const struct udevice_id omap_gpio_ids[] = {
 341        { .compatible = "ti,omap3-gpio" },
 342        { .compatible = "ti,omap4-gpio" },
 343        { .compatible = "ti,am4372-gpio" },
 344        { }
 345};
 346
 347static int omap_gpio_of_to_plat(struct udevice *dev)
 348{
 349        struct omap_gpio_plat *plat = dev_get_plat(dev);
 350        fdt_addr_t addr;
 351
 352        addr = dev_read_addr(dev);
 353        if (addr == FDT_ADDR_T_NONE)
 354                return -EINVAL;
 355
 356        plat->base = addr;
 357        return 0;
 358}
 359#endif
 360
 361U_BOOT_DRIVER(gpio_omap) = {
 362        .name   = "gpio_omap",
 363        .id     = UCLASS_GPIO,
 364#if CONFIG_IS_ENABLED(OF_CONTROL)
 365#if CONFIG_IS_ENABLED(OF_REAL)
 366        .of_match = omap_gpio_ids,
 367        .of_to_plat = of_match_ptr(omap_gpio_of_to_plat),
 368        .plat_auto      = sizeof(struct omap_gpio_plat),
 369#endif
 370#else
 371        .bind   = omap_gpio_bind,
 372#endif
 373        .ops    = &gpio_omap_ops,
 374        .probe  = omap_gpio_probe,
 375        .priv_auto      = sizeof(struct gpio_bank),
 376#if !CONFIG_IS_ENABLED(OF_CONTROL)
 377        .flags = DM_FLAG_PRE_RELOC,
 378#endif
 379};
 380
 381#endif /* !DM_GPIO */
 382