未验证 提交 0af7af7d 编写于 作者: S Sylwester Nawrocki 提交者: Mark Brown

spi: spi-s3c64xx: Allow higher transfer lengths in polling IO mode

Some variants of the SPI controller have no DMA support, in such case
SPI transfers longer than the FIFO length are not currently properly
handled by the driver. Fix it by doing multiple transfers in the
s3c64xx_spi_transfer_one() function if the SPI transfer length exceeds
the FIFO size.
Signed-off-by: NSylwester Nawrocki <s.nawrocki@samsung.com>
Reviewed-by: NAndi Shyti <andi@etezian.org>
Signed-off-by: NMark Brown <broonie@kernel.org>
上级 f6364e66
...@@ -635,11 +635,14 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, ...@@ -635,11 +635,14 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
{ {
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1; const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1;
const void *tx_buf = NULL;
void *rx_buf = NULL;
int target_len = 0, origin_len = 0;
int use_dma = 0;
int status; int status;
u32 speed; u32 speed;
u8 bpw; u8 bpw;
unsigned long flags; unsigned long flags;
int use_dma;
reinit_completion(&sdd->xfer_completion); reinit_completion(&sdd->xfer_completion);
...@@ -654,47 +657,77 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, ...@@ -654,47 +657,77 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
s3c64xx_spi_config(sdd); s3c64xx_spi_config(sdd);
} }
/* Polling method for xfers not bigger than FIFO capacity */
use_dma = 0;
if (!is_polling(sdd) && (xfer->len > fifo_len) && if (!is_polling(sdd) && (xfer->len > fifo_len) &&
sdd->rx_dma.ch && sdd->tx_dma.ch) sdd->rx_dma.ch && sdd->tx_dma.ch) {
use_dma = 1; use_dma = 1;
spin_lock_irqsave(&sdd->lock, flags); } else if (is_polling(sdd) && xfer->len > fifo_len) {
tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf;
origin_len = xfer->len;
/* Pending only which is to be done */ target_len = xfer->len;
sdd->state &= ~RXBUSY; if (xfer->len > fifo_len)
sdd->state &= ~TXBUSY; xfer->len = fifo_len;
}
do {
spin_lock_irqsave(&sdd->lock, flags);
s3c64xx_enable_datapath(sdd, xfer, use_dma); /* Pending only which is to be done */
sdd->state &= ~RXBUSY;
sdd->state &= ~TXBUSY;
/* Start the signals */ s3c64xx_enable_datapath(sdd, xfer, use_dma);
s3c64xx_spi_set_cs(spi, true);
spin_unlock_irqrestore(&sdd->lock, flags); /* Start the signals */
s3c64xx_spi_set_cs(spi, true);
if (use_dma) spin_unlock_irqrestore(&sdd->lock, flags);
status = s3c64xx_wait_for_dma(sdd, xfer);
else if (use_dma)
status = s3c64xx_wait_for_pio(sdd, xfer); status = s3c64xx_wait_for_dma(sdd, xfer);
else
if (status) { status = s3c64xx_wait_for_pio(sdd, xfer);
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, if (status) {
(sdd->state & RXBUSY) ? 'f' : 'p', dev_err(&spi->dev,
(sdd->state & TXBUSY) ? 'f' : 'p', "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
xfer->len); xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
(sdd->state & RXBUSY) ? 'f' : 'p',
if (use_dma) { (sdd->state & TXBUSY) ? 'f' : 'p',
if (xfer->tx_buf != NULL xfer->len);
&& (sdd->state & TXBUSY))
dmaengine_terminate_all(sdd->tx_dma.ch); if (use_dma) {
if (xfer->rx_buf != NULL if (xfer->tx_buf && (sdd->state & TXBUSY))
&& (sdd->state & RXBUSY)) dmaengine_terminate_all(sdd->tx_dma.ch);
dmaengine_terminate_all(sdd->rx_dma.ch); if (xfer->rx_buf && (sdd->state & RXBUSY))
dmaengine_terminate_all(sdd->rx_dma.ch);
}
} else {
s3c64xx_flush_fifo(sdd);
} }
} else { if (target_len > 0) {
s3c64xx_flush_fifo(sdd); target_len -= xfer->len;
if (xfer->tx_buf)
xfer->tx_buf += xfer->len;
if (xfer->rx_buf)
xfer->rx_buf += xfer->len;
if (target_len > fifo_len)
xfer->len = fifo_len;
else
xfer->len = target_len;
}
} while (target_len > 0);
if (origin_len) {
/* Restore original xfer buffers and length */
xfer->tx_buf = tx_buf;
xfer->rx_buf = rx_buf;
xfer->len = origin_len;
} }
return status; return status;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册