virtio-mem: simplify high-level unplug handling in Sub Block Mode
[linux-2.6-microblaze.git] / drivers / spi / spi-atmel.c
index 7cd5fe0..2ef7488 100644 (file)
@@ -700,7 +700,6 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
 static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
                                struct spi_transfer *xfer,
                                u32 *plen)
-       __must_hold(&as->lock)
 {
        struct atmel_spi        *as = spi_master_get_devdata(master);
        struct dma_chan         *rxchan = master->dma_rx;
@@ -716,8 +715,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
        if (!rxchan || !txchan)
                return -ENODEV;
 
-       /* release lock for DMA operations */
-       atmel_spi_unlock(as);
 
        *plen = xfer->len;
 
@@ -786,15 +783,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
        rxchan->device->device_issue_pending(rxchan);
        txchan->device->device_issue_pending(txchan);
 
-       /* take back lock */
-       atmel_spi_lock(as);
        return 0;
 
 err_dma:
        spi_writel(as, IDR, SPI_BIT(OVRES));
        atmel_spi_stop_dma(master);
 err_exit:
-       atmel_spi_lock(as);
        return -ENOMEM;
 }
 
@@ -863,7 +857,6 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
  * lock is held, spi irq is blocked
  */
 static void atmel_spi_pdc_next_xfer(struct spi_master *master,
-                                       struct spi_message *msg,
                                        struct spi_transfer *xfer)
 {
        struct atmel_spi        *as = spi_master_get_devdata(master);
@@ -879,12 +872,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
        spi_writel(as, RPR, rx_dma);
        spi_writel(as, TPR, tx_dma);
 
-       if (msg->spi->bits_per_word > 8)
+       if (xfer->bits_per_word > 8)
                len >>= 1;
        spi_writel(as, RCR, len);
        spi_writel(as, TCR, len);
 
-       dev_dbg(&msg->spi->dev,
+       dev_dbg(&master->dev,
                "  start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
                xfer, xfer->len, xfer->tx_buf,
                (unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -898,12 +891,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
                spi_writel(as, RNPR, rx_dma);
                spi_writel(as, TNPR, tx_dma);
 
-               if (msg->spi->bits_per_word > 8)
+               if (xfer->bits_per_word > 8)
                        len >>= 1;
                spi_writel(as, RNCR, len);
                spi_writel(as, TNCR, len);
 
-               dev_dbg(&msg->spi->dev,
+               dev_dbg(&master->dev,
                        "  next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
                        xfer, xfer->len, xfer->tx_buf,
                        (unsigned long long)xfer->tx_dma, xfer->rx_buf,
@@ -1054,8 +1047,6 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
 
 /* Interrupt
  *
- * No need for locking in this Interrupt handler: done_status is the
- * only information modified.
  */
 static irqreturn_t
 atmel_spi_pio_interrupt(int irq, void *dev_id)
@@ -1273,12 +1264,28 @@ static int atmel_spi_setup(struct spi_device *spi)
        return 0;
 }
 
+static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct atmel_spi *as = spi_master_get_devdata(spi->master);
+       /* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW
+        * since we already have routines for activate/deactivate translate
+        * high/low to active/inactive
+        */
+       enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
+
+       if (enable) {
+               cs_activate(as, spi);
+       } else {
+               cs_deactivate(as, spi);
+       }
+
+}
+
 static int atmel_spi_one_transfer(struct spi_master *master,
-                                       struct spi_message *msg,
+                                       struct spi_device *spi,
                                        struct spi_transfer *xfer)
 {
        struct atmel_spi        *as;
-       struct spi_device       *spi = msg->spi;
        u8                      bits;
        u32                     len;
        struct atmel_spi_device *asd;
@@ -1288,11 +1295,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
 
        as = spi_master_get_devdata(master);
 
-       if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
-               dev_dbg(&spi->dev, "missing rx or tx buf\n");
-               return -EINVAL;
-       }
-
        asd = spi->controller_state;
        bits = (asd->csr >> 4) & 0xf;
        if (bits != xfer->bits_per_word - 8) {
@@ -1305,13 +1307,13 @@ static int atmel_spi_one_transfer(struct spi_master *master,
         * DMA map early, for performance (empties dcache ASAP) and
         * better fault reporting.
         */
-       if ((!msg->is_dma_mapped)
+       if ((!master->cur_msg_mapped)
                && as->use_pdc) {
                if (atmel_spi_dma_map_xfer(as, xfer) < 0)
                        return -ENOMEM;
        }
 
-       atmel_spi_set_xfer_speed(as, msg->spi, xfer);
+       atmel_spi_set_xfer_speed(as, spi, xfer);
 
        as->done_status = 0;
        as->current_transfer = xfer;
@@ -1320,7 +1322,9 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                reinit_completion(&as->xfer_completion);
 
                if (as->use_pdc) {
-                       atmel_spi_pdc_next_xfer(master, msg, xfer);
+                       atmel_spi_lock(as);
+                       atmel_spi_pdc_next_xfer(master, xfer);
+                       atmel_spi_unlock(as);
                } else if (atmel_spi_use_dma(as, xfer)) {
                        len = as->current_remaining_bytes;
                        ret = atmel_spi_next_xfer_dma_submit(master,
@@ -1328,21 +1332,21 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                        if (ret) {
                                dev_err(&spi->dev,
                                        "unable to use DMA, fallback to PIO\n");
-                               atmel_spi_next_xfer_pio(master, xfer);
+                               as->done_status = ret;
+                               break;
                        } else {
                                as->current_remaining_bytes -= len;
                                if (as->current_remaining_bytes < 0)
                                        as->current_remaining_bytes = 0;
                        }
                } else {
+                       atmel_spi_lock(as);
                        atmel_spi_next_xfer_pio(master, xfer);
+                       atmel_spi_unlock(as);
                }
 
-               /* interrupts are disabled, so free the lock for schedule */
-               atmel_spi_unlock(as);
                dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
                                                          SPI_DMA_TIMEOUT);
-               atmel_spi_lock(as);
                if (WARN_ON(dma_timeout == 0)) {
                        dev_err(&spi->dev, "spi transfer timeout\n");
                        as->done_status = -EIO;
@@ -1381,90 +1385,16 @@ static int atmel_spi_one_transfer(struct spi_master *master,
                } else if (atmel_spi_use_dma(as, xfer)) {
                        atmel_spi_stop_dma(master);
                }
-
-               if (!msg->is_dma_mapped
-                       && as->use_pdc)
-                       atmel_spi_dma_unmap_xfer(master, xfer);
-
-               return 0;
-
-       } else {
-               /* only update length if no error */
-               msg->actual_length += xfer->len;
        }
 
-       if (!msg->is_dma_mapped
+       if (!master->cur_msg_mapped
                && as->use_pdc)
                atmel_spi_dma_unmap_xfer(master, xfer);
 
-       spi_transfer_delay_exec(xfer);
-
-       if (xfer->cs_change) {
-               if (list_is_last(&xfer->transfer_list,
-                                &msg->transfers)) {
-                       as->keep_cs = true;
-               } else {
-                       cs_deactivate(as, msg->spi);
-                       udelay(10);
-                       cs_activate(as, msg->spi);
-               }
-       }
-
-       return 0;
-}
-
-static int atmel_spi_transfer_one_message(struct spi_master *master,
-                                               struct spi_message *msg)
-{
-       struct atmel_spi *as;
-       struct spi_transfer *xfer;
-       struct spi_device *spi = msg->spi;
-       int ret = 0;
-
-       as = spi_master_get_devdata(master);
-
-       dev_dbg(&spi->dev, "new message %p submitted for %s\n",
-                                       msg, dev_name(&spi->dev));
-
-       atmel_spi_lock(as);
-       cs_activate(as, spi);
-
-       as->keep_cs = false;
-
-       msg->status = 0;
-       msg->actual_length = 0;
-
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               trace_spi_transfer_start(msg, xfer);
-
-               ret = atmel_spi_one_transfer(master, msg, xfer);
-               if (ret)
-                       goto msg_done;
-
-               trace_spi_transfer_stop(msg, xfer);
-       }
-
        if (as->use_pdc)
                atmel_spi_disable_pdc_transfer(as);
 
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               dev_dbg(&spi->dev,
-                       "  xfer %p: len %u tx %p/%pad rx %p/%pad\n",
-                       xfer, xfer->len,
-                       xfer->tx_buf, &xfer->tx_dma,
-                       xfer->rx_buf, &xfer->rx_dma);
-       }
-
-msg_done:
-       if (!as->keep_cs)
-               cs_deactivate(as, msg->spi);
-
-       atmel_spi_unlock(as);
-
-       msg->status = as->done_status;
-       spi_finalize_current_message(spi->master);
-
-       return ret;
+       return as->done_status;
 }
 
 static void atmel_spi_cleanup(struct spi_device *spi)
@@ -1554,7 +1484,8 @@ static int atmel_spi_probe(struct platform_device *pdev)
        master->num_chipselect = 4;
        master->setup = atmel_spi_setup;
        master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
-       master->transfer_one_message = atmel_spi_transfer_one_message;
+       master->transfer_one = atmel_spi_one_transfer;
+       master->set_cs = atmel_spi_set_cs;
        master->cleanup = atmel_spi_cleanup;
        master->auto_runtime_pm = true;
        master->max_dma_len = SPI_MAX_DMA_XFER;