diff options
| -rw-r--r-- | drivers/spi/spi-rspi.c | 94 |
1 files changed, 58 insertions, 36 deletions
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index c850dfdfa9e3..ad87a98f8f68 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c | |||
| @@ -472,25 +472,52 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, | |||
| 472 | dma_cookie_t cookie; | 472 | dma_cookie_t cookie; |
| 473 | int ret; | 473 | int ret; |
| 474 | 474 | ||
| 475 | if (tx) { | 475 | /* First prepare and submit the DMA request(s), as this may fail */ |
| 476 | desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, | ||
| 477 | tx->sgl, tx->nents, DMA_TO_DEVICE, | ||
| 478 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
| 479 | if (!desc_tx) | ||
| 480 | goto no_dma; | ||
| 481 | |||
| 482 | irq_mask |= SPCR_SPTIE; | ||
| 483 | } | ||
| 484 | if (rx) { | 476 | if (rx) { |
| 485 | desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, | 477 | desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, |
| 486 | rx->sgl, rx->nents, DMA_FROM_DEVICE, | 478 | rx->sgl, rx->nents, DMA_FROM_DEVICE, |
| 487 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | 479 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
| 488 | if (!desc_rx) | 480 | if (!desc_rx) { |
| 489 | goto no_dma; | 481 | ret = -EAGAIN; |
| 482 | goto no_dma_rx; | ||
| 483 | } | ||
| 484 | |||
| 485 | desc_rx->callback = rspi_dma_complete; | ||
| 486 | desc_rx->callback_param = rspi; | ||
| 487 | cookie = dmaengine_submit(desc_rx); | ||
| 488 | if (dma_submit_error(cookie)) { | ||
| 489 | ret = cookie; | ||
| 490 | goto no_dma_rx; | ||
| 491 | } | ||
| 490 | 492 | ||
| 491 | irq_mask |= SPCR_SPRIE; | 493 | irq_mask |= SPCR_SPRIE; |
| 492 | } | 494 | } |
| 493 | 495 | ||
| 496 | if (tx) { | ||
| 497 | desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, | ||
| 498 | tx->sgl, tx->nents, DMA_TO_DEVICE, | ||
| 499 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
| 500 | if (!desc_tx) { | ||
| 501 | ret = -EAGAIN; | ||
| 502 | goto no_dma_tx; | ||
| 503 | } | ||
| 504 | |||
| 505 | if (rx) { | ||
| 506 | /* No callback */ | ||
| 507 | desc_tx->callback = NULL; | ||
| 508 | } else { | ||
| 509 | desc_tx->callback = rspi_dma_complete; | ||
| 510 | desc_tx->callback_param = rspi; | ||
| 511 | } | ||
| 512 | cookie = dmaengine_submit(desc_tx); | ||
| 513 | if (dma_submit_error(cookie)) { | ||
| 514 | ret = cookie; | ||
| 515 | goto no_dma_tx; | ||
| 516 | } | ||
| 517 | |||
| 518 | irq_mask |= SPCR_SPTIE; | ||
| 519 | } | ||
| 520 | |||
| 494 | /* | 521 | /* |
| 495 | * DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be | 522 | * DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be |
| 496 | * called. So, this driver disables the IRQ while DMA transfer. | 523 | * called. So, this driver disables the IRQ while DMA transfer. |
| @@ -503,34 +530,24 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, | |||
| 503 | rspi_enable_irq(rspi, irq_mask); | 530 | rspi_enable_irq(rspi, irq_mask); |
| 504 | rspi->dma_callbacked = 0; | 531 | rspi->dma_callbacked = 0; |
| 505 | 532 | ||
| 506 | if (rx) { | 533 | /* Now start DMA */ |
| 507 | desc_rx->callback = rspi_dma_complete; | 534 | if (rx) |
| 508 | desc_rx->callback_param = rspi; | ||
| 509 | cookie = dmaengine_submit(desc_rx); | ||
| 510 | if (dma_submit_error(cookie)) | ||
| 511 | return cookie; | ||
| 512 | dma_async_issue_pending(rspi->master->dma_rx); | 535 | dma_async_issue_pending(rspi->master->dma_rx); |
| 513 | } | 536 | if (tx) |
| 514 | if (tx) { | ||
| 515 | if (rx) { | ||
| 516 | /* No callback */ | ||
| 517 | desc_tx->callback = NULL; | ||
| 518 | } else { | ||
| 519 | desc_tx->callback = rspi_dma_complete; | ||
| 520 | desc_tx->callback_param = rspi; | ||
| 521 | } | ||
| 522 | cookie = dmaengine_submit(desc_tx); | ||
| 523 | if (dma_submit_error(cookie)) | ||
| 524 | return cookie; | ||
| 525 | dma_async_issue_pending(rspi->master->dma_tx); | 537 | dma_async_issue_pending(rspi->master->dma_tx); |
| 526 | } | ||
| 527 | 538 | ||
| 528 | ret = wait_event_interruptible_timeout(rspi->wait, | 539 | ret = wait_event_interruptible_timeout(rspi->wait, |
| 529 | rspi->dma_callbacked, HZ); | 540 | rspi->dma_callbacked, HZ); |
| 530 | if (ret > 0 && rspi->dma_callbacked) | 541 | if (ret > 0 && rspi->dma_callbacked) |
| 531 | ret = 0; | 542 | ret = 0; |
| 532 | else if (!ret) | 543 | else if (!ret) { |
| 544 | dev_err(&rspi->master->dev, "DMA timeout\n"); | ||
| 533 | ret = -ETIMEDOUT; | 545 | ret = -ETIMEDOUT; |
| 546 | if (tx) | ||
| 547 | dmaengine_terminate_all(rspi->master->dma_tx); | ||
| 548 | if (rx) | ||
| 549 | dmaengine_terminate_all(rspi->master->dma_rx); | ||
| 550 | } | ||
| 534 | 551 | ||
| 535 | rspi_disable_irq(rspi, irq_mask); | 552 | rspi_disable_irq(rspi, irq_mask); |
| 536 | 553 | ||
| @@ -541,11 +558,16 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, | |||
| 541 | 558 | ||
| 542 | return ret; | 559 | return ret; |
| 543 | 560 | ||
| 544 | no_dma: | 561 | no_dma_tx: |
| 545 | pr_warn_once("%s %s: DMA not available, falling back to PIO\n", | 562 | if (rx) |
| 546 | dev_driver_string(&rspi->master->dev), | 563 | dmaengine_terminate_all(rspi->master->dma_rx); |
| 547 | dev_name(&rspi->master->dev)); | 564 | no_dma_rx: |
| 548 | return -EAGAIN; | 565 | if (ret == -EAGAIN) { |
| 566 | pr_warn_once("%s %s: DMA not available, falling back to PIO\n", | ||
| 567 | dev_driver_string(&rspi->master->dev), | ||
| 568 | dev_name(&rspi->master->dev)); | ||
| 569 | } | ||
| 570 | return ret; | ||
| 549 | } | 571 | } |
| 550 | 572 | ||
| 551 | static void rspi_receive_init(const struct rspi_data *rspi) | 573 | static void rspi_receive_init(const struct rspi_data *rspi) |
