Commit bbe48ecc authored by Jan Nikitenko's avatar Jan Nikitenko Committed by Linus Torvalds

spi: au1550_spi: improve pio transfer mode

Improve PIO transfer mode of au1550 spi controller by continuing of spi
transfer, instead of aborting transfer when transmit underflow interrupt
occurrs.

Verified by oscilloscope that the spi clock pauses on trasmit underflow,
so transfer continuation is perfectly valid even though au1550 datasheet
says that on tx underflow zeroes will be transfered.

Also make some error messages more specific.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: default avatarJan Nikitenko <jan.nikitenko@gmail.com>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 3a93a159
...@@ -484,9 +484,13 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw) ...@@ -484,9 +484,13 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
au1xxx_dbdma_reset(hw->dma_tx_ch); au1xxx_dbdma_reset(hw->dma_tx_ch);
au1550_spi_reset_fifos(hw); au1550_spi_reset_fifos(hw);
dev_err(hw->dev, if (evnt == PSC_SPIEVNT_RO)
"Unexpected SPI error: event=0x%x stat=0x%x!\n", dev_err(hw->dev,
evnt, stat); "dma transfer: receive FIFO overflow!\n");
else
dev_err(hw->dev,
"dma transfer: unexpected SPI error "
"(event=0x%x stat=0x%x)!\n", evnt, stat);
complete(&hw->master_done); complete(&hw->master_done);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -596,17 +600,17 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw) ...@@ -596,17 +600,17 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
| PSC_SPIEVNT_RU | PSC_SPIEVNT_TO | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
| PSC_SPIEVNT_TU | PSC_SPIEVNT_SD)) | PSC_SPIEVNT_SD))
!= 0) { != 0) {
dev_err(hw->dev,
"Unexpected SPI error: event=0x%x stat=0x%x!\n",
evnt, stat);
/* /*
* due to an error we consider transfer as done, * due to an error we consider transfer as done,
* so mask all events until before next transfer start * so mask all events until before next transfer start
*/ */
au1550_spi_mask_ack_all(hw); au1550_spi_mask_ack_all(hw);
au1550_spi_reset_fifos(hw); au1550_spi_reset_fifos(hw);
dev_err(hw->dev,
"pio transfer: unexpected SPI error "
"(event=0x%x stat=0x%x)!\n", evnt, stat);
complete(&hw->master_done); complete(&hw->master_done);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -620,27 +624,50 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw) ...@@ -620,27 +624,50 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
stat = hw->regs->psc_spistat; stat = hw->regs->psc_spistat;
au_sync(); au_sync();
if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) { /*
* Take care to not let the Rx FIFO overflow.
*
* We only write a byte if we have read one at least. Initially,
* the write fifo is full, so we should read from the read fifo
* first.
* In case we miss a word from the read fifo, we should get a
* RO event and should back out.
*/
if (!(stat & PSC_SPISTAT_RE) && hw->rx_count < hw->len) {
hw->rx_word(hw); hw->rx_word(hw);
/* ack the receive request event */
hw->regs->psc_spievent = PSC_SPIEVNT_RR;
au_sync();
busy = 1; busy = 1;
}
if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) { if (!(stat & PSC_SPISTAT_TF) && hw->tx_count < hw->len)
hw->tx_word(hw); hw->tx_word(hw);
/* ack the transmit request event */
hw->regs->psc_spievent = PSC_SPIEVNT_TR;
au_sync();
busy = 1;
} }
} while (busy); } while (busy);
evnt = hw->regs->psc_spievent; hw->regs->psc_spievent = PSC_SPIEVNT_RR | PSC_SPIEVNT_TR;
au_sync(); au_sync();
if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) { /*
* Restart the SPI transmission in case of a transmit underflow.
* This seems to work despite the notes in the Au1550 data book
* of Figure 8-4 with flowchart for SPI master operation:
*
* """Note 1: An XFR Error Interrupt occurs, unless masked,
* for any of the following events: Tx FIFO Underflow,
* Rx FIFO Overflow, or Multiple-master Error
* Note 2: In case of a Tx Underflow Error, all zeroes are
* transmitted."""
*
* By simply restarting the spi transfer on Tx Underflow Error,
* we assume that spi transfer was paused instead of zeroes
* transmittion mentioned in the Note 2 of Au1550 data book.
*/
if (evnt & PSC_SPIEVNT_TU) {
hw->regs->psc_spievent = PSC_SPIEVNT_TU | PSC_SPIEVNT_MD;
au_sync();
hw->regs->psc_spipcr = PSC_SPIPCR_MS;
au_sync();
}
if (hw->rx_count >= hw->len) {
/* transfer completed successfully */ /* transfer completed successfully */
au1550_spi_mask_ack_all(hw); au1550_spi_mask_ack_all(hw);
complete(&hw->master_done); complete(&hw->master_done);
...@@ -729,6 +756,8 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw) ...@@ -729,6 +756,8 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
stat = hw->regs->psc_spistat; stat = hw->regs->psc_spistat;
au_sync(); au_sync();
} while ((stat & PSC_SPISTAT_DR) == 0); } while ((stat & PSC_SPISTAT_DR) == 0);
au1550_spi_reset_fifos(hw);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment