uboot/drivers/spi/omap3_spi.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
   3 *
   4 * Driver for McSPI controller on OMAP3. Based on davinci_spi.c
   5 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
   6 *
   7 * Copyright (C) 2007 Atmel Corporation
   8 *
   9 * Parts taken from linux/drivers/spi/omap2_mcspi.c
  10 * Copyright (C) 2005, 2006 Nokia Corporation
  11 *
  12 * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.com>
  13 *
  14 * SPDX-License-Identifier:     GPL-2.0+
  15 */
  16
  17#include <common.h>
  18#include <spi.h>
  19#include <malloc.h>
  20#include <asm/io.h>
  21#include "omap3_spi.h"
  22
  23#define WORD_LEN        8
  24#define SPI_WAIT_TIMEOUT 3000000;
  25
  26static void spi_reset(struct omap3_spi_slave *ds)
  27{
  28        unsigned int tmp;
  29
  30        writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &ds->regs->sysconfig);
  31        do {
  32                tmp = readl(&ds->regs->sysstatus);
  33        } while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
  34
  35        writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
  36                                 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
  37                                 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE,
  38                                 &ds->regs->sysconfig);
  39
  40        writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &ds->regs->wakeupenable);
  41}
  42
  43static void omap3_spi_write_chconf(struct omap3_spi_slave *ds, int val)
  44{
  45        writel(val, &ds->regs->channel[ds->slave.cs].chconf);
  46        /* Flash post writes to make immediate effect */
  47        readl(&ds->regs->channel[ds->slave.cs].chconf);
  48}
  49
  50static void omap3_spi_set_enable(struct omap3_spi_slave *ds, int enable)
  51{
  52        writel(enable, &ds->regs->channel[ds->slave.cs].chctrl);
  53        /* Flash post writes to make immediate effect */
  54        readl(&ds->regs->channel[ds->slave.cs].chctrl);
  55}
  56
  57void spi_init()
  58{
  59        /* do nothing */
  60}
  61
  62struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  63                                  unsigned int max_hz, unsigned int mode)
  64{
  65        struct omap3_spi_slave  *ds;
  66        struct mcspi *regs;
  67
  68        /*
  69         * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
  70         * with different number of chip selects (CS, channels):
  71         * McSPI1 has 4 CS (bus 0, cs 0 - 3)
  72         * McSPI2 has 2 CS (bus 1, cs 0 - 1)
  73         * McSPI3 has 2 CS (bus 2, cs 0 - 1)
  74         * McSPI4 has 1 CS (bus 3, cs 0)
  75         */
  76
  77        switch (bus) {
  78        case 0:
  79                regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
  80                break;
  81#ifdef OMAP3_MCSPI2_BASE
  82        case 1:
  83                regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
  84                break;
  85#endif
  86#ifdef OMAP3_MCSPI3_BASE
  87        case 2:
  88                regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
  89                break;
  90#endif
  91#ifdef OMAP3_MCSPI4_BASE
  92        case 3:
  93                regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
  94                break;
  95#endif
  96        default:
  97                printf("SPI error: unsupported bus %i. \
  98                        Supported busses 0 - 3\n", bus);
  99                return NULL;
 100        }
 101
 102        if (((bus == 0) && (cs > 3)) ||
 103                        ((bus == 1) && (cs > 1)) ||
 104                        ((bus == 2) && (cs > 1)) ||
 105                        ((bus == 3) && (cs > 0))) {
 106                printf("SPI error: unsupported chip select %i \
 107                        on bus %i\n", cs, bus);
 108                return NULL;
 109        }
 110
 111        if (max_hz > OMAP3_MCSPI_MAX_FREQ) {
 112                printf("SPI error: unsupported frequency %i Hz. \
 113                        Max frequency is 48 Mhz\n", max_hz);
 114                return NULL;
 115        }
 116
 117        if (mode > SPI_MODE_3) {
 118                printf("SPI error: unsupported SPI mode %i\n", mode);
 119                return NULL;
 120        }
 121
 122        ds = spi_alloc_slave(struct omap3_spi_slave, bus, cs);
 123        if (!ds) {
 124                printf("SPI error: malloc of SPI structure failed\n");
 125                return NULL;
 126        }
 127
 128        ds->regs = regs;
 129        ds->freq = max_hz;
 130        ds->mode = mode;
 131
 132        return &ds->slave;
 133}
 134
 135void spi_free_slave(struct spi_slave *slave)
 136{
 137        struct omap3_spi_slave *ds = to_omap3_spi(slave);
 138
 139        free(ds);
 140}
 141
 142int spi_claim_bus(struct spi_slave *slave)
 143{
 144        struct omap3_spi_slave *ds = to_omap3_spi(slave);
 145        unsigned int conf, div = 0;
 146
 147        /* McSPI global module configuration */
 148
 149        /*
 150         * setup when switching from (reset default) slave mode
 151         * to single-channel master mode
 152         */
 153        spi_reset(ds);
 154        conf = readl(&ds->regs->modulctrl);
 155        conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
 156        conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
 157        writel(conf, &ds->regs->modulctrl);
 158
 159        /* McSPI individual channel configuration */
 160
 161        /* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
 162        if (ds->freq) {
 163                while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
 164                                         > ds->freq)
 165                        div++;
 166        } else
 167                div = 0xC;
 168
 169        conf = readl(&ds->regs->channel[ds->slave.cs].chconf);
 170
 171        /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
 172         * REVISIT: this controller could support SPI_3WIRE mode.
 173         */
 174#ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
 175        /*
 176         * Some boards have D0 wired as MOSI / D1 as MISO instead of
 177         * The normal D0 as MISO / D1 as MOSI.
 178         */
 179        conf &= ~OMAP3_MCSPI_CHCONF_DPE0;
 180        conf |= OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1;
 181#else
 182        conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
 183        conf |= OMAP3_MCSPI_CHCONF_DPE0;
 184#endif
 185
 186        /* wordlength */
 187        conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
 188        conf |= (WORD_LEN - 1) << 7;
 189
 190        /* set chipselect polarity; manage with FORCE */
 191        if (!(ds->mode & SPI_CS_HIGH))
 192                conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
 193        else
 194                conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
 195
 196        /* set clock divisor */
 197        conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
 198        conf |= div << 2;
 199
 200        /* set SPI mode 0..3 */
 201        if (ds->mode & SPI_CPOL)
 202                conf |= OMAP3_MCSPI_CHCONF_POL;
 203        else
 204                conf &= ~OMAP3_MCSPI_CHCONF_POL;
 205        if (ds->mode & SPI_CPHA)
 206                conf |= OMAP3_MCSPI_CHCONF_PHA;
 207        else
 208                conf &= ~OMAP3_MCSPI_CHCONF_PHA;
 209
 210        /* Transmit & receive mode */
 211        conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
 212
 213        omap3_spi_write_chconf(ds,conf);
 214
 215        return 0;
 216}
 217
 218void spi_release_bus(struct spi_slave *slave)
 219{
 220        struct omap3_spi_slave *ds = to_omap3_spi(slave);
 221
 222        /* Reset the SPI hardware */
 223        spi_reset(ds);
 224}
 225
 226int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
 227                    unsigned long flags)
 228{
 229        struct omap3_spi_slave *ds = to_omap3_spi(slave);
 230        int i;
 231        int timeout = SPI_WAIT_TIMEOUT;
 232        int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
 233
 234        /* Enable the channel */
 235        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
 236
 237        chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
 238        chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
 239        chconf |= OMAP3_MCSPI_CHCONF_FORCE;
 240        omap3_spi_write_chconf(ds,chconf);
 241
 242        for (i = 0; i < len; i++) {
 243                /* wait till TX register is empty (TXS == 1) */
 244                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
 245                         OMAP3_MCSPI_CHSTAT_TXS)) {
 246                        if (--timeout <= 0) {
 247                                printf("SPI TXS timed out, status=0x%08x\n",
 248                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
 249                                return -1;
 250                        }
 251                }
 252                /* Write the data */
 253                writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
 254        }
 255
 256        /* wait to finish of transfer */
 257        while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
 258                         OMAP3_MCSPI_CHSTAT_EOT));
 259
 260        /* Disable the channel otherwise the next immediate RX will get affected */
 261        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
 262
 263        if (flags & SPI_XFER_END) {
 264
 265                chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
 266                omap3_spi_write_chconf(ds,chconf);
 267        }
 268        return 0;
 269}
 270
 271int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
 272                   unsigned long flags)
 273{
 274        struct omap3_spi_slave *ds = to_omap3_spi(slave);
 275        int i;
 276        int timeout = SPI_WAIT_TIMEOUT;
 277        int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
 278
 279        /* Enable the channel */
 280        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
 281
 282        chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
 283        chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
 284        chconf |= OMAP3_MCSPI_CHCONF_FORCE;
 285        omap3_spi_write_chconf(ds,chconf);
 286
 287        writel(0, &ds->regs->channel[ds->slave.cs].tx);
 288
 289        for (i = 0; i < len; i++) {
 290                /* Wait till RX register contains data (RXS == 1) */
 291                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
 292                         OMAP3_MCSPI_CHSTAT_RXS)) {
 293                        if (--timeout <= 0) {
 294                                printf("SPI RXS timed out, status=0x%08x\n",
 295                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
 296                                return -1;
 297                        }
 298                }
 299
 300                /* Disable the channel to prevent furher receiving */
 301                if(i == (len - 1))
 302                        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
 303
 304                /* Read the data */
 305                rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
 306        }
 307
 308        if (flags & SPI_XFER_END) {
 309                chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
 310                omap3_spi_write_chconf(ds,chconf);
 311        }
 312
 313        return 0;
 314}
 315
 316/*McSPI Transmit Receive Mode*/
 317int omap3_spi_txrx(struct spi_slave *slave,
 318                unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
 319{
 320        struct omap3_spi_slave *ds = to_omap3_spi(slave);
 321        int timeout = SPI_WAIT_TIMEOUT;
 322        int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
 323        int irqstatus = readl(&ds->regs->irqstatus);
 324        int i=0;
 325
 326        /*Enable SPI channel*/
 327        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
 328
 329        /*set TRANSMIT-RECEIVE Mode*/
 330        chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
 331        chconf |= OMAP3_MCSPI_CHCONF_FORCE;
 332        omap3_spi_write_chconf(ds,chconf);
 333
 334        /*Shift in and out 1 byte at time*/
 335        for (i=0; i < len; i++){
 336                /* Write: wait for TX empty (TXS == 1)*/
 337                irqstatus |= (1<< (4*(ds->slave.bus)));
 338                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
 339                         OMAP3_MCSPI_CHSTAT_TXS)) {
 340                        if (--timeout <= 0) {
 341                                printf("SPI TXS timed out, status=0x%08x\n",
 342                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
 343                                return -1;
 344                        }
 345                }
 346                /* Write the data */
 347                writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
 348
 349                /*Read: wait for RX containing data (RXS == 1)*/
 350                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
 351                         OMAP3_MCSPI_CHSTAT_RXS)) {
 352                        if (--timeout <= 0) {
 353                                printf("SPI RXS timed out, status=0x%08x\n",
 354                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
 355                                return -1;
 356                        }
 357                }
 358                /* Read the data */
 359                rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
 360        }
 361        /* Disable the channel */
 362        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
 363
 364        /*if transfer must be terminated disable the channel*/
 365        if (flags & SPI_XFER_END) {
 366                chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
 367                omap3_spi_write_chconf(ds,chconf);
 368        }
 369
 370        return 0;
 371}
 372
 373int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 374             const void *dout, void *din, unsigned long flags)
 375{
 376        struct omap3_spi_slave *ds = to_omap3_spi(slave);
 377        unsigned int    len;
 378        const u8        *txp = dout;
 379        u8              *rxp = din;
 380        int ret = -1;
 381
 382        if (bitlen % 8)
 383                return -1;
 384
 385        len = bitlen / 8;
 386
 387        if (bitlen == 0) {       /* only change CS */
 388                int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
 389
 390                if (flags & SPI_XFER_BEGIN) {
 391                        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN);
 392                        chconf |= OMAP3_MCSPI_CHCONF_FORCE;
 393                        omap3_spi_write_chconf(ds,chconf);
 394                }
 395                if (flags & SPI_XFER_END) {
 396                        chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
 397                        omap3_spi_write_chconf(ds,chconf);
 398                        omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
 399                }
 400                ret = 0;
 401        } else {
 402                if (dout != NULL && din != NULL)
 403                        ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
 404                else if (dout != NULL)
 405                        ret = omap3_spi_write(slave, len, txp, flags);
 406                else if (din != NULL)
 407                        ret = omap3_spi_read(slave, len, rxp, flags);
 408        }
 409        return ret;
 410}
 411
 412int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 413{
 414        return 1;
 415}
 416
 417void spi_cs_activate(struct spi_slave *slave)
 418{
 419}
 420
 421void spi_cs_deactivate(struct spi_slave *slave)
 422{
 423}
 424