aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Nikitenko <jan.nikitenko@gmail.com>2008-07-24 00:29:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:30 -0400
commitbbe48ecc7f6559318cfc6c023da225a0b0e14ab3 (patch)
treebc31e1fbea4180a6822abe4247c9cfdb59e6b206
parent3a93a159c61e38a12f7ecbb3a25cf3f012abcf7a (diff)
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: Jan Nikitenko <jan.nikitenko@gmail.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/spi/au1550_spi.c69
1 files changed, 49 insertions, 20 deletions
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
index 3860dd2fa5d9..9149689c79d9 100644
--- a/drivers/spi/au1550_spi.c
+++ b/drivers/spi/au1550_spi.c
@@ -484,9 +484,13 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
484 au1xxx_dbdma_reset(hw->dma_tx_ch); 484 au1xxx_dbdma_reset(hw->dma_tx_ch);
485 au1550_spi_reset_fifos(hw); 485 au1550_spi_reset_fifos(hw);
486 486
487 dev_err(hw->dev, 487 if (evnt == PSC_SPIEVNT_RO)
488 "Unexpected SPI error: event=0x%x stat=0x%x!\n", 488 dev_err(hw->dev,
489 evnt, stat); 489 "dma transfer: receive FIFO overflow!\n");
490 else
491 dev_err(hw->dev,
492 "dma transfer: unexpected SPI error "
493 "(event=0x%x stat=0x%x)!\n", evnt, stat);
490 494
491 complete(&hw->master_done); 495 complete(&hw->master_done);
492 return IRQ_HANDLED; 496 return IRQ_HANDLED;
@@ -596,17 +600,17 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
596 600
597 if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO 601 if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
598 | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO 602 | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
599 | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD)) 603 | PSC_SPIEVNT_SD))
600 != 0) { 604 != 0) {
601 dev_err(hw->dev,
602 "Unexpected SPI error: event=0x%x stat=0x%x!\n",
603 evnt, stat);
604 /* 605 /*
605 * due to an error we consider transfer as done, 606 * due to an error we consider transfer as done,
606 * so mask all events until before next transfer start 607 * so mask all events until before next transfer start
607 */ 608 */
608 au1550_spi_mask_ack_all(hw); 609 au1550_spi_mask_ack_all(hw);
609 au1550_spi_reset_fifos(hw); 610 au1550_spi_reset_fifos(hw);
611 dev_err(hw->dev,
612 "pio transfer: unexpected SPI error "
613 "(event=0x%x stat=0x%x)!\n", evnt, stat);
610 complete(&hw->master_done); 614 complete(&hw->master_done);
611 return IRQ_HANDLED; 615 return IRQ_HANDLED;
612 } 616 }
@@ -620,27 +624,50 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
620 stat = hw->regs->psc_spistat; 624 stat = hw->regs->psc_spistat;
621 au_sync(); 625 au_sync();
622 626
623 if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) { 627 /*
628 * Take care to not let the Rx FIFO overflow.
629 *
630 * We only write a byte if we have read one at least. Initially,
631 * the write fifo is full, so we should read from the read fifo
632 * first.
633 * In case we miss a word from the read fifo, we should get a
634 * RO event and should back out.
635 */
636 if (!(stat & PSC_SPISTAT_RE) && hw->rx_count < hw->len) {
624 hw->rx_word(hw); 637 hw->rx_word(hw);
625 /* ack the receive request event */
626 hw->regs->psc_spievent = PSC_SPIEVNT_RR;
627 au_sync();
628 busy = 1; 638 busy = 1;
629 }
630 639
631 if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) { 640 if (!(stat & PSC_SPISTAT_TF) && hw->tx_count < hw->len)
632 hw->tx_word(hw); 641 hw->tx_word(hw);
633 /* ack the transmit request event */
634 hw->regs->psc_spievent = PSC_SPIEVNT_TR;
635 au_sync();
636 busy = 1;
637 } 642 }
638 } while (busy); 643 } while (busy);
639 644
640 evnt = hw->regs->psc_spievent; 645 hw->regs->psc_spievent = PSC_SPIEVNT_RR | PSC_SPIEVNT_TR;
641 au_sync(); 646 au_sync();
642 647
643 if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) { 648 /*
649 * Restart the SPI transmission in case of a transmit underflow.
650 * This seems to work despite the notes in the Au1550 data book
651 * of Figure 8-4 with flowchart for SPI master operation:
652 *
653 * """Note 1: An XFR Error Interrupt occurs, unless masked,
654 * for any of the following events: Tx FIFO Underflow,
655 * Rx FIFO Overflow, or Multiple-master Error
656 * Note 2: In case of a Tx Underflow Error, all zeroes are
657 * transmitted."""
658 *
659 * By simply restarting the spi transfer on Tx Underflow Error,
660 * we assume that spi transfer was paused instead of zeroes
661 * transmittion mentioned in the Note 2 of Au1550 data book.
662 */
663 if (evnt & PSC_SPIEVNT_TU) {
664 hw->regs->psc_spievent = PSC_SPIEVNT_TU | PSC_SPIEVNT_MD;
665 au_sync();
666 hw->regs->psc_spipcr = PSC_SPIPCR_MS;
667 au_sync();
668 }
669
670 if (hw->rx_count >= hw->len) {
644 /* transfer completed successfully */ 671 /* transfer completed successfully */
645 au1550_spi_mask_ack_all(hw); 672 au1550_spi_mask_ack_all(hw);
646 complete(&hw->master_done); 673 complete(&hw->master_done);
@@ -729,6 +756,8 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
729 stat = hw->regs->psc_spistat; 756 stat = hw->regs->psc_spistat;
730 au_sync(); 757 au_sync();
731 } while ((stat & PSC_SPISTAT_DR) == 0); 758 } while ((stat & PSC_SPISTAT_DR) == 0);
759
760 au1550_spi_reset_fifos(hw);
732} 761}
733 762
734 763