diff options
author | Stephen Street <stephen@streetfiresound.com> | 2006-05-20 18:00:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-21 15:59:20 -0400 |
commit | 5daa3ba0c6a41a8bb4ba17ad8d5514172e103504 (patch) | |
tree | b1b55ad5fb5feca7455112d6a95547c4e9913585 /drivers | |
parent | 7fba53402eb0fb4209c74469814c583b6455e096 (diff) |
[PATCH] pxa2xx-spi update
Fix some outstanding issues with the pxa2xx_spi driver when running on a
PXA270:
- Wrong timeout calculation in the setup function due to different
peripheral clock rates in the PXAxxx family.
- Bad handling of SSSR_TFS interrupts in interrupt_transfer function.
- Added locking to interface between the pump_messages workqueue and the
pump_transfers tasklet.
Much thanks to Juergen Beisert for the extensive testing on the PXA270.
Signed-off-by: Stephen Street <stephen@streetfiresound.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/spi/pxa2xx_spi.c | 93 |
1 files changed, 56 insertions, 37 deletions
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 596bf820b70c..29aec77f98be 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c | |||
@@ -363,25 +363,30 @@ static void unmap_dma_buffers(struct driver_data *drv_data) | |||
363 | } | 363 | } |
364 | 364 | ||
365 | /* caller already set message->status; dma and pio irqs are blocked */ | 365 | /* caller already set message->status; dma and pio irqs are blocked */ |
366 | static void giveback(struct spi_message *message, struct driver_data *drv_data) | 366 | static void giveback(struct driver_data *drv_data) |
367 | { | 367 | { |
368 | struct spi_transfer* last_transfer; | 368 | struct spi_transfer* last_transfer; |
369 | unsigned long flags; | ||
370 | struct spi_message *msg; | ||
369 | 371 | ||
370 | last_transfer = list_entry(message->transfers.prev, | 372 | spin_lock_irqsave(&drv_data->lock, flags); |
373 | msg = drv_data->cur_msg; | ||
374 | drv_data->cur_msg = NULL; | ||
375 | drv_data->cur_transfer = NULL; | ||
376 | drv_data->cur_chip = NULL; | ||
377 | queue_work(drv_data->workqueue, &drv_data->pump_messages); | ||
378 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
379 | |||
380 | last_transfer = list_entry(msg->transfers.prev, | ||
371 | struct spi_transfer, | 381 | struct spi_transfer, |
372 | transfer_list); | 382 | transfer_list); |
373 | 383 | ||
374 | if (!last_transfer->cs_change) | 384 | if (!last_transfer->cs_change) |
375 | drv_data->cs_control(PXA2XX_CS_DEASSERT); | 385 | drv_data->cs_control(PXA2XX_CS_DEASSERT); |
376 | 386 | ||
377 | message->state = NULL; | 387 | msg->state = NULL; |
378 | if (message->complete) | 388 | if (msg->complete) |
379 | message->complete(message->context); | 389 | msg->complete(msg->context); |
380 | |||
381 | drv_data->cur_msg = NULL; | ||
382 | drv_data->cur_transfer = NULL; | ||
383 | drv_data->cur_chip = NULL; | ||
384 | queue_work(drv_data->workqueue, &drv_data->pump_messages); | ||
385 | } | 390 | } |
386 | 391 | ||
387 | static int wait_ssp_rx_stall(void *ioaddr) | 392 | static int wait_ssp_rx_stall(void *ioaddr) |
@@ -415,10 +420,11 @@ static void dma_handler(int channel, void *data, struct pt_regs *regs) | |||
415 | if (irq_status & DCSR_BUSERR) { | 420 | if (irq_status & DCSR_BUSERR) { |
416 | 421 | ||
417 | /* Disable interrupts, clear status and reset DMA */ | 422 | /* Disable interrupts, clear status and reset DMA */ |
423 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); | ||
424 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | ||
418 | if (drv_data->ssp_type != PXA25x_SSP) | 425 | if (drv_data->ssp_type != PXA25x_SSP) |
419 | write_SSTO(0, reg); | 426 | write_SSTO(0, reg); |
420 | write_SSSR(drv_data->clear_sr, reg); | 427 | write_SSSR(drv_data->clear_sr, reg); |
421 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | ||
422 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; | 428 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
423 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; | 429 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
424 | 430 | ||
@@ -454,8 +460,8 @@ static void dma_handler(int channel, void *data, struct pt_regs *regs) | |||
454 | "dma_handler: ssp rx stall failed\n"); | 460 | "dma_handler: ssp rx stall failed\n"); |
455 | 461 | ||
456 | /* Clear and disable interrupts on SSP and DMA channels*/ | 462 | /* Clear and disable interrupts on SSP and DMA channels*/ |
457 | write_SSSR(drv_data->clear_sr, reg); | ||
458 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | 463 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); |
464 | write_SSSR(drv_data->clear_sr, reg); | ||
459 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; | 465 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
460 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; | 466 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
461 | if (wait_dma_channel_stop(drv_data->rx_channel) == 0) | 467 | if (wait_dma_channel_stop(drv_data->rx_channel) == 0) |
@@ -497,10 +503,11 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) | |||
497 | irq_status = read_SSSR(reg) & drv_data->mask_sr; | 503 | irq_status = read_SSSR(reg) & drv_data->mask_sr; |
498 | if (irq_status & SSSR_ROR) { | 504 | if (irq_status & SSSR_ROR) { |
499 | /* Clear and disable interrupts on SSP and DMA channels*/ | 505 | /* Clear and disable interrupts on SSP and DMA channels*/ |
506 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); | ||
507 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | ||
500 | if (drv_data->ssp_type != PXA25x_SSP) | 508 | if (drv_data->ssp_type != PXA25x_SSP) |
501 | write_SSTO(0, reg); | 509 | write_SSTO(0, reg); |
502 | write_SSSR(drv_data->clear_sr, reg); | 510 | write_SSSR(drv_data->clear_sr, reg); |
503 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | ||
504 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; | 511 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
505 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; | 512 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
506 | unmap_dma_buffers(drv_data); | 513 | unmap_dma_buffers(drv_data); |
@@ -526,10 +533,10 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) | |||
526 | if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) { | 533 | if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) { |
527 | 534 | ||
528 | /* Clear and disable interrupts on SSP and DMA channels*/ | 535 | /* Clear and disable interrupts on SSP and DMA channels*/ |
536 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | ||
529 | if (drv_data->ssp_type != PXA25x_SSP) | 537 | if (drv_data->ssp_type != PXA25x_SSP) |
530 | write_SSTO(0, reg); | 538 | write_SSTO(0, reg); |
531 | write_SSSR(drv_data->clear_sr, reg); | 539 | write_SSSR(drv_data->clear_sr, reg); |
532 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | ||
533 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; | 540 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
534 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; | 541 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
535 | 542 | ||
@@ -572,26 +579,30 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) | |||
572 | 579 | ||
573 | static irqreturn_t interrupt_transfer(struct driver_data *drv_data) | 580 | static irqreturn_t interrupt_transfer(struct driver_data *drv_data) |
574 | { | 581 | { |
575 | u32 irq_status; | ||
576 | struct spi_message *msg = drv_data->cur_msg; | 582 | struct spi_message *msg = drv_data->cur_msg; |
577 | void *reg = drv_data->ioaddr; | 583 | void *reg = drv_data->ioaddr; |
578 | irqreturn_t handled = IRQ_NONE; | ||
579 | unsigned long limit = loops_per_jiffy << 1; | 584 | unsigned long limit = loops_per_jiffy << 1; |
585 | u32 irq_status; | ||
586 | u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ? | ||
587 | drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; | ||
580 | 588 | ||
581 | while ((irq_status = (read_SSSR(reg) & drv_data->mask_sr))) { | 589 | while ((irq_status = read_SSSR(reg) & irq_mask)) { |
582 | 590 | ||
583 | if (irq_status & SSSR_ROR) { | 591 | if (irq_status & SSSR_ROR) { |
584 | 592 | ||
585 | /* Clear and disable interrupts */ | 593 | /* Clear and disable interrupts */ |
594 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); | ||
595 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | ||
586 | if (drv_data->ssp_type != PXA25x_SSP) | 596 | if (drv_data->ssp_type != PXA25x_SSP) |
587 | write_SSTO(0, reg); | 597 | write_SSTO(0, reg); |
588 | write_SSSR(drv_data->clear_sr, reg); | 598 | write_SSSR(drv_data->clear_sr, reg); |
589 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | ||
590 | 599 | ||
591 | if (flush(drv_data) == 0) | 600 | if (flush(drv_data) == 0) |
592 | dev_err(&drv_data->pdev->dev, | 601 | dev_err(&drv_data->pdev->dev, |
593 | "interrupt_transfer: flush fail\n"); | 602 | "interrupt_transfer: flush fail\n"); |
594 | 603 | ||
604 | /* Stop the SSP */ | ||
605 | |||
595 | dev_warn(&drv_data->pdev->dev, | 606 | dev_warn(&drv_data->pdev->dev, |
596 | "interrupt_transfer: fifo overun\n"); | 607 | "interrupt_transfer: fifo overun\n"); |
597 | 608 | ||
@@ -613,6 +624,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) | |||
613 | if (drv_data->tx == drv_data->tx_end) { | 624 | if (drv_data->tx == drv_data->tx_end) { |
614 | /* Disable tx interrupt */ | 625 | /* Disable tx interrupt */ |
615 | write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); | 626 | write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); |
627 | irq_mask = drv_data->mask_sr & ~SSSR_TFS; | ||
616 | 628 | ||
617 | /* PXA25x_SSP has no timeout, read trailing bytes */ | 629 | /* PXA25x_SSP has no timeout, read trailing bytes */ |
618 | if (drv_data->ssp_type == PXA25x_SSP) { | 630 | if (drv_data->ssp_type == PXA25x_SSP) { |
@@ -630,10 +642,10 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) | |||
630 | || (drv_data->rx == drv_data->rx_end)) { | 642 | || (drv_data->rx == drv_data->rx_end)) { |
631 | 643 | ||
632 | /* Clear timeout */ | 644 | /* Clear timeout */ |
645 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | ||
633 | if (drv_data->ssp_type != PXA25x_SSP) | 646 | if (drv_data->ssp_type != PXA25x_SSP) |
634 | write_SSTO(0, reg); | 647 | write_SSTO(0, reg); |
635 | write_SSSR(drv_data->clear_sr, reg); | 648 | write_SSSR(drv_data->clear_sr, reg); |
636 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | ||
637 | 649 | ||
638 | /* Update total byte transfered */ | 650 | /* Update total byte transfered */ |
639 | msg->actual_length += drv_data->len; | 651 | msg->actual_length += drv_data->len; |
@@ -648,24 +660,29 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) | |||
648 | 660 | ||
649 | /* Schedule transfer tasklet */ | 661 | /* Schedule transfer tasklet */ |
650 | tasklet_schedule(&drv_data->pump_transfers); | 662 | tasklet_schedule(&drv_data->pump_transfers); |
651 | |||
652 | return IRQ_HANDLED; | ||
653 | } | 663 | } |
654 | |||
655 | /* We did something */ | ||
656 | handled = IRQ_HANDLED; | ||
657 | } | 664 | } |
658 | 665 | ||
659 | return handled; | 666 | /* We did something */ |
667 | return IRQ_HANDLED; | ||
660 | } | 668 | } |
661 | 669 | ||
662 | static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs) | 670 | static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs) |
663 | { | 671 | { |
664 | struct driver_data *drv_data = (struct driver_data *)dev_id; | 672 | struct driver_data *drv_data = (struct driver_data *)dev_id; |
673 | void *reg = drv_data->ioaddr; | ||
665 | 674 | ||
666 | if (!drv_data->cur_msg) { | 675 | if (!drv_data->cur_msg) { |
676 | |||
677 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); | ||
678 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | ||
679 | if (drv_data->ssp_type != PXA25x_SSP) | ||
680 | write_SSTO(0, reg); | ||
681 | write_SSSR(drv_data->clear_sr, reg); | ||
682 | |||
667 | dev_err(&drv_data->pdev->dev, "bad message state " | 683 | dev_err(&drv_data->pdev->dev, "bad message state " |
668 | "in interrupt handler\n"); | 684 | "in interrupt handler"); |
685 | |||
669 | /* Never fail */ | 686 | /* Never fail */ |
670 | return IRQ_HANDLED; | 687 | return IRQ_HANDLED; |
671 | } | 688 | } |
@@ -694,14 +711,14 @@ static void pump_transfers(unsigned long data) | |||
694 | /* Handle for abort */ | 711 | /* Handle for abort */ |
695 | if (message->state == ERROR_STATE) { | 712 | if (message->state == ERROR_STATE) { |
696 | message->status = -EIO; | 713 | message->status = -EIO; |
697 | giveback(message, drv_data); | 714 | giveback(drv_data); |
698 | return; | 715 | return; |
699 | } | 716 | } |
700 | 717 | ||
701 | /* Handle end of message */ | 718 | /* Handle end of message */ |
702 | if (message->state == DONE_STATE) { | 719 | if (message->state == DONE_STATE) { |
703 | message->status = 0; | 720 | message->status = 0; |
704 | giveback(message, drv_data); | 721 | giveback(drv_data); |
705 | return; | 722 | return; |
706 | } | 723 | } |
707 | 724 | ||
@@ -718,7 +735,7 @@ static void pump_transfers(unsigned long data) | |||
718 | if (flush(drv_data) == 0) { | 735 | if (flush(drv_data) == 0) { |
719 | dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); | 736 | dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n"); |
720 | message->status = -EIO; | 737 | message->status = -EIO; |
721 | giveback(message, drv_data); | 738 | giveback(drv_data); |
722 | return; | 739 | return; |
723 | } | 740 | } |
724 | drv_data->n_bytes = chip->n_bytes; | 741 | drv_data->n_bytes = chip->n_bytes; |
@@ -782,7 +799,7 @@ static void pump_transfers(unsigned long data) | |||
782 | 799 | ||
783 | cr0 = clk_div | 800 | cr0 = clk_div |
784 | | SSCR0_Motorola | 801 | | SSCR0_Motorola |
785 | | SSCR0_DataSize(bits & 0x0f) | 802 | | SSCR0_DataSize(bits > 16 ? bits - 16 : bits) |
786 | | SSCR0_SSE | 803 | | SSCR0_SSE |
787 | | (bits > 16 ? SSCR0_EDSS : 0); | 804 | | (bits > 16 ? SSCR0_EDSS : 0); |
788 | 805 | ||
@@ -890,8 +907,6 @@ static void pump_messages(void *data) | |||
890 | drv_data->cur_msg = list_entry(drv_data->queue.next, | 907 | drv_data->cur_msg = list_entry(drv_data->queue.next, |
891 | struct spi_message, queue); | 908 | struct spi_message, queue); |
892 | list_del_init(&drv_data->cur_msg->queue); | 909 | list_del_init(&drv_data->cur_msg->queue); |
893 | drv_data->busy = 1; | ||
894 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
895 | 910 | ||
896 | /* Initial message state*/ | 911 | /* Initial message state*/ |
897 | drv_data->cur_msg->state = START_STATE; | 912 | drv_data->cur_msg->state = START_STATE; |
@@ -905,6 +920,9 @@ static void pump_messages(void *data) | |||
905 | 920 | ||
906 | /* Mark as busy and launch transfers */ | 921 | /* Mark as busy and launch transfers */ |
907 | tasklet_schedule(&drv_data->pump_transfers); | 922 | tasklet_schedule(&drv_data->pump_transfers); |
923 | |||
924 | drv_data->busy = 1; | ||
925 | spin_unlock_irqrestore(&drv_data->lock, flags); | ||
908 | } | 926 | } |
909 | 927 | ||
910 | static int transfer(struct spi_device *spi, struct spi_message *msg) | 928 | static int transfer(struct spi_device *spi, struct spi_message *msg) |
@@ -958,7 +976,7 @@ static int setup(struct spi_device *spi) | |||
958 | 976 | ||
959 | chip->cs_control = null_cs_control; | 977 | chip->cs_control = null_cs_control; |
960 | chip->enable_dma = 0; | 978 | chip->enable_dma = 0; |
961 | chip->timeout = 5; | 979 | chip->timeout = SSP_TIMEOUT(1000); |
962 | chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1); | 980 | chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1); |
963 | chip->dma_burst_size = drv_data->master_info->enable_dma ? | 981 | chip->dma_burst_size = drv_data->master_info->enable_dma ? |
964 | DCMD_BURST8 : 0; | 982 | DCMD_BURST8 : 0; |
@@ -971,7 +989,7 @@ static int setup(struct spi_device *spi) | |||
971 | if (chip_info->cs_control) | 989 | if (chip_info->cs_control) |
972 | chip->cs_control = chip_info->cs_control; | 990 | chip->cs_control = chip_info->cs_control; |
973 | 991 | ||
974 | chip->timeout = (chip_info->timeout_microsecs * 10000) / 2712; | 992 | chip->timeout = SSP_TIMEOUT(chip_info->timeout_microsecs); |
975 | 993 | ||
976 | chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold) | 994 | chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold) |
977 | | SSCR1_TxTresh(chip_info->tx_threshold); | 995 | | SSCR1_TxTresh(chip_info->tx_threshold); |
@@ -1013,7 +1031,8 @@ static int setup(struct spi_device *spi) | |||
1013 | 1031 | ||
1014 | chip->cr0 = clk_div | 1032 | chip->cr0 = clk_div |
1015 | | SSCR0_Motorola | 1033 | | SSCR0_Motorola |
1016 | | SSCR0_DataSize(spi->bits_per_word & 0x0f) | 1034 | | SSCR0_DataSize(spi->bits_per_word > 16 ? |
1035 | spi->bits_per_word - 16 : spi->bits_per_word) | ||
1017 | | SSCR0_SSE | 1036 | | SSCR0_SSE |
1018 | | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0); | 1037 | | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0); |
1019 | chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4) | 1038 | chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4) |
@@ -1196,7 +1215,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) | |||
1196 | goto out_error_master_alloc; | 1215 | goto out_error_master_alloc; |
1197 | } | 1216 | } |
1198 | 1217 | ||
1199 | drv_data->ioaddr = (void *)io_p2v(memory_resource->start); | 1218 | drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start)); |
1200 | drv_data->ssdr_physical = memory_resource->start + 0x00000010; | 1219 | drv_data->ssdr_physical = memory_resource->start + 0x00000010; |
1201 | if (platform_info->ssp_type == PXA25x_SSP) { | 1220 | if (platform_info->ssp_type == PXA25x_SSP) { |
1202 | drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; | 1221 | drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; |
@@ -1218,7 +1237,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) | |||
1218 | goto out_error_master_alloc; | 1237 | goto out_error_master_alloc; |
1219 | } | 1238 | } |
1220 | 1239 | ||
1221 | status = request_irq(irq, ssp_int, SA_INTERRUPT, dev->bus_id, drv_data); | 1240 | status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data); |
1222 | if (status < 0) { | 1241 | if (status < 0) { |
1223 | dev_err(&pdev->dev, "can not get IRQ\n"); | 1242 | dev_err(&pdev->dev, "can not get IRQ\n"); |
1224 | goto out_error_master_alloc; | 1243 | goto out_error_master_alloc; |