Merge tag 'spi-v3.15-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[cascardo/linux.git] / drivers / spi / spi-s3c64xx.c
index ae907dd..f19cd97 100644 (file)
 
 #include <linux/platform_data/spi-s3c64xx.h>
 
-#ifdef CONFIG_S3C_DMA
-#include <mach/dma.h>
-#endif
-
 #define MAX_SPI_PORTS          3
 #define S3C64XX_SPI_QUIRK_POLL         (1 << 0)
 
@@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data {
        unsigned                        cur_speed;
        struct s3c64xx_spi_dma_data     rx_dma;
        struct s3c64xx_spi_dma_data     tx_dma;
-#ifdef CONFIG_S3C_DMA
-       struct samsung_dma_ops          *ops;
-#endif
        struct s3c64xx_spi_port_config  *port_conf;
        unsigned int                    port_id;
        bool                            cs_gpio;
@@ -284,104 +277,8 @@ static void s3c64xx_spi_dmacb(void *data)
        spin_unlock_irqrestore(&sdd->lock, flags);
 }
 
-#ifdef CONFIG_S3C_DMA
-/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */
-
-static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
-       .name = "samsung-spi-dma",
-};
-
-static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
-                                       unsigned len, dma_addr_t buf)
-{
-       struct s3c64xx_spi_driver_data *sdd;
-       struct samsung_dma_prep info;
-       struct samsung_dma_config config;
-
-       if (dma->direction == DMA_DEV_TO_MEM) {
-               sdd = container_of((void *)dma,
-                       struct s3c64xx_spi_driver_data, rx_dma);
-               config.direction = sdd->rx_dma.direction;
-               config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
-               config.width = sdd->cur_bpw / 8;
-               sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config);
-       } else {
-               sdd = container_of((void *)dma,
-                       struct s3c64xx_spi_driver_data, tx_dma);
-               config.direction =  sdd->tx_dma.direction;
-               config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
-               config.width = sdd->cur_bpw / 8;
-               sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config);
-       }
-
-       info.cap = DMA_SLAVE;
-       info.len = len;
-       info.fp = s3c64xx_spi_dmacb;
-       info.fp_param = dma;
-       info.direction = dma->direction;
-       info.buf = buf;
-
-       sdd->ops->prepare((enum dma_ch)dma->ch, &info);
-       sdd->ops->trigger((enum dma_ch)dma->ch);
-}
-
-static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
-{
-       struct samsung_dma_req req;
-       struct device *dev = &sdd->pdev->dev;
-
-       sdd->ops = samsung_dma_get_ops();
-
-       req.cap = DMA_SLAVE;
-       req.client = &s3c64xx_spi_dma_client;
-
-       sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
-                                       sdd->rx_dma.dmach, &req, dev, "rx");
-       sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
-                                       sdd->tx_dma.dmach, &req, dev, "tx");
-
-       return 1;
-}
-
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
-{
-       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
-       /*
-        * If DMA resource was not available during
-        * probe, no need to continue with dma requests
-        * else Acquire DMA channels
-        */
-       while (!is_polling(sdd) && !acquire_dma(sdd))
-               usleep_range(10000, 11000);
-
-       return 0;
-}
-
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
-{
-       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
-       /* Free DMA channels */
-       if (!is_polling(sdd)) {
-               sdd->ops->release((enum dma_ch)sdd->rx_dma.ch,
-                                       &s3c64xx_spi_dma_client);
-               sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
-                                       &s3c64xx_spi_dma_client);
-       }
-
-       return 0;
-}
-
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
-                                struct s3c64xx_spi_dma_data *dma)
-{
-       sdd->ops->stop((enum dma_ch)dma->ch);
-}
-#else
-
 static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
-                                       unsigned len, dma_addr_t buf)
+                       struct sg_table *sgt)
 {
        struct s3c64xx_spi_driver_data *sdd;
        struct dma_slave_config config;
@@ -407,8 +304,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
                dmaengine_slave_config(dma->ch, &config);
        }
 
-       desc = dmaengine_prep_slave_single(dma->ch, buf, len,
-                                       dma->direction, DMA_PREP_INTERRUPT);
+       desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
+                                      dma->direction, DMA_PREP_INTERRUPT);
 
        desc->callback = s3c64xx_spi_dmacb;
        desc->callback_param = dma;
@@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
                        ret = -EBUSY;
                        goto out;
                }
