aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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