netns xfrm: fix "ip xfrm state|policy count" misreport
[safe/jmp/linux-2.6] / drivers / spi / spi_bfin5xx.c
index 1222925..1d41058 100644 (file)
 
 #define DRV_NAME       "bfin-spi"
 #define DRV_AUTHOR     "Bryan Wu, Luke Yang"
-#define DRV_DESC       "Blackfin BF5xx on-chip SPI Controller Driver"
+#define DRV_DESC       "Blackfin on-chip SPI Controller Driver"
 #define DRV_VERSION    "1.0"
 
 MODULE_AUTHOR(DRV_AUTHOR);
 MODULE_DESCRIPTION(DRV_DESC);
 MODULE_LICENSE("GPL");
 
-#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07) == 0)
-
 #define START_STATE    ((void *)0)
 #define RUNNING_STATE  ((void *)1)
 #define DONE_STATE     ((void *)2)
@@ -45,6 +43,9 @@ MODULE_LICENSE("GPL");
 #define QUEUE_RUNNING  0
 #define QUEUE_STOPPED  1
 
+/* Value to send if no TX value is supplied */
+#define SPI_IDLE_TXVAL 0x0000
+
 struct driver_data {
        /* Driver model hookup */
        struct platform_device *pdev;
@@ -111,6 +112,8 @@ struct chip_data {
        u8 bits_per_word;       /* 8 or 16 */
        u8 cs_change_per_word;
        u16 cs_chg_udelay;      /* Some devices require > 255usec delay */
+       u32 cs_gpio;
+       u16 idle_tx_val;
        void (*write) (struct driver_data *);
        void (*read) (struct driver_data *);
        void (*duplex) (struct driver_data *);
@@ -161,12 +164,12 @@ static u16 hz_to_spi_baud(u32 speed_hz)
        return spi_baud;
 }
 
-static int flush(struct driver_data *drv_data)
+static int bfin_spi_flush(struct driver_data *drv_data)
 {
        unsigned long limit = loops_per_jiffy << 1;
 
        /* wait for stop and clear stat */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && limit--)
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && --limit)
                cpu_relax();
 
        write_STAT(drv_data, BIT_STAT_CLR);
@@ -175,24 +178,32 @@ static int flush(struct driver_data *drv_data)
 }
 
 /* Chip select operation functions for cs_change flag */
-static void cs_active(struct driver_data *drv_data, struct chip_data *chip)
+static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *chip)
 {
-       u16 flag = read_FLAG(drv_data);
+       if (likely(chip->chip_select_num)) {
+               u16 flag = read_FLAG(drv_data);
 
-       flag |= chip->flag;
-       flag &= ~(chip->flag << 8);
+               flag |= chip->flag;
+               flag &= ~(chip->flag << 8);
 
-       write_FLAG(drv_data, flag);
+               write_FLAG(drv_data, flag);
+       } else {
+               gpio_set_value(chip->cs_gpio, 0);
+       }
 }
 
-static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
+static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
 {
-       u16 flag = read_FLAG(drv_data);
+       if (likely(chip->chip_select_num)) {
+               u16 flag = read_FLAG(drv_data);
 
-       flag &= ~chip->flag;
-       flag |= (chip->flag << 8);
+               flag &= ~chip->flag;
+               flag |= (chip->flag << 8);
 
-       write_FLAG(drv_data, flag);
+               write_FLAG(drv_data, flag);
+       } else {
+               gpio_set_value(chip->cs_gpio, 1);
+       }
 
        /* Move delay here for consistency */
        if (chip->cs_chg_udelay)
@@ -200,7 +211,7 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
 }
 
 /* stop controller and re-config current chip*/
-static void restore_state(struct driver_data *drv_data)
+static void bfin_spi_restore_state(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
@@ -214,294 +225,256 @@ static void restore_state(struct driver_data *drv_data)
        write_BAUD(drv_data, chip->baud);
 
        bfin_spi_enable(drv_data);
-       cs_active(drv_data, chip);
+       bfin_spi_cs_active(drv_data, chip);
 }
 
-/* used to kick off transfer in rx mode */
-static unsigned short dummy_read(struct driver_data *drv_data)
+/* used to kick off transfer in rx mode and read unwanted RX data */
+static inline void bfin_spi_dummy_read(struct driver_data *drv_data)
 {
-       unsigned short tmp;
-       tmp = read_RDBR(drv_data);
-       return tmp;
+       (void) read_RDBR(drv_data);
 }
 
