uboot/drivers/gpio/imx_rgpio2p.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2016 Freescale Semiconductor, Inc.
   4 *
   5 * RGPIO2P driver for the Freescale i.MX7ULP.
   6 */
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <errno.h>
  11#include <fdtdec.h>
  12#include <asm/gpio.h>
  13#include <asm/io.h>
  14#include <malloc.h>
  15
  16enum imx_rgpio2p_direction {
  17        IMX_RGPIO2P_DIRECTION_IN,
  18        IMX_RGPIO2P_DIRECTION_OUT,
  19};
  20
  21#define GPIO_PER_BANK                   32
  22
  23struct imx_rgpio2p_data {
  24        struct gpio_regs *regs;
  25};
  26
  27struct imx_rgpio2p_plat {
  28        int bank_index;
  29        struct gpio_regs *regs;
  30};
  31
  32static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset)
  33{
  34        u32 val;
  35
  36        val = readl(&regs->gpio_pddr);
  37
  38        return val & (1 << offset) ? 1 : 0;
  39}
  40
  41static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset,
  42                                    enum imx_rgpio2p_direction direction)
  43{
  44        u32 l;
  45
  46        l = readl(&regs->gpio_pddr);
  47
  48        switch (direction) {
  49        case IMX_RGPIO2P_DIRECTION_OUT:
  50                l |= 1 << offset;
  51                break;
  52        case IMX_RGPIO2P_DIRECTION_IN:
  53                l &= ~(1 << offset);
  54        }
  55        writel(l, &regs->gpio_pddr);
  56}
  57
  58static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset,
  59                                    int value)
  60{
  61        if (value)
  62                writel((1 << offset), &regs->gpio_psor);
  63        else
  64                writel((1 << offset), &regs->gpio_pcor);
  65}
  66
  67static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset)
  68{
  69        return (readl(&regs->gpio_pdir) >> offset) & 0x01;
  70}
  71
  72static int  imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset)
  73{
  74        struct imx_rgpio2p_data *bank = dev_get_priv(dev);
  75
  76        /* Configure GPIO direction as input. */
  77        imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN);
  78
  79        return 0;
  80}
  81
  82static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset,
  83                                       int value)
  84{
  85        struct imx_rgpio2p_data *bank = dev_get_priv(dev);
  86
  87        /* Configure GPIO output value. */
  88        imx_rgpio2p_bank_set_value(bank->regs, offset, value);
  89
  90        /* Configure GPIO direction as output. */
  91        imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT);
  92
  93        return 0;
  94}
  95
  96static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset)
  97{
  98        struct imx_rgpio2p_data *bank = dev_get_priv(dev);
  99
 100        return imx_rgpio2p_bank_get_value(bank->regs, offset);
 101}
 102
 103static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset,
 104                                 int value)
 105{
 106        struct imx_rgpio2p_data *bank = dev_get_priv(dev);
 107
 108        imx_rgpio2p_bank_set_value(bank->regs, offset, value);
 109
 110        return 0;
 111}
 112
 113static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset)
 114{
 115        struct imx_rgpio2p_data *bank = dev_get_priv(dev);
 116
 117        /* GPIOF_FUNC is not implemented yet */
 118        if (imx_rgpio2p_is_output(bank->regs, offset))
 119                return GPIOF_OUTPUT;
 120        else
 121                return GPIOF_INPUT;
 122}
 123
 124static const struct dm_gpio_ops imx_rgpio2p_ops = {
 125        .direction_input        = imx_rgpio2p_direction_input,
 126        .direction_output       = imx_rgpio2p_direction_output,
 127        .get_value              = imx_rgpio2p_get_value,
 128        .set_value              = imx_rgpio2p_set_value,
 129        .get_function           = imx_rgpio2p_get_function,
 130};
 131
 132static int imx_rgpio2p_probe(struct udevice *dev)
 133{
 134        struct imx_rgpio2p_data *bank = dev_get_priv(dev);
 135        struct imx_rgpio2p_plat *plat = dev_get_platdata(dev);
 136        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 137        int banknum;
 138        char name[18], *str;
 139
 140        banknum = plat->bank_index;
 141        sprintf(name, "GPIO%d_", banknum + 1);
 142        str = strdup(name);
 143        if (!str)
 144                return -ENOMEM;
 145        uc_priv->bank_name = str;
 146        uc_priv->gpio_count = GPIO_PER_BANK;
 147        bank->regs = plat->regs;
 148
 149        return 0;
 150}
 151
 152static int imx_rgpio2p_bind(struct udevice *dev)
 153{
 154        struct imx_rgpio2p_plat *plat = dev->platdata;
 155        fdt_addr_t addr;
 156
 157        /*
 158         * If platdata already exsits, directly return.
 159         * Actually only when DT is not supported, platdata
 160         * is statically initialized in U_BOOT_DEVICES.Here
 161         * will return.
 162         */
 163        if (plat)
 164                return 0;
 165
 166        addr = devfdt_get_addr_index(dev, 1);
 167        if (addr == FDT_ADDR_T_NONE)
 168                return -EINVAL;
 169
 170        /*
 171         * TODO:
 172         * When every board is converted to driver model and DT is supported,
 173         * this can be done by auto-alloc feature, but not using calloc
 174         * to alloc memory for platdata.
 175         *
 176         * For example imx_rgpio2p_plat uses platform data rather than device
 177         * tree.
 178         *
 179         * NOTE: DO NOT COPY this code if you are using device tree.
 180         */
 181        plat = calloc(1, sizeof(*plat));
 182        if (!plat)
 183                return -ENOMEM;
 184
 185        plat->regs = (struct gpio_regs *)addr;
 186        plat->bank_index = dev->req_seq;
 187        dev->platdata = plat;
 188
 189        return 0;
 190}
 191
 192
 193static const struct udevice_id imx_rgpio2p_ids[] = {
 194        { .compatible = "fsl,imx7ulp-gpio" },
 195        { }
 196};
 197
 198U_BOOT_DRIVER(imx_rgpio2p) = {
 199        .name   = "imx_rgpio2p",
 200        .id     = UCLASS_GPIO,
 201        .ops    = &imx_rgpio2p_ops,
 202        .probe  = imx_rgpio2p_probe,
 203        .priv_auto_alloc_size = sizeof(struct imx_rgpio2p_plat),
 204        .of_match = imx_rgpio2p_ids,
 205        .bind   = imx_rgpio2p_bind,
 206};
 207
 208#if !CONFIG_IS_ENABLED(OF_CONTROL)
 209static const struct imx_rgpio2p_plat imx_plat[] = {
 210        { 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR },
 211        { 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR },
 212        { 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR },
 213        { 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR },
 214        { 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR },
 215        { 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR },
 216};
 217
 218U_BOOT_DEVICES(imx_rgpio2ps) = {
 219        { "imx_rgpio2p", &imx_plat[0] },
 220        { "imx_rgpio2p", &imx_plat[1] },
 221        { "imx_rgpio2p", &imx_plat[2] },
 222        { "imx_rgpio2p", &imx_plat[3] },
 223        { "imx_rgpio2p", &imx_plat[4] },
 224        { "imx_rgpio2p", &imx_plat[5] },
 225};
 226#endif
 227