aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-omap2-mcspi.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-04-23 08:51:48 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-07-31 07:06:24 -0400
commit53741ed8f0a3fc646576b6d7adf563f403ba6c03 (patch)
tree6124b0c1e9f453810961809c13f772ad0860e306 /drivers/spi/spi-omap2-mcspi.c
parent8a23fa1b95b2e3878c16dcc4e18976bc46dd970b (diff)
spi: omap2-mcspi: add DMA engine support
Add DMA engine support to the OMAP SPI driver. This supplements the private DMA API implementation contained within this driver, and the driver can be independently switched at build time between using DMA engine and the private DMA API for the transmit and receive sides. Tested-by: Shubhrajyoti <shubhrajyoti@ti.com> Acked-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/spi/spi-omap2-mcspi.c')
-rw-r--r--drivers/spi/spi-omap2-mcspi.c181
1 files changed, 150 insertions, 31 deletions
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 0c73dd4f43a0..9fdb7a9ae03f 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -20,6 +20,8 @@
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * 21 *
22 */ 22 */
23#define USE_DMA_ENGINE_RX
24#define USE_DMA_ENGINE_TX
23 25
24#include <linux/kernel.h> 26#include <linux/kernel.h>
25#include <linux/init.h> 27#include <linux/init.h>
@@ -28,6 +30,8 @@
28#include <linux/device.h> 30#include <linux/device.h>
29#include <linux/delay.h> 31#include <linux/delay.h>
30#include <linux/dma-mapping.h> 32#include <linux/dma-mapping.h>
33#include <linux/dmaengine.h>
34#include <linux/omap-dma.h>
31#include <linux/platform_device.h> 35#include <linux/platform_device.h>
32#include <linux/err.h> 36#include <linux/err.h>
33#include <linux/clk.h> 37#include <linux/clk.h>
@@ -93,6 +97,8 @@
93 97
94/* We have 2 DMA channels per CS, one for RX and one for TX */ 98/* We have 2 DMA channels per CS, one for RX and one for TX */
95struct omap2_mcspi_dma { 99struct omap2_mcspi_dma {
100 struct dma_chan *dma_tx;
101 struct dma_chan *dma_rx;
96 int dma_tx_channel; 102 int dma_tx_channel;
97 int dma_rx_channel; 103 int dma_rx_channel;
98 104
@@ -300,6 +306,30 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
300 return 0; 306 return 0;
301} 307}
302 308
309static void omap2_mcspi_rx_callback(void *data)
310{
311 struct spi_device *spi = data;
312 struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
313 struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
314
315 complete(&mcspi_dma->dma_rx_completion);
316
317 /* We must disable the DMA RX request */
318 omap2_mcspi_set_dma_req(spi, 1, 0);
319}
320
321static void omap2_mcspi_tx_callback(void *data)
322{
323 struct spi_device *spi = data;
324 struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
325 struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
326
327 complete(&mcspi_dma->dma_tx_completion);
328
329 /* We must disable the DMA TX request */
330 omap2_mcspi_set_dma_req(spi, 0, 0);
331}
332
303static unsigned 333static unsigned
304omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) 334omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
305{ 335{
@@ -314,6 +344,9 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
314 u8 * rx; 344 u8 * rx;
315 const u8 * tx; 345 const u8 * tx;
316 void __iomem *chstat_reg; 346 void __iomem *chstat_reg;
347 struct dma_slave_config cfg;
348 enum dma_slave_buswidth width;
349 unsigned es;
317 350
318 mcspi = spi_master_get_devdata(spi->master); 351 mcspi = spi_master_get_devdata(spi->master);
319 mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 352 mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -321,6 +354,71 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
321 354
322 chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; 355 chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
323 356
357 if (cs->word_len <= 8) {
358 width = DMA_SLAVE_BUSWIDTH_1_BYTE;
359 es = 1;
360 } else if (cs->word_len <= 16) {
361 width = DMA_SLAVE_BUSWIDTH_2_BYTES;
362 es = 2;
363 } else {
364 width = DMA_SLAVE_BUSWIDTH_4_BYTES;
365 es = 4;
366 }
367
368 memset(&cfg, 0, sizeof(cfg));
369 cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
370 cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
371 cfg.src_addr_width = width;
372 cfg.dst_addr_width = width;
373 cfg.src_maxburst = 1;
374 cfg.dst_maxburst = 1;
375
376 if (xfer->tx_buf && mcspi_dma->dma_tx) {
377 struct dma_async_tx_descriptor *tx;
378 struct scatterlist sg;
379
380 dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
381
382 sg_init_table(&sg, 1);
383 sg_dma_address(&sg) = xfer->tx_dma;
384 sg_dma_len(&sg) = xfer->len;
385
386 tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
387 DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
388 if (tx) {
389 tx->callback = omap2_mcspi_tx_callback;
390 tx->callback_param = spi;
391 dmaengine_submit(tx);
392 } else {
393 /* FIXME: fall back to PIO? */
394 }
395 }
396
397 if (xfer->rx_buf && mcspi_dma->dma_rx) {
398 struct dma_async_tx_descriptor *tx;
399 struct scatterlist sg;
400 size_t len = xfer->len - es;
401
402 dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
403
404 if (l & OMAP2_MCSPI_CHCONF_TURBO)
405 len -= es;
406
407 sg_init_table(&sg, 1);
408 sg_dma_address(&sg) = xfer->rx_dma;
409 sg_dma_len(&sg) = len;
410
411 tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
412 DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
413 if (tx) {
414 tx->callback = omap2_mcspi_rx_callback;
415 tx->callback_param = spi;
416 dmaengine_submit(tx);
417 } else {
418 /* FIXME: fall back to PIO? */
419 }
420 }
421
324 count = xfer->len; 422 count = xfer->len;
325 c = count; 423 c = count;
326 word_len = cs->word_len; 424 word_len = cs->word_len;
@@ -342,7 +440,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
342 element_count = count >> 2; 440 element_count = count >> 2;
343 } 441 }
344 442
345 if (tx != NULL) { 443 if (tx != NULL && mcspi_dma->dma_tx_channel != -1) {
346 omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel, 444 omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
347 data_type, element_count, 1, 445 data_type, element_count, 1,
348 OMAP_DMA_SYNC_ELEMENT, 446 OMAP_DMA_SYNC_ELEMENT,
@@ -357,7 +455,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
357 xfer->tx_dma, 0, 0); 455 xfer->tx_dma, 0, 0);
358 } 456 }
359 457
360 if (rx != NULL) { 458 if (rx != NULL && mcspi_dma->dma_rx_channel != -1) {
361 elements = element_count - 1; 459 elements = element_count - 1;
362 if (l & OMAP2_MCSPI_CHCONF_TURBO) 460 if (l & OMAP2_MCSPI_CHCONF_TURBO)
363 elements--; 461 elements--;
@@ -377,12 +475,18 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
377 } 475 }
378 476
379 if (tx != NULL) { 477 if (tx != NULL) {
380 omap_start_dma(mcspi_dma->dma_tx_channel); 478 if (mcspi_dma->dma_tx)
479 dma_async_issue_pending(mcspi_dma->dma_tx);
480 else
481 omap_start_dma(mcspi_dma->dma_tx_channel);
381 omap2_mcspi_set_dma_req(spi, 0, 1); 482 omap2_mcspi_set_dma_req(spi, 0, 1);
382 } 483 }
383 484
384 if (rx != NULL) { 485 if (rx != NULL) {
385 omap_start_dma(mcspi_dma->dma_rx_channel); 486 if (mcspi_dma->dma_rx)
487 dma_async_issue_pending(mcspi_dma->dma_rx);
488 else
489 omap_start_dma(mcspi_dma->dma_rx_channel);
386 omap2_mcspi_set_dma_req(spi, 1, 1); 490 omap2_mcspi_set_dma_req(spi, 1, 1);
387 } 491 }
388 492
@@ -406,7 +510,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
406 dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE); 510 dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE);
407 omap2_mcspi_set_enable(spi, 0); 511 omap2_mcspi_set_enable(spi, 0);
408 512
513 elements = element_count - 1;
514
409 if (l & OMAP2_MCSPI_CHCONF_TURBO) { 515 if (l & OMAP2_MCSPI_CHCONF_TURBO) {
516 elements--;
410 517
411 if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) 518 if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
412 & OMAP2_MCSPI_CHSTAT_RXS)) { 519 & OMAP2_MCSPI_CHSTAT_RXS)) {
@@ -725,32 +832,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
725 832
726static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data) 833static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
727{ 834{
728 struct spi_device *spi = data; 835 omap2_mcspi_rx_callback(data);
729 struct omap2_mcspi *mcspi;
730 struct omap2_mcspi_dma *mcspi_dma;
731
732 mcspi = spi_master_get_devdata(spi->master);
733 mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
734
735 complete(&mcspi_dma->dma_rx_completion);
736
737 /* We must disable the DMA RX request */
738 omap2_mcspi_set_dma_req(spi, 1, 0);
739} 836}
740 837
741static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data) 838static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
742{ 839{
743 struct spi_device *spi = data; 840 omap2_mcspi_tx_callback(data);
744 struct omap2_mcspi *mcspi;
745 struct omap2_mcspi_dma *mcspi_dma;
746
747 mcspi = spi_master_get_devdata(spi->master);
748 mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
749
750 complete(&mcspi_dma->dma_tx_completion);
751
752 /* We must disable the DMA TX request */
753 omap2_mcspi_set_dma_req(spi, 0, 0);
754} 841}
755 842
756static int omap2_mcspi_request_dma(struct spi_device *spi) 843static int omap2_mcspi_request_dma(struct spi_device *spi)
@@ -758,17 +845,43 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
758 struct spi_master *master = spi->master; 845 struct spi_master *master = spi->master;
759 struct omap2_mcspi *mcspi; 846 struct omap2_mcspi *mcspi;
760 struct omap2_mcspi_dma *mcspi_dma; 847 struct omap2_mcspi_dma *mcspi_dma;
848 dma_cap_mask_t mask;
849 unsigned sig;
761 850
762 mcspi = spi_master_get_devdata(master); 851 mcspi = spi_master_get_devdata(master);
763 mcspi_dma = mcspi->dma_channels + spi->chip_select; 852 mcspi_dma = mcspi->dma_channels + spi->chip_select;
764 853
854 init_completion(&mcspi_dma->dma_rx_completion);
855 init_completion(&mcspi_dma->dma_tx_completion);
856
857 dma_cap_zero(mask);
858 dma_cap_set(DMA_SLAVE, mask);
859#ifdef USE_DMA_ENGINE_RX
860 sig = mcspi_dma->dma_rx_sync_dev;
861 mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
862 if (!mcspi_dma->dma_rx) {
863 dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n");
864 return -EAGAIN;
865 }
866#else
765 if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX", 867 if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
766 omap2_mcspi_dma_rx_callback, spi, 868 omap2_mcspi_dma_rx_callback, spi,
767 &mcspi_dma->dma_rx_channel)) { 869 &mcspi_dma->dma_rx_channel)) {
768 dev_err(&spi->dev, "no RX DMA channel for McSPI\n"); 870 dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
769 return -EAGAIN; 871 return -EAGAIN;
770 } 872 }
873#endif
771 874
875#ifdef USE_DMA_ENGINE_TX
876 sig = mcspi_dma->dma_tx_sync_dev;
877 mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
878 if (!mcspi_dma->dma_tx) {
879 dev_err(&spi->dev, "no TX DMA engine channel for McSPI\n");
880 dma_release_channel(mcspi_dma->dma_rx);
881 mcspi_dma->dma_rx = NULL;
882 return -EAGAIN;
883 }
884#else
772 if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX", 885 if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
773 omap2_mcspi_dma_tx_callback, spi, 886 omap2_mcspi_dma_tx_callback, spi,
774 &mcspi_dma->dma_tx_channel)) { 887 &mcspi_dma->dma_tx_channel)) {
@@ -777,9 +890,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
777 dev_err(&spi->dev, "no TX DMA channel for McSPI\n"); 890 dev_err(&spi->dev, "no TX DMA channel for McSPI\n");
778 return -EAGAIN; 891 return -EAGAIN;
779 } 892 }
780 893#endif
781 init_completion(&mcspi_dma->dma_rx_completion);
782 init_completion(&mcspi_dma->dma_tx_completion);
783 894
784 return 0; 895 return 0;
785} 896}
@@ -812,8 +923,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
812 list_add_tail(&cs->node, &ctx->cs); 923 list_add_tail(&cs->node, &ctx->cs);
813 } 924 }
814 925
815 if (mcspi_dma->dma_rx_channel == -1 926 if ((!mcspi_dma->dma_rx && mcspi_dma->dma_rx_channel == -1) ||
816 || mcspi_dma->dma_tx_channel == -1) { 927 (!mcspi_dma->dma_tx && mcspi_dma->dma_tx_channel == -1)) {
817 ret = omap2_mcspi_request_dma(spi); 928 ret = omap2_mcspi_request_dma(spi);
818 if (ret < 0) 929 if (ret < 0)
819 return ret; 930 return ret;
@@ -848,6 +959,14 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
848 if (spi->chip_select < spi->master->num_chipselect) { 959 if (spi->chip_select < spi->master->num_chipselect) {
849 mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 960 mcspi_dma = &mcspi->dma_channels[spi->chip_select];
850 961
962 if (mcspi_dma->dma_rx) {
963 dma_release_channel(mcspi_dma->dma_rx);
964 mcspi_dma->dma_rx = NULL;
965 }
966 if (mcspi_dma->dma_tx) {
967 dma_release_channel(mcspi_dma->dma_tx);
968 mcspi_dma->dma_tx = NULL;
969 }
851 if (mcspi_dma->dma_rx_channel != -1) { 970 if (mcspi_dma->dma_rx_channel != -1) {
852 omap_free_dma(mcspi_dma->dma_rx_channel); 971 omap_free_dma(mcspi_dma->dma_rx_channel);
853 mcspi_dma->dma_rx_channel = -1; 972 mcspi_dma->dma_rx_channel = -1;