uboot/drivers/spi/bfin_spi.c
<<
>>
Prefs
   1/*
   2 * Driver for Blackfin On-Chip SPI device
   3 *
   4 * Copyright (c) 2005-2010 Analog Devices Inc.
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9/*#define DEBUG*/
  10
  11#include <common.h>
  12#include <console.h>
  13#include <malloc.h>
  14#include <spi.h>
  15
  16#include <asm/blackfin.h>
  17#include <asm/clock.h>
  18#include <asm/gpio.h>
  19#include <asm/portmux.h>
  20#include <asm/mach-common/bits/spi.h>
  21
  22struct bfin_spi_slave {
  23        struct spi_slave slave;
  24        void *mmr_base;
  25        u16 ctl, baud, flg;
  26};
  27
  28#define MAKE_SPI_FUNC(mmr, off) \
  29static inline void write_##mmr(struct bfin_spi_slave *bss, u16 val) { bfin_write16(bss->mmr_base + off, val); } \
  30static inline u16 read_##mmr(struct bfin_spi_slave *bss) { return bfin_read16(bss->mmr_base + off); }
  31MAKE_SPI_FUNC(SPI_CTL,  0x00)
  32MAKE_SPI_FUNC(SPI_FLG,  0x04)
  33MAKE_SPI_FUNC(SPI_STAT, 0x08)
  34MAKE_SPI_FUNC(SPI_TDBR, 0x0c)
  35MAKE_SPI_FUNC(SPI_RDBR, 0x10)
  36MAKE_SPI_FUNC(SPI_BAUD, 0x14)
  37
  38#define to_bfin_spi_slave(s) container_of(s, struct bfin_spi_slave, slave)
  39
  40#define gpio_cs(cs) ((cs) - MAX_CTRL_CS)
  41#ifdef CONFIG_BFIN_SPI_GPIO_CS
  42# define is_gpio_cs(cs) ((cs) > MAX_CTRL_CS)
  43#else
  44# define is_gpio_cs(cs) 0
  45#endif
  46
  47int spi_cs_is_valid(unsigned int bus, unsigned int cs)
  48{
  49        if (is_gpio_cs(cs))
  50                return gpio_is_valid(gpio_cs(cs));
  51        else
  52                return (cs >= 1 && cs <= MAX_CTRL_CS);
  53}
  54
  55void spi_cs_activate(struct spi_slave *slave)
  56{
  57        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
  58
  59        if (is_gpio_cs(slave->cs)) {
  60                unsigned int cs = gpio_cs(slave->cs);
  61                gpio_set_value(cs, bss->flg);
  62                debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
  63        } else {
  64                write_SPI_FLG(bss,
  65                        (read_SPI_FLG(bss) &
  66                        ~((!bss->flg << 8) << slave->cs)) |
  67                        (1 << slave->cs));
  68                debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
  69        }
  70
  71        SSYNC();
  72}
  73
  74void spi_cs_deactivate(struct spi_slave *slave)
  75{
  76        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
  77
  78        if (is_gpio_cs(slave->cs)) {
  79                unsigned int cs = gpio_cs(slave->cs);
  80                gpio_set_value(cs, !bss->flg);
  81                debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
  82        } else {
  83                u16 flg;
  84
  85                /* make sure we force the cs to deassert rather than let the
  86                 * pin float back up.  otherwise, exact timings may not be
  87                 * met some of the time leading to random behavior (ugh).
  88                 */
  89                flg = read_SPI_FLG(bss) | ((!bss->flg << 8) << slave->cs);
  90                write_SPI_FLG(bss, flg);
  91                SSYNC();
  92                debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
  93
  94                flg &= ~(1 << slave->cs);
  95                write_SPI_FLG(bss, flg);
  96                debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
  97        }
  98
  99        SSYNC();
 100}
 101
 102void spi_init()
 103{
 104}
 105
 106#ifdef SPI_CTL
 107# define SPI0_CTL SPI_CTL
 108#endif
 109
 110#define SPI_PINS(n) \
 111        [n] = { 0, P_SPI##n##_SCK, P_SPI##n##_MISO, P_SPI##n##_MOSI, 0 }
 112static unsigned short pins[][5] = {
 113#ifdef SPI0_CTL
 114        SPI_PINS(0),
 115#endif
 116#ifdef SPI1_CTL
 117        SPI_PINS(1),
 118#endif
 119#ifdef SPI2_CTL
 120        SPI_PINS(2),
 121#endif
 122};
 123
 124#define SPI_CS_PINS(n) \
 125        [n] = { \
 126                P_SPI##n##_SSEL1, P_SPI##n##_SSEL2, P_SPI##n##_SSEL3, \
 127                P_SPI##n##_SSEL4, P_SPI##n##_SSEL5, P_SPI##n##_SSEL6, \
 128                P_SPI##n##_SSEL7, \
 129        }
 130static const unsigned short cs_pins[][7] = {
 131#ifdef SPI0_CTL
 132        SPI_CS_PINS(0),
 133#endif
 134#ifdef SPI1_CTL
 135        SPI_CS_PINS(1),
 136#endif
 137#ifdef SPI2_CTL
 138        SPI_CS_PINS(2),
 139#endif
 140};
 141
 142void spi_set_speed(struct spi_slave *slave, uint hz)
 143{
 144        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
 145        ulong clk;
 146        u32 baud;
 147
 148        clk = get_spi_clk();
 149        /* baud should be rounded up */
 150        baud = DIV_ROUND_UP(clk, 2 * hz);
 151        if (baud < 2)
 152                baud = 2;
 153        else if (baud > (u16)-1)
 154                baud = -1;
 155        bss->baud = baud;
 156}
 157
 158struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 159                unsigned int max_hz, unsigned int mode)
 160{
 161        struct bfin_spi_slave *bss;
 162        u32 mmr_base;
 163
 164        if (!spi_cs_is_valid(bus, cs))
 165                return NULL;
 166
 167        switch (bus) {
 168#ifdef SPI0_CTL
 169        case 0:
 170                mmr_base = SPI0_CTL; break;
 171#endif
 172#ifdef SPI1_CTL
 173        case 1:
 174                mmr_base = SPI1_CTL; break;
 175#endif
 176#ifdef SPI2_CTL
 177        case 2:
 178                mmr_base = SPI2_CTL; break;
 179#endif
 180        default:
 181                debug("%s: invalid bus %u\n", __func__, bus);
 182                return NULL;
 183        }
 184
 185        bss = spi_alloc_slave(struct bfin_spi_slave, bus, cs);
 186        if (!bss)
 187                return NULL;
 188
 189        bss->mmr_base = (void *)mmr_base;
 190        bss->ctl = SPE | MSTR | TDBR_CORE;
 191        if (mode & SPI_CPHA) bss->ctl |= CPHA;
 192        if (mode & SPI_CPOL) bss->ctl |= CPOL;
 193        if (mode & SPI_LSB_FIRST) bss->ctl |= LSBF;
 194        bss->flg = mode & SPI_CS_HIGH ? 1 : 0;
 195        spi_set_speed(&bss->slave, max_hz);
 196
 197        debug("%s: bus:%i cs:%i mmr:%x ctl:%x baud:%i flg:%i\n", __func__,
 198                bus, cs, mmr_base, bss->ctl, bss->baud, bss->flg);
 199
 200        return &bss->slave;
 201}
 202
 203void spi_free_slave(struct spi_slave *slave)
 204{
 205        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
 206        free(bss);
 207}
 208
 209int spi_claim_bus(struct spi_slave *slave)
 210{
 211        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
 212
 213        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
 214
 215        if (is_gpio_cs(slave->cs)) {
 216                unsigned int cs = gpio_cs(slave->cs);
 217                gpio_request(cs, "bfin-spi");
 218                gpio_direction_output(cs, !bss->flg);
 219                pins[slave->bus][0] = P_DONTCARE;
 220        } else
 221                pins[slave->bus][0] = cs_pins[slave->bus][slave->cs - 1];
 222        peripheral_request_list(pins[slave->bus], "bfin-spi");
 223
 224        write_SPI_CTL(bss, bss->ctl);
 225        write_SPI_BAUD(bss, bss->baud);
 226        SSYNC();
 227
 228        return 0;
 229}
 230
 231void spi_release_bus(struct spi_slave *slave)
 232{
 233        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
 234
 235        debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
 236
 237        peripheral_free_list(pins[slave->bus]);
 238        if (is_gpio_cs(slave->cs))
 239                gpio_free(gpio_cs(slave->cs));
 240
 241        write_SPI_CTL(bss, 0);
 242        SSYNC();
 243}
 244
 245#ifndef CONFIG_BFIN_SPI_IDLE_VAL
 246# define CONFIG_BFIN_SPI_IDLE_VAL 0xff
 247#endif
 248
 249static int spi_pio_xfer(struct bfin_spi_slave *bss, const u8 *tx, u8 *rx,
 250                        uint bytes)
 251{
 252        /* discard invalid data and clear RXS */
 253        read_SPI_RDBR(bss);
 254        /* todo: take advantage of hardware fifos  */
 255        while (bytes--) {
 256                u8 value = (tx ? *tx++ : CONFIG_BFIN_SPI_IDLE_VAL);
 257                debug("%s: tx:%x ", __func__, value);
 258                write_SPI_TDBR(bss, value);
 259                SSYNC();
 260                while ((read_SPI_STAT(bss) & TXS))
 261                        if (ctrlc())
 262                                return -1;
 263                while (!(read_SPI_STAT(bss) & SPIF))
 264                        if (ctrlc())
 265                                return -1;
 266                while (!(read_SPI_STAT(bss) & RXS))
 267                        if (ctrlc())
 268                                return -1;
 269                value = read_SPI_RDBR(bss);
 270                if (rx)
 271                        *rx++ = value;
 272                debug("rx:%x\n", value);
 273        }
 274
 275        return 0;
 276}
 277
 278int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 279                void *din, unsigned long flags)
 280{
 281        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
 282        const u8 *tx = dout;
 283        u8 *rx = din;
 284        uint bytes = bitlen / 8;
 285        int ret = 0;
 286
 287        debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
 288                slave->bus, slave->cs, bitlen, bytes, flags);
 289
 290        if (bitlen == 0)
 291                goto done;
 292
 293        /* we can only do 8 bit transfers */
 294        if (bitlen % 8) {
 295                flags |= SPI_XFER_END;
 296                goto done;
 297        }
 298
 299        if (flags & SPI_XFER_BEGIN)
 300                spi_cs_activate(slave);
 301
 302        ret = spi_pio_xfer(bss, tx, rx, bytes);
 303
 304 done:
 305        if (flags & SPI_XFER_END)
 306                spi_cs_deactivate(slave);
 307
 308        return ret;
 309}
 310