uboot/drivers/spi/ep93xx_spi.c
<<
>>
Prefs
   1/*
   2 * SPI Driver for EP93xx
   3 *
   4 * Copyright (C) 2013 Sergey Kostanabev <sergey.kostanbaev <at> fairwaves.ru>
   5 *
   6 * Inspired form linux kernel driver and atmel uboot driver
   7 *
   8 * SPDX-License-Identifier:     GPL-2.0+
   9 */
  10
  11#include <common.h>
  12#include <spi.h>
  13#include <malloc.h>
  14
  15#include <asm/io.h>
  16
  17#include <asm/arch/ep93xx.h>
  18
  19#define SSPBASE                 SPI_BASE
  20
  21#define SSPCR0                  0x0000
  22#define SSPCR0_MODE_SHIFT       6
  23#define SSPCR0_SCR_SHIFT        8
  24#define SSPCR0_SPH              BIT(7)
  25#define SSPCR0_SPO              BIT(6)
  26#define SSPCR0_FRF_SPI          0
  27#define SSPCR0_DSS_8BIT         7
  28
  29#define SSPCR1                  0x0004
  30#define SSPCR1_RIE              BIT(0)
  31#define SSPCR1_TIE              BIT(1)
  32#define SSPCR1_RORIE            BIT(2)
  33#define SSPCR1_LBM              BIT(3)
  34#define SSPCR1_SSE              BIT(4)
  35#define SSPCR1_MS               BIT(5)
  36#define SSPCR1_SOD              BIT(6)
  37
  38#define SSPDR                   0x0008
  39
  40#define SSPSR                   0x000c
  41#define SSPSR_TFE               BIT(0)
  42#define SSPSR_TNF               BIT(1)
  43#define SSPSR_RNE               BIT(2)
  44#define SSPSR_RFF               BIT(3)
  45#define SSPSR_BSY               BIT(4)
  46#define SSPCPSR                 0x0010
  47
  48#define SSPIIR                  0x0014
  49#define SSPIIR_RIS              BIT(0)
  50#define SSPIIR_TIS              BIT(1)
  51#define SSPIIR_RORIS            BIT(2)
  52#define SSPICR                  SSPIIR
  53
  54#define SSPCLOCK                14745600
  55#define SSP_MAX_RATE            (SSPCLOCK / 2)
  56#define SSP_MIN_RATE            (SSPCLOCK / (254 * 256))
  57
  58/* timeout in milliseconds */
  59#define SPI_TIMEOUT             5
  60/* maximum depth of RX/TX FIFO */
  61#define SPI_FIFO_SIZE           8
  62
  63struct ep93xx_spi_slave {
  64        struct spi_slave slave;
  65
  66        unsigned sspcr0;
  67        unsigned sspcpsr;
  68};
  69
  70static inline struct ep93xx_spi_slave *to_ep93xx_spi(struct spi_slave *slave)
  71{
  72        return container_of(slave, struct ep93xx_spi_slave, slave);
  73}
  74
  75void spi_init()
  76{
  77}
  78
  79static inline void ep93xx_spi_write_u8(u16 reg, u8 value)
  80{
  81        writel(value, (unsigned int *)(SSPBASE + reg));
  82}
  83
  84static inline u8 ep93xx_spi_read_u8(u16 reg)
  85{
  86        return readl((unsigned int *)(SSPBASE + reg));
  87}
  88
  89static inline void ep93xx_spi_write_u16(u16 reg, u16 value)
  90{
  91        writel(value, (unsigned int *)(SSPBASE + reg));
  92}
  93
  94static inline u16 ep93xx_spi_read_u16(u16 reg)
  95{
  96        return (u16)readl((unsigned int *)(SSPBASE + reg));
  97}
  98
  99static int ep93xx_spi_init_hw(unsigned int rate, unsigned int mode,
 100                                struct ep93xx_spi_slave *slave)
 101{
 102        unsigned cpsr, scr;
 103
 104        if (rate > SSP_MAX_RATE)
 105                rate = SSP_MAX_RATE;
 106
 107        if (rate < SSP_MIN_RATE)
 108                return -1;
 109
 110        /* Calculate divisors so that we can get speed according the
 111         * following formula:
 112         *      rate = spi_clock_rate / (cpsr * (1 + scr))
 113         *
 114         * cpsr must be even number and starts from 2, scr can be any number
 115         * between 0 and 255.
 116         */
 117        for (cpsr = 2; cpsr <= 254; cpsr += 2) {
 118                for (scr = 0; scr <= 255; scr++) {
 119                        if ((SSPCLOCK / (cpsr * (scr + 1))) <= rate) {
 120                                /* Set CHPA and CPOL, SPI format and 8bit */
 121                                unsigned sspcr0 = (scr << SSPCR0_SCR_SHIFT) |
 122                                        SSPCR0_FRF_SPI | SSPCR0_DSS_8BIT;
 123                                if (mode & SPI_CPHA)
 124                                        sspcr0 |= SSPCR0_SPH;
 125                                if (mode & SPI_CPOL)
 126                                        sspcr0 |= SSPCR0_SPO;
 127
 128                                slave->sspcr0 = sspcr0;
 129                                slave->sspcpsr = cpsr;
 130                                return 0;
 131                        }
 132                }
 133        }
 134
 135        return -1;
 136}
 137
 138void spi_set_speed(struct spi_slave *slave, unsigned int hz)
 139{
 140        struct ep93xx_spi_slave *as = to_ep93xx_spi(slave);
 141
 142        unsigned int mode = 0;
 143        if (as->sspcr0 & SSPCR0_SPH)
 144                mode |= SPI_CPHA;
 145        if (as->sspcr0 & SSPCR0_SPO)
 146                mode |= SPI_CPOL;
 147
 148        ep93xx_spi_init_hw(hz, mode, as);
 149}
 150
 151struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 152                        unsigned int max_hz, unsigned int mode)
 153{
 154        struct ep93xx_spi_slave *as;
 155
 156        if (!spi_cs_is_valid(bus, cs))
 157                return NULL;
 158
 159        as = spi_alloc_slave(struct ep93xx_spi_slave, bus, cs);
 160        if (!as)
 161                return NULL;
 162
 163        if (ep93xx_spi_init_hw(max_hz, mode, as)) {
 164                free(as);
 165                return NULL;
 166        }
 167
 168        return &as->slave;
 169}
 170
 171void spi_free_slave(struct spi_slave *slave)
 172{
 173        struct ep93xx_spi_slave *as = to_ep93xx_spi(slave);
 174
 175        free(as);
 176}
 177
 178int spi_claim_bus(struct spi_slave *slave)
 179{
 180        struct ep93xx_spi_slave *as = to_ep93xx_spi(slave);
 181
 182        /* Enable the SPI hardware */
 183        ep93xx_spi_write_u8(SSPCR1, SSPCR1_SSE);
 184
 185
 186        ep93xx_spi_write_u8(SSPCPSR, as->sspcpsr);
 187        ep93xx_spi_write_u16(SSPCR0, as->sspcr0);
 188
 189        debug("Select CS:%d SSPCPSR=%02x SSPCR0=%04x\n",
 190              slave->cs, as->sspcpsr, as->sspcr0);
 191        return 0;
 192}
 193
 194void spi_release_bus(struct spi_slave *slave)
 195{
 196        /* Disable the SPI hardware */
 197        ep93xx_spi_write_u8(SSPCR1, 0);
 198}
 199
 200int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 201                const void *dout, void *din, unsigned long flags)
 202{
 203        unsigned int    len_tx;
 204        unsigned int    len_rx;
 205        unsigned int    len;
 206        u32             status;
 207        const u8        *txp = dout;
 208        u8              *rxp = din;
 209        u8              value;
 210
 211        debug("spi_xfer: slave %u:%u dout %p din %p bitlen %u\n",
 212              slave->bus, slave->cs, (uint *)dout, (uint *)din, bitlen);
 213
 214
 215        if (bitlen == 0)
 216                /* Finish any previously submitted transfers */
 217                goto out;
 218
 219        if (bitlen % 8) {
 220                /* Errors always terminate an ongoing transfer */
 221                flags |= SPI_XFER_END;
 222                goto out;
 223        }
 224
 225        len = bitlen / 8;
 226
 227
 228        if (flags & SPI_XFER_BEGIN) {
 229                /* Empty RX FIFO */
 230                while ((ep93xx_spi_read_u8(SSPSR) & SSPSR_RNE))
 231                        ep93xx_spi_read_u8(SSPDR);
 232
 233                spi_cs_activate(slave);
 234        }
 235
 236        for (len_tx = 0, len_rx = 0; len_rx < len; ) {
 237                status = ep93xx_spi_read_u8(SSPSR);
 238
 239                if ((len_tx < len) && (status & SSPSR_TNF)) {
 240                        if (txp)
 241                                value = *txp++;
 242                        else
 243                                value = 0xff;
 244
 245                        ep93xx_spi_write_u8(SSPDR, value);
 246                        len_tx++;
 247                }
 248
 249                if (status & SSPSR_RNE) {
 250                        value = ep93xx_spi_read_u8(SSPDR);
 251
 252                        if (rxp)
 253                                *rxp++ = value;
 254                        len_rx++;
 255                }
 256        }
 257
 258out:
 259        if (flags & SPI_XFER_END) {
 260                /*
 261                 * Wait until the transfer is completely done before
 262                 * we deactivate CS.
 263                 */
 264                do {
 265                        status = ep93xx_spi_read_u8(SSPSR);
 266                } while (status & SSPSR_BSY);
 267
 268                spi_cs_deactivate(slave);
 269        }
 270
 271        return 0;
 272}
 273