-static void null_writer(struct driver_data *drv_data)
+static void bfin_spi_null_writer(struct driver_data *drv_data)
 {
        u8 n_bytes = drv_data->n_bytes;
+       u16 tx_val = drv_data->cur_chip->idle_tx_val;
+
+       /* clear RXS (we check for RXS inside the loop) */
+       bfin_spi_dummy_read(drv_data);
 
        while (drv_data->tx < drv_data->tx_end) {
-               write_TDBR(drv_data, 0);
-               while ((read_STAT(drv_data) & BIT_STAT_TXS))
-                       cpu_relax();
+               write_TDBR(drv_data, tx_val);
                drv_data->tx += n_bytes;
+               /* wait until transfer finished.
+                  checking SPIF or TXS may not guarantee transfer completion */
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+                       cpu_relax();
+               /* discard RX data and clear RXS */
+               bfin_spi_dummy_read(drv_data);
        }
 }
 
-static void null_reader(struct driver_data *drv_data)
+static void bfin_spi_null_reader(struct driver_data *drv_data)
 {
        u8 n_bytes = drv_data->n_bytes;
-       dummy_read(drv_data);
+       u16 tx_val = drv_data->cur_chip->idle_tx_val;
+
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
 
        while (drv_data->rx < drv_data->rx_end) {
+               write_TDBR(drv_data, tx_val);
+               drv_data->rx += n_bytes;
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-               dummy_read(drv_data);
-               drv_data->rx += n_bytes;
+               bfin_spi_dummy_read(drv_data);
        }
 }
 
-static void u8_writer(struct driver_data *drv_data)
+static void bfin_spi_u8_writer(struct driver_data *drv_data)
 {
-       dev_dbg(&drv_data->pdev->dev,
-               "cr8-s is 0x%x\n", read_STAT(drv_data));
+       /* clear RXS (we check for RXS inside the loop) */
+       bfin_spi_dummy_read(drv_data);
 
        while (drv_data->tx < drv_data->tx_end) {
-               write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
+               write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
+               /* wait until transfer finished.
+                  checking SPIF or TXS may not guarantee transfer completion */
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-               ++drv_data->tx;
+               /* discard RX data and clear RXS */
+               bfin_spi_dummy_read(drv_data);
        }
-
-       /* poll for SPI completion before return */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
 }
 
