linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: arnd@arndb.de (Arnd Bergmann)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 15/23] spi: s3c64xx: move to generic dmaengine API
Date: Tue,  5 Mar 2013 18:42:25 +0100	[thread overview]
Message-ID: <1362505353-8873-16-git-send-email-arnd@arndb.de> (raw)
In-Reply-To: <1362505353-8873-1-git-send-email-arnd@arndb.de>

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@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;
 };
 
 /**
-- 
1.8.1.2

  parent reply	other threads:[~2013-03-05 17:42 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-05 17:42 [PATCH 00/23] RFC: exynos multiplatform support Arnd Bergmann
2013-03-05 17:42 ` [PATCH 01/23] ARM: exynos: introduce EXYNOS_ATAGS symbol Arnd Bergmann
2013-03-05 17:42 ` [PATCH 02/23] irqchip: exynos: remove dependency on mach/irqs.h Arnd Bergmann
2013-03-05 17:42 ` [PATCH 03/23] tty: serial/samsung: prepare for common clock API Arnd Bergmann
2013-03-05 17:42 ` [PATCH 04/23] tty: serial/samsung: make register definitions global Arnd Bergmann
2013-03-05 17:42 ` [PATCH 05/23] tty: serial/samsung: fix modular build Arnd Bergmann
2013-03-05 17:42 ` [PATCH 06/23] ARM: exynos: move debug-macro.S to include/debug/ Arnd Bergmann
2013-03-05 17:42 ` [PATCH 07/23] i2c: s3c2410: make header file local Arnd Bergmann
2013-04-02 20:36   ` Heiko Stübner
2013-03-05 17:42 ` [PATCH 08/23] mmc: sdhci-s3c: remove platform dependencies Arnd Bergmann
2013-03-05 17:42 ` [PATCH 09/23] usb: exynos: do not include plat/usb-phy.h Arnd Bergmann
2013-03-05 17:42 ` [PATCH 10/23] [media] exynos: remove unnecessary header inclusions Arnd Bergmann
2013-04-02 13:08   ` Sylwester Nawrocki
2013-03-05 17:42 ` [PATCH 11/23] video/exynos: " Arnd Bergmann
2013-03-05 17:42 ` [PATCH 12/23] thermal/exynos: " Arnd Bergmann
2013-03-05 17:42 ` [PATCH 13/23] mtd: onenand/samsung: make regs-onenand.h file local Arnd Bergmann
2013-03-05 17:42 ` [PATCH 14/23] rtc: s3c: make header " Arnd Bergmann
2013-03-05 17:42 ` Arnd Bergmann [this message]
2013-03-06  9:14   ` [PATCH 15/23] spi: s3c64xx: move to generic dmaengine API Padma Venkat
2013-03-05 17:42 ` [PATCH 16/23] pwm: samsung: repair the worst MMIO abuses Arnd Bergmann
2013-03-05 17:42 ` [PATCH 17/23] ASoC: samsung: move plat/ headers to local directory Arnd Bergmann
2013-03-05 17:42 ` [PATCH 18/23] ASoC: samsung: convert to dmaengine API Arnd Bergmann
2013-03-06  8:58   ` Padma Venkat
2013-03-06 12:01     ` Arnd Bergmann
2013-03-05 17:42 ` [PATCH 19/23] ASoC: samsung: use irq resource for idma Arnd Bergmann
2013-03-05 17:42 ` [PATCH 20/23] ARM: exynos: prepare for sparse IRQ Arnd Bergmann
2013-03-05 17:42 ` [PATCH 21/23] ARM: exynos: hack to disable private clock code Arnd Bergmann
2013-03-05 17:42 ` [PATCH 22/23] ARM: exynos: work around missing gpio code on multiplatform Arnd Bergmann
2013-03-05 17:42 ` [PATCH 23/23] ARM: exynos: experimental multiplatform support Arnd Bergmann
2013-03-05 18:27 ` [PATCH 00/23] RFC: exynos " Tony Lindgren
2013-03-05 18:28 ` Tomasz Figa
2013-03-05 19:19   ` Arnd Bergmann
2013-03-05 22:48     ` Tomasz Figa
2013-03-06 10:50       ` Arnd Bergmann
2013-03-06 12:34         ` Thierry Reding
2013-03-06 22:57           ` Tomasz Figa
2013-03-07  3:02           ` Arnd Bergmann
2013-03-07  7:22             ` Thierry Reding
2013-03-08  0:40               ` Tomasz Figa
2013-03-08 12:52                 ` Arnd Bergmann
2013-03-06 22:14       ` Heiko Stübner
2013-03-06 22:55         ` Tomasz Figa
2013-03-05 20:50 ` Heiko Stübner
2013-03-05 21:24   ` Arnd Bergmann
2013-03-05 21:54     ` Arnd Bergmann
2013-03-05 22:12       ` Tomasz Figa
2013-03-05 22:21         ` Arnd Bergmann
2013-03-05 22:25       ` Heiko Stübner
2013-03-05 22:43         ` Arnd Bergmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1362505353-8873-16-git-send-email-arnd@arndb.de \
    --to=arnd@arndb.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).