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