Merge commit 'v2.6.39' into spi/next
authorGrant Likely <grant.likely@secretlab.ca>
Fri, 20 May 2011 06:43:00 +0000 (00:43 -0600)
committerGrant Likely <grant.likely@secretlab.ca>
Fri, 20 May 2011 06:43:00 +0000 (00:43 -0600)
drivers/spi/dw_spi.c
drivers/spi/dw_spi.h

index 871e337c917fe7313621e651be0da62891545b05..919fa9d9e16bab34fef8af03a5a6286ac9fad394 100644 (file)
@@ -58,8 +58,6 @@ struct chip_data {
        u8 bits_per_word;
        u16 clk_div;            /* baud rate divider */
        u32 speed_hz;           /* baud rate */
-       int (*write)(struct dw_spi *dws);
-       int (*read)(struct dw_spi *dws);
        void (*cs_control)(u32 command);
 };
 
@@ -162,107 +160,70 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static void wait_till_not_busy(struct dw_spi *dws)
+/* Return the max entries we can fill into tx fifo */
+static inline u32 tx_max(struct dw_spi *dws)
 {
-       unsigned long end = jiffies + 1 + usecs_to_jiffies(5000);
+       u32 tx_left, tx_room, rxtx_gap;
 
-       while (time_before(jiffies, end)) {
-               if (!(dw_readw(dws, sr) & SR_BUSY))
-                       return;
-               cpu_relax();
-       }
-       dev_err(&dws->master->dev,
-               "DW SPI: Status keeps busy for 5000us after a read/write!\n");
-}
-
-static void flush(struct dw_spi *dws)
-{
-       while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) {
-               dw_readw(dws, dr);
-               cpu_relax();
-       }
-
-       wait_till_not_busy(dws);
-}
-
-static int null_writer(struct dw_spi *dws)
-{
-       u8 n_bytes = dws->n_bytes;
+       tx_left = (dws->tx_end - dws->tx) / dws->n_bytes;
+       tx_room = dws->fifo_len - dw_readw(dws, txflr);
 
-       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
-               || (dws->tx == dws->tx_end))
-               return 0;
-       dw_writew(dws, dr, 0);
-       dws->tx += n_bytes;
+       /*
+        * Another concern is about the tx/rx mismatch, we
+        * though to use (dws->fifo_len - rxflr - txflr) as
+        * one maximum value for tx, but it doesn't cover the
+        * data which is out of tx/rx fifo and inside the
+        * shift registers. So a control from sw point of
+        * view is taken.
+        */
+       rxtx_gap =  ((dws->rx_end - dws->rx) - (dws->tx_end - dws->tx))
+                       / dws->n_bytes;
 
-       wait_till_not_busy(dws);
-       return 1;
+       return min3(tx_left, tx_room, (u32) (dws->fifo_len - rxtx_gap));
 }
 
-static int null_reader(struct dw_spi *dws)
+/* Return the max entries we should read out of rx fifo */
+static inline u32 rx_max(struct dw_spi *dws)
 {
-       u8 n_bytes = dws->n_bytes;
+       u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes;
 
-       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
-               && (dws->rx < dws->rx_end)) {
-               dw_readw(dws, dr);
-               dws->rx += n_bytes;
-       }
-       wait_till_not_busy(dws);
-       return dws->rx == dws->rx_end;
+       return min(rx_left, (u32)dw_readw(dws, rxflr));
 }
 
-static int u8_writer(struct dw_spi *dws)
+static void dw_writer(struct dw_spi *dws)
 {
-       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
-               || (dws->tx == dws->tx_end))
-               return 0;
+       u32 max = tx_max(dws);
+       u16 txw = 0;
 
