- struct scatterlist sg, sg_dummy;
- void *dummy = NULL, *rx_buf = NULL;
- struct dma_async_tx_descriptor *desc, *desc_dummy;
- unsigned int len;
- int ret = 0;
-
- if (rspi->dma_width_16bit) {
- /*
- * If DMAC bus width is 16-bit, the driver allocates a dummy
- * buffer. And, finally the driver converts the DMAC data into
- * actual data as the following format:
- * DMAC data: 1st byte, dummy, 2nd byte, dummy ...
- * actual data: 1st byte, 2nd byte ...
- */
- len = t->len * 2;
- rx_buf = kmalloc(len, GFP_KERNEL);
- if (!rx_buf)
- return -ENOMEM;
- } else {
- len = t->len;
- rx_buf = t->rx_buf;
- }
-
- /* prepare dummy transfer to generate SPI clocks */
- dummy = kzalloc(len, GFP_KERNEL);
- if (!dummy) {
- ret = -ENOMEM;
- goto end_nomap;
- }
- if (!rspi_dma_map_sg(&sg_dummy, dummy, len, rspi->chan_tx,
- DMA_TO_DEVICE)) {
- ret = -EFAULT;
- goto end_nomap;
- }
- desc_dummy = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_dummy, 1,
- DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_dummy) {
- ret = -EIO;
- goto end_dummy_mapped;
- }
-
- /* prepare receive transfer */
- if (!rspi_dma_map_sg(&sg, rx_buf, len, rspi->chan_rx,
- DMA_FROM_DEVICE)) {
- ret = -EFAULT;
- goto end_dummy_mapped;
-
- }
- desc = dmaengine_prep_slave_sg(rspi->chan_rx, &sg, 1, DMA_FROM_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc) {
- ret = -EIO;
- goto end;
- }
-
- rspi_receive_init(rspi);
-
- /*
- * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
- * called. So, this driver disables the IRQ while DMA transfer.
- */
- disable_irq(rspi->tx_irq);
- if (rspi->rx_irq != rspi->tx_irq)
- disable_irq(rspi->rx_irq);
-
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
- rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
- rspi->dma_callbacked = 0;
-
- desc->callback = rspi_dma_complete;
- desc->callback_param = rspi;
- dmaengine_submit(desc);
- dma_async_issue_pending(rspi->chan_rx);
-
- desc_dummy->callback = NULL; /* No callback */
- dmaengine_submit(desc_dummy);
- dma_async_issue_pending(rspi->chan_tx);
-
- ret = wait_event_interruptible_timeout(rspi->wait,
- rspi->dma_callbacked, HZ);
- if (ret > 0 && rspi->dma_callbacked)
- ret = 0;
- else if (!ret)
- ret = -ETIMEDOUT;
- rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
-
- enable_irq(rspi->tx_irq);
- if (rspi->rx_irq != rspi->tx_irq)
- enable_irq(rspi->rx_irq);
-
-end:
- rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
-end_dummy_mapped:
- rspi_dma_unmap_sg(&sg_dummy, rspi->chan_tx, DMA_TO_DEVICE);
-end_nomap:
- if (rspi->dma_width_16bit) {
- if (!ret)
- rspi_memory_from_8bit(t->rx_buf, rx_buf, t->len);
- kfree(rx_buf);
- }
- kfree(dummy);
-
- return ret;