uboot/drivers/spi/altera_spi.c
<<
>>
Prefs
   1/*
   2 * Altera SPI driver
   3 *
   4 * based on bfin_spi.c
   5 * Copyright (c) 2005-2008 Analog Devices Inc.
   6 * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
   7 *
   8 * SPDX-License-Identifier:     GPL-2.0+
   9 */
  10#include <common.h>
  11#include <dm.h>
  12#include <errno.h>
  13#include <malloc.h>
  14#include <fdtdec.h>
  15#include <spi.h>
  16#include <asm/io.h>
  17
  18DECLARE_GLOBAL_DATA_PTR;
  19
  20#define ALTERA_SPI_STATUS_RRDY_MSK      BIT(7)
  21#define ALTERA_SPI_CONTROL_SSO_MSK      BIT(10)
  22
  23#ifndef CONFIG_ALTERA_SPI_IDLE_VAL
  24#define CONFIG_ALTERA_SPI_IDLE_VAL      0xff
  25#endif
  26
  27struct altera_spi_regs {
  28        u32     rxdata;
  29        u32     txdata;
  30        u32     status;
  31        u32     control;
  32        u32     _reserved;
  33        u32     slave_sel;
  34};
  35
  36struct altera_spi_platdata {
  37        struct altera_spi_regs *regs;
  38};
  39
  40struct altera_spi_priv {
  41        struct altera_spi_regs *regs;
  42};
  43
  44static void spi_cs_activate(struct udevice *dev, uint cs)
  45{
  46        struct udevice *bus = dev->parent;
  47        struct altera_spi_priv *priv = dev_get_priv(bus);
  48        struct altera_spi_regs *const regs = priv->regs;
  49
  50        writel(1 << cs, &regs->slave_sel);
  51        writel(ALTERA_SPI_CONTROL_SSO_MSK, &regs->control);
  52}
  53
  54static void spi_cs_deactivate(struct udevice *dev)
  55{
  56        struct udevice *bus = dev->parent;
  57        struct altera_spi_priv *priv = dev_get_priv(bus);
  58        struct altera_spi_regs *const regs = priv->regs;
  59
  60        writel(0, &regs->control);
  61        writel(0, &regs->slave_sel);
  62}
  63
  64static int altera_spi_claim_bus(struct udevice *dev)
  65{
  66        struct udevice *bus = dev->parent;
  67        struct altera_spi_priv *priv = dev_get_priv(bus);
  68        struct altera_spi_regs *const regs = priv->regs;
  69
  70        writel(0, &regs->control);
  71        writel(0, &regs->slave_sel);
  72
  73        return 0;
  74}
  75
  76static int altera_spi_release_bus(struct udevice *dev)
  77{
  78        struct udevice *bus = dev->parent;
  79        struct altera_spi_priv *priv = dev_get_priv(bus);
  80        struct altera_spi_regs *const regs = priv->regs;
  81
  82        writel(0, &regs->slave_sel);
  83
  84        return 0;
  85}
  86
  87static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen,
  88                            const void *dout, void *din, unsigned long flags)
  89{
  90        struct udevice *bus = dev->parent;
  91        struct altera_spi_priv *priv = dev_get_priv(bus);
  92        struct altera_spi_regs *const regs = priv->regs;
  93        struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
  94
  95        /* assume spi core configured to do 8 bit transfers */
  96        unsigned int bytes = bitlen / 8;
  97        const unsigned char *txp = dout;
  98        unsigned char *rxp = din;
  99        uint32_t reg, data, start;
 100
 101        debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
 102              bus->seq, slave_plat->cs, bitlen, bytes, flags);
 103
 104        if (bitlen == 0)
 105                goto done;
 106
 107        if (bitlen % 8) {
 108                flags |= SPI_XFER_END;
 109                goto done;
 110        }
 111
 112        /* empty read buffer */
 113        if (readl(&regs->status) & ALTERA_SPI_STATUS_RRDY_MSK)
 114                readl(&regs->rxdata);
 115
 116        if (flags & SPI_XFER_BEGIN)
 117                spi_cs_activate(dev, slave_plat->cs);
 118
 119        while (bytes--) {
 120                if (txp)
 121                        data = *txp++;
 122                else
 123                        data = CONFIG_ALTERA_SPI_IDLE_VAL;
 124
 125                debug("%s: tx:%x ", __func__, data);
 126                writel(data, &regs->txdata);
 127
 128                start = get_timer(0);
 129                while (1) {
 130                        reg = readl(&regs->status);
 131                        if (reg & ALTERA_SPI_STATUS_RRDY_MSK)
 132                                break;
 133                        if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
 134                                debug("%s: Transmission timed out!\n", __func__);
 135                                return -1;
 136                        }
 137                }
 138
 139                data = readl(&regs->rxdata);
 140                if (rxp)
 141                        *rxp++ = data & 0xff;
 142
 143                debug("rx:%x\n", data);
 144        }
 145
 146done:
 147        if (flags & SPI_XFER_END)
 148                spi_cs_deactivate(dev);
 149
 150        return 0;
 151}
 152
 153static int altera_spi_set_speed(struct udevice *bus, uint speed)
 154{
 155        return 0;
 156}
 157
 158static int altera_spi_set_mode(struct udevice *bus, uint mode)
 159{
 160        return 0;
 161}
 162
 163static int altera_spi_probe(struct udevice *bus)
 164{
 165        struct altera_spi_platdata *plat = dev_get_platdata(bus);
 166        struct altera_spi_priv *priv = dev_get_priv(bus);
 167
 168        priv->regs = plat->regs;
 169
 170        return 0;
 171}
 172
 173static int altera_spi_ofdata_to_platdata(struct udevice *bus)
 174{
 175        struct altera_spi_platdata *plat = dev_get_platdata(bus);
 176
 177        plat->regs = map_physmem(dev_get_addr(bus),
 178                                 sizeof(struct altera_spi_regs),
 179                                 MAP_NOCACHE);
 180
 181        return 0;
 182}
 183
 184static const struct dm_spi_ops altera_spi_ops = {
 185        .claim_bus      = altera_spi_claim_bus,
 186        .release_bus    = altera_spi_release_bus,
 187        .xfer           = altera_spi_xfer,
 188        .set_speed      = altera_spi_set_speed,
 189        .set_mode       = altera_spi_set_mode,
 190        /*
 191         * cs_info is not needed, since we require all chip selects to be
 192         * in the device tree explicitly
 193         */
 194};
 195
 196static const struct udevice_id altera_spi_ids[] = {
 197        { .compatible = "altr,spi-1.0" },
 198        {}
 199};
 200
 201U_BOOT_DRIVER(altera_spi) = {
 202        .name   = "altera_spi",
 203        .id     = UCLASS_SPI,
 204        .of_match = altera_spi_ids,
 205        .ops    = &altera_spi_ops,
 206        .ofdata_to_platdata = altera_spi_ofdata_to_platdata,
 207        .platdata_auto_alloc_size = sizeof(struct altera_spi_platdata),
 208        .priv_auto_alloc_size = sizeof(struct altera_spi_priv),
 209        .probe  = altera_spi_probe,
 210};
 211