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_plat {
  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_plat *plat = dev_get_plat(dev);
  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_plat *parent_plat = dev_get_plat(parent);
 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_plat *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                                  dev_ofnode(parent), &dev);
 195                if (ret)
 196                        return ret;
 197        }
 198
 199        return 0;
 200}
 201
 202static int tegra186_gpio_probe(struct udevice *dev)
 203{
 204        struct tegra186_gpio_plat *plat = dev_get_plat(dev);
 205        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 206
 207        /* Only child devices have ports */
 208        if (!plat)
 209                return 0;
 210
 211        uc_priv->gpio_count = TEGRA186_GPIO_PER_GPIO_COUNT;
 212        uc_priv->bank_name = plat->name;
 213
 214        return 0;
 215}
 216
 217static const struct tegra186_gpio_port_data tegra186_gpio_main_ports[] = {
 218        {"A",  0x2000},
 219        {"B",  0x3000},
 220        {"C",  0x3200},
 221        {"D",  0x3400},
 222        {"E",  0x2200},
 223        {"F",  0x2400},
 224        {"G",  0x4200},
 225        {"H",  0x1000},
 226        {"I",  0x0800},
 227        {"J",  0x5000},
 228        {"K",  0x5200},
 229        {"L",  0x1200},
 230        {"M",  0x5600},
 231        {"N",  0x0000},
 232        {"O",  0x0200},
 233        {"P",  0x4000},
 234        {"Q",  0x0400},
 235        {"R",  0x0a00},
 236        {"T",  0x0600},
 237        {"X",  0x1400},
 238        {"Y",  0x1600},
 239        {"BB", 0x2600},
 240        {"CC", 0x5400},
 241};
 242
 243static const struct tegra186_gpio_ctlr_data tegra186_gpio_main_data = {
 244        .ports = tegra186_gpio_main_ports,
 245        .port_count = ARRAY_SIZE(tegra186_gpio_main_ports),
 246};
 247
 248static const struct tegra186_gpio_port_data tegra186_gpio_aon_ports[] = {
 249        {"S",  0x0200},
 250        {"U",  0x0400},
 251        {"V",  0x0800},
 252        {"W",  0x0a00},
 253        {"Z",  0x0e00},
 254        {"AA", 0x0c00},
 255        {"EE", 0x0600},
 256        {"FF", 0x0000},
 257};
 258
 259static const struct tegra186_gpio_ctlr_data tegra186_gpio_aon_data = {
 260        .ports = tegra186_gpio_aon_ports,
 261        .port_count = ARRAY_SIZE(tegra186_gpio_aon_ports),
 262};
 263
 264static const struct udevice_id tegra186_gpio_ids[] = {
 265        {
 266                .compatible = "nvidia,tegra186-gpio",
 267                .data = (ulong)&tegra186_gpio_main_data,
 268        },
 269        {
 270                .compatible = "nvidia,tegra186-gpio-aon",
 271                .data = (ulong)&tegra186_gpio_aon_data,
 272        },
 273        { }
 274};
 275
 276U_BOOT_DRIVER(tegra186_gpio) = {
 277        .name = "tegra186_gpio",
 278        .id = UCLASS_GPIO,
 279        .of_match = tegra186_gpio_ids,
 280        .bind = tegra186_gpio_bind,
 281        .probe = tegra186_gpio_probe,
 282        .ops = &tegra186_gpio_ops,
 283};
 284