-       dw_writew(dws, dr, *(u8 *)(dws->tx));
-       ++dws->tx;
-
-       wait_till_not_busy(dws);
-       return 1;
-}
-
-static int u8_reader(struct dw_spi *dws)
-{
-       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
-               && (dws->rx < dws->rx_end)) {
-               *(u8 *)(dws->rx) = dw_readw(dws, dr);
-               ++dws->rx;
+       while (max--) {
+               /* Set the tx word if the transfer's original "tx" is not null */
+               if (dws->tx_end - dws->len) {
+                       if (dws->n_bytes == 1)
+                               txw = *(u8 *)(dws->tx);
+                       else
+                               txw = *(u16 *)(dws->tx);
+               }
+               dw_writew(dws, dr, txw);
+               dws->tx += dws->n_bytes;
        }
-
-       wait_till_not_busy(dws);
-       return dws->rx == dws->rx_end;
 }
 
-static int u16_writer(struct dw_spi *dws)
+static void dw_reader(struct dw_spi *dws)
 {
-       if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
-               || (dws->tx == dws->tx_end))
-               return 0;
+       u32 max = rx_max(dws);
+       u16 rxw;
 
-       dw_writew(dws, dr, *(u16 *)(dws->tx));
-       dws->tx += 2;
-
-       wait_till_not_busy(dws);
-       return 1;
-}
-
-static int u16_reader(struct dw_spi *dws)
-{
-       u16 temp;
-
-       while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
-               && (dws->rx < dws->rx_end)) {
-               temp = dw_readw(dws, dr);
-               *(u16 *)(dws->rx) = temp;
-               dws->rx += 2;
+       while (max--) {
+               rxw = dw_readw(dws, dr);
+               /* Care rx only if the transfer's original "rx" is not null */
+               if (dws->rx_end - dws->len) {
+                       if (dws->n_bytes == 1)
+                               *(u8 *)(dws->rx) = rxw;
+                       else
+                               *(u16 *)(dws->rx) = rxw;
+               }
+               dws->rx += dws->n_bytes;
        }
-
-       wait_till_not_busy(dws);
-       return dws->rx == dws->rx_end;
 }
 
 static void *next_transfer(struct dw_spi *dws)
