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 <asm/io.h>
  12#include <malloc.h>
  13#include <spi.h>
  14
  15#define ALTERA_SPI_RXDATA       0
  16#define ALTERA_SPI_TXDATA       4
  17#define ALTERA_SPI_STATUS       8
  18#define ALTERA_SPI_CONTROL      12
  19#define ALTERA_SPI_SLAVE_SEL    20
  20
  21#define ALTERA_SPI_STATUS_ROE_MSK       (0x8)
  22#define ALTERA_SPI_STATUS_TOE_MSK       (0x10)
  23#define ALTERA_SPI_STATUS_TMT_MSK       (0x20)
  24#define ALTERA_SPI_STATUS_TRDY_MSK      (0x40)
  25#define ALTERA_SPI_STATUS_RRDY_MSK      (0x80)
  26#define ALTERA_SPI_STATUS_E_MSK (0x100)
  27
  28#define ALTERA_SPI_CONTROL_IROE_MSK     (0x8)
  29#define ALTERA_SPI_CONTROL_ITOE_MSK     (0x10)
  30#define ALTERA_SPI_CONTROL_ITRDY_MSK    (0x40)
  31#define ALTERA_SPI_CONTROL_IRRDY_MSK    (0x80)
  32#define ALTERA_SPI_CONTROL_IE_MSK       (0x100)
  33#define ALTERA_SPI_CONTROL_SSO_MSK      (0x400)
  34
  35#ifndef CONFIG_SYS_ALTERA_SPI_LIST
  36#define CONFIG_SYS_ALTERA_SPI_LIST { CONFIG_SYS_SPI_BASE }
  37#endif
  38
  39static ulong altera_spi_base_list[] = CONFIG_SYS_ALTERA_SPI_LIST;
  40
  41struct altera_spi_slave {
  42        struct spi_slave slave;
  43        ulong base;
  44};
  45#define to_altera_spi_slave(s) container_of(s, struct altera_spi_slave, slave)
  46
  47__attribute__((weak))
  48int spi_cs_is_valid(unsigned int bus, unsigned int cs)
  49{
  50        return bus < ARRAY_SIZE(altera_spi_base_list) && cs < 32;
  51}
  52
  53__attribute__((weak))
  54void spi_cs_activate(struct spi_slave *slave)
  55{
  56        struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
  57        writel(1 << slave->cs, altspi->base + ALTERA_SPI_SLAVE_SEL);
  58        writel(ALTERA_SPI_CONTROL_SSO_MSK, altspi->base + ALTERA_SPI_CONTROL);
  59}
  60
  61__attribute__((weak))
  62void spi_cs_deactivate(struct spi_slave *slave)
  63{
  64        struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
  65        writel(0, altspi->base + ALTERA_SPI_CONTROL);
  66        writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
  67}
  68
  69void spi_init(void)
  70{
  71}
  72
  73void spi_set_speed(struct spi_slave *slave, uint hz)
  74{
  75        /* altera spi core does not support programmable speed */
  76}
  77
  78struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  79                                  unsigned int max_hz, unsigned int mode)
  80{
  81        struct altera_spi_slave *altspi;
  82
  83        if (!spi_cs_is_valid(bus, cs))
  84                return NULL;
  85
  86        altspi = spi_alloc_slave(struct altera_spi_slave, bus, cs);
  87        if (!altspi)
  88                return NULL;
  89
  90        altspi->base = altera_spi_base_list[bus];
  91        debug("%s: bus:%i cs:%i base:%lx\n", __func__,
  92                bus, cs, altspi->base);
  93
  94        return &altspi->slave;
  95}
  96
  97void spi_free_slave(struct spi_slave *slave)
  98{
  99        struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
 100        free(altspi);
 101}
 102
 103int spi_claim_bus(struct spi_slave *slave)
 104{
 105        struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
 106
 107        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
 108        writel(0, altspi->base + ALTERA_SPI_CONTROL);
 109        writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
 110        return 0;
 111}
 112
 113void spi_release_bus(struct spi_slave *slave)
 114{
 115        struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
 116
 117        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
 118        writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL);
 119}
 120
 121#ifndef CONFIG_ALTERA_SPI_IDLE_VAL
 122# define CONFIG_ALTERA_SPI_IDLE_VAL 0xff
 123#endif
 124
 125int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 126             void *din, unsigned long flags)
 127{
 128        struct altera_spi_slave *altspi = to_altera_spi_slave(slave);
 129        /* assume spi core configured to do 8 bit transfers */
 130        uint bytes = bitlen / 8;
 131        const uchar *txp = dout;
 132        uchar *rxp = din;
 133
 134        debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
 135                slave->bus, slave->cs, bitlen, bytes, flags);
 136        if (bitlen == 0)
 137                goto done;
 138
 139        if (bitlen % 8) {
 140                flags |= SPI_XFER_END;
 141                goto done;
 142        }
 143
 144        /* empty read buffer */
 145        if (readl(altspi->base + ALTERA_SPI_STATUS) &
 146            ALTERA_SPI_STATUS_RRDY_MSK)
 147                readl(altspi->base + ALTERA_SPI_RXDATA);
 148        if (flags & SPI_XFER_BEGIN)
 149                spi_cs_activate(slave);
 150
 151        while (bytes--) {
 152                uchar d = txp ? *txp++ : CONFIG_ALTERA_SPI_IDLE_VAL;
 153                debug("%s: tx:%x ", __func__, d);
 154                writel(d, altspi->base + ALTERA_SPI_TXDATA);
 155                while (!(readl(altspi->base + ALTERA_SPI_STATUS) &
 156                         ALTERA_SPI_STATUS_RRDY_MSK))
 157                        ;
 158                d = readl(altspi->base + ALTERA_SPI_RXDATA);
 159                if (rxp)
 160                        *rxp++ = d;
 161                debug("rx:%x\n", d);
 162        }
 163 done:
 164        if (flags & SPI_XFER_END)
 165                spi_cs_deactivate(slave);
 166
 167        return 0;
 168}
 169