]> git.sur5r.net Git - u-boot/blobdiff - drivers/spi/omap3_spi.c
mmc: sdhci: add the DMA select for SDMA
[u-boot] / drivers / spi / omap3_spi.c
index af12c0e590b954830fa91cd41c51a01e5e39e110..e40a632caa040eba54ee0f2f6549c1da537152af 100644 (file)
@@ -86,15 +86,21 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
        case 0:
                ds->regs = (struct mcspi *)OMAP3_MCSPI1_BASE;
                break;
+#ifdef OMAP3_MCSPI2_BASE
        case 1:
                ds->regs = (struct mcspi *)OMAP3_MCSPI2_BASE;
                break;
+#endif
+#ifdef OMAP3_MCSPI3_BASE 
        case 2:
                ds->regs = (struct mcspi *)OMAP3_MCSPI3_BASE;
                break;
+#endif
+#ifdef OMAP3_MCSPI4_BASE
        case 3:
                ds->regs = (struct mcspi *)OMAP3_MCSPI4_BASE;
                break;
+#endif
        default:
                printf("SPI error: unsupported bus %i. \
                        Supported busses 0 - 3\n", bus);
@@ -167,8 +173,18 @@ int spi_claim_bus(struct spi_slave *slave)
        /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
         * REVISIT: this controller could support SPI_3WIRE mode.
         */
+#ifdef CONFIG_AM33XX
+       /*
+        * The reference design on AM33xx has D0 and D1 wired up opposite
+        * of how it has been done on previous platforms.  We assume that
+        * custom hardware will also follow this convention.
+        */
+       conf &= OMAP3_MCSPI_CHCONF_DPE0;
+       conf |= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
+#else
        conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
        conf |= OMAP3_MCSPI_CHCONF_DPE0;
+#endif
 
        /* wordlength */
        conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
@@ -297,6 +313,65 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
        return 0;
 }
 
+/*McSPI Transmit Receive Mode*/
+int omap3_spi_txrx(struct spi_slave *slave,
+               unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
+{
+       struct omap3_spi_slave *ds = to_omap3_spi(slave);
+       int timeout = SPI_WAIT_TIMEOUT;
+       int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
+       int irqstatus = readl(&ds->regs->irqstatus);
+       int i=0;
+
+       /*Enable SPI channel*/
+       if (flags & SPI_XFER_BEGIN)
+               writel(OMAP3_MCSPI_CHCTRL_EN,
+                      &ds->regs->channel[ds->slave.cs].chctrl);
+
+       /*set TRANSMIT-RECEIVE Mode*/
+       chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
+       chconf |= OMAP3_MCSPI_CHCONF_FORCE;
+       writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
+
+       /*Shift in and out 1 byte at time*/
+       for (i=0; i < len; i++){
+               /* Write: wait for TX empty (TXS == 1)*/
+               irqstatus |= (1<< (4*(ds->slave.bus)));
+               while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
+                        OMAP3_MCSPI_CHSTAT_TXS)) {
+                       if (--timeout <= 0) {
+                               printf("SPI TXS timed out, status=0x%08x\n",
+                                      readl(&ds->regs->channel[ds->slave.cs].chstat));
+                               return -1;
+                       }
+               }
+               /* Write the data */
+               writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
+
+               /*Read: wait for RX containing data (RXS == 1)*/
+               while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
+                        OMAP3_MCSPI_CHSTAT_RXS)) {
+                       if (--timeout <= 0) {
+                               printf("SPI RXS timed out, status=0x%08x\n",
+                                      readl(&ds->regs->channel[ds->slave.cs].chstat));
+                               return -1;
+                       }
+               }
+               /* Read the data */
+               rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
+       }
+
+       /*if transfer must be terminated disable the channel*/
+       if (flags & SPI_XFER_END) {
+               chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
+               writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
+
+               writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
+       }
+
+       return 0;
+}
+
 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
             const void *dout, void *din, unsigned long flags)
 {
@@ -329,10 +404,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
                }
                ret = 0;
        } else {
-               if (dout != NULL)
+               if (dout != NULL && din != NULL)
+                       ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
+               else if (dout != NULL)
                        ret = omap3_spi_write(slave, len, txp, flags);
-
-               if (din != NULL)
+               else if (din != NULL)
                        ret = omap3_spi_read(slave, len, rxp, flags);
        }
        return ret;