Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: s3c64xx: move to generic dmaengine API

The spi-s3c64xx uses a Samsung proprietary interface for
talking to the DMA engine, which does not work with
multiplatform kernels.

This version of the patch leaves the old code in place,
behind an #ifdef. This can be removed in the future,
after the s3c64xx platform start supporting the regular
dmaengine interface. An earlier version of this patch was
tested successfully on exynos5250 by Padma Venkat.

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>

authored by

Arnd Bergmann and committed by
Mark Brown
78843727 6b8cc330

+154 -44
+10
arch/arm/plat-samsung/devs.c
··· 10 10 * published by the Free Software Foundation. 11 11 */ 12 12 13 + #include <linux/amba/pl330.h> 13 14 #include <linux/kernel.h> 14 15 #include <linux/types.h> 15 16 #include <linux/interrupt.h> ··· 1553 1552 pd.num_cs = num_cs; 1554 1553 pd.src_clk_nr = src_clk_nr; 1555 1554 pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio; 1555 + #ifdef CONFIG_PL330_DMA 1556 + pd.filter = pl330_filter; 1557 + #endif 1556 1558 1557 1559 s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0); 1558 1560 } ··· 1594 1590 pd.num_cs = num_cs; 1595 1591 pd.src_clk_nr = src_clk_nr; 1596 1592 pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio; 1593 + #ifdef CONFIG_PL330_DMA 1594 + pd.filter = pl330_filter; 1595 + #endif 1597 1596 1598 1597 s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1); 1599 1598 } ··· 1635 1628 pd.num_cs = num_cs; 1636 1629 pd.src_clk_nr = src_clk_nr; 1637 1630 pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio; 1631 + #ifdef CONFIG_PL330_DMA 1632 + pd.filter = pl330_filter; 1633 + #endif 1638 1634 1639 1635 s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2); 1640 1636 }
+141 -44
drivers/spi/spi-s3c64xx.c
··· 24 24 #include <linux/delay.h> 25 25 #include <linux/clk.h> 26 26 #include <linux/dma-mapping.h> 27 + #include <linux/dmaengine.h> 27 28 #include <linux/platform_device.h> 28 29 #include <linux/pm_runtime.h> 29 30 #include <linux/spi/spi.h> ··· 32 31 #include <linux/of.h> 33 32 #include <linux/of_gpio.h> 34 33 35 - #include <mach/dma.h> 36 34 #include <linux/platform_data/spi-s3c64xx.h> 35 + 36 + #ifdef CONFIG_SAMSUNG_DMADEV 37 + #include <mach/dma.h> 38 + #endif 37 39 38 40 #define MAX_SPI_PORTS 3 39 41 ··· 135 131 #define TXBUSY (1<<3) 136 132 137 133 struct s3c64xx_spi_dma_data { 138 - unsigned ch; 134 + struct dma_chan *ch; 139 135 enum dma_transfer_direction direction; 140 - enum dma_ch dmach; 136 + unsigned int dmach; 141 137 }; 142 138 143 139 /** ··· 199 195 unsigned cur_speed; 200 196 struct s3c64xx_spi_dma_data rx_dma; 201 197 struct s3c64xx_spi_dma_data tx_dma; 198 + #ifdef CONFIG_SAMSUNG_DMADEV 202 199 struct samsung_dma_ops *ops; 200 + #endif 203 201 struct s3c64xx_spi_port_config *port_conf; 204 202 unsigned int port_id; 205 203 unsigned long gpios[4]; 206 - }; 207 - 208 - static struct s3c2410_dma_client s3c64xx_spi_dma_client = { 209 - .name = "samsung-spi-dma", 210 204 }; 211 205 212 206 static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) ··· 283 281 spin_unlock_irqrestore(&sdd->lock, flags); 284 282 } 285 283 284 + #ifdef CONFIG_SAMSUNG_DMADEV 285 + /* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */ 286 + 287 + static struct s3c2410_dma_client s3c64xx_spi_dma_client = { 288 + .name = "samsung-spi-dma", 289 + }; 290 + 286 291 static void prepare_dma(struct s3c64xx_spi_dma_data *dma, 287 292 unsigned len, dma_addr_t buf) 288 293 { ··· 303 294 config.direction = sdd->rx_dma.direction; 304 295 config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; 305 296 config.width = sdd->cur_bpw / 8; 306 - sdd->ops->config(sdd->rx_dma.ch, &config); 297 + sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config); 307 298 } else { 308 299 sdd = container_of((void *)dma, 309 300 struct s3c64xx_spi_driver_data, tx_dma); 310 301 config.direction = sdd->tx_dma.direction; 311 302 config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; 312 303 config.width = sdd->cur_bpw / 8; 313 - sdd->ops->config(sdd->tx_dma.ch, &config); 304 + sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config); 314 305 } 315 306 316 307 info.cap = DMA_SLAVE; ··· 320 311 info.direction = dma->direction; 321 312 info.buf = buf; 322 313 323 - sdd->ops->prepare(dma->ch, &info); 324 - sdd->ops->trigger(dma->ch); 314 + sdd->ops->prepare((enum dma_ch)dma->ch, &info); 315 + sdd->ops->trigger((enum dma_ch)dma->ch); 325 316 } 326 317 327 318 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) ··· 334 325 req.cap = DMA_SLAVE; 335 326 req.client = &s3c64xx_spi_dma_client; 336 327 337 - sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx"); 338 - sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx"); 328 + sdd->rx_dma.ch = (void *)sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx"); 329 + sdd->tx_dma.ch = (void *)sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx"); 339 330 340 331 return 1; 341 332 } 333 + 334 + static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) 335 + { 336 + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); 337 + 338 + /* Acquire DMA channels */ 339 + while (!acquire_dma(sdd)) 340 + usleep_range(10000, 11000); 341 + 342 + pm_runtime_get_sync(&sdd->pdev->dev); 343 + 344 + return 0; 345 + } 346 + 347 + static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) 348 + { 349 + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); 350 + 351 + /* Free DMA channels */ 352 + sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, &s3c64xx_spi_dma_client); 353 + sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, &s3c64xx_spi_dma_client); 354 + 355 + pm_runtime_put(&sdd->pdev->dev); 356 + 357 + return 0; 358 + } 359 + 360 + static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, 361 + struct s3c64xx_spi_dma_data *dma) 362 + { 363 + sdd->ops->stop((enum dma_ch)dma->ch); 364 + } 365 + #else 366 + 367 + static void prepare_dma(struct s3c64xx_spi_dma_data *dma, 368 + unsigned len, dma_addr_t buf) 369 + { 370 + struct s3c64xx_spi_driver_data *sdd; 371 + struct dma_slave_config config; 372 + struct scatterlist sg; 373 + struct dma_async_tx_descriptor *desc; 374 + 375 + if (dma->direction == DMA_DEV_TO_MEM) { 376 + sdd = container_of((void *)dma, 377 + struct s3c64xx_spi_driver_data, rx_dma); 378 + config.direction = dma->direction; 379 + config.src_addr = sdd->sfr_start + S3C64XX_SPI_RX_DATA; 380 + config.src_addr_width = sdd->cur_bpw / 8; 381 + config.src_maxburst = 1; 382 + dmaengine_slave_config(dma->ch, &config); 383 + } else { 384 + sdd = container_of((void *)dma, 385 + struct s3c64xx_spi_driver_data, tx_dma); 386 + config.direction = dma->direction; 387 + config.dst_addr = sdd->sfr_start + S3C64XX_SPI_TX_DATA; 388 + config.dst_addr_width = sdd->cur_bpw / 8; 389 + config.dst_maxburst = 1; 390 + dmaengine_slave_config(dma->ch, &config); 391 + } 392 + 393 + sg_init_table(&sg, 1); 394 + sg_dma_len(&sg) = len; 395 + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)), 396 + len, offset_in_page(buf)); 397 + sg_dma_address(&sg) = buf; 398 + 399 + desc = dmaengine_prep_slave_sg(dma->ch, 400 + &sg, 1, dma->direction, DMA_PREP_INTERRUPT); 401 + 402 + desc->callback = s3c64xx_spi_dmacb; 403 + desc->callback_param = dma; 404 + 405 + dmaengine_submit(desc); 406 + dma_async_issue_pending(dma->ch); 407 + } 408 + 409 + static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) 410 + { 411 + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); 412 + dma_filter_fn filter = sdd->cntrlr_info->filter; 413 + struct device *dev = &sdd->pdev->dev; 414 + dma_cap_mask_t mask; 415 + 416 + dma_cap_zero(mask); 417 + dma_cap_set(DMA_SLAVE, mask); 418 + 419 + /* Acquire DMA channels */ 420 + sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter, 421 + (void*)sdd->rx_dma.dmach, dev, "rx"); 422 + sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter, 423 + (void*)sdd->tx_dma.dmach, dev, "tx"); 424 + pm_runtime_get_sync(&sdd->pdev->dev); 425 + 426 + return 0; 427 + } 428 + 429 + static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) 430 + { 431 + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); 432 + 433 + /* Free DMA channels */ 434 + dma_release_channel(sdd->rx_dma.ch); 435 + dma_release_channel(sdd->tx_dma.ch); 436 + 437 + pm_runtime_put(&sdd->pdev->dev); 438 + return 0; 439 + } 440 + 441 + static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, 442 + struct s3c64xx_spi_dma_data *dma) 443 + { 444 + dmaengine_terminate_all(dma->ch); 445 + } 446 + #endif 342 447 343 448 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, 344 449 struct spi_device *spi, ··· 836 713 } 837 714 838 715 /* Polling method for xfers not bigger than FIFO capacity */ 839 - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) 840 - use_dma = 0; 841 - else 716 + use_dma = 0; 717 + if (sdd->rx_dma.ch && sdd->tx_dma.ch && 718 + (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1))) 842 719 use_dma = 1; 843 720 844 721 spin_lock_irqsave(&sdd->lock, flags); ··· 873 750 if (use_dma) { 874 751 if (xfer->tx_buf != NULL 875 752 && (sdd->state & TXBUSY)) 876 - sdd->ops->stop(sdd->tx_dma.ch); 753 + s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); 877 754 if (xfer->rx_buf != NULL 878 755 && (sdd->state & RXBUSY)) 879 - sdd->ops->stop(sdd->rx_dma.ch); 756 + s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); 880 757 } 881 758 882 759 goto out; ··· 909 786 msg->status = status; 910 787 911 788 spi_finalize_current_message(master); 912 - 913 - return 0; 914 - } 915 - 916 - static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) 917 - { 918 - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); 919 - 920 - /* Acquire DMA channels */ 921 - while (!acquire_dma(sdd)) 922 - usleep_range(10000, 11000); 923 - 924 - pm_runtime_get_sync(&sdd->pdev->dev); 925 - 926 - return 0; 927 - } 928 - 929 - static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) 930 - { 931 - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); 932 - 933 - /* Free DMA channels */ 934 - sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client); 935 - sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client); 936 - 937 - pm_runtime_put(&sdd->pdev->dev); 938 789 939 790 return 0; 940 791 }
+3
include/linux/platform_data/spi-s3c64xx.h
··· 11 11 #ifndef __S3C64XX_PLAT_SPI_H 12 12 #define __S3C64XX_PLAT_SPI_H 13 13 14 + #include <linux/dmaengine.h> 15 + 14 16 struct platform_device; 15 17 16 18 /** ··· 40 38 int src_clk_nr; 41 39 int num_cs; 42 40 int (*cfg_gpio)(void); 41 + dma_filter_fn filter; 43 42 }; 44 43 45 44 /**