spi: pxa2xx: Fix too early chipselect deassert
[cascardo/linux.git] / drivers / spi / spi-pxa2xx.c
index b25dc71..ce66cf4 100644 (file)
@@ -496,6 +496,7 @@ static void giveback(struct driver_data *drv_data)
 {
        struct spi_transfer* last_transfer;
        struct spi_message *msg;
+       unsigned long timeout;
 
        msg = drv_data->cur_msg;
        drv_data->cur_msg = NULL;
@@ -508,6 +509,12 @@ static void giveback(struct driver_data *drv_data)
        if (last_transfer->delay_usecs)
                udelay(last_transfer->delay_usecs);
 
+       /* Wait until SSP becomes idle before deasserting the CS */
+       timeout = jiffies + msecs_to_jiffies(10);
+       while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY &&
+              !time_after(jiffies, timeout))
+               cpu_relax();
+
        /* Drop chip select UNLESS cs_change is true or we are returning
         * a message with an error, or next message is for another chip
         */
@@ -572,7 +579,7 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg)
 
 static void int_transfer_complete(struct driver_data *drv_data)
 {
-       /* Stop SSP */
+       /* Clear and disable interrupts */
        write_SSSR_CS(drv_data, drv_data->clear_sr);
        reset_sccr1(drv_data);
        if (!pxa25x_ssp_comp(drv_data))
@@ -1001,19 +1008,6 @@ static void pump_transfers(unsigned long data)
                                             "pump_transfers: DMA burst size reduced to match bits_per_word\n");
        }
 
-       /* NOTE:  PXA25x_SSP _could_ use external clocking ... */
-       cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
-       if (!pxa25x_ssp_comp(drv_data))
-               dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
-                       drv_data->master->max_speed_hz
-                               / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)),
-                       chip->enable_dma ? "DMA" : "PIO");
-       else
-               dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
-                       drv_data->master->max_speed_hz / 2
-                               / (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)),
-                       chip->enable_dma ? "DMA" : "PIO");
-
        message->state = RUNNING_STATE;
 
        drv_data->dma_mapped = 0;
@@ -1040,6 +1034,19 @@ static void pump_transfers(unsigned long data)
                write_SSSR_CS(drv_data, drv_data->clear_sr);
        }
 
+       /* NOTE:  PXA25x_SSP _could_ use external clocking ... */
+       cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
+       if (!pxa25x_ssp_comp(drv_data))
+               dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
+                       drv_data->master->max_speed_hz
+                               / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)),
+                       drv_data->dma_mapped ? "DMA" : "PIO");
+       else
+               dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
+                       drv_data->master->max_speed_hz / 2
+                               / (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)),
+                       drv_data->dma_mapped ? "DMA" : "PIO");
+
        if (is_lpss_ssp(drv_data)) {
                if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
                    != chip->lpss_rx_threshold)
@@ -1567,9 +1574,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        if (!is_quark_x1000_ssp(drv_data))
                pxa2xx_spi_write(drv_data, SSPSP, 0);
 
-       if (is_lpss_ssp(drv_data))
-               lpss_ssp_setup(drv_data);
-
        if (is_lpss_ssp(drv_data)) {
                lpss_ssp_setup(drv_data);
                config = lpss_get_config(drv_data);