+               spi->dma_rx = sdd->rx_dma.ch;
 
                sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
                                   (void *)sdd->tx_dma.dmach, dev, "tx");
@@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
                        ret = -EBUSY;
                        goto out_rx;
                }
+               spi->dma_tx = sdd->tx_dma.ch;
        }
 
        ret = pm_runtime_get_sync(&sdd->pdev->dev);
@@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
        return 0;
 }
 
-static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
-                                struct s3c64xx_spi_dma_data *dma)
+static bool s3c64xx_spi_can_dma(struct spi_master *master,
+                               struct spi_device *spi,
+                               struct spi_transfer *xfer)
 {
-       dmaengine_terminate_all(dma->ch);
+       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+
+       return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
 }
-#endif
 
 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                                struct spi_device *spi,
@@ -515,7 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                chcfg |= S3C64XX_SPI_CH_TXCH_ON;
                if (dma_mode) {
                        modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
-                       prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
+                       prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
                } else {
                        switch (sdd->cur_bpw) {
                        case 32:
@@ -547,7 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                        writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
                                        | S3C64XX_SPI_PACKET_CNT_EN,
                                        regs + S3C64XX_SPI_PACKET_CNT);
-                       prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
+                       prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
                }
        }
 
@@ -555,23 +456,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
        writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
 }
 
-static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_device *spi)
-{
-       if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
-               if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
-                       /* Deselect the last toggled device */
-                       if (spi->cs_gpio >= 0)
-                               gpio_set_value(spi->cs_gpio,
-                                       spi->mode & SPI_CS_HIGH ? 0 : 1);
-               }
-               sdd->tgl_spi = NULL;
-       }
-
-       if (spi->cs_gpio >= 0)
-               gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
-}
-
 static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
                                        int timeout_ms)
 {
@@ -593,112 +477,111 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
        return RX_FIFO_LVL(status, sdd);
 }
 
-static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
-                               struct spi_transfer *xfer, int dma_mode)
+static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
+                       struct spi_transfer *xfer)
 {
        void __iomem *regs = sdd->regs;
        unsigned long val;
+       u32 status;
        int ms;
 
        /* millisecs to xfer 'len' bytes @ 'cur_speed' */
        ms = xfer->len * 8 * 1000 / sdd->cur_speed;
        ms += 10; /* some tolerance */
 
-       if (dma_mode) {
-               val = msecs_to_jiffies(ms) + 10;
-               val = wait_for_completion_timeout(&sdd->xfer_completion, val);
-       } else {
-               u32 status;
-               val = msecs_to_loops(ms);
-               do {
+       val = msecs_to_jiffies(ms) + 10;
+       val = wait_for_completion_timeout(&sdd->xfer_completion, val);
+
+       /*
+        * If the previous xfer was completed within timeout, then
+        * proceed further else return -EIO.
+        * DmaTx returns after simply writing data in the FIFO,
+        * w/o waiting for real transmission on the bus to finish.
+        * DmaRx returns only after Dma read data from FIFO which
+        * needs bus transmission to finish, so we don't worry if
+        * Xfer involved Rx(with or without Tx).
+        */
+       if (val && !xfer->rx_buf) {
+               val = msecs_to_loops(10);
+               status = readl(regs + S3C64XX_SPI_STATUS);
+               while ((TX_FIFO_LVL(status, sdd)
+                       || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
+                      && --val) {
+                       cpu_relax();
                        status = readl(regs + S3C64XX_SPI_STATUS);
-               } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
+               }
+
        }
 
-       if (dma_mode) {
-               u32 status;
-
-               /*
-                * If the previous xfer was completed within timeout, then
-                * proceed further else return -EIO.
-                * DmaTx returns after simply writing data in the FIFO,
-                * w/o waiting for real transmission on the bus to finish.
-                * DmaRx returns only after Dma read data from FIFO which
-                * needs bus transmission to finish, so we don't worry if
-                * Xfer involved Rx(with or without Tx).
-                */
-               if (val && !xfer->rx_buf) {
-                       val = msecs_to_loops(10);
-                       status = readl(regs + S3C64XX_SPI_STATUS);
-                       while ((TX_FIFO_LVL(status, sdd)
-                               || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
-                                       && --val) {
-                               cpu_relax();
-                               status = readl(regs + S3C64XX_SPI_STATUS);
-                       }
+       /* If timed out while checking rx/tx status return error */
+       if (!val)
+               return -EIO;
 
-               }
+       return 0;
+}
 
-               /* If timed out while checking rx/tx status return error */
-               if (!val)
-                       return -EIO;
-       } else {
-               int loops;
-               u32 cpy_len;
-               u8 *buf;
-
-               /* If it was only Tx */
-               if (!xfer->rx_buf) {
-                       sdd->state &= ~TXBUSY;
-                       return 0;
-               }
+static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
+                       struct spi_transfer *xfer)
+{
+       void __iomem *regs = sdd->regs;
+       unsigned long val;
+       u32 status;
+       int loops;
+       u32 cpy_len;
+       u8 *buf;
+       int ms;
 
-               /*
-                * If the receive length is bigger than the controller fifo
-                * size, calculate the loops and read the fifo as many times.
-                * loops = length / max fifo size (calculated by using the
-                * fifo mask).
-                * For any size less than the fifo size the below code is
-                * executed atleast once.
-                */
-               loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
-               buf = xfer->rx_buf;
-               do {
-                       /* wait for data to be received in the fifo */
-                       cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
-                                               (loops ? ms : 0));
+       /* millisecs to xfer 'len' bytes @ 'cur_speed' */
+       ms = xfer->len * 8 * 1000 / sdd->cur_speed;
+       ms += 10; /* some tolerance */
 
-                       switch (sdd->cur_bpw) {
-                       case 32:
-                               ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
-                                       buf, cpy_len / 4);
-                               break;
-                       case 16:
-                               ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
-                                       buf, cpy_len / 2);
-                               break;
-                       default:
-                               ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
-                                       buf, cpy_len);
-                               break;
-                       }
+       val = msecs_to_loops(ms);
+       do {
+               status = readl(regs + S3C64XX_SPI_STATUS);
+       } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
 
-                       buf = buf + cpy_len;
-               } while (loops--);
-               sdd->state &= ~RXBUSY;
+
+       /* If it was only Tx */
+       if (!xfer->rx_buf) {
+               sdd->state &= ~TXBUSY;
+               return 0;
        }
 
