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