uboot/drivers/gpio/tegra186_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2010-2016, NVIDIA CORPORATION.
   4 * (based on tegra_gpio.c)
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <malloc.h>
  10#include <errno.h>
  11#include <fdtdec.h>
  12#include <asm/io.h>
  13#include <asm/bitops.h>
  14#include <asm/gpio.h>
  15#include <dm/device-internal.h>
  16#include <dt-bindings/gpio/gpio.h>
  17#include "tegra186_gpio_priv.h"
  18
  19struct tegra186_gpio_port_data {
  20        const char *name;
  21        uint32_t offset;
  22};
  23
  24struct tegra186_gpio_ctlr_data {
  25        const struct tegra186_gpio_port_data *ports;
  26        uint32_t port_count;
  27};
  28
  29struct tegra186_gpio_platdata {
  30        const char *name;
  31        uint32_t *regs;
  32};
  33
  34static uint32_t *tegra186_gpio_reg(struct udevice *dev, uint32_t reg,
  35                                   uint32_t gpio)
  36{
  37        struct tegra186_gpio_platdata *plat = dev->platdata;
  38        uint32_t index = (reg + (gpio * TEGRA186_GPIO_PER_GPIO_STRIDE)) / 4;
  39
  40        return &(plat->regs[index]);
  41}
  42
  43static int tegra186_gpio_set_out(struct udevice *dev, unsigned offset,
  44                                 bool output)
  45{
  46        uint32_t *reg;
  47        uint32_t rval;
  48
  49        reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_CONTROL, offset);
  50        rval = readl(reg);
  51        if (output)
  52                rval &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
  53        else
  54                rval |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
  55        writel(rval, reg);
  56
  57        reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
  58        rval = readl(reg);
  59        if (output)
  60                rval |= TEGRA186_GPIO_ENABLE_CONFIG_OUT;
  61        else
  62                rval &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT;
  63        rval |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
  64        writel(rval, reg);
  65
  66        return 0;
  67}
  68
  69static int tegra186_gpio_set_val(struct udevice *dev, unsigned offset, bool val)
  70{
  71        uint32_t *reg;
  72        uint32_t rval;
  73
  74        reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE, offset);
  75        rval = readl(reg);
  76        if (val)
  77                rval |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
  78        else
  79                rval &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
  80        writel(rval, reg);
  81
  82        return 0;
  83}
  84
  85static int tegra186_gpio_direction_input(struct udevice *dev, unsigned offset)
  86{
  87        return tegra186_gpio_set_out(dev, offset, false);
  88}
  89
  90static int tegra186_gpio_direction_output(struct udevice *dev, unsigned offset,
  91                                       int value)
  92{
  93        int ret;
  94
  95        ret = tegra186_gpio_set_val(dev, offset, value != 0);
  96        if (ret)
  97                return ret;
  98        return tegra186_gpio_set_out(dev, offset, true);
  99}
 100
 101static int tegra186_gpio_get_value(struct udevice *dev, unsigned offset)
 102{
 103        uint32_t *reg;
 104        uint32_t rval;
 105
 106        reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
 107        rval = readl(reg);
 108
 109        if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
 110                reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE,
 111                                        offset);
 112        else
 113                reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_INPUT, offset);
 114
 115        rval = readl(reg);
 116        return !!rval;
 117}
 118
 119static int tegra186_gpio_set_value(struct udevice *dev, unsigned offset,
 120                                   int value)
 121{
 122        return tegra186_gpio_set_val(dev, offset, value != 0);
 123}
 124
 125static int tegra186_gpio_get_function(struct udevice *dev, unsigned offset)
 126{
 127        uint32_t *reg;
 128        uint32_t rval;
 129
 130        reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
 131        rval = readl(reg);
 132        if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
 133                return GPIOF_OUTPUT;
 134        else
 135                return GPIOF_INPUT;
 136}
 137
 138static int tegra186_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
 139                               struct ofnode_phandle_args *args)
 140{
 141        int gpio, port, ret;
 142
 143        gpio = args->args[0];
 144        port = gpio / TEGRA186_GPIO_PER_GPIO_COUNT;
 145        ret = device_get_child(dev, port, &desc->dev);
 146        if (ret)
 147                return ret;
 148        desc->offset = gpio % TEGRA186_GPIO_PER_GPIO_COUNT;
 149        desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
 150
 151        return 0;
 152}
 153
 154static const struct dm_gpio_ops tegra186_gpio_ops = {
 155        .direction_input        = tegra186_gpio_direction_input,
 156        .direction_output       = tegra186_gpio_direction_output,
 157        .get_value              = tegra186_gpio_get_value,
 158        .set_value              = tegra186_gpio_set_value,
 159        .get_function           = tegra186_gpio_get_function,
 160        .xlate                  = tegra186_gpio_xlate,
 161};
 162
 163/**
 164 * We have a top-level GPIO device with no actual GPIOs. It has a child device
 165 * for each port within the controller.
 166 */
 167static int tegra186_gpio_bind(struct udevice *parent)
 168{
 169        struct tegra186_gpio_platdata *parent_plat = parent->platdata;
 170        struct tegra186_gpio_ctlr_data *ctlr_data =
 171                (struct tegra186_gpio_ctlr_data *)dev_get_driver_data(parent);
 172        uint32_t *regs;
 173        int port, ret;
 174
 175        /* If this is a child device, there is nothing to do here */
 176        if (parent_plat)
 177                return 0;
 178
 179        regs = (uint32_t *)devfdt_get_addr_name(parent, "gpio");
 180        if (regs == (uint32_t *)FDT_ADDR_T_NONE)
 181                return -EINVAL;
 182
 183        for (port = 0; port < ctlr_data->port_count; port++) {
 184                struct tegra186_gpio_platdata *plat;
 185                struct udevice *dev;
 186
 187                plat = calloc(1, sizeof(*plat));
 188                if (!plat)
 189                        return -ENOMEM;
 190                plat->name = ctlr_data->ports[port].name;
 191                plat->regs = &(regs[ctlr_data->ports[port].offset / 4]);
 192
 193                ret = device_bind(parent, parent->driver, plat->name, plat,
 194                                  -1, &dev);
 195                if (ret)
 196                        return ret;
 197                dev_set_of_offset(dev, dev_of_offset(parent));
 198        }
 199
 200        return 0;
 201}
 202
 203static int tegra186_gpio_probe(struct udevice *dev)
 204{
 205        struct tegra186_gpio_platdata *plat = dev->platdata;
 206        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 207
 208        /* Only child devices have ports */
 209        if (!plat)
 210                return 0;
 211
 212        uc_priv->gpio_count = TEGRA186_GPIO_PER_GPIO_COUNT;
 213        uc_priv->bank_name = plat->name;
 214
 215        return 0;
 216}
 217
 218static const struct tegra186_gpio_port_data tegra186_gpio_main_ports[] = {
 219        {"A",  0x2000},
 220        {"B",  0x3000},
 221        {"C",  0x3200},
 222        {"D",  0x3400},
 223        {"E",  0x2200},
 224        {"F",  0x2400},
 225        {"G",  0x4200},
 226        {"H",  0x1000},
 227        {"I",  0x0800},
 228        {"J",  0x5000},
 229        {"K",  0x5200},
 230        {"L",  0x1200},
 231        {"M",  0x5600},
 232        {"N",  0x0000},
 233        {"O",  0x0200},
 234        {"P",  0x4000},
 235        {"Q",  0x0400},
 236        {"R",  0x0a00},
 237        {"T",  0x0600},
 238        {"X",  0x1400},
 239        {"Y",  0x1600},
 240        {"BB", 0x2600},
 241        {"CC", 0x5400},
 242};
 243
 244static const struct tegra186_gpio_ctlr_data tegra186_gpio_main_data = {
 245        .ports = tegra186_gpio_main_ports,
 246        .port_count = ARRAY_SIZE(tegra186_gpio_main_ports),
 247};
 248
 249static const struct tegra186_gpio_port_data tegra186_gpio_aon_ports[] = {
 250        {"S",  0x0200},
 251        {"U",  0x0400},
 252        {"V",  0x0800},
 253        {"W",  0x0a00},
 254        {"Z",  0x0e00},
 255        {"AA", 0x0c00},
 256        {"EE", 0x0600},
 257        {"FF", 0x0000},
 258};
 259
 260static const struct tegra186_gpio_ctlr_data tegra186_gpio_aon_data = {
 261        .ports = tegra186_gpio_aon_ports,
 262        .port_count = ARRAY_SIZE(tegra186_gpio_aon_ports),
 263};
 264
 265static const struct udevice_id tegra186_gpio_ids[] = {
 266        {
 267                .compatible = "nvidia,tegra186-gpio",
 268                .data = (ulong)&tegra186_gpio_main_data,
 269        },
 270        {
 271                .compatible = "nvidia,tegra186-gpio-aon",
 272                .data = (ulong)&tegra186_gpio_aon_data,
 273        },
 274        { }
 275};
 276
 277U_BOOT_DRIVER(tegra186_gpio) = {
 278        .name = "tegra186_gpio",
 279        .id = UCLASS_GPIO,
 280        .of_match = tegra186_gpio_ids,
 281        .bind = tegra186_gpio_bind,
 282        .probe = tegra186_gpio_probe,
 283        .ops = &tegra186_gpio_ops,
 284};
 285