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