diff options
author | Tony Lindgren <tony@atomide.com> | 2010-03-01 17:19:05 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-03-01 17:19:05 -0500 |
commit | d702d12167a2c05a346f49aac7a311d597762495 (patch) | |
tree | baae42c299cce34d6df24b5d01f8b1d0b481bd9a /drivers/spi/dw_spi.c | |
parent | 9418c65f9bd861d0f7e39aab9cfb3aa6f2275d11 (diff) | |
parent | ac0f6f927db539e03e1f3f61bcd4ed57d5cde7a9 (diff) |
Merge with mainline to remove plat-omap/Kconfig conflict
Conflicts:
arch/arm/plat-omap/Kconfig
Diffstat (limited to 'drivers/spi/dw_spi.c')
-rw-r--r-- | drivers/spi/dw_spi.c | 111 |
1 files changed, 78 insertions, 33 deletions
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 31620fae77be..8ed38f1d6c18 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c | |||
@@ -152,6 +152,7 @@ static void mrst_spi_debugfs_remove(struct dw_spi *dws) | |||
152 | #else | 152 | #else |
153 | static inline int mrst_spi_debugfs_init(struct dw_spi *dws) | 153 | static inline int mrst_spi_debugfs_init(struct dw_spi *dws) |
154 | { | 154 | { |
155 | return 0; | ||
155 | } | 156 | } |
156 | 157 | ||
157 | static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) | 158 | static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) |
@@ -161,14 +162,14 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) | |||
161 | 162 | ||
162 | static void wait_till_not_busy(struct dw_spi *dws) | 163 | static void wait_till_not_busy(struct dw_spi *dws) |
163 | { | 164 | { |
164 | unsigned long end = jiffies + usecs_to_jiffies(1000); | 165 | unsigned long end = jiffies + 1 + usecs_to_jiffies(1000); |
165 | 166 | ||
166 | while (time_before(jiffies, end)) { | 167 | while (time_before(jiffies, end)) { |
167 | if (!(dw_readw(dws, sr) & SR_BUSY)) | 168 | if (!(dw_readw(dws, sr) & SR_BUSY)) |
168 | return; | 169 | return; |
169 | } | 170 | } |
170 | dev_err(&dws->master->dev, | 171 | dev_err(&dws->master->dev, |
171 | "DW SPI: Stutus keeps busy for 1000us after a read/write!\n"); | 172 | "DW SPI: Status keeps busy for 1000us after a read/write!\n"); |
172 | } | 173 | } |
173 | 174 | ||
174 | static void flush(struct dw_spi *dws) | 175 | static void flush(struct dw_spi *dws) |
@@ -358,6 +359,8 @@ static void transfer_complete(struct dw_spi *dws) | |||
358 | static irqreturn_t interrupt_transfer(struct dw_spi *dws) | 359 | static irqreturn_t interrupt_transfer(struct dw_spi *dws) |
359 | { | 360 | { |
360 | u16 irq_status, irq_mask = 0x3f; | 361 | u16 irq_status, irq_mask = 0x3f; |
362 | u32 int_level = dws->fifo_len / 2; | ||
363 | u32 left; | ||
361 | 364 | ||
362 | irq_status = dw_readw(dws, isr) & irq_mask; | 365 | irq_status = dw_readw(dws, isr) & irq_mask; |
363 | /* Error handling */ | 366 | /* Error handling */ |
@@ -369,22 +372,23 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) | |||
369 | return IRQ_HANDLED; | 372 | return IRQ_HANDLED; |
370 | } | 373 | } |
371 | 374 | ||
372 | /* INT comes from tx */ | 375 | if (irq_status & SPI_INT_TXEI) { |
373 | if (dws->tx && (irq_status & SPI_INT_TXEI)) { | 376 | spi_mask_intr(dws, SPI_INT_TXEI); |
374 | while (dws->tx < dws->tx_end) | 377 | |
378 | left = (dws->tx_end - dws->tx) / dws->n_bytes; | ||
379 | left = (left > int_level) ? int_level : left; | ||
380 | |||
381 | while (left--) | ||
375 | dws->write(dws); | 382 | dws->write(dws); |
383 | dws->read(dws); | ||
376 | 384 | ||
377 | if (dws->tx == dws->tx_end) { | 385 | /* Re-enable the IRQ if there is still data left to tx */ |
378 | spi_mask_intr(dws, SPI_INT_TXEI); | 386 | if (dws->tx_end > dws->tx) |
387 | spi_umask_intr(dws, SPI_INT_TXEI); | ||
388 | else | ||
379 | transfer_complete(dws); | 389 | transfer_complete(dws); |
380 | } | ||
381 | } | 390 | } |
382 | 391 | ||
383 | /* INT comes from rx */ | ||
384 | if (dws->rx && (irq_status & SPI_INT_RXFI)) { | ||
385 | if (dws->read(dws)) | ||
386 | transfer_complete(dws); | ||
387 | } | ||
388 | return IRQ_HANDLED; | 392 | return IRQ_HANDLED; |
389 | } | 393 | } |
390 | 394 | ||
@@ -404,12 +408,9 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id) | |||
404 | /* Must be called inside pump_transfers() */ | 408 | /* Must be called inside pump_transfers() */ |
405 | static void poll_transfer(struct dw_spi *dws) | 409 | static void poll_transfer(struct dw_spi *dws) |
406 | { | 410 | { |
407 | if (dws->tx) { | 411 | while (dws->write(dws)) |
408 | while (dws->write(dws)) | 412 | dws->read(dws); |
409 | dws->read(dws); | ||
410 | } | ||
411 | 413 | ||
412 | dws->read(dws); | ||
413 | transfer_complete(dws); | 414 | transfer_complete(dws); |
414 | } | 415 | } |
415 | 416 | ||
@@ -428,6 +429,7 @@ static void pump_transfers(unsigned long data) | |||
428 | u8 bits = 0; | 429 | u8 bits = 0; |
429 | u8 imask = 0; | 430 | u8 imask = 0; |
430 | u8 cs_change = 0; | 431 | u8 cs_change = 0; |
432 | u16 txint_level = 0; | ||
431 | u16 clk_div = 0; | 433 | u16 clk_div = 0; |
432 | u32 speed = 0; | 434 | u32 speed = 0; |
433 | u32 cr0 = 0; | 435 | u32 cr0 = 0; |
@@ -438,6 +440,9 @@ static void pump_transfers(unsigned long data) | |||
438 | chip = dws->cur_chip; | 440 | chip = dws->cur_chip; |
439 | spi = message->spi; | 441 | spi = message->spi; |
440 | 442 | ||
443 | if (unlikely(!chip->clk_div)) | ||
444 | chip->clk_div = dws->max_freq / chip->speed_hz; | ||
445 | |||
441 | if (message->state == ERROR_STATE) { | 446 | if (message->state == ERROR_STATE) { |
442 | message->status = -EIO; | 447 | message->status = -EIO; |
443 | goto early_exit; | 448 | goto early_exit; |
@@ -492,7 +497,7 @@ static void pump_transfers(unsigned long data) | |||
492 | 497 | ||
493 | /* clk_div doesn't support odd number */ | 498 | /* clk_div doesn't support odd number */ |
494 | clk_div = dws->max_freq / speed; | 499 | clk_div = dws->max_freq / speed; |
495 | clk_div = (clk_div >> 1) << 1; | 500 | clk_div = (clk_div + 1) & 0xfffe; |
496 | 501 | ||
497 | chip->speed_hz = speed; | 502 | chip->speed_hz = speed; |
498 | chip->clk_div = clk_div; | 503 | chip->clk_div = clk_div; |
@@ -532,14 +537,35 @@ static void pump_transfers(unsigned long data) | |||
532 | } | 537 | } |
533 | message->state = RUNNING_STATE; | 538 | message->state = RUNNING_STATE; |
534 | 539 | ||
540 | /* | ||
541 | * Adjust transfer mode if necessary. Requires platform dependent | ||
542 | * chipselect mechanism. | ||
543 | */ | ||
544 | if (dws->cs_control) { | ||
545 | if (dws->rx && dws->tx) | ||
546 | chip->tmode = 0x00; | ||
547 | else if (dws->rx) | ||
548 | chip->tmode = 0x02; | ||
549 | else | ||
550 | chip->tmode = 0x01; | ||
551 | |||
552 | cr0 &= ~(0x3 << SPI_MODE_OFFSET); | ||
553 | cr0 |= (chip->tmode << SPI_TMOD_OFFSET); | ||
554 | } | ||
555 | |||
535 | /* Check if current transfer is a DMA transaction */ | 556 | /* Check if current transfer is a DMA transaction */ |
536 | dws->dma_mapped = map_dma_buffers(dws); | 557 | dws->dma_mapped = map_dma_buffers(dws); |
537 | 558 | ||
559 | /* | ||
560 | * Interrupt mode | ||
561 | * we only need set the TXEI IRQ, as TX/RX always happen syncronizely | ||
562 | */ | ||
538 | if (!dws->dma_mapped && !chip->poll_mode) { | 563 | if (!dws->dma_mapped && !chip->poll_mode) { |
539 | if (dws->rx) | 564 | int templen = dws->len / dws->n_bytes; |
540 | imask |= SPI_INT_RXFI; | 565 | txint_level = dws->fifo_len / 2; |
541 | if (dws->tx) | 566 | txint_level = (templen > txint_level) ? txint_level : templen; |
542 | imask |= SPI_INT_TXEI; | 567 | |
568 | imask |= SPI_INT_TXEI; | ||
543 | dws->transfer_handler = interrupt_transfer; | 569 | dws->transfer_handler = interrupt_transfer; |
544 | } | 570 | } |
545 | 571 | ||
@@ -549,21 +575,23 @@ static void pump_transfers(unsigned long data) | |||
549 | * 2. clk_div is changed | 575 | * 2. clk_div is changed |
550 | * 3. control value changes | 576 | * 3. control value changes |
551 | */ | 577 | */ |
552 | if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div) { | 578 | if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div || imask) { |
553 | spi_enable_chip(dws, 0); | 579 | spi_enable_chip(dws, 0); |
554 | 580 | ||
555 | if (dw_readw(dws, ctrl0) != cr0) | 581 | if (dw_readw(dws, ctrl0) != cr0) |
556 | dw_writew(dws, ctrl0, cr0); | 582 | dw_writew(dws, ctrl0, cr0); |
557 | 583 | ||
584 | spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); | ||
585 | spi_chip_sel(dws, spi->chip_select); | ||
586 | |||
558 | /* Set the interrupt mask, for poll mode just diable all int */ | 587 | /* Set the interrupt mask, for poll mode just diable all int */ |
559 | spi_mask_intr(dws, 0xff); | 588 | spi_mask_intr(dws, 0xff); |
560 | if (!chip->poll_mode) | 589 | if (imask) |
561 | spi_umask_intr(dws, imask); | 590 | spi_umask_intr(dws, imask); |
591 | if (txint_level) | ||
592 | dw_writew(dws, txfltr, txint_level); | ||
562 | 593 | ||
563 | spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); | ||
564 | spi_chip_sel(dws, spi->chip_select); | ||
565 | spi_enable_chip(dws, 1); | 594 | spi_enable_chip(dws, 1); |
566 | |||
567 | if (cs_change) | 595 | if (cs_change) |
568 | dws->prev_chip = chip; | 596 | dws->prev_chip = chip; |
569 | } | 597 | } |
@@ -712,11 +740,11 @@ static int dw_spi_setup(struct spi_device *spi) | |||
712 | } | 740 | } |
713 | chip->bits_per_word = spi->bits_per_word; | 741 | chip->bits_per_word = spi->bits_per_word; |
714 | 742 | ||
743 | if (!spi->max_speed_hz) { | ||
744 | dev_err(&spi->dev, "No max speed HZ parameter\n"); | ||
745 | return -EINVAL; | ||
746 | } | ||
715 | chip->speed_hz = spi->max_speed_hz; | 747 | chip->speed_hz = spi->max_speed_hz; |
716 | if (chip->speed_hz) | ||
717 | chip->clk_div = 25000000 / chip->speed_hz; | ||
718 | else | ||
719 | chip->clk_div = 8; /* default value */ | ||
720 | 748 | ||
721 | chip->tmode = 0; /* Tx & Rx */ | 749 | chip->tmode = 0; /* Tx & Rx */ |
722 | /* Default SPI mode is SCPOL = 0, SCPH = 0 */ | 750 | /* Default SPI mode is SCPOL = 0, SCPH = 0 */ |
@@ -735,7 +763,7 @@ static void dw_spi_cleanup(struct spi_device *spi) | |||
735 | kfree(chip); | 763 | kfree(chip); |
736 | } | 764 | } |
737 | 765 | ||
738 | static int __init init_queue(struct dw_spi *dws) | 766 | static int __devinit init_queue(struct dw_spi *dws) |
739 | { | 767 | { |
740 | INIT_LIST_HEAD(&dws->queue); | 768 | INIT_LIST_HEAD(&dws->queue); |
741 | spin_lock_init(&dws->lock); | 769 | spin_lock_init(&dws->lock); |
@@ -817,6 +845,22 @@ static void spi_hw_init(struct dw_spi *dws) | |||
817 | spi_mask_intr(dws, 0xff); | 845 | spi_mask_intr(dws, 0xff); |
818 | spi_enable_chip(dws, 1); | 846 | spi_enable_chip(dws, 1); |
819 | flush(dws); | 847 | flush(dws); |
848 | |||
849 | /* | ||
850 | * Try to detect the FIFO depth if not set by interface driver, | ||
851 | * the depth could be from 2 to 256 from HW spec | ||
852 | */ | ||
853 | if (!dws->fifo_len) { | ||
854 | u32 fifo; | ||
855 | for (fifo = 2; fifo <= 257; fifo++) { | ||
856 | dw_writew(dws, txfltr, fifo); | ||
857 | if (fifo != dw_readw(dws, txfltr)) | ||
858 | break; | ||
859 | } | ||
860 | |||
861 | dws->fifo_len = (fifo == 257) ? 0 : fifo; | ||
862 | dw_writew(dws, txfltr, 0); | ||
863 | } | ||
820 | } | 864 | } |
821 | 865 | ||
822 | int __devinit dw_spi_add_host(struct dw_spi *dws) | 866 | int __devinit dw_spi_add_host(struct dw_spi *dws) |
@@ -913,6 +957,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws) | |||
913 | /* Disconnect from the SPI framework */ | 957 | /* Disconnect from the SPI framework */ |
914 | spi_unregister_master(dws->master); | 958 | spi_unregister_master(dws->master); |
915 | } | 959 | } |
960 | EXPORT_SYMBOL(dw_spi_remove_host); | ||
916 | 961 | ||
917 | int dw_spi_suspend_host(struct dw_spi *dws) | 962 | int dw_spi_suspend_host(struct dw_spi *dws) |
918 | { | 963 | { |