aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi_imx.c
diff options
context:
space:
mode:
authorAndrea Paterniani <a.paterniani@swapp-eng.it>2008-04-28 05:14:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 11:58:31 -0400
commit5d9f3f6b7c4c9fe1706006f24f964e7c0fa49fb7 (patch)
treed0cd42d5c5acbfa99f5f100d563a04d5a065a361 /drivers/spi/spi_imx.c
parent06719814780da741e7acf587367a86c3965c03a2 (diff)
spi: spi_imx updates
Updates to the i.MX SPI controller driver: 1) Some comments changed and/or added. 2) End of transfers is now managed on TXFIFO empty interrupt after the last write to TXFIFO. This speeds interrupt execution by removing the wait for TXFIFO to become empty. On TXFIFO empty interrupt the handler needs only to poll for the end of the ongoing transaction (SPI_CONTROL_XCH) to close the transfer. (2.1) Write only transfers are closed flushing RXFIFO. (2.2) Read transfers are closed reading trailing bytes from RXFIFO. (2.3) Read transfers where RXFIFO overrun occurred are closed by flushing RXFIFO and aborting the message. 3) Fifos are now flushed via SPI disable after the end of ongoing transaction. Signed-off-by: Andrea Paterniani <a.paterniani@swapp-eng.it> 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>
Diffstat (limited to 'drivers/spi/spi_imx.c')
-rw-r--r--drivers/spi/spi_imx.c223
1 files changed, 114 insertions, 109 deletions
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index d4ba640366b6..c730d05bfeb6 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -270,19 +270,26 @@ struct chip_data {
270 270
271static void pump_messages(struct work_struct *work); 271static void pump_messages(struct work_struct *work);
272 272
273static int flush(struct driver_data *drv_data) 273static void flush(struct driver_data *drv_data)
274{ 274{
275 unsigned long limit = loops_per_jiffy << 1;
276 void __iomem *regs = drv_data->regs; 275 void __iomem *regs = drv_data->regs;
277 volatile u32 d; 276 u32 control;
278 277
279 dev_dbg(&drv_data->pdev->dev, "flush\n"); 278 dev_dbg(&drv_data->pdev->dev, "flush\n");
279
280 /* Wait for end of transaction */
280 do { 281 do {
281 while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR) 282 control = readl(regs + SPI_CONTROL);
282 d = readl(regs + SPI_RXDATA); 283 } while (control & SPI_CONTROL_XCH);
283 } while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--); 284
285 /* Release chip select if requested, transfer delays are
286 handled in pump_transfers */
287 if (drv_data->cs_change)
288 drv_data->cs_control(SPI_CS_DEASSERT);
284 289
285 return limit; 290 /* Disable SPI to flush FIFOs */
291 writel(control & ~SPI_CONTROL_SPIEN, regs + SPI_CONTROL);
292 writel(control, regs + SPI_CONTROL);
286} 293}
287 294
288static void restore_state(struct driver_data *drv_data) 295static void restore_state(struct driver_data *drv_data)
@@ -570,6 +577,7 @@ static void giveback(struct spi_message *message, struct driver_data *drv_data)
570 writel(0, regs + SPI_INT_STATUS); 577 writel(0, regs + SPI_INT_STATUS);
571 writel(0, regs + SPI_DMA); 578 writel(0, regs + SPI_DMA);
572 579
580 /* Unconditioned deselct */
573 drv_data->cs_control(SPI_CS_DEASSERT); 581 drv_data->cs_control(SPI_CS_DEASSERT);
574 582
575 message->state = NULL; 583 message->state = NULL;
@@ -592,13 +600,10 @@ static void dma_err_handler(int channel, void *data, int errcode)
592 /* Disable both rx and tx dma channels */ 600 /* Disable both rx and tx dma channels */
593 imx_dma_disable(drv_data->rx_channel); 601 imx_dma_disable(drv_data->rx_channel);
594 imx_dma_disable(drv_data->tx_channel); 602 imx_dma_disable(drv_data->tx_channel);
595
596 if (flush(drv_data) == 0)
597 dev_err(&drv_data->pdev->dev,
598 "dma_err_handler - flush failed\n");
599
600 unmap_dma_buffers(drv_data); 603 unmap_dma_buffers(drv_data);
601 604
605 flush(drv_data);
606
602 msg->state = ERROR_STATE; 607 msg->state = ERROR_STATE;
603 tasklet_schedule(&drv_data->pump_transfers); 608 tasklet_schedule(&drv_data->pump_transfers);
604} 609}
@@ -612,8 +617,7 @@ static void dma_tx_handler(int channel, void *data)
612 imx_dma_disable(channel); 617 imx_dma_disable(channel);
613 618
614 /* Now waits for TX FIFO empty */ 619 /* Now waits for TX FIFO empty */
615 writel(readl(drv_data->regs + SPI_INT_STATUS) | SPI_INTEN_TE, 620 writel(SPI_INTEN_TE, drv_data->regs + SPI_INT_STATUS);
616 drv_data->regs + SPI_INT_STATUS);
617} 621}
618 622
619static irqreturn_t dma_transfer(struct driver_data *drv_data) 623static irqreturn_t dma_transfer(struct driver_data *drv_data)
@@ -621,19 +625,18 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
621 u32 status; 625 u32 status;
622 struct spi_message *msg = drv_data->cur_msg; 626 struct spi_message *msg = drv_data->cur_msg;
623 void __iomem *regs = drv_data->regs; 627 void __iomem *regs = drv_data->regs;
624 unsigned long limit;
625 628
626 status = readl(regs + SPI_INT_STATUS); 629 status = readl(regs + SPI_INT_STATUS);
627 630
628 if ((status & SPI_INTEN_RO) && (status & SPI_STATUS_RO)) { 631 if ((status & (SPI_INTEN_RO | SPI_STATUS_RO))
632 == (SPI_INTEN_RO | SPI_STATUS_RO)) {
629 writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS); 633 writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
630 634
635 imx_dma_disable(drv_data->tx_channel);
631 imx_dma_disable(drv_data->rx_channel); 636 imx_dma_disable(drv_data->rx_channel);
632 unmap_dma_buffers(drv_data); 637 unmap_dma_buffers(drv_data);
633 638
634 if (flush(drv_data) == 0) 639 flush(drv_data);
635 dev_err(&drv_data->pdev->dev,
636 "dma_transfer - flush failed\n");
637 640
638 dev_warn(&drv_data->pdev->dev, 641 dev_warn(&drv_data->pdev->dev,
639 "dma_transfer - fifo overun\n"); 642 "dma_transfer - fifo overun\n");
@@ -649,20 +652,17 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
649 652
650 if (drv_data->rx) { 653 if (drv_data->rx) {
651 /* Wait end of transfer before read trailing data */ 654 /* Wait end of transfer before read trailing data */
652 limit = loops_per_jiffy << 1; 655 while (readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH)
653 while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && 656 cpu_relax();
654 limit--);
655
656 if (limit == 0)
657 dev_err(&drv_data->pdev->dev,
658 "dma_transfer - end of tx failed\n");
659 else
660 dev_dbg(&drv_data->pdev->dev,
661 "dma_transfer - end of tx\n");
662 657
663 imx_dma_disable(drv_data->rx_channel); 658 imx_dma_disable(drv_data->rx_channel);
664 unmap_dma_buffers(drv_data); 659 unmap_dma_buffers(drv_data);
665 660
661 /* Release chip select if requested, transfer delays are
662 handled in pump_transfers() */
663 if (drv_data->cs_change)
664 drv_data->cs_control(SPI_CS_DEASSERT);
665
666 /* Calculate number of trailing data and read them */ 666 /* Calculate number of trailing data and read them */
667 dev_dbg(&drv_data->pdev->dev, 667 dev_dbg(&drv_data->pdev->dev,
668 "dma_transfer - test = 0x%08X\n", 668 "dma_transfer - test = 0x%08X\n",
@@ -676,19 +676,12 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
676 /* Write only transfer */ 676 /* Write only transfer */
677 unmap_dma_buffers(drv_data); 677 unmap_dma_buffers(drv_data);
678 678
679 if (flush(drv_data) == 0) 679 flush(drv_data);
680 dev_err(&drv_data->pdev->dev,
681 "dma_transfer - flush failed\n");
682 } 680 }
683 681
684 /* End of transfer, update total byte transfered */ 682 /* End of transfer, update total byte transfered */
685 msg->actual_length += drv_data->len; 683 msg->actual_length += drv_data->len;
686 684
687 /* Release chip select if requested, transfer delays are
688 handled in pump_transfers() */
689 if (drv_data->cs_change)
690 drv_data->cs_control(SPI_CS_DEASSERT);
691
692 /* Move to next transfer */ 685 /* Move to next transfer */
693 msg->state = next_transfer(drv_data); 686 msg->state = next_transfer(drv_data);
694 687
@@ -711,44 +704,43 @@ static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
711 704
712 status = readl(regs + SPI_INT_STATUS); 705 status = readl(regs + SPI_INT_STATUS);
713 706
714 while (status & SPI_STATUS_TH) { 707 if (status & SPI_INTEN_TE) {
708 /* TXFIFO Empty Interrupt on the last transfered word */
709 writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
715 dev_dbg(&drv_data->pdev->dev, 710 dev_dbg(&drv_data->pdev->dev,
716 "interrupt_wronly_transfer - status = 0x%08X\n", status); 711 "interrupt_wronly_transfer - end of tx\n");
717 712
718 /* Pump data */ 713 flush(drv_data);
719 if (write(drv_data)) {
720 writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
721 regs + SPI_INT_STATUS);
722 714
723 dev_dbg(&drv_data->pdev->dev, 715 /* Update total byte transfered */
724 "interrupt_wronly_transfer - end of tx\n"); 716 msg->actual_length += drv_data->len;
725 717
726 if (flush(drv_data) == 0) 718 /* Move to next transfer */
727 dev_err(&drv_data->pdev->dev, 719 msg->state = next_transfer(drv_data);
728 "interrupt_wronly_transfer - "
729 "flush failed\n");
730 720
731 /* End of transfer, update total byte transfered */ 721 /* Schedule transfer tasklet */
732 msg->actual_length += drv_data->len; 722 tasklet_schedule(&drv_data->pump_transfers);
733 723
734 /* Release chip select if requested, transfer delays are 724 return IRQ_HANDLED;
735 handled in pump_transfers */ 725 } else {
736 if (drv_data->cs_change) 726 while (status & SPI_STATUS_TH) {
737 drv_data->cs_control(SPI_CS_DEASSERT); 727 dev_dbg(&drv_data->pdev->dev,
728 "interrupt_wronly_transfer - status = 0x%08X\n",
729 status);
738 730
739 /* Move to next transfer */ 731 /* Pump data */
740 msg->state = next_transfer(drv_data); 732 if (write(drv_data)) {
733 /* End of TXFIFO writes,
734 now wait until TXFIFO is empty */
735 writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
736 return IRQ_HANDLED;
737 }
741 738
742 /* Schedule transfer tasklet */ 739 status = readl(regs + SPI_INT_STATUS);
743 tasklet_schedule(&drv_data->pump_transfers);
744 740
745 return IRQ_HANDLED; 741 /* We did something */
742 handled = IRQ_HANDLED;
746 } 743 }
747
748 status = readl(regs + SPI_INT_STATUS);
749
750 /* We did something */
751 handled = IRQ_HANDLED;
752 } 744 }
753 745
754 return handled; 746 return handled;
@@ -758,45 +750,31 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
758{ 750{
759 struct spi_message *msg = drv_data->cur_msg; 751 struct spi_message *msg = drv_data->cur_msg;
760 void __iomem *regs = drv_data->regs; 752 void __iomem *regs = drv_data->regs;
761 u32 status; 753 u32 status, control;
762 irqreturn_t handled = IRQ_NONE; 754 irqreturn_t handled = IRQ_NONE;
763 unsigned long limit; 755 unsigned long limit;
764 756
765 status = readl(regs + SPI_INT_STATUS); 757 status = readl(regs + SPI_INT_STATUS);
766 758
767 while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) { 759 if (status & SPI_INTEN_TE) {
760 /* TXFIFO Empty Interrupt on the last transfered word */
761 writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
768 dev_dbg(&drv_data->pdev->dev, 762 dev_dbg(&drv_data->pdev->dev,
769 "interrupt_transfer - status = 0x%08X\n", status); 763 "interrupt_transfer - end of tx\n");
770
771 if (status & SPI_STATUS_RO) {
772 writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
773 regs + SPI_INT_STATUS);
774
775 dev_warn(&drv_data->pdev->dev,
776 "interrupt_transfer - fifo overun\n"
777 " data not yet written = %d\n"
778 " data not yet read = %d\n",
779 data_to_write(drv_data),
780 data_to_read(drv_data));
781
782 if (flush(drv_data) == 0)
783 dev_err(&drv_data->pdev->dev,
784 "interrupt_transfer - flush failed\n");
785
786 msg->state = ERROR_STATE;
787 tasklet_schedule(&drv_data->pump_transfers);
788 764
789 return IRQ_HANDLED; 765 if (msg->state == ERROR_STATE) {
790 } 766 /* RXFIFO overrun was detected and message aborted */
791 767 flush(drv_data);
792 /* Pump data */ 768 } else {
793 read(drv_data); 769 /* Wait for end of transaction */
794 if (write(drv_data)) { 770 do {
795 writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN, 771 control = readl(regs + SPI_CONTROL);
796 regs + SPI_INT_STATUS); 772 } while (control & SPI_CONTROL_XCH);
797 773
798 dev_dbg(&drv_data->pdev->dev, 774 /* Release chip select if requested, transfer delays are
799 "interrupt_transfer - end of tx\n"); 775 handled in pump_transfers */
776 if (drv_data->cs_change)
777 drv_data->cs_control(SPI_CS_DEASSERT);
800 778
801 /* Read trailing bytes */ 779 /* Read trailing bytes */
802 limit = loops_per_jiffy << 1; 780 limit = loops_per_jiffy << 1;
@@ -810,27 +788,54 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
810 dev_dbg(&drv_data->pdev->dev, 788 dev_dbg(&drv_data->pdev->dev,
811 "interrupt_transfer - end of rx\n"); 789 "interrupt_transfer - end of rx\n");
812 790
813 /* End of transfer, update total byte transfered */ 791 /* Update total byte transfered */
814 msg->actual_length += drv_data->len; 792 msg->actual_length += drv_data->len;
815 793
816 /* Release chip select if requested, transfer delays are
817 handled in pump_transfers */
818 if (drv_data->cs_change)
819 drv_data->cs_control(SPI_CS_DEASSERT);
820
821 /* Move to next transfer */ 794 /* Move to next transfer */
822 msg->state = next_transfer(drv_data); 795 msg->state = next_transfer(drv_data);
796 }
823 797
824 /* Schedule transfer tasklet */ 798 /* Schedule transfer tasklet */
825 tasklet_schedule(&drv_data->pump_transfers); 799 tasklet_schedule(&drv_data->pump_transfers);
826 800
827 return IRQ_HANDLED; 801 return IRQ_HANDLED;
828 } 802 } else {
803 while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
804 dev_dbg(&drv_data->pdev->dev,
805 "interrupt_transfer - status = 0x%08X\n",
806 status);
807
808 if (status & SPI_STATUS_RO) {
809 /* RXFIFO overrun, abort message end wait
810 until TXFIFO is empty */
811 writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
812
813 dev_warn(&drv_data->pdev->dev,
814 "interrupt_transfer - fifo overun\n"
815 " data not yet written = %d\n"
816 " data not yet read = %d\n",
817 data_to_write(drv_data),
818 data_to_read(drv_data));
819
820 msg->state = ERROR_STATE;
821
822 return IRQ_HANDLED;
823 }
829 824
830 status = readl(regs + SPI_INT_STATUS); 825 /* Pump data */
826 read(drv_data);
827 if (write(drv_data)) {
828 /* End of TXFIFO writes,
829 now wait until TXFIFO is empty */
830 writel(SPI_INTEN_TE, regs + SPI_INT_STATUS);
831 return IRQ_HANDLED;
832 }
831 833
832 /* We did something */ 834 status = readl(regs + SPI_INT_STATUS);
833 handled = IRQ_HANDLED; 835
836 /* We did something */
837 handled = IRQ_HANDLED;
838 }
834 } 839 }
835 840
836 return handled; 841 return handled;