uboot/drivers/spi/atmel_spi.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Atmel Corporation
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6#include <common.h>
   7#include <spi.h>
   8#include <malloc.h>
   9
  10#include <asm/io.h>
  11
  12#include <asm/arch/clk.h>
  13#include <asm/arch/hardware.h>
  14
  15#include "atmel_spi.h"
  16
  17static int spi_has_wdrbt(struct atmel_spi_slave *slave)
  18{
  19        unsigned int ver;
  20
  21        ver = spi_readl(slave, VERSION);
  22
  23        return (ATMEL_SPI_VERSION_REV(ver) >= 0x210);
  24}
  25
  26void spi_init()
  27{
  28
  29}
  30
  31struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  32                        unsigned int max_hz, unsigned int mode)
  33{
  34        struct atmel_spi_slave  *as;
  35        unsigned int            scbr;
  36        u32                     csrx;
  37        void                    *regs;
  38
  39        if (!spi_cs_is_valid(bus, cs))
  40                return NULL;
  41
  42        switch (bus) {
  43        case 0:
  44                regs = (void *)ATMEL_BASE_SPI0;
  45                break;
  46#ifdef ATMEL_BASE_SPI1
  47        case 1:
  48                regs = (void *)ATMEL_BASE_SPI1;
  49                break;
  50#endif
  51#ifdef ATMEL_BASE_SPI2
  52        case 2:
  53                regs = (void *)ATMEL_BASE_SPI2;
  54                break;
  55#endif
  56#ifdef ATMEL_BASE_SPI3
  57        case 3:
  58                regs = (void *)ATMEL_BASE_SPI3;
  59                break;
  60#endif
  61        default:
  62                return NULL;
  63        }
  64
  65
  66        scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz;
  67        if (scbr > ATMEL_SPI_CSRx_SCBR_MAX)
  68                /* Too low max SCK rate */
  69                return NULL;
  70        if (scbr < 1)
  71                scbr = 1;
  72
  73        csrx = ATMEL_SPI_CSRx_SCBR(scbr);
  74        csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8);
  75        if (!(mode & SPI_CPHA))
  76                csrx |= ATMEL_SPI_CSRx_NCPHA;
  77        if (mode & SPI_CPOL)
  78                csrx |= ATMEL_SPI_CSRx_CPOL;
  79
  80        as = spi_alloc_slave(struct atmel_spi_slave, bus, cs);
  81        if (!as)
  82                return NULL;
  83
  84        as->regs = regs;
  85        as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS
  86                        | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf);
  87        if (spi_has_wdrbt(as))
  88                as->mr |= ATMEL_SPI_MR_WDRBT;
  89
  90        spi_writel(as, CSR(cs), csrx);
  91
  92        return &as->slave;
  93}
  94
  95void spi_free_slave(struct spi_slave *slave)
  96{
  97        struct atmel_spi_slave *as = to_atmel_spi(slave);
  98
  99        free(as);
 100}
 101
 102int spi_claim_bus(struct spi_slave *slave)
 103{
 104        struct atmel_spi_slave *as = to_atmel_spi(slave);
 105
 106        /* Enable the SPI hardware */
 107        spi_writel(as, CR, ATMEL_SPI_CR_SPIEN);
 108
 109        /*
 110         * Select the slave. This should set SCK to the correct
 111         * initial state, etc.
 112         */
 113        spi_writel(as, MR, as->mr);
 114
 115        return 0;
 116}
 117
 118void spi_release_bus(struct spi_slave *slave)
 119{
 120        struct atmel_spi_slave *as = to_atmel_spi(slave);
 121
 122        /* Disable the SPI hardware */
 123        spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS);
 124}
 125
 126int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 127                const void *dout, void *din, unsigned long flags)
 128{
 129        struct atmel_spi_slave *as = to_atmel_spi(slave);
 130        unsigned int    len_tx;
 131        unsigned int    len_rx;
 132        unsigned int    len;
 133        u32             status;
 134        const u8        *txp = dout;
 135        u8              *rxp = din;
 136        u8              value;
 137
 138        if (bitlen == 0)
 139                /* Finish any previously submitted transfers */
 140                goto out;
 141
 142        /*
 143         * TODO: The controller can do non-multiple-of-8 bit
 144         * transfers, but this driver currently doesn't support it.
 145         *
 146         * It's also not clear how such transfers are supposed to be
 147         * represented as a stream of bytes...this is a limitation of
 148         * the current SPI interface.
 149         */
 150        if (bitlen % 8) {
 151                /* Errors always terminate an ongoing transfer */
 152                flags |= SPI_XFER_END;
 153                goto out;
 154        }
 155
 156        len = bitlen / 8;
 157
 158        /*
 159         * The controller can do automatic CS control, but it is
 160         * somewhat quirky, and it doesn't really buy us much anyway
 161         * in the context of U-Boot.
 162         */
 163        if (flags & SPI_XFER_BEGIN) {
 164                spi_cs_activate(slave);
 165                /*
 166                 * sometimes the RDR is not empty when we get here,
 167                 * in theory that should not happen, but it DOES happen.
 168                 * Read it here to be on the safe side.
 169                 * That also clears the OVRES flag. Required if the
 170                 * following loop exits due to OVRES!
 171                 */
 172                spi_readl(as, RDR);
 173        }
 174
 175        for (len_tx = 0, len_rx = 0; len_rx < len; ) {
 176                status = spi_readl(as, SR);
 177
 178                if (status & ATMEL_SPI_SR_OVRES)
 179                        return -1;
 180
 181                if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) {
 182                        if (txp)
 183                                value = *txp++;
 184                        else
 185                                value = 0;
 186                        spi_writel(as, TDR, value);
 187                        len_tx++;
 188                }
 189                if (status & ATMEL_SPI_SR_RDRF) {
 190                        value = spi_readl(as, RDR);
 191                        if (rxp)
 192                                *rxp++ = value;
 193                        len_rx++;
 194                }
 195        }
 196
 197out:
 198        if (flags & SPI_XFER_END) {
 199                /*
 200                 * Wait until the transfer is completely done before
 201                 * we deactivate CS.
 202                 */
 203                do {
 204                        status = spi_readl(as, SR);
 205                } while (!(status & ATMEL_SPI_SR_TXEMPTY));
 206
 207                spi_cs_deactivate(slave);
 208        }
 209
 210        return 0;
 211}
 212