spi: sirf: fix the issue while transferring more than 256 words
currently, spi irq handler only does rx processing and fetching data from rx fifo when "FRM_END" irq happens. FRM_END indicates one transfer completes. if rx size is less than 256, it works well. but the problem is that spi rx fifo size is only 256 bytes, then if data size of one frame is more than 256, before FRM_END comes, rx fifo will be filled with RXFIFO_OFLOW overflow interrupt, it will make us lose some data due to fifo overflow. Explicitly we need do fetch work from device rx fifo in irq handler not only in "FRM_END" irq but also in "THD_REACH" irq. THD_REACH means rx fifo has come to its threshold and will come to overflow if we don't take data from it in time. In this patch, we fix this issue. we take data from rx fifo when either FRM_END or RX_THD_REACH irq comes, we put data into tx fifo when either TX_FIFO_EMPTY or TX_THD_REACH irq comes. Signed-off-by: Qipan Li <Qipan.Li@csr.com> Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
Родитель
de1f9f270e
Коммит
237ce4665c
|
@ -140,9 +140,6 @@ struct sirfsoc_spi {
|
|||
unsigned int left_tx_cnt;
|
||||
unsigned int left_rx_cnt;
|
||||
|
||||
/* tasklet to push tx msg into FIFO */
|
||||
struct tasklet_struct tasklet_tx;
|
||||
|
||||
int chipselect[0];
|
||||
};
|
||||
|
||||
|
@ -234,17 +231,6 @@ static void spi_sirfsoc_tx_word_u32(struct sirfsoc_spi *sspi)
|
|||
sspi->left_tx_cnt--;
|
||||
}
|
||||
|
||||
static void spi_sirfsoc_tasklet_tx(unsigned long arg)
|
||||
{
|
||||
struct sirfsoc_spi *sspi = (struct sirfsoc_spi *)arg;
|
||||
|
||||
/* Fill Tx FIFO while there are left words to be transmitted */
|
||||
while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) &
|
||||
SIRFSOC_SPI_FIFO_FULL)) &&
|
||||
sspi->left_tx_cnt)
|
||||
sspi->tx_word(sspi);
|
||||
}
|
||||
|
||||
static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sirfsoc_spi *sspi = dev_id;
|
||||
|
@ -259,25 +245,25 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
|
|||
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
||||
}
|
||||
|
||||
if (spi_stat & SIRFSOC_SPI_FRM_END) {
|
||||
if (spi_stat & (SIRFSOC_SPI_FRM_END
|
||||
| SIRFSOC_SPI_RXFIFO_THD_REACH))
|
||||
while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
|
||||
& SIRFSOC_SPI_FIFO_EMPTY)) &&
|
||||
sspi->left_rx_cnt)
|
||||
sspi->rx_word(sspi);
|
||||
|
||||
/* Received all words */
|
||||
if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
|
||||
complete(&sspi->done);
|
||||
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
||||
}
|
||||
if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY
|
||||
| SIRFSOC_SPI_TXFIFO_THD_REACH))
|
||||
while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
|
||||
& SIRFSOC_SPI_FIFO_FULL)) &&
|
||||
sspi->left_tx_cnt)
|
||||
sspi->tx_word(sspi);
|
||||
|
||||
/* Received all words */
|
||||
if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
|
||||
complete(&sspi->done);
|
||||
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
||||
}
|
||||
|
||||
if (spi_stat & SIRFSOC_SPI_RXFIFO_THD_REACH ||
|
||||
spi_stat & SIRFSOC_SPI_TXFIFO_THD_REACH ||
|
||||
spi_stat & SIRFSOC_SPI_RX_FIFO_FULL ||
|
||||
spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY)
|
||||
tasklet_schedule(&sspi->tasklet_tx);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -566,9 +552,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
|||
|
||||
init_completion(&sspi->done);
|
||||
|
||||
tasklet_init(&sspi->tasklet_tx, spi_sirfsoc_tasklet_tx,
|
||||
(unsigned long)sspi);
|
||||
|
||||
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
||||
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
||||
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
||||
|
|
Загрузка…
Ссылка в новой задаче