-       return 0;
-}
+       /*
+        * If the receive length is bigger than the controller fifo
+        * size, calculate the loops and read the fifo as many times.
+        * loops = length / max fifo size (calculated by using the
+        * fifo mask).
+        * For any size less than the fifo size the below code is
+        * executed atleast once.
+        */
+       loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
+       buf = xfer->rx_buf;
+       do {
+               /* wait for data to be received in the fifo */
+               cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
+                                                      (loops ? ms : 0));
+
+               switch (sdd->cur_bpw) {
+               case 32:
+                       ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
+                                    buf, cpy_len / 4);
+                       break;
+               case 16:
+                       ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
+                                    buf, cpy_len / 2);
+                       break;
+               default:
+                       ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
+                                   buf, cpy_len);
+                       break;
+               }
 
-static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_device *spi)
-{
-       if (sdd->tgl_spi == spi)
-               sdd->tgl_spi = NULL;
+               buf = buf + cpy_len;
+       } while (loops--);
+       sdd->state &= ~RXBUSY;
 
-       if (spi->cs_gpio >= 0)
-               gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
+       return 0;
 }
 
 static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
@@ -774,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 
 #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
 
-static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_message *msg)
-{
-       struct device *dev = &sdd->pdev->dev;
-       struct spi_transfer *xfer;
-
-       if (is_polling(sdd) || msg->is_dma_mapped)
-               return 0;
-
-       /* First mark all xfer unmapped */
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               xfer->rx_dma = XFER_DMAADDR_INVALID;
-               xfer->tx_dma = XFER_DMAADDR_INVALID;
-       }
-
-       /* Map until end or first fail */
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
-               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
-                       continue;
-
-               if (xfer->tx_buf != NULL) {
-                       xfer->tx_dma = dma_map_single(dev,
-                                       (void *)xfer->tx_buf, xfer->len,
-                                       DMA_TO_DEVICE);
-                       if (dma_mapping_error(dev, xfer->tx_dma)) {
-                               dev_err(dev, "dma_map_single Tx failed\n");
-                               xfer->tx_dma = XFER_DMAADDR_INVALID;
-                               return -ENOMEM;
-                       }
-               }
-
-               if (xfer->rx_buf != NULL) {
-                       xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
-                                               xfer->len, DMA_FROM_DEVICE);
-                       if (dma_mapping_error(dev, xfer->rx_dma)) {
-                               dev_err(dev, "dma_map_single Rx failed\n");
-                               dma_unmap_single(dev, xfer->tx_dma,
-                                               xfer->len, DMA_TO_DEVICE);
-                               xfer->tx_dma = XFER_DMAADDR_INVALID;
-                               xfer->rx_dma = XFER_DMAADDR_INVALID;
-                               return -ENOMEM;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
-                                               struct spi_message *msg)
-{
-       struct device *dev = &sdd->pdev->dev;
-       struct spi_transfer *xfer;
-
-       if (is_polling(sdd) || msg->is_dma_mapped)
-               return;
-
-       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-
-               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
-                       continue;
-
-               if (xfer->rx_buf != NULL
-                               && xfer->rx_dma != XFER_DMAADDR_INVALID)
-                       dma_unmap_single(dev, xfer->rx_dma,
-                                               xfer->len, DMA_FROM_DEVICE);
-
-               if (xfer->tx_buf != NULL
-                               && xfer->tx_dma != XFER_DMAADDR_INVALID)
-                       dma_unmap_single(dev, xfer->tx_dma,
-                                               xfer->len, DMA_TO_DEVICE);
-       }
-}
-
 static int s3c64xx_spi_prepare_message(struct spi_master *master,
                                       struct spi_message *msg)
 {
@@ -866,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
                s3c64xx_spi_config(sdd);
        }
 