-static void u8_cs_chg_writer(struct driver_data *drv_data)
+static void bfin_spi_u8_cs_chg_writer(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       while (drv_data->tx < drv_data->tx_end) {
-               cs_active(drv_data, chip);
+       /* clear RXS (we check for RXS inside the loop) */
+       bfin_spi_dummy_read(drv_data);
 
-               write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (read_STAT(drv_data) & BIT_STAT_TXS)
-                       cpu_relax();
-               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
+       while (drv_data->tx < drv_data->tx_end) {
+               bfin_spi_cs_active(drv_data, chip);
+               write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
+               /* make sure transfer finished before deactiving CS */
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-
-               cs_deactive(drv_data, chip);
-
-               ++drv_data->tx;
+               bfin_spi_dummy_read(drv_data);
+               bfin_spi_cs_deactive(drv_data, chip);
        }
 }
 
-static void u8_reader(struct driver_data *drv_data)
+static void bfin_spi_u8_reader(struct driver_data *drv_data)
 {
-       dev_dbg(&drv_data->pdev->dev,
-               "cr-8 is 0x%x\n", read_STAT(drv_data));
-
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
+       u16 tx_val = drv_data->cur_chip->idle_tx_val;
 
-       /* clear TDBR buffer before read(else it will be shifted out) */
-       write_TDBR(drv_data, 0xFFFF);
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
 
-       dummy_read(drv_data);
-
-       while (drv_data->rx < drv_data->rx_end - 1) {
+       while (drv_data->rx < drv_data->rx_end) {
+               write_TDBR(drv_data, tx_val);
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-               *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
-               ++drv_data->rx;
+               *(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
        }
-
-       while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-               cpu_relax();
-       *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
-       ++drv_data->rx;
 }
 
-static void u8_cs_chg_reader(struct driver_data *drv_data)
+static void bfin_spi_u8_cs_chg_reader(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
+       u16 tx_val = chip->idle_tx_val;
 
-       while (drv_data->rx < drv_data->rx_end) {
-               cs_active(drv_data, chip);
-               read_RDBR(drv_data);    /* kick off */
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
 
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_spi_cs_active(drv_data, chip);
+               write_TDBR(drv_data, tx_val);
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-                       cpu_relax();
-
-               *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
-               cs_deactive(drv_data, chip);
-
-               ++drv_data->rx;
+               *(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
+               bfin_spi_cs_deactive(drv_data, chip);
        }
 }
 
-static void u8_duplex(struct driver_data *drv_data)
+static void bfin_spi_u8_duplex(struct driver_data *drv_data)
 {
-       /* in duplex mode, clk is triggered by writing of TDBR */
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
+
        while (drv_data->rx < drv_data->rx_end) {
-               write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
-               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-                       cpu_relax();
+               write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-               *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
-               ++drv_data->rx;
-               ++drv_data->tx;
+               *(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
        }
 }
 
-static void u8_cs_chg_duplex(struct driver_data *drv_data)
+static void bfin_spi_u8_cs_chg_duplex(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       while (drv_data->rx < drv_data->rx_end) {
-               cs_active(drv_data, chip);
-
-               write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
 
-               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-                       cpu_relax();
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_spi_cs_active(drv_data, chip);
+               write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-               *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
-
-               cs_deactive(drv_data, chip);
-
-               ++drv_data->rx;
-               ++drv_data->tx;
+               *(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
+               bfin_spi_cs_deactive(drv_data, chip);
        }
 }
 
-static void u16_writer(struct driver_data *drv_data)
+static void bfin_spi_u16_writer(struct driver_data *drv_data)
 {
-       dev_dbg(&drv_data->pdev->dev,
-               "cr16 is 0x%x\n", read_STAT(drv_data));
+       /* clear RXS (we check for RXS inside the loop) */
+       bfin_spi_dummy_read(drv_data);
 
        while (drv_data->tx < drv_data->tx_end) {
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while ((read_STAT(drv_data) & BIT_STAT_TXS))
-                       cpu_relax();
                drv_data->tx += 2;
+               /* wait until transfer finished.
+                  checking SPIF or TXS may not guarantee transfer completion */
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+                       cpu_relax();
+               /* discard RX data and clear RXS */
+               bfin_spi_dummy_read(drv_data);
        }
-
-       /* poll for SPI completion before return */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
 }
 
-static void u16_cs_chg_writer(struct driver_data *drv_data)
+static void bfin_spi_u16_cs_chg_writer(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       while (drv_data->tx < drv_data->tx_end) {
-               cs_active(drv_data, chip);
+       /* clear RXS (we check for RXS inside the loop) */
+       bfin_spi_dummy_read(drv_data);
 
+       while (drv_data->tx < drv_data->tx_end) {
+               bfin_spi_cs_active(drv_data, chip);
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while ((read_STAT(drv_data) & BIT_STAT_TXS))
-                       cpu_relax();
-               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-                       cpu_relax();
-
-               cs_deactive(drv_data, chip);
-
                drv_data->tx += 2;
+               /* make sure transfer finished before deactiving CS */
+               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+                       cpu_relax();
+               bfin_spi_dummy_read(drv_data);
+               bfin_spi_cs_deactive(drv_data, chip);
        }
 }
 
-static void u16_reader(struct driver_data *drv_data)
+static void bfin_spi_u16_reader(struct driver_data *drv_data)
 {
-       dev_dbg(&drv_data->pdev->dev,
-               "cr-16 is 0x%x\n", read_STAT(drv_data));
-
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
-       /* clear TDBR buffer before read(else it will be shifted out) */
-       write_TDBR(drv_data, 0xFFFF);
+       u16 tx_val = drv_data->cur_chip->idle_tx_val;
 
-       dummy_read(drv_data);
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
 
-       while (drv_data->rx < (drv_data->rx_end - 2)) {
+       while (drv_data->rx < drv_data->rx_end) {
+               write_TDBR(drv_data, tx_val);
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
                *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
                drv_data->rx += 2;
        }
-
-       while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-               cpu_relax();
-       *(u16 *) (drv_data->rx) = read_SHAW(drv_data);
-       drv_data->rx += 2;
 }
 
-static void u16_cs_chg_reader(struct driver_data *drv_data)
+static void bfin_spi_u16_cs_chg_reader(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
+       u16 tx_val = chip->idle_tx_val;
 
-       /* poll for SPI completion before start */
-       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-               cpu_relax();
-
-       /* clear TDBR buffer before read(else it will be shifted out) */
-       write_TDBR(drv_data, 0xFFFF);
-
-       cs_active(drv_data, chip);
-       dummy_read(drv_data);
-
-       while (drv_data->rx < drv_data->rx_end - 2) {
-               cs_deactive(drv_data, chip);
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
 
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_spi_cs_active(drv_data, chip);
+               write_TDBR(drv_data, tx_val);
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
-               cs_active(drv_data, chip);
                *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
                drv_data->rx += 2;
+               bfin_spi_cs_deactive(drv_data, chip);
        }
-       cs_deactive(drv_data, chip);
-
-       while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-               cpu_relax();
-       *(u16 *) (drv_data->rx) = read_SHAW(drv_data);
-       drv_data->rx += 2;
 }
 
-static void u16_duplex(struct driver_data *drv_data)
+static void bfin_spi_u16_duplex(struct driver_data *drv_data)
 {
-       /* in duplex mode, clk is triggered by writing of TDBR */
-       while (drv_data->tx < drv_data->tx_end) {
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
+
+       while (drv_data->rx < drv_data->rx_end) {
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-                       cpu_relax();
+               drv_data->tx += 2;
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
                *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
                drv_data->rx += 2;
-               drv_data->tx += 2;
        }
 }
 
-static void u16_cs_chg_duplex(struct driver_data *drv_data)
+static void bfin_spi_u16_cs_chg_duplex(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
 
-       while (drv_data->tx < drv_data->tx_end) {
-               cs_active(drv_data, chip);
+       /* discard old RX data and clear RXS */
+       bfin_spi_dummy_read(drv_data);
 
+       while (drv_data->rx < drv_data->rx_end) {
+               bfin_spi_cs_active(drv_data, chip);
                write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
-                       cpu_relax();
+               drv_data->tx += 2;
                while (!(read_STAT(drv_data) & BIT_STAT_RXS))
                        cpu_relax();
                *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
-
-               cs_deactive(drv_data, chip);
-
                drv_data->rx += 2;
-               drv_data->tx += 2;
+               bfin_spi_cs_deactive(drv_data, chip);
        }
 }
 
 /* test if ther is more transfer to be done */
-static void *next_transfer(struct driver_data *drv_data)
+static void *bfin_spi_next_transfer(struct driver_data *drv_data)
 {
        struct spi_message *msg = drv_data->cur_msg;
        struct spi_transfer *trans = drv_data->cur_transfer;
@@ -520,7 +493,7 @@ static void *next_transfer(struct driver_data *drv_data)
  * caller already set message->status;
  * dma and pio irqs are blocked give finished message back
  */
-static void giveback(struct driver_data *drv_data)
+static void bfin_spi_giveback(struct driver_data *drv_data)
 {
        struct chip_data *chip = drv_data->cur_chip;
        struct spi_transfer *last_transfer;
@@ -540,20 +513,18 @@ static void giveback(struct driver_data *drv_data)
 
        msg->state = NULL;
 
-       /* disable chip select signal. And not stop spi in autobuffer mode */
-       if (drv_data->tx_dma != 0xFFFF) {
-               cs_deactive(drv_data, chip);
-               bfin_spi_disable(drv_data);
-       }
-
        if (!drv_data->cs_change)
-               cs_deactive(drv_data, chip);
+               bfin_spi_cs_deactive(drv_data, chip);
+
+       /* Not stop spi in autobuffer mode */
+       if (drv_data->tx_dma != 0xFFFF)
+               bfin_spi_disable(drv_data);
 
        if (msg->complete)
                msg->complete(msg->context);
 }
 
-static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
 {
        struct driver_data *drv_data = dev_id;
        struct chip_data *chip = drv_data->cur_chip;
@@ -603,10 +574,10 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
                msg->actual_length += drv_data->len_in_bytes;
 
                if (drv_data->cs_change)
-                       cs_deactive(drv_data, chip);
+                       bfin_spi_cs_deactive(drv_data, chip);
 
                /* Move to next transfer */
-               msg->state = next_transfer(drv_data);
+               msg->state = bfin_spi_next_transfer(drv_data);
        }
 
        /* Schedule transfer tasklet */
@@ -621,7 +592,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void pump_transfers(unsigned long data)
+static void bfin_spi_pump_transfers(unsigned long data)
 {
        struct driver_data *drv_data = (struct driver_data *)data;
        struct spi_message *message = NULL;
@@ -646,7 +617,7 @@ static void pump_transfers(unsigned long data)
        if (message->state == ERROR_STATE) {
                dev_dbg(&drv_data->pdev->dev, "transfer: we've hit an error\n");
                message->status = -EIO;
-               giveback(drv_data);
+               bfin_spi_giveback(drv_data);
                return;
        }
 
@@ -654,7 +625,7 @@ static void pump_transfers(unsigned long data)
        if (message->state == DONE_STATE) {
                dev_dbg(&drv_data->pdev->dev, "transfer: all done!\n");
                message->status = 0;
-               giveback(drv_data);
+               bfin_spi_giveback(drv_data);
                return;
        }
 
@@ -668,13 +639,20 @@ static void pump_transfers(unsigned long data)
        }
 
        /* Setup the transfer state based on the type of transfer */
-       if (flush(drv_data) == 0) {
+       if (bfin_spi_flush(drv_data) == 0) {
                dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
                message->status = -EIO;
-               giveback(drv_data);
+               bfin_spi_giveback(drv_data);
                return;
        }
 
+       if (transfer->len == 0) {
+               /* Move to next transfer of this msg */
+               message->state = bfin_spi_next_transfer(drv_data);
+               /* Schedule next transfer tasklet */
+               tasklet_schedule(&drv_data->pump_transfers);
+       }
+
        if (transfer->tx_buf != NULL) {
                drv_data->tx = (void *)transfer->tx_buf;
                drv_data->tx_end = drv_data->tx + transfer->len;
@@ -705,31 +683,31 @@ static void pump_transfers(unsigned long data)
                drv_data->n_bytes = 1;
                width = CFG_SPI_WORDSIZE8;
                drv_data->read = chip->cs_change_per_word ?
-                       u8_cs_chg_reader : u8_reader;
+                       bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader;
                drv_data->write = chip->cs_change_per_word ?
-                       u8_cs_chg_writer : u8_writer;
+                       bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer;
                drv_data->duplex = chip->cs_change_per_word ?
-                       u8_cs_chg_duplex : u8_duplex;
+                       bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex;
                break;
 
        case 16:
                drv_data->n_bytes = 2;
                width = CFG_SPI_WORDSIZE16;
                drv_data->read = chip->cs_change_per_word ?
-                       u16_cs_chg_reader : u16_reader;
+                       bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader;
                drv_data->write = chip->cs_change_per_word ?
-                       u16_cs_chg_writer : u16_writer;
+                       bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer;
                drv_data->duplex = chip->cs_change_per_word ?
-                       u16_cs_chg_duplex : u16_duplex;
+                       bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex;
                break;
 
        default:
                /* No change, the same as default setting */
                drv_data->n_bytes = chip->n_bytes;
                width = chip->width;
-               drv_data->write = drv_data->tx ? chip->write : null_writer;
-               drv_data->read = drv_data->rx ? chip->read : null_reader;
-               drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
+               drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer;
+               drv_data->read = drv_data->rx ? chip->read : bfin_spi_null_reader;
+               drv_data->duplex = chip->duplex ? chip->duplex : bfin_spi_null_writer;
                break;
        }
        cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
@@ -743,7 +721,7 @@ static void pump_transfers(unsigned long data)
        }
        dev_dbg(&drv_data->pdev->dev,
                "transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
-               drv_data->write, chip->write, null_writer);
+               drv_data->write, chip->write, bfin_spi_null_writer);
 
        /* speed and width has been set on per message */
        message->state = RUNNING_STATE;
@@ -757,7 +735,8 @@ static void pump_transfers(unsigned long data)
 
        write_STAT(drv_data, BIT_STAT_CLR);
        cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
-       cs_active(drv_data, chip);
+       if (drv_data->cs_change)
+               bfin_spi_cs_active(drv_data, chip);
 
        dev_dbg(&drv_data->pdev->dev,
                "now pumping a transfer: width is %d, len is %d\n",
@@ -812,7 +791,7 @@ static void pump_transfers(unsigned long data)
                         * in this mode
                         */
                        message->status = 0;
-                       giveback(drv_data);
+                       bfin_spi_giveback(drv_data);
                        return;
                }
 
@@ -824,14 +803,11 @@ static void pump_transfers(unsigned long data)
                                drv_data->rx, drv_data->len_in_bytes);
 
                        /* invalidate caches, if needed */
-                       if (bfin_addr_dcachable((unsigned long) drv_data->rx))
+                       if (bfin_addr_dcacheable((unsigned long) drv_data->rx))
                                invalidate_dcache_range((unsigned long) drv_data->rx,
                                                        (unsigned long) (drv_data->rx +
                                                        drv_data->len_in_bytes));
 
-                       /* clear tx reg soformer data is not shifted out */
-                       write_TDBR(drv_data, 0xFFFF);
-
                        dma_config |= WNR;
                        dma_start_addr = (unsigned long)drv_data->rx;
                        cr |= BIT_CTL_TIMOD_DMA_RX | BIT_CTL_SENDOPT;
@@ -840,7 +816,7 @@ static void pump_transfers(unsigned long data)
                        dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
 
                        /* flush caches, if needed */
-                       if (bfin_addr_dcachable((unsigned long) drv_data->tx))
+                       if (bfin_addr_dcacheable((unsigned long) drv_data->tx))
                                flush_dcache_range((unsigned long) drv_data->tx,
                                                (unsigned long) (drv_data->tx +
                                                drv_data->len_in_bytes));
@@ -873,6 +849,11 @@ static void pump_transfers(unsigned long data)
                /* IO mode write then read */
                dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
 
+               /* we always use SPI_WRITE mode. SPI_READ mode
+                  seems to have problems with setting up the
+                  output value in TDBR prior to the transfer. */
+               write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
+
                if (full_duplex) {
                        /* full duplex mode */
                        BUG_ON((drv_data->tx_end - drv_data->tx) !=
@@ -880,9 +861,6 @@ static void pump_transfers(unsigned long data)
                        dev_dbg(&drv_data->pdev->dev,
                                "IO duplex: cr is 0x%x\n", cr);
 
-                       /* set SPI transfer mode */
-                       write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
-
                        drv_data->duplex(drv_data);
 
                        if (drv_data->tx != drv_data->tx_end)
@@ -892,9 +870,6 @@ static void pump_transfers(unsigned long data)
                        dev_dbg(&drv_data->pdev->dev,
                                "IO write: cr is 0x%x\n", cr);
 
-                       /* set SPI transfer mode */
-                       write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
-
                        drv_data->write(drv_data);
 
                        if (drv_data->tx != drv_data->tx_end)
@@ -904,9 +879,6 @@ static void pump_transfers(unsigned long data)
                        dev_dbg(&drv_data->pdev->dev,
                                "IO read: cr is 0x%x\n", cr);
 
-                       /* set SPI transfer mode */
-                       write_CTRL(drv_data, (cr | CFG_SPI_READ));
-
                        drv_data->read(drv_data);
                        if (drv_data->rx != drv_data->rx_end)
                                tranf_success = 0;
@@ -919,19 +891,18 @@ static void pump_transfers(unsigned long data)
                } else {
                        /* Update total byte transfered */
                        message->actual_length += drv_data->len_in_bytes;
-
                        /* Move to next transfer of this msg */
-                       message->state = next_transfer(drv_data);
+                       message->state = bfin_spi_next_transfer(drv_data);
+                       if (drv_data->cs_change)
+                               bfin_spi_cs_deactive(drv_data, chip);
                }
-
                /* Schedule next transfer tasklet */
                tasklet_schedule(&drv_data->pump_transfers);
-
        }
 }
 
 /* pop a msg from queue and kick off real transfer */
-static void pump_messages(struct work_struct *work)
+static void bfin_spi_pump_messages(struct work_struct *work)
 {
        struct driver_data *drv_data;
        unsigned long flags;
@@ -959,7 +930,7 @@ static void pump_messages(struct work_struct *work)
 
        /* Setup the SSP using the per chip configuration */
        drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
-       restore_state(drv_data);
+       bfin_spi_restore_state(drv_data);
 
        list_del_init(&drv_data->cur_msg->queue);
 
@@ -988,7 +959,7 @@ static void pump_messages(struct work_struct *work)
  * got a msg to transfer, queue it in drv_data->queue.
  * And kick off message pumper
  */
-static int transfer(struct spi_device *spi, struct spi_message *msg)
+static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 {
        struct driver_data *drv_data = spi_master_get_devdata(spi->master);
        unsigned long flags;
@@ -1032,21 +1003,12 @@ static u16 ssel[][MAX_SPI_SSEL] = {
 };
 
 /* first setup for new devices */
-static int setup(struct spi_device *spi)
+static int bfin_spi_setup(struct spi_device *spi)
 {
        struct bfin5xx_spi_chip *chip_info = NULL;
        struct chip_data *chip;
        struct driver_data *drv_data = spi_master_get_devdata(spi->master);
-
-       /* Abort device setup if requested features are not supported */
-       if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
-               dev_err(&spi->dev, "requested mode not fully supported\n");
-               return -EINVAL;
-       }
-
-       /* Zero (the default) here means 8 bits */
-       if (!spi->bits_per_word)
-               spi->bits_per_word = 8;
+       int ret;
 
        if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
                return -EINVAL;
@@ -1082,6 +1044,8 @@ static int setup(struct spi_device *spi)
                chip->bits_per_word = chip_info->bits_per_word;
                chip->cs_change_per_word = chip_info->cs_change_per_word;
                chip->cs_chg_udelay = chip_info->cs_chg_udelay;
+               chip->cs_gpio = chip_info->cs_gpio;
+               chip->idle_tx_val = chip_info->idle_tx_val;
        }
 
        /* translate common spi framework into our register */
@@ -1106,7 +1070,7 @@ static int setup(struct spi_device *spi)
                        return -ENODEV;
                }
                if (set_dma_callback(drv_data->dma_channel,
-                   dma_irq_handler, drv_data) < 0) {
+                   bfin_spi_dma_irq_handler, drv_data) < 0) {
                        dev_dbg(&spi->dev, "Unable to set dma callback\n");
                        return -EPERM;
                }
@@ -1122,33 +1086,44 @@ static int setup(struct spi_device *spi)
        chip->flag = 1 << (spi->chip_select);
        chip->chip_select_num = spi->chip_select;
 
+       if (chip->chip_select_num == 0) {
+               ret = gpio_request(chip->cs_gpio, spi->modalias);
+               if (ret) {
+                       if (drv_data->dma_requested)
+                               free_dma(drv_data->dma_channel);
+                       return ret;
+               }
+               gpio_direction_output(chip->cs_gpio, 1);
+       }
+
        switch (chip->bits_per_word) {
        case 8:
                chip->n_bytes = 1;
                chip->width = CFG_SPI_WORDSIZE8;
                chip->read = chip->cs_change_per_word ?
-                       u8_cs_chg_reader : u8_reader;
+                       bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader;
                chip->write = chip->cs_change_per_word ?
-                       u8_cs_chg_writer : u8_writer;
+                       bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer;
                chip->duplex = chip->cs_change_per_word ?
-                       u8_cs_chg_duplex : u8_duplex;
+                       bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex;
                break;
 
        case 16:
                chip->n_bytes = 2;
                chip->width = CFG_SPI_WORDSIZE16;
                chip->read = chip->cs_change_per_word ?
-                       u16_cs_chg_reader : u16_reader;
+                       bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader;
                chip->write = chip->cs_change_per_word ?
-                       u16_cs_chg_writer : u16_writer;
+                       bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer;
                chip->duplex = chip->cs_change_per_word ?
-                       u16_cs_chg_duplex : u16_duplex;
+                       bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex;
                break;
 
        default:
                dev_err(&spi->dev, "%d bits_per_word is not supported\n",
                                chip->bits_per_word);
-               kfree(chip);
+               if (chip_info)
+                       kfree(chip);
                return -ENODEV;
        }
 
@@ -1165,7 +1140,7 @@ static int setup(struct spi_device *spi)
                peripheral_request(ssel[spi->master->bus_num]
                        [chip->chip_select_num-1], spi->modalias);
 
-       cs_deactive(drv_data, chip);
+       bfin_spi_cs_deactive(drv_data, chip);
 
        return 0;
 }
@@ -1174,19 +1149,25 @@ static int setup(struct spi_device *spi)
  * callback for spi framework.
  * clean driver specific data
  */
-static void cleanup(struct spi_device *spi)
+static void bfin_spi_cleanup(struct spi_device *spi)
 {
        struct chip_data *chip = spi_get_ctldata(spi);
 
+       if (!chip)
+               return;
+
        if ((chip->chip_select_num > 0)
                && (chip->chip_select_num <= spi->master->num_chipselect))
                peripheral_free(ssel[spi->master->bus_num]
                                        [chip->chip_select_num-1]);
 
+       if (chip->chip_select_num == 0)
+               gpio_free(chip->cs_gpio);
+
        kfree(chip);
 }
 
-static inline int init_queue(struct driver_data *drv_data)
+static inline int bfin_spi_init_queue(struct driver_data *drv_data)
 {
        INIT_LIST_HEAD(&drv_data->queue);
        spin_lock_init(&drv_data->lock);
@@ -1196,10 +1177,10 @@ static inline int init_queue(struct driver_data *drv_data)
 
        /* init transfer tasklet */
        tasklet_init(&drv_data->pump_transfers,
-                    pump_transfers, (unsigned long)drv_data);
+                    bfin_spi_pump_transfers, (unsigned long)drv_data);
 
        /* init messages workqueue */
-       INIT_WORK(&drv_data->pump_messages, pump_messages);
+       INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages);
        drv_data->workqueue = create_singlethread_workqueue(
                                dev_name(drv_data->master->dev.parent));
        if (drv_data->workqueue == NULL)
@@ -1208,7 +1189,7 @@ static inline int init_queue(struct driver_data *drv_data)
        return 0;
 }
 
-static inline int start_queue(struct driver_data *drv_data)
+static inline int bfin_spi_start_queue(struct driver_data *drv_data)
 {
        unsigned long flags;
 
@@ -1230,7 +1211,7 @@ static inline int start_queue(struct driver_data *drv_data)
        return 0;
 }
 
-static inline int stop_queue(struct driver_data *drv_data)
+static inline int bfin_spi_stop_queue(struct driver_data *drv_data)
 {
        unsigned long flags;
        unsigned limit = 500;
@@ -1259,11 +1240,11 @@ static inline int stop_queue(struct driver_data *drv_data)
        return status;
 }
 
-static inline int destroy_queue(struct driver_data *drv_data)
+static inline int bfin_spi_destroy_queue(struct driver_data *drv_data)
 {
        int status;
 
-       status = stop_queue(drv_data);
+       status = bfin_spi_stop_queue(drv_data);
        if (status != 0)
                return status;
 
@@ -1272,7 +1253,7 @@ static inline int destroy_queue(struct driver_data *drv_data)
        return 0;
 }
 
-static int __init bfin5xx_spi_probe(struct platform_device *pdev)
+static int __init bfin_spi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct bfin5xx_spi_master *platform_info;
@@ -1296,11 +1277,14 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
        drv_data->pdev = pdev;
        drv_data->pin_req = platform_info->pin_req;
 
+       /* the spi->mode bits supported by this driver: */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+
        master->bus_num = pdev->id;
        master->num_chipselect = platform_info->num_chipselect;
-       master->cleanup = cleanup;
-       master->setup = setup;
-       master->transfer = transfer;
+       master->cleanup = bfin_spi_cleanup;
+       master->setup = bfin_spi_setup;
+       master->transfer = bfin_spi_transfer;
 
        /* Find and map our resources */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1310,7 +1294,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
                goto out_error_get_res;
        }
 
-       drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1));
+       drv_data->regs_base = ioremap(res->start, resource_size(res));
        if (drv_data->regs_base == NULL) {
                dev_err(dev, "Cannot map IO\n");
                status = -ENXIO;
@@ -1325,13 +1309,13 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
        }
 
        /* Initial and start queue */
-       status = init_queue(drv_data);
+       status = bfin_spi_init_queue(drv_data);
        if (status != 0) {
                dev_err(dev, "problem initializing queue\n");
                goto out_error_queue_alloc;
        }
 
-       status = start_queue(drv_data);
+       status = bfin_spi_start_queue(drv_data);
        if (status != 0) {
                dev_err(dev, "problem starting queue\n");
                goto out_error_queue_alloc;
@@ -1357,7 +1341,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
        return status;
 
 out_error_queue_alloc:
-       destroy_queue(drv_data);
+       bfin_spi_destroy_queue(drv_data);
 out_error_no_dma_ch:
        iounmap((void *) drv_data->regs_base);
 out_error_ioremap:
@@ -1368,7 +1352,7 @@ out_error_get_res:
 }
 
 /* stop hardware and remove the driver */
-static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
+static int __devexit bfin_spi_remove(struct platform_device *pdev)
 {
        struct driver_data *drv_data = platform_get_drvdata(pdev);
        int status = 0;
@@ -1377,7 +1361,7 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
                return 0;
 
        /* Remove the queue */
-       status = destroy_queue(drv_data);
+       status = bfin_spi_destroy_queue(drv_data);
        if (status != 0)
                return status;
 
@@ -1402,12 +1386,12 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct driver_data *drv_data = platform_get_drvdata(pdev);
        int status = 0;
 
-       status = stop_queue(drv_data);
+       status = bfin_spi_stop_queue(drv_data);
        if (status != 0)
                return status;
 
@@ -1417,7 +1401,7 @@ static int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int bfin5xx_spi_resume(struct platform_device *pdev)
+static int bfin_spi_resume(struct platform_device *pdev)
 {
        struct driver_data *drv_data = platform_get_drvdata(pdev);
        int status = 0;
@@ -1426,7 +1410,7 @@ static int bfin5xx_spi_resume(struct platform_device *pdev)
        bfin_spi_enable(drv_data);
 
        /* Start the queue running */
-       status = start_queue(drv_data);
+       status = bfin_spi_start_queue(drv_data);
        if (status != 0) {
                dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
                return status;
@@ -1435,29 +1419,29 @@ static int bfin5xx_spi_resume(struct platform_device *pdev)
        return 0;
 }
 #else
-#define bfin5xx_spi_suspend NULL
-#define bfin5xx_spi_resume NULL
+#define bfin_spi_suspend NULL
+#define bfin_spi_resume NULL
 #endif                         /* CONFIG_PM */
 
 MODULE_ALIAS("platform:bfin-spi");
-static struct platform_driver bfin5xx_spi_driver = {
+static struct platform_driver bfin_spi_driver = {
        .driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
-       .suspend        = bfin5xx_spi_suspend,
-       .resume         = bfin5xx_spi_resume,
-       .remove         = __devexit_p(bfin5xx_spi_remove),
+       .suspend        = bfin_spi_suspend,
+       .resume         = bfin_spi_resume,
+       .remove         = __devexit_p(bfin_spi_remove),
 };
 
-static int __init bfin5xx_spi_init(void)
+static int __init bfin_spi_init(void)
 {
-       return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);
+       return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe);
 }
-module_init(bfin5xx_spi_init);
+module_init(bfin_spi_init);
 
-static void __exit bfin5xx_spi_exit(void)
+static void __exit bfin_spi_exit(void)
 {
-       platform_driver_unregister(&bfin5xx_spi_driver);
+       platform_driver_unregister(&bfin_spi_driver);
 }
-module_exit(bfin5xx_spi_exit);
+module_exit(bfin_spi_exit);