diff options
Diffstat (limited to 'drivers/spi/spi-omap2-mcspi.c')
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 229 |
1 files changed, 127 insertions, 102 deletions
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 7d46b15e1520..bc4778175e34 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/dma-mapping.h> | 30 | #include <linux/dma-mapping.h> |
31 | #include <linux/dmaengine.h> | ||
32 | #include <linux/omap-dma.h> | ||
31 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
32 | #include <linux/err.h> | 34 | #include <linux/err.h> |
33 | #include <linux/clk.h> | 35 | #include <linux/clk.h> |
@@ -39,7 +41,6 @@ | |||
39 | 41 | ||
40 | #include <linux/spi/spi.h> | 42 | #include <linux/spi/spi.h> |
41 | 43 | ||
42 | #include <plat/dma.h> | ||
43 | #include <plat/clock.h> | 44 | #include <plat/clock.h> |
44 | #include <plat/mcspi.h> | 45 | #include <plat/mcspi.h> |
45 | 46 | ||
@@ -93,8 +94,8 @@ | |||
93 | 94 | ||
94 | /* We have 2 DMA channels per CS, one for RX and one for TX */ | 95 | /* We have 2 DMA channels per CS, one for RX and one for TX */ |
95 | struct omap2_mcspi_dma { | 96 | struct omap2_mcspi_dma { |
96 | int dma_tx_channel; | 97 | struct dma_chan *dma_tx; |
97 | int dma_rx_channel; | 98 | struct dma_chan *dma_rx; |
98 | 99 | ||
99 | int dma_tx_sync_dev; | 100 | int dma_tx_sync_dev; |
100 | int dma_rx_sync_dev; | 101 | int dma_rx_sync_dev; |
@@ -300,20 +301,46 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) | |||
300 | return 0; | 301 | return 0; |
301 | } | 302 | } |
302 | 303 | ||
304 | static void omap2_mcspi_rx_callback(void *data) | ||
305 | { | ||
306 | struct spi_device *spi = data; | ||
307 | struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); | ||
308 | struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; | ||
309 | |||
310 | complete(&mcspi_dma->dma_rx_completion); | ||
311 | |||
312 | /* We must disable the DMA RX request */ | ||
313 | omap2_mcspi_set_dma_req(spi, 1, 0); | ||
314 | } | ||
315 | |||
316 | static void omap2_mcspi_tx_callback(void *data) | ||
317 | { | ||
318 | struct spi_device *spi = data; | ||
319 | struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); | ||
320 | struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; | ||
321 | |||
322 | complete(&mcspi_dma->dma_tx_completion); | ||
323 | |||
324 | /* We must disable the DMA TX request */ | ||
325 | omap2_mcspi_set_dma_req(spi, 0, 0); | ||
326 | } | ||
327 | |||
303 | static unsigned | 328 | static unsigned |
304 | omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) | 329 | omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) |
305 | { | 330 | { |
306 | struct omap2_mcspi *mcspi; | 331 | struct omap2_mcspi *mcspi; |
307 | struct omap2_mcspi_cs *cs = spi->controller_state; | 332 | struct omap2_mcspi_cs *cs = spi->controller_state; |
308 | struct omap2_mcspi_dma *mcspi_dma; | 333 | struct omap2_mcspi_dma *mcspi_dma; |
309 | unsigned int count, c; | 334 | unsigned int count; |
310 | unsigned long base, tx_reg, rx_reg; | 335 | int word_len, element_count; |
311 | int word_len, data_type, element_count; | ||
312 | int elements = 0; | 336 | int elements = 0; |
313 | u32 l; | 337 | u32 l; |
314 | u8 * rx; | 338 | u8 * rx; |
315 | const u8 * tx; | 339 | const u8 * tx; |
316 | void __iomem *chstat_reg; | 340 | void __iomem *chstat_reg; |
341 | struct dma_slave_config cfg; | ||
342 | enum dma_slave_buswidth width; | ||
343 | unsigned es; | ||
317 | 344 | ||
318 | mcspi = spi_master_get_devdata(spi->master); | 345 | mcspi = spi_master_get_devdata(spi->master); |
319 | mcspi_dma = &mcspi->dma_channels[spi->chip_select]; | 346 | mcspi_dma = &mcspi->dma_channels[spi->chip_select]; |
@@ -321,68 +348,92 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) | |||
321 | 348 | ||
322 | chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; | 349 | chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; |
323 | 350 | ||
351 | if (cs->word_len <= 8) { | ||
352 | width = DMA_SLAVE_BUSWIDTH_1_BYTE; | ||
353 | es = 1; | ||
354 | } else if (cs->word_len <= 16) { | ||
355 | width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
356 | es = 2; | ||
357 | } else { | ||
358 | width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
359 | es = 4; | ||
360 | } | ||
361 | |||
362 | memset(&cfg, 0, sizeof(cfg)); | ||
363 | cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; | ||
364 | cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; | ||
365 | cfg.src_addr_width = width; | ||
366 | cfg.dst_addr_width = width; | ||
367 | cfg.src_maxburst = 1; | ||
368 | cfg.dst_maxburst = 1; | ||
369 | |||
370 | if (xfer->tx_buf && mcspi_dma->dma_tx) { | ||
371 | struct dma_async_tx_descriptor *tx; | ||
372 | struct scatterlist sg; | ||
373 | |||
374 | dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); | ||
375 | |||
376 | sg_init_table(&sg, 1); | ||
377 | sg_dma_address(&sg) = xfer->tx_dma; | ||
378 | sg_dma_len(&sg) = xfer->len; | ||
379 | |||
380 | tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1, | ||
381 | DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
382 | if (tx) { | ||
383 | tx->callback = omap2_mcspi_tx_callback; | ||
384 | tx->callback_param = spi; | ||
385 | dmaengine_submit(tx); | ||
386 | } else { | ||
387 | /* FIXME: fall back to PIO? */ | ||
388 | } | ||
389 | } | ||
390 | |||
391 | if (xfer->rx_buf && mcspi_dma->dma_rx) { | ||
392 | struct dma_async_tx_descriptor *tx; | ||
393 | struct scatterlist sg; | ||
394 | size_t len = xfer->len - es; | ||
395 | |||
396 | dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); | ||
397 | |||
398 | if (l & OMAP2_MCSPI_CHCONF_TURBO) | ||
399 | len -= es; | ||
400 | |||
401 | sg_init_table(&sg, 1); | ||
402 | sg_dma_address(&sg) = xfer->rx_dma; | ||
403 | sg_dma_len(&sg) = len; | ||
404 | |||
405 | tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, | ||
406 | DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
407 | if (tx) { | ||
408 | tx->callback = omap2_mcspi_rx_callback; | ||
409 | tx->callback_param = spi; | ||
410 | dmaengine_submit(tx); | ||
411 | } else { | ||
412 | /* FIXME: fall back to PIO? */ | ||
413 | } | ||
414 | } | ||
415 | |||
324 | count = xfer->len; | 416 | count = xfer->len; |
325 | c = count; | ||
326 | word_len = cs->word_len; | 417 | word_len = cs->word_len; |
327 | 418 | ||
328 | base = cs->phys; | ||
329 | tx_reg = base + OMAP2_MCSPI_TX0; | ||
330 | rx_reg = base + OMAP2_MCSPI_RX0; | ||
331 | rx = xfer->rx_buf; | 419 | rx = xfer->rx_buf; |
332 | tx = xfer->tx_buf; | 420 | tx = xfer->tx_buf; |
333 | 421 | ||
334 | if (word_len <= 8) { | 422 | if (word_len <= 8) { |
335 | data_type = OMAP_DMA_DATA_TYPE_S8; | ||
336 | element_count = count; | 423 | element_count = count; |
337 | } else if (word_len <= 16) { | 424 | } else if (word_len <= 16) { |
338 | data_type = OMAP_DMA_DATA_TYPE_S16; | ||
339 | element_count = count >> 1; | 425 | element_count = count >> 1; |
340 | } else /* word_len <= 32 */ { | 426 | } else /* word_len <= 32 */ { |
341 | data_type = OMAP_DMA_DATA_TYPE_S32; | ||
342 | element_count = count >> 2; | 427 | element_count = count >> 2; |
343 | } | 428 | } |
344 | 429 | ||
345 | if (tx != NULL) { | 430 | if (tx != NULL) { |
346 | omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel, | 431 | dma_async_issue_pending(mcspi_dma->dma_tx); |
347 | data_type, element_count, 1, | ||
348 | OMAP_DMA_SYNC_ELEMENT, | ||
349 | mcspi_dma->dma_tx_sync_dev, 0); | ||
350 | |||
351 | omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0, | ||
352 | OMAP_DMA_AMODE_CONSTANT, | ||
353 | tx_reg, 0, 0); | ||
354 | |||
355 | omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0, | ||
356 | OMAP_DMA_AMODE_POST_INC, | ||
357 | xfer->tx_dma, 0, 0); | ||
358 | } | ||
359 | |||
360 | if (rx != NULL) { | ||
361 | elements = element_count - 1; | ||
362 | if (l & OMAP2_MCSPI_CHCONF_TURBO) | ||
363 | elements--; | ||
364 | |||
365 | omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel, | ||
366 | data_type, elements, 1, | ||
367 | OMAP_DMA_SYNC_ELEMENT, | ||
368 | mcspi_dma->dma_rx_sync_dev, 1); | ||
369 | |||
370 | omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0, | ||
371 | OMAP_DMA_AMODE_CONSTANT, | ||
372 | rx_reg, 0, 0); | ||
373 | |||
374 | omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0, | ||
375 | OMAP_DMA_AMODE_POST_INC, | ||
376 | xfer->rx_dma, 0, 0); | ||
377 | } | ||
378 | |||
379 | if (tx != NULL) { | ||
380 | omap_start_dma(mcspi_dma->dma_tx_channel); | ||
381 | omap2_mcspi_set_dma_req(spi, 0, 1); | 432 | omap2_mcspi_set_dma_req(spi, 0, 1); |
382 | } | 433 | } |
383 | 434 | ||
384 | if (rx != NULL) { | 435 | if (rx != NULL) { |
385 | omap_start_dma(mcspi_dma->dma_rx_channel); | 436 | dma_async_issue_pending(mcspi_dma->dma_rx); |
386 | omap2_mcspi_set_dma_req(spi, 1, 1); | 437 | omap2_mcspi_set_dma_req(spi, 1, 1); |
387 | } | 438 | } |
388 | 439 | ||
@@ -408,7 +459,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) | |||
408 | DMA_FROM_DEVICE); | 459 | DMA_FROM_DEVICE); |
409 | omap2_mcspi_set_enable(spi, 0); | 460 | omap2_mcspi_set_enable(spi, 0); |
410 | 461 | ||
462 | elements = element_count - 1; | ||
463 | |||
411 | if (l & OMAP2_MCSPI_CHCONF_TURBO) { | 464 | if (l & OMAP2_MCSPI_CHCONF_TURBO) { |
465 | elements--; | ||
412 | 466 | ||
413 | if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) | 467 | if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) |
414 | & OMAP2_MCSPI_CHSTAT_RXS)) { | 468 | & OMAP2_MCSPI_CHSTAT_RXS)) { |
@@ -725,64 +779,38 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, | |||
725 | return 0; | 779 | return 0; |
726 | } | 780 | } |
727 | 781 | ||
728 | static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data) | ||
729 | { | ||
730 | struct spi_device *spi = data; | ||
731 | struct omap2_mcspi *mcspi; | ||
732 | struct omap2_mcspi_dma *mcspi_dma; | ||
733 | |||
734 | mcspi = spi_master_get_devdata(spi->master); | ||
735 | mcspi_dma = &(mcspi->dma_channels[spi->chip_select]); | ||
736 | |||
737 | complete(&mcspi_dma->dma_rx_completion); | ||
738 | |||
739 | /* We must disable the DMA RX request */ | ||
740 | omap2_mcspi_set_dma_req(spi, 1, 0); | ||
741 | } | ||
742 | |||
743 | static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data) | ||
744 | { | ||
745 | struct spi_device *spi = data; | ||
746 | struct omap2_mcspi *mcspi; | ||
747 | struct omap2_mcspi_dma *mcspi_dma; | ||
748 | |||
749 | mcspi = spi_master_get_devdata(spi->master); | ||
750 | mcspi_dma = &(mcspi->dma_channels[spi->chip_select]); | ||
751 | |||
752 | complete(&mcspi_dma->dma_tx_completion); | ||
753 | |||
754 | /* We must disable the DMA TX request */ | ||
755 | omap2_mcspi_set_dma_req(spi, 0, 0); | ||
756 | } | ||
757 | |||
758 | static int omap2_mcspi_request_dma(struct spi_device *spi) | 782 | static int omap2_mcspi_request_dma(struct spi_device *spi) |
759 | { | 783 | { |
760 | struct spi_master *master = spi->master; | 784 | struct spi_master *master = spi->master; |
761 | struct omap2_mcspi *mcspi; | 785 | struct omap2_mcspi *mcspi; |
762 | struct omap2_mcspi_dma *mcspi_dma; | 786 | struct omap2_mcspi_dma *mcspi_dma; |
787 | dma_cap_mask_t mask; | ||
788 | unsigned sig; | ||
763 | 789 | ||
764 | mcspi = spi_master_get_devdata(master); | 790 | mcspi = spi_master_get_devdata(master); |
765 | mcspi_dma = mcspi->dma_channels + spi->chip_select; | 791 | mcspi_dma = mcspi->dma_channels + spi->chip_select; |
766 | 792 | ||
767 | if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX", | 793 | init_completion(&mcspi_dma->dma_rx_completion); |
768 | omap2_mcspi_dma_rx_callback, spi, | 794 | init_completion(&mcspi_dma->dma_tx_completion); |
769 | &mcspi_dma->dma_rx_channel)) { | 795 | |
770 | dev_err(&spi->dev, "no RX DMA channel for McSPI\n"); | 796 | dma_cap_zero(mask); |
797 | dma_cap_set(DMA_SLAVE, mask); | ||
798 | sig = mcspi_dma->dma_rx_sync_dev; | ||
799 | mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); | ||
800 | if (!mcspi_dma->dma_rx) { | ||
801 | dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n"); | ||
771 | return -EAGAIN; | 802 | return -EAGAIN; |
772 | } | 803 | } |
773 | 804 | ||
774 | if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX", | 805 | sig = mcspi_dma->dma_tx_sync_dev; |
775 | omap2_mcspi_dma_tx_callback, spi, | 806 | mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); |
776 | &mcspi_dma->dma_tx_channel)) { | 807 | if (!mcspi_dma->dma_tx) { |
777 | omap_free_dma(mcspi_dma->dma_rx_channel); | 808 | dev_err(&spi->dev, "no TX DMA engine channel for McSPI\n"); |
778 | mcspi_dma->dma_rx_channel = -1; | 809 | dma_release_channel(mcspi_dma->dma_rx); |
779 | dev_err(&spi->dev, "no TX DMA channel for McSPI\n"); | 810 | mcspi_dma->dma_rx = NULL; |
780 | return -EAGAIN; | 811 | return -EAGAIN; |
781 | } | 812 | } |
782 | 813 | ||
783 | init_completion(&mcspi_dma->dma_rx_completion); | ||
784 | init_completion(&mcspi_dma->dma_tx_completion); | ||
785 | |||
786 | return 0; | 814 | return 0; |
787 | } | 815 | } |
788 | 816 | ||
@@ -814,8 +842,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) | |||
814 | list_add_tail(&cs->node, &ctx->cs); | 842 | list_add_tail(&cs->node, &ctx->cs); |
815 | } | 843 | } |
816 | 844 | ||
817 | if (mcspi_dma->dma_rx_channel == -1 | 845 | if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) { |
818 | || mcspi_dma->dma_tx_channel == -1) { | ||
819 | ret = omap2_mcspi_request_dma(spi); | 846 | ret = omap2_mcspi_request_dma(spi); |
820 | if (ret < 0) | 847 | if (ret < 0) |
821 | return ret; | 848 | return ret; |
@@ -850,13 +877,13 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) | |||
850 | if (spi->chip_select < spi->master->num_chipselect) { | 877 | if (spi->chip_select < spi->master->num_chipselect) { |
851 | mcspi_dma = &mcspi->dma_channels[spi->chip_select]; | 878 | mcspi_dma = &mcspi->dma_channels[spi->chip_select]; |
852 | 879 | ||
853 | if (mcspi_dma->dma_rx_channel != -1) { | 880 | if (mcspi_dma->dma_rx) { |
854 | omap_free_dma(mcspi_dma->dma_rx_channel); | 881 | dma_release_channel(mcspi_dma->dma_rx); |
855 | mcspi_dma->dma_rx_channel = -1; | 882 | mcspi_dma->dma_rx = NULL; |
856 | } | 883 | } |
857 | if (mcspi_dma->dma_tx_channel != -1) { | 884 | if (mcspi_dma->dma_tx) { |
858 | omap_free_dma(mcspi_dma->dma_tx_channel); | 885 | dma_release_channel(mcspi_dma->dma_tx); |
859 | mcspi_dma->dma_tx_channel = -1; | 886 | mcspi_dma->dma_tx = NULL; |
860 | } | 887 | } |
861 | } | 888 | } |
862 | } | 889 | } |
@@ -1176,7 +1203,6 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) | |||
1176 | break; | 1203 | break; |
1177 | } | 1204 | } |
1178 | 1205 | ||
1179 | mcspi->dma_channels[i].dma_rx_channel = -1; | ||
1180 | mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start; | 1206 | mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start; |
1181 | sprintf(dma_ch_name, "tx%d", i); | 1207 | sprintf(dma_ch_name, "tx%d", i); |
1182 | dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, | 1208 | dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, |
@@ -1187,7 +1213,6 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev) | |||
1187 | break; | 1213 | break; |
1188 | } | 1214 | } |
1189 | 1215 | ||
1190 | mcspi->dma_channels[i].dma_tx_channel = -1; | ||
1191 | mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; | 1216 | mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; |
1192 | } | 1217 | } |
1193 | 1218 | ||