[PATCH 15/23] spi: s3c64xx: move to generic dmaengine API

Padma Venkat padma.kvr at gmail.com
Wed Mar 6 04:14:36 EST 2013


Hi Arnd,

On Tue, Mar 5, 2013 at 11:12 PM, Arnd Bergmann <arnd at arndb.de> wrote:
> The spi-s3c64xx uses a Samsung proprietary interface for
> talking to the DMA engine, which does not work with
> multiplatform kernels. Since the driver can also operate
> in PIO mode without any DMA, older platforms that do
> not support the DMA engine API will still work, although
> slower.
>
> The conversion was rather mechanical, since the samsung
> interface is just a shallow wrapper around the dmaengine
> interface.
>
> Signed-off-by: Arnd Bergmann <arnd at arndb.de>
> ---
>  arch/arm/plat-samsung/devs.c              |  10 +++
>  drivers/spi/spi-s3c64xx.c                 | 107 ++++++++++++++----------------
>  include/linux/platform_data/spi-s3c64xx.h |   3 +
>  3 files changed, 62 insertions(+), 58 deletions(-)
>
> diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
> index 76209c9..58fb02a 100644
> --- a/arch/arm/plat-samsung/devs.c
> +++ b/arch/arm/plat-samsung/devs.c
> @@ -10,6 +10,7 @@
>   * published by the Free Software Foundation.
>  */
>
> +#include <linux/amba/pl330.h>
>  #include <linux/kernel.h>
>  #include <linux/types.h>
>  #include <linux/interrupt.h>
> @@ -1551,6 +1552,9 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
>         pd.num_cs = num_cs;
>         pd.src_clk_nr = src_clk_nr;
>         pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
> +#ifdef CONFIG_PL330_DMA
> +       pd.filter = pl330_filter;
> +#endif
>
>         s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0);
>  }
> @@ -1589,6 +1593,9 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
>         pd.num_cs = num_cs;
>         pd.src_clk_nr = src_clk_nr;
>         pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
> +#ifdef CONFIG_PL330_DMA
> +       pd.filter = pl330_filter;
> +#endif
>
>         s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
>  }
> @@ -1627,6 +1634,9 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
>         pd.num_cs = num_cs;
>         pd.src_clk_nr = src_clk_nr;
>         pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
> +#ifdef CONFIG_PL330_DMA
> +       pd.filter = pl330_filter;
> +#endif
>
>         s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);
>  }
> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
> index e862ab8..9be07a6 100644
> --- a/drivers/spi/spi-s3c64xx.c
> +++ b/drivers/spi/spi-s3c64xx.c
> @@ -22,8 +22,10 @@
>  #include <linux/workqueue.h>
>  #include <linux/interrupt.h>
>  #include <linux/delay.h>
> +#include <linux/amba/pl330.h>
>  #include <linux/clk.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/dmaengine.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/spi/spi.h>
> @@ -31,7 +33,6 @@
>  #include <linux/of.h>
>  #include <linux/of_gpio.h>
>
> -#include <mach/dma.h>
>  #include <linux/platform_data/spi-s3c64xx.h>
>
>  #define MAX_SPI_PORTS          3
> @@ -131,9 +132,9 @@
>  #define TXBUSY    (1<<3)
>
>  struct s3c64xx_spi_dma_data {
> -       unsigned                ch;
> +       struct dma_chan *ch;
>         enum dma_transfer_direction direction;
> -       enum dma_ch     dmach;
> +       unsigned int request;
>  };
>
>  /**
> @@ -195,16 +196,11 @@ struct s3c64xx_spi_driver_data {
>         unsigned                        cur_speed;
>         struct s3c64xx_spi_dma_data     rx_dma;
>         struct s3c64xx_spi_dma_data     tx_dma;
> -       struct samsung_dma_ops          *ops;
>         struct s3c64xx_spi_port_config  *port_conf;
>         unsigned int                    port_id;
>         unsigned long                   gpios[4];
>  };
>
> -static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
> -       .name = "samsung-spi-dma",
> -};
> -
>  static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
>  {
>         void __iomem *regs = sdd->regs;
> @@ -285,50 +281,42 @@ 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;
> +       struct dma_slave_config config;
> +       struct scatterlist sg;
> +       struct dma_async_tx_descriptor *desc;
>
>         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(sdd->rx_dma.ch, &config);
> +               config.direction = dma->direction;
> +               config.src_addr = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
> +               config.src_addr_width = sdd->cur_bpw / 8;
> +               config.src_maxburst = 1;
> +               dmaengine_slave_config(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(sdd->tx_dma.ch, &config);
> +               config.direction = dma->direction;
> +               config.dst_addr = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
> +               config.dst_addr_width = sdd->cur_bpw / 8;
> +               config.dst_maxburst = 1;
> +               dmaengine_slave_config(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;
> +       sg_init_table(&sg, 1);
> +       sg_dma_len(&sg) = len;
> +       sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
> +                   len, offset_in_page(buf));
> +       sg_dma_address(&sg) = buf;
>
> -       sdd->ops->prepare(dma->ch, &info);
> -       sdd->ops->trigger(dma->ch);
> -}
> +       desc = dmaengine_prep_slave_sg(dma->ch,
> +               &sg, 1, dma->direction, DMA_PREP_INTERRUPT);
>
> -static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
> -{
> -       struct samsung_dma_req req;
> -       struct device *dev = &sdd->pdev->dev;
> +       desc->callback = s3c64xx_spi_dmacb;
> +       desc->callback_param = dma;
>
> -       sdd->ops = samsung_dma_get_ops();
> -
> -       req.cap = DMA_SLAVE;
> -       req.client = &s3c64xx_spi_dma_client;
> -
> -       sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
> -       sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
> -
> -       return 1;
> +       dmaengine_submit(desc);
> +       dma_async_issue_pending(dma->ch);
>  }
>
>  static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
> @@ -713,9 +701,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
>                 }
>
>                 /* Polling method for xfers not bigger than FIFO capacity */
> -               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
> -                       use_dma = 0;
> -               else
> +               use_dma = 0;
> +               if (sdd->rx_dma.ch && sdd->tx_dma.ch &&
> +                   (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))
>                         use_dma = 1;
>
>                 spin_lock_irqsave(&sdd->lock, flags);
> @@ -750,10 +738,10 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
>                         if (use_dma) {
>                                 if (xfer->tx_buf != NULL
>                                                 && (sdd->state & TXBUSY))
> -                                       sdd->ops->stop(sdd->tx_dma.ch);
> +                                       dmaengine_terminate_all(sdd->tx_dma.ch);
>                                 if (xfer->rx_buf != NULL
>                                                 && (sdd->state & RXBUSY))
> -                                       sdd->ops->stop(sdd->rx_dma.ch);
> +                                       dmaengine_terminate_all(sdd->rx_dma.ch);
>                         }
>
>                         goto out;
> @@ -793,11 +781,18 @@ out:
>  static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
>  {
>         struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
> +       dma_filter_fn filter = sdd->cntrlr_info->filter;
> +       struct device *dev = &sdd->pdev->dev;
> +       dma_cap_mask_t mask;
>
> -       /* Acquire DMA channels */
> -       while (!acquire_dma(sdd))
> -               usleep_range(10000, 11000);
> +       dma_cap_zero(mask);
> +       dma_cap_set(DMA_SLAVE, mask);
>
> +       /* Acquire DMA channels */
> +       sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
> +                               (void*)sdd->rx_dma.request, dev, "rx");
> +       sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
> +                               (void*)sdd->tx_dma.request, dev, "tx");
>         pm_runtime_get_sync(&sdd->pdev->dev);
>
>         return 0;
> @@ -808,11 +803,10 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
>         struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
>
>         /* Free DMA channels */
> -       sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
> -       sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
> +       dma_release_channel(sdd->rx_dma.ch);
> +       dma_release_channel(sdd->tx_dma.ch);
>
>         pm_runtime_put(&sdd->pdev->dev);
> -
>         return 0;
>  }
>
> @@ -1149,7 +1143,6 @@ static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
>  static int s3c64xx_spi_probe(struct platform_device *pdev)
>  {
>         struct resource *mem_res;
> -       struct resource *res;
>         struct s3c64xx_spi_driver_data *sdd;
>         struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
>         struct spi_master *master;
> @@ -1207,15 +1200,15 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
>         }
>
>         sdd->cur_bpw = 8;
> -
>         if (!sdd->pdev->dev.of_node) {
> +               struct resource *res;
>                 res = platform_get_resource(pdev, IORESOURCE_DMA,  0);
>                 if (!res) {
>                         dev_err(&pdev->dev, "Unable to get SPI tx dma "
>                                         "resource\n");
>                         return -ENXIO;
>                 }
> -               sdd->tx_dma.dmach = res->start;
> +               sdd->tx_dma.request = res->start;
>
>                 res = platform_get_resource(pdev, IORESOURCE_DMA,  1);
>                 if (!res) {
> @@ -1223,12 +1216,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
>                                         "resource\n");
>                         return -ENXIO;
>                 }
> -               sdd->rx_dma.dmach = res->start;
> +               sdd->rx_dma.request = res->start;
>         }
>
>         sdd->tx_dma.direction = DMA_MEM_TO_DEV;
>         sdd->rx_dma.direction = DMA_DEV_TO_MEM;
> -
>         master->dev.of_node = pdev->dev.of_node;
>         master->bus_num = sdd->port_id;
>         master->setup = s3c64xx_spi_setup;
> @@ -1314,8 +1306,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
>                                         sdd->port_id, master->num_chipselect);
>         dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
>                                         mem_res->end, mem_res->start,
> -                                       sdd->rx_dma.dmach, sdd->tx_dma.dmach);
> -
> +                                       sdd->rx_dma.request, sdd->tx_dma.request);
>         pm_runtime_enable(&pdev->dev);
>
>         return 0;
> diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h
> index ceba18d..8447f63 100644
> --- a/include/linux/platform_data/spi-s3c64xx.h
> +++ b/include/linux/platform_data/spi-s3c64xx.h
> @@ -11,6 +11,8 @@
>  #ifndef __S3C64XX_PLAT_SPI_H
>  #define __S3C64XX_PLAT_SPI_H
>
> +#include <linux/dmaengine.h>
> +
>  struct platform_device;
>
>  /**
> @@ -38,6 +40,7 @@ struct s3c64xx_spi_info {
>         int src_clk_nr;
>         int num_cs;
>         int (*cfg_gpio)(void);
> +       dma_filter_fn filter;
>  };
>

This one also tested on exynos5250. It's working fine.

Thanks
Padma
>  /**
> --
> 1.8.1.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the linux-arm-kernel mailing list