|
@@ -636,48 +636,38 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
|
|
dma_cookie_t cookie;
|
|
dma_cookie_t cookie;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- if (tx) {
|
|
|
|
- ier_bits |= IER_TDREQE | IER_TDMAE;
|
|
|
|
- dma_sync_single_for_device(p->master->dma_tx->device->dev,
|
|
|
|
- p->tx_dma_addr, len, DMA_TO_DEVICE);
|
|
|
|
- desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
|
|
|
|
- p->tx_dma_addr, len, DMA_TO_DEVICE,
|
|
|
|
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
|
|
|
- if (!desc_tx)
|
|
|
|
- return -EAGAIN;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ /* First prepare and submit the DMA request(s), as this may fail */
|
|
if (rx) {
|
|
if (rx) {
|
|
ier_bits |= IER_RDREQE | IER_RDMAE;
|
|
ier_bits |= IER_RDREQE | IER_RDMAE;
|
|
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
|
|
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
|
|
p->rx_dma_addr, len, DMA_FROM_DEVICE,
|
|
p->rx_dma_addr, len, DMA_FROM_DEVICE,
|
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
|
- if (!desc_rx)
|
|
|
|
- return -EAGAIN;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* 1 stage FIFO watermarks for DMA */
|
|
|
|
- sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
|
|
|
|
-
|
|
|
|
- /* setup msiof transfer mode registers (32-bit words) */
|
|
|
|
- sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
|
|
|
|
-
|
|
|
|
- sh_msiof_write(p, IER, ier_bits);
|
|
|
|
-
|
|
|
|
- reinit_completion(&p->done);
|
|
|
|
|
|
+ if (!desc_rx) {
|
|
|
|
+ ret = -EAGAIN;
|
|
|
|
+ goto no_dma_rx;
|
|
|
|
+ }
|
|
|
|
|
|
- if (rx) {
|
|
|
|
desc_rx->callback = sh_msiof_dma_complete;
|
|
desc_rx->callback = sh_msiof_dma_complete;
|
|
desc_rx->callback_param = p;
|
|
desc_rx->callback_param = p;
|
|
cookie = dmaengine_submit(desc_rx);
|
|
cookie = dmaengine_submit(desc_rx);
|
|
if (dma_submit_error(cookie)) {
|
|
if (dma_submit_error(cookie)) {
|
|
ret = cookie;
|
|
ret = cookie;
|
|
- goto stop_ier;
|
|
|
|
|
|
+ goto no_dma_rx;
|
|
}
|
|
}
|
|
- dma_async_issue_pending(p->master->dma_rx);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if (tx) {
|
|
if (tx) {
|
|
|
|
+ ier_bits |= IER_TDREQE | IER_TDMAE;
|
|
|
|
+ dma_sync_single_for_device(p->master->dma_tx->device->dev,
|
|
|
|
+ p->tx_dma_addr, len, DMA_TO_DEVICE);
|
|
|
|
+ desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
|
|
|
|
+ p->tx_dma_addr, len, DMA_TO_DEVICE,
|
|
|
|
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
|
|
|
+ if (!desc_tx) {
|
|
|
|
+ ret = -EAGAIN;
|
|
|
|
+ goto no_dma_tx;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (rx) {
|
|
if (rx) {
|
|
/* No callback */
|
|
/* No callback */
|
|
desc_tx->callback = NULL;
|
|
desc_tx->callback = NULL;
|
|
@@ -688,15 +678,30 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
|
|
cookie = dmaengine_submit(desc_tx);
|
|
cookie = dmaengine_submit(desc_tx);
|
|
if (dma_submit_error(cookie)) {
|
|
if (dma_submit_error(cookie)) {
|
|
ret = cookie;
|
|
ret = cookie;
|
|
- goto stop_rx;
|
|
|
|
|
|
+ goto no_dma_tx;
|
|
}
|
|
}
|
|
- dma_async_issue_pending(p->master->dma_tx);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* 1 stage FIFO watermarks for DMA */
|
|
|
|
+ sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
|
|
|
|
+
|
|
|
|
+ /* setup msiof transfer mode registers (32-bit words) */
|
|
|
|
+ sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
|
|
|
|
+
|
|
|
|
+ sh_msiof_write(p, IER, ier_bits);
|
|
|
|
+
|
|
|
|
+ reinit_completion(&p->done);
|
|
|
|
+
|
|
|
|
+ /* Now start DMA */
|
|
|
|
+ if (tx)
|
|
|
|
+ dma_async_issue_pending(p->master->dma_rx);
|
|
|
|
+ if (rx)
|
|
|
|
+ dma_async_issue_pending(p->master->dma_tx);
|
|
|
|
+
|
|
ret = sh_msiof_spi_start(p, rx);
|
|
ret = sh_msiof_spi_start(p, rx);
|
|
if (ret) {
|
|
if (ret) {
|
|
dev_err(&p->pdev->dev, "failed to start hardware\n");
|
|
dev_err(&p->pdev->dev, "failed to start hardware\n");
|
|
- goto stop_tx;
|
|
|
|
|
|
+ goto stop_dma;
|
|
}
|
|
}
|
|
|
|
|
|
/* wait for tx fifo to be emptied / rx fifo to be filled */
|
|
/* wait for tx fifo to be emptied / rx fifo to be filled */
|
|
@@ -726,14 +731,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
|
|
stop_reset:
|
|
stop_reset:
|
|
sh_msiof_reset_str(p);
|
|
sh_msiof_reset_str(p);
|
|
sh_msiof_spi_stop(p, rx);
|
|
sh_msiof_spi_stop(p, rx);
|
|
-stop_tx:
|
|
|
|
|
|
+stop_dma:
|
|
if (tx)
|
|
if (tx)
|
|
dmaengine_terminate_all(p->master->dma_tx);
|
|
dmaengine_terminate_all(p->master->dma_tx);
|
|
-stop_rx:
|
|
|
|
|
|
+no_dma_tx:
|
|
if (rx)
|
|
if (rx)
|
|
dmaengine_terminate_all(p->master->dma_rx);
|
|
dmaengine_terminate_all(p->master->dma_rx);
|
|
-stop_ier:
|
|
|
|
sh_msiof_write(p, IER, 0);
|
|
sh_msiof_write(p, IER, 0);
|
|
|
|
+no_dma_rx:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|