diff options
Diffstat (limited to 'drivers/spi/spi-omap2-mcspi.c')
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 181 |
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 */ |
95 | struct omap2_mcspi_dma { | 99 | struct 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 | ||
309 | static 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 | |||
321 | static 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 | |||
303 | static unsigned | 333 | static unsigned |
304 | omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) | 334 | omap2_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 | ||
726 | static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data) | 833 | static 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 | ||
741 | static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data) | 838 | static 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 | ||
756 | static int omap2_mcspi_request_dma(struct spi_device *spi) | 843 | static 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; |