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