-       /* Map all the transfers if needed */
-       if (s3c64xx_spi_map_mssg(sdd, msg)) {
-               dev_err(&spi->dev,
-                       "Xfer: Unable to map message buffers!\n");
-               return -ENOMEM;
-       }
-
        /* Configure feedback delay */
        writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
 
@@ -896,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
        bpw = xfer->bits_per_word;
        speed = xfer->speed_hz ? : spi->max_speed_hz;
 
-       if (xfer->len % (bpw / 8)) {
-               dev_err(&spi->dev,
-                       "Xfer length(%u) not a multiple of word size(%u)\n",
-                       xfer->len, bpw / 8);
-               return -EIO;
-       }
-
        if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
                sdd->cur_bpw = bpw;
                sdd->cur_speed = speed;
@@ -929,7 +723,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
 
        spin_unlock_irqrestore(&sdd->lock, flags);
 
-       status = wait_for_xfer(sdd, xfer, use_dma);
+       if (use_dma)
+               status = wait_for_dma(sdd, xfer);
+       else
+               status = wait_for_pio(sdd, xfer);
 
        if (status) {
                dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
@@ -941,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
                if (use_dma) {
                        if (xfer->tx_buf != NULL
                            && (sdd->state & TXBUSY))
-                               s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
+                               dmaengine_terminate_all(sdd->tx_dma.ch);
                        if (xfer->rx_buf != NULL
                            && (sdd->state & RXBUSY))
-                               s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
+                               dmaengine_terminate_all(sdd->rx_dma.ch);
                }
        } else {
                flush_fifo(sdd);
@@ -953,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
        return status;
 }
 
-static int s3c64xx_spi_unprepare_message(struct spi_master *master,
-                                           struct spi_message *msg)
-{
-       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-
-       s3c64xx_spi_unmap_mssg(sdd, msg);
-
-       return 0;
-}
-
 static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
                                struct spi_device *spi)
 {
@@ -1092,14 +879,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
 
        pm_runtime_put(&sdd->pdev->dev);
        writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
-       disable_cs(sdd, spi);
        return 0;
 
 setup_exit:
        pm_runtime_put(&sdd->pdev->dev);
        /* setup() returns with device de-selected */
        writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
-       disable_cs(sdd, spi);
 
        gpio_free(cs->line);
        spi_set_ctldata(spi, NULL);
@@ -1338,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
        master->prepare_message = s3c64xx_spi_prepare_message;
        master->transfer_one = s3c64xx_spi_transfer_one;
-       master->unprepare_message = s3c64xx_spi_unprepare_message;
        master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
        master->num_chipselect = sci->num_cs;
        master->dma_alignment = 8;
@@ -1347,6 +1131,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->auto_runtime_pm = true;
+       if (!is_polling(sdd))
+               master->can_dma = s3c64xx_spi_can_dma;
 
        sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
        if (IS_ERR(sdd->regs)) {