@@ -334,8 +295,7 @@ static void giveback(struct dw_spi *dws)
 
 static void int_error_stop(struct dw_spi *dws, const char *msg)
 {
-       /* Stop and reset hw */
-       flush(dws);
+       /* Stop the hw */
        spi_enable_chip(dws, 0);
 
        dev_err(&dws->master->dev, "%s\n", msg);
@@ -362,35 +322,28 @@ EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
 
 static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 {
-       u16 irq_status, irq_mask = 0x3f;
-       u32 int_level = dws->fifo_len / 2;
-       u32 left;
+       u16 irq_status = dw_readw(dws, isr);
 
-       irq_status = dw_readw(dws, isr) & irq_mask;
        /* Error handling */
        if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
                dw_readw(dws, txoicr);
                dw_readw(dws, rxoicr);
                dw_readw(dws, rxuicr);
-               int_error_stop(dws, "interrupt_transfer: fifo overrun");
+               int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");
                return IRQ_HANDLED;
        }
 
+       dw_reader(dws);
+       if (dws->rx_end == dws->rx) {
+               spi_mask_intr(dws, SPI_INT_TXEI);
+               dw_spi_xfer_done(dws);
+               return IRQ_HANDLED;
+       }
        if (irq_status & SPI_INT_TXEI) {
                spi_mask_intr(dws, SPI_INT_TXEI);
-
-               left = (dws->tx_end - dws->tx) / dws->n_bytes;
-               left = (left > int_level) ? int_level : left;
-
-               while (left--)
-                       dws->write(dws);
-               dws->read(dws);
-
-               /* Re-enable the IRQ if there is still data left to tx */
-               if (dws->tx_end > dws->tx)
-                       spi_umask_intr(dws, SPI_INT_TXEI);
-               else
-                       dw_spi_xfer_done(dws);
+               dw_writer(dws);
+               /* Enable TX irq always, it will be disabled when RX finished */
+               spi_umask_intr(dws, SPI_INT_TXEI);
        }
 
        return IRQ_HANDLED;
@@ -399,15 +352,13 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 {
        struct dw_spi *dws = dev_id;
-       u16 irq_status, irq_mask = 0x3f;
+       u16 irq_status = dw_readw(dws, isr) & 0x3f;
 
-       irq_status = dw_readw(dws, isr) & irq_mask;
        if (!irq_status)
                return IRQ_NONE;
 
        if (!dws->cur_msg) {
                spi_mask_intr(dws, SPI_INT_TXEI);
-               /* Never fail */
                return IRQ_HANDLED;
        }
 
@@ -417,13 +368,11 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 /* Must be called inside pump_transfers() */
 static void poll_transfer(struct dw_spi *dws)
 {
-       while (dws->write(dws))
-               dws->read(dws);
-       /*
-        * There is a possibility that the last word of a transaction
-        * will be lost if data is not ready. Re-read to solve this issue.
-        */
-       dws->read(dws);
+       do {
+               dw_writer(dws);
+               dw_reader(dws);
+               cpu_relax();
+       } while (dws->rx_end > dws->rx);
 
        dw_spi_xfer_done(dws);
 }
@@ -483,8 +432,6 @@ static void pump_transfers(unsigned long data)
        dws->tx_end = dws->tx + transfer->len;
        dws->rx = transfer->rx_buf;
        dws->rx_end = dws->rx + transfer->len;
-       dws->write = dws->tx ? chip->write : null_writer;
-       dws->read = dws->rx ? chip->read : null_reader;
        dws->cs_change = transfer->cs_change;
        dws->len = dws->cur_transfer->len;
        if (chip != dws->prev_chip)
@@ -518,20 +465,8 @@ static void pump_transfers(unsigned long data)
 
                switch (bits) {
                case 8:
-                       dws->n_bytes = 1;
-                       dws->dma_width = 1;
-                       dws->read = (dws->read != null_reader) ?
-                                       u8_reader : null_reader;
-                       dws->write = (dws->write != null_writer) ?
-                                       u8_writer : null_writer;
-                       break;
                case 16:
-                       dws->n_bytes = 2;
-                       dws->dma_width = 2;
-                       dws->read = (dws->read != null_reader) ?
-                                       u16_reader : null_reader;
-                       dws->write = (dws->write != null_writer) ?
-                                       u16_writer : null_writer;
+                       dws->n_bytes = dws->dma_width = bits >> 3;
                        break;
                default:
                        printk(KERN_ERR "MRST SPI0: unsupported bits:"
@@ -575,7 +510,7 @@ static void pump_transfers(unsigned long data)
                txint_level = dws->fifo_len / 2;
                txint_level = (templen > txint_level) ? txint_level : templen;
 
-               imask |= SPI_INT_TXEI;
+               imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI;
                dws->transfer_handler = interrupt_transfer;
        }
 
@@ -733,13 +668,9 @@ static int dw_spi_setup(struct spi_device *spi)
        if (spi->bits_per_word <= 8) {
                chip->n_bytes = 1;
                chip->dma_width = 1;
-               chip->read = u8_reader;
-               chip->write = u8_writer;
        } else if (spi->bits_per_word <= 16) {
                chip->n_bytes = 2;
                chip->dma_width = 2;
-               chip->read = u16_reader;
-               chip->write = u16_writer;
        } else {
                /* Never take >16b case for MRST SPIC */
                dev_err(&spi->dev, "invalid wordsize\n");
@@ -851,7 +782,6 @@ static void spi_hw_init(struct dw_spi *dws)
        spi_enable_chip(dws, 0);
        spi_mask_intr(dws, 0xff);
        spi_enable_chip(dws, 1);
-       flush(dws);
 
        /*
         * Try to detect the FIFO depth if not set by interface driver,
index b23e452adaf7d94cb09f255e5c745fdd0627500c..7a5e78d2a5cb98c1de9c04fbde849885e643dd4e 100644 (file)
@@ -137,8 +137,6 @@ struct dw_spi {
        u8                      max_bits_per_word;      /* maxim is 16b */
        u32                     dma_width;
        int                     cs_change;
-       int                     (*write)(struct dw_spi *dws);
-       int                     (*read)(struct dw_spi *dws);
        irqreturn_t             (*transfer_handler)(struct dw_spi *dws);
        void                    (*cs_control)(u32 command);