diff options
| author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2010-11-22 20:12:17 -0500 |
|---|---|---|
| committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2010-12-02 11:55:12 -0500 |
| commit | 2a8626a9e2d86d114a2d9f813a1acebf9d53dd10 (patch) | |
| tree | fa8764bdc568371a6e3038a402cc101eda07bb19 | |
| parent | d0777f2c3eda180e3fc549e0efbe741014f17689 (diff) | |
spi/pxa2xx: Add chipselect support for Sodaville
The SPI core on Sodaville supports chip selects. Its configuration
moved into the SSSR register at bit 0 and 1. Thus Sodaville can be hooked
up with up to 4 devices.
This patch ensures that the bits which are otherwiese reserved are only
touched on Sodaville and not on any other PXAs. Also it makes sure that
the status register does not lose the CS information while clearing the
ROR bit.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
| -rw-r--r-- | drivers/spi/pxa2xx_spi.c | 93 | ||||
| -rw-r--r-- | include/linux/pxa2xx_ssp.h | 2 |
2 files changed, 70 insertions, 25 deletions
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 81cfbbc58e94..a54685bb7e53 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c | |||
| @@ -163,7 +163,10 @@ struct chip_data { | |||
| 163 | u8 enable_dma; | 163 | u8 enable_dma; |
| 164 | u8 bits_per_word; | 164 | u8 bits_per_word; |
| 165 | u32 speed_hz; | 165 | u32 speed_hz; |
| 166 | int gpio_cs; | 166 | union { |
| 167 | int gpio_cs; | ||
| 168 | unsigned int frm; | ||
| 169 | }; | ||
| 167 | int gpio_cs_inverted; | 170 | int gpio_cs_inverted; |
| 168 | int (*write)(struct driver_data *drv_data); | 171 | int (*write)(struct driver_data *drv_data); |
| 169 | int (*read)(struct driver_data *drv_data); | 172 | int (*read)(struct driver_data *drv_data); |
| @@ -176,6 +179,11 @@ static void cs_assert(struct driver_data *drv_data) | |||
| 176 | { | 179 | { |
| 177 | struct chip_data *chip = drv_data->cur_chip; | 180 | struct chip_data *chip = drv_data->cur_chip; |
| 178 | 181 | ||
| 182 | if (drv_data->ssp_type == CE4100_SSP) { | ||
| 183 | write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr); | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | |||
| 179 | if (chip->cs_control) { | 187 | if (chip->cs_control) { |
| 180 | chip->cs_control(PXA2XX_CS_ASSERT); | 188 | chip->cs_control(PXA2XX_CS_ASSERT); |
| 181 | return; | 189 | return; |
| @@ -189,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data) | |||
| 189 | { | 197 | { |
| 190 | struct chip_data *chip = drv_data->cur_chip; | 198 | struct chip_data *chip = drv_data->cur_chip; |
| 191 | 199 | ||
| 200 | if (drv_data->ssp_type == CE4100_SSP) | ||
| 201 | return; | ||
| 202 | |||
| 192 | if (chip->cs_control) { | 203 | if (chip->cs_control) { |
| 193 | chip->cs_control(PXA2XX_CS_DEASSERT); | 204 | chip->cs_control(PXA2XX_CS_DEASSERT); |
| 194 | return; | 205 | return; |
| @@ -198,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data) | |||
| 198 | gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted); | 209 | gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted); |
| 199 | } | 210 | } |
| 200 | 211 | ||
| 212 | static void write_SSSR_CS(struct driver_data *drv_data, u32 val) | ||
| 213 | { | ||
| 214 | void __iomem *reg = drv_data->ioaddr; | ||
| 215 | |||
| 216 | if (drv_data->ssp_type == CE4100_SSP) | ||
| 217 | val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK; | ||
| 218 | |||
| 219 | write_SSSR(val, reg); | ||
| 220 | } | ||
| 221 | |||
| 222 | static int pxa25x_ssp_comp(struct driver_data *drv_data) | ||
| 223 | { | ||
| 224 | if (drv_data->ssp_type == PXA25x_SSP) | ||
| 225 | return 1; | ||
| 226 | if (drv_data->ssp_type == CE4100_SSP) | ||
| 227 | return 1; | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 201 | static int flush(struct driver_data *drv_data) | 231 | static int flush(struct driver_data *drv_data) |
| 202 | { | 232 | { |
| 203 | unsigned long limit = loops_per_jiffy << 1; | 233 | unsigned long limit = loops_per_jiffy << 1; |
| @@ -209,7 +239,7 @@ static int flush(struct driver_data *drv_data) | |||
| 209 | read_SSDR(reg); | 239 | read_SSDR(reg); |
| 210 | } | 240 | } |
| 211 | } while ((read_SSSR(reg) & SSSR_BSY) && --limit); | 241 | } while ((read_SSSR(reg) & SSSR_BSY) && --limit); |
| 212 | write_SSSR(SSSR_ROR, reg); | 242 | write_SSSR_CS(drv_data, SSSR_ROR); |
| 213 | 243 | ||
| 214 | return limit; | 244 | return limit; |
| 215 | } | 245 | } |
| @@ -502,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg) | |||
| 502 | /* Stop and reset */ | 532 | /* Stop and reset */ |
| 503 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; | 533 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
| 504 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; | 534 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
| 505 | write_SSSR(drv_data->clear_sr, reg); | 535 | write_SSSR_CS(drv_data, drv_data->clear_sr); |
| 506 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | 536 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); |
| 507 | if (drv_data->ssp_type != PXA25x_SSP) | 537 | if (!pxa25x_ssp_comp(drv_data)) |
| 508 | write_SSTO(0, reg); | 538 | write_SSTO(0, reg); |
| 509 | flush(drv_data); | 539 | flush(drv_data); |
| 510 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); | 540 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); |
| @@ -524,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data) | |||
| 524 | 554 | ||
| 525 | /* Clear and disable interrupts on SSP and DMA channels*/ | 555 | /* Clear and disable interrupts on SSP and DMA channels*/ |
| 526 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); | 556 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); |
| 527 | write_SSSR(drv_data->clear_sr, reg); | 557 | write_SSSR_CS(drv_data, drv_data->clear_sr); |
| 528 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; | 558 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
| 529 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; | 559 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
| 530 | 560 | ||
| @@ -617,7 +647,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) | |||
| 617 | 647 | ||
| 618 | /* Clear and disable timeout interrupt, do the rest in | 648 | /* Clear and disable timeout interrupt, do the rest in |
| 619 | * dma_transfer_complete */ | 649 | * dma_transfer_complete */ |
| 620 | if (drv_data->ssp_type != PXA25x_SSP) | 650 | if (!pxa25x_ssp_comp(drv_data)) |
| 621 | write_SSTO(0, reg); | 651 | write_SSTO(0, reg); |
| 622 | 652 | ||
| 623 | /* finish this transfer, start the next */ | 653 | /* finish this transfer, start the next */ |
| @@ -635,9 +665,9 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg) | |||
| 635 | void __iomem *reg = drv_data->ioaddr; | 665 | void __iomem *reg = drv_data->ioaddr; |
| 636 | 666 | ||
| 637 | /* Stop and reset SSP */ | 667 | /* Stop and reset SSP */ |
| 638 | write_SSSR(drv_data->clear_sr, reg); | 668 | write_SSSR_CS(drv_data, drv_data->clear_sr); |
| 639 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | 669 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); |
| 640 | if (drv_data->ssp_type != PXA25x_SSP) | 670 | if (!pxa25x_ssp_comp(drv_data)) |
| 641 | write_SSTO(0, reg); | 671 | write_SSTO(0, reg); |
| 642 | flush(drv_data); | 672 | flush(drv_data); |
| 643 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); | 673 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); |
| @@ -653,9 +683,9 @@ static void int_transfer_complete(struct driver_data *drv_data) | |||
| 653 | void __iomem *reg = drv_data->ioaddr; | 683 | void __iomem *reg = drv_data->ioaddr; |
| 654 | 684 | ||
| 655 | /* Stop SSP */ | 685 | /* Stop SSP */ |
| 656 | write_SSSR(drv_data->clear_sr, reg); | 686 | write_SSSR_CS(drv_data, drv_data->clear_sr); |
| 657 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | 687 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); |
| 658 | if (drv_data->ssp_type != PXA25x_SSP) | 688 | if (!pxa25x_ssp_comp(drv_data)) |
| 659 | write_SSTO(0, reg); | 689 | write_SSTO(0, reg); |
| 660 | 690 | ||
| 661 | /* Update total byte transfered return count actual bytes read */ | 691 | /* Update total byte transfered return count actual bytes read */ |
| @@ -711,7 +741,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) | |||
| 711 | if (drv_data->tx == drv_data->tx_end) { | 741 | if (drv_data->tx == drv_data->tx_end) { |
| 712 | write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); | 742 | write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); |
| 713 | /* PXA25x_SSP has no timeout, read trailing bytes */ | 743 | /* PXA25x_SSP has no timeout, read trailing bytes */ |
| 714 | if (drv_data->ssp_type == PXA25x_SSP) { | 744 | if (pxa25x_ssp_comp(drv_data)) { |
| 715 | if (!wait_ssp_rx_stall(reg)) | 745 | if (!wait_ssp_rx_stall(reg)) |
| 716 | { | 746 | { |
| 717 | int_error_stop(drv_data, "interrupt_transfer: " | 747 | int_error_stop(drv_data, "interrupt_transfer: " |
| @@ -754,9 +784,9 @@ static irqreturn_t ssp_int(int irq, void *dev_id) | |||
| 754 | 784 | ||
| 755 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); | 785 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); |
| 756 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); | 786 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); |
| 757 | if (drv_data->ssp_type != PXA25x_SSP) | 787 | if (!pxa25x_ssp_comp(drv_data)) |
| 758 | write_SSTO(0, reg); | 788 | write_SSTO(0, reg); |
| 759 | write_SSSR(drv_data->clear_sr, reg); | 789 | write_SSSR_CS(drv_data, drv_data->clear_sr); |
| 760 | 790 | ||
| 761 | dev_err(&drv_data->pdev->dev, "bad message state " | 791 | dev_err(&drv_data->pdev->dev, "bad message state " |
| 762 | "in interrupt handler\n"); | 792 | "in interrupt handler\n"); |
| @@ -869,7 +899,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate) | |||
| 869 | { | 899 | { |
| 870 | unsigned long ssp_clk = clk_get_rate(ssp->clk); | 900 | unsigned long ssp_clk = clk_get_rate(ssp->clk); |
| 871 | 901 | ||
| 872 | if (ssp->type == PXA25x_SSP) | 902 | if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP) |
| 873 | return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; | 903 | return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; |
| 874 | else | 904 | else |
| 875 | return ((ssp_clk / rate - 1) & 0xfff) << 8; | 905 | return ((ssp_clk / rate - 1) & 0xfff) << 8; |
| @@ -1095,7 +1125,7 @@ static void pump_transfers(unsigned long data) | |||
| 1095 | |||
