Merge remote-tracking branch 'spi/fix/sh-msiof' into spi-linus

This commit is contained in:
Mark Brown 2014-08-30 19:28:03 +01:00
commit e0a7ab4b50

View File

@ -636,6 +636,26 @@ 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;
/* First prepare and submit the DMA request(s), as this may fail */
if (rx) {
ier_bits |= IER_RDREQE | IER_RDMAE;
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
p->rx_dma_addr, len, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) {
ret = -EAGAIN;
goto no_dma_rx;
}
desc_rx->callback = sh_msiof_dma_complete;
desc_rx->callback_param = p;
cookie = dmaengine_submit(desc_rx);
if (dma_submit_error(cookie)) {
ret = cookie;
goto no_dma_rx;
}
}
if (tx) { if (tx) {
ier_bits |= IER_TDREQE | IER_TDMAE; ier_bits |= IER_TDREQE | IER_TDMAE;
dma_sync_single_for_device(p->master->dma_tx->device->dev, dma_sync_single_for_device(p->master->dma_tx->device->dev,
@ -643,17 +663,23 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
p->tx_dma_addr, len, DMA_TO_DEVICE, p->tx_dma_addr, len, DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) if (!desc_tx) {
return -EAGAIN; ret = -EAGAIN;
} goto no_dma_tx;
}
if (rx) { if (rx) {
ier_bits |= IER_RDREQE | IER_RDMAE; /* No callback */
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, desc_tx->callback = NULL;
p->rx_dma_addr, len, DMA_FROM_DEVICE, } else {
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); desc_tx->callback = sh_msiof_dma_complete;
if (!desc_rx) desc_tx->callback_param = p;
return -EAGAIN; }
cookie = dmaengine_submit(desc_tx);
if (dma_submit_error(cookie)) {
ret = cookie;
goto no_dma_tx;
}
} }
/* 1 stage FIFO watermarks for DMA */ /* 1 stage FIFO watermarks for DMA */
@ -666,37 +692,16 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
reinit_completion(&p->done); reinit_completion(&p->done);
if (rx) { /* Now start DMA */
desc_rx->callback = sh_msiof_dma_complete; if (tx)
desc_rx->callback_param = p;
cookie = dmaengine_submit(desc_rx);
if (dma_submit_error(cookie)) {
ret = cookie;
goto stop_ier;
}
dma_async_issue_pending(p->master->dma_rx); dma_async_issue_pending(p->master->dma_rx);
} if (rx)
if (tx) {
if (rx) {
/* No callback */
desc_tx->callback = NULL;
} else {
desc_tx->callback = sh_msiof_dma_complete;
desc_tx->callback_param = p;
}
cookie = dmaengine_submit(desc_tx);
if (dma_submit_error(cookie)) {
ret = cookie;
goto stop_rx;
}
dma_async_issue_pending(p->master->dma_tx); 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;
} }