Hi Arnd, On Tue, Mar 5, 2013 at 11:12 PM, Arnd Bergmann <arnd@xxxxxxxx> 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@xxxxxxxx> > --- > 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@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html