diff options
| author | Jassi Brar <jassi.brar@samsung.com> | 2010-09-29 04:31:33 -0400 |
|---|---|---|
| committer | Grant Likely <grant.likely@secretlab.ca> | 2010-09-29 04:31:33 -0400 |
| commit | 0c92ecf10d9fb80b1798d2a9adfdea17f8f5e6d9 (patch) | |
| tree | d8b4f864e8d037542301be4088fd0048e46d2097 | |
| parent | b42a81ca0fa7b3b442a0731ffc4e7db44464b5f2 (diff) | |
spi/s3c64xx: Correction for 16,32 bits bus width
We can't do without setting channel and bus width to
same size. In order to do that, use loop read/writes in
polling mode and appropriate burst size in DMA mode.
Signed-off-by: Jassi Brar <jassi.brar@samsung.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
| -rw-r--r-- | drivers/spi/spi_s3c64xx.c | 56 |
1 files changed, 41 insertions, 15 deletions
diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 9e0aa3c7b4d1..795828b90f45 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c | |||
| @@ -261,15 +261,25 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, | |||
| 261 | chcfg |= S3C64XX_SPI_CH_TXCH_ON; | 261 | chcfg |= S3C64XX_SPI_CH_TXCH_ON; |
| 262 | if (dma_mode) { | 262 | if (dma_mode) { |
| 263 | modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; | 263 | modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; |
| 264 | s3c2410_dma_config(sdd->tx_dmach, 1); | 264 | s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8); |
| 265 | s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd, | 265 | s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd, |
| 266 | xfer->tx_dma, xfer->len); | 266 | xfer->tx_dma, xfer->len); |
| 267 | s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START); | 267 | s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START); |
| 268 | } else { | 268 | } else { |
| 269 | unsigned char *buf = (unsigned char *) xfer->tx_buf; | 269 | switch (sdd->cur_bpw) { |
| 270 | int i = 0; | 270 | case 32: |
| 271 | while (i < xfer->len) | 271 | iowrite32_rep(regs + S3C64XX_SPI_TX_DATA, |
| 272 | writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA); | 272 | xfer->tx_buf, xfer->len / 4); |
| 273 | break; | ||
| 274 | case 16: | ||
| 275 | iowrite16_rep(regs + S3C64XX_SPI_TX_DATA, | ||
| 276 | xfer->tx_buf, xfer->len / 2); | ||
| 277 | break; | ||
| 278 | default: | ||
| 279 | iowrite8_rep(regs + S3C64XX_SPI_TX_DATA, | ||
| 280 | xfer->tx_buf, xfer->len); | ||
| 281 | break; | ||
| 282 | } | ||
| 273 | } | 283 | } |
| 274 | } | 284 | } |
| 275 | 285 | ||
| @@ -286,7 +296,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, | |||
| 286 | writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | 296 | writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) |
| 287 | | S3C64XX_SPI_PACKET_CNT_EN, | 297 | | S3C64XX_SPI_PACKET_CNT_EN, |
| 288 | regs + S3C64XX_SPI_PACKET_CNT); | 298 | regs + S3C64XX_SPI_PACKET_CNT); |
| 289 | s3c2410_dma_config(sdd->rx_dmach, 1); | 299 | s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8); |
| 290 | s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd, | 300 | s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd, |
| 291 | xfer->rx_dma, xfer->len); | 301 | xfer->rx_dma, xfer->len); |
| 292 | s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START); | 302 | s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START); |
| @@ -366,20 +376,26 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, | |||
| 366 | return -EIO; | 376 | return -EIO; |
| 367 | } | 377 | } |
| 368 | } else { | 378 | } else { |
| 369 | unsigned char *buf; | ||
| 370 | int i; | ||
| 371 | |||
| 372 | /* If it was only Tx */ | 379 | /* If it was only Tx */ |
| 373 | if (xfer->rx_buf == NULL) { | 380 | if (xfer->rx_buf == NULL) { |
| 374 | sdd->state &= ~TXBUSY; | 381 | sdd->state &= ~TXBUSY; |
| 375 | return 0; | 382 | return 0; |
| 376 | } | 383 | } |
| 377 | 384 | ||
| 378 | i = 0; | 385 | switch (sdd->cur_bpw) { |
| 379 | buf = xfer->rx_buf; | 386 | case 32: |
| 380 | while (i < xfer->len) | 387 | ioread32_rep(regs + S3C64XX_SPI_RX_DATA, |
| 381 | buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA); | 388 | xfer->rx_buf, xfer->len / 4); |
| 382 | 389 | break; | |
| 390 | case 16: | ||
| 391 | ioread16_rep(regs + S3C64XX_SPI_RX_DATA, | ||
| 392 | xfer->rx_buf, xfer->len / 2); | ||
| 393 | break; | ||
| 394 | default: | ||
| 395 | ioread8_rep(regs + S3C64XX_SPI_RX_DATA, | ||
| 396 | xfer->rx_buf, xfer->len); | ||
| 397 | break; | ||
| 398 | } | ||
| 383 | sdd->state &= ~RXBUSY; | 399 | sdd->state &= ~RXBUSY; |
| 384 | } | 400 | } |
| 385 | 401 | ||
| @@ -434,15 +450,17 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) | |||
| 434 | switch (sdd->cur_bpw) { | 450 | switch (sdd->cur_bpw) { |
| 435 | case 32: | 451 | case 32: |
| 436 | val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD; | 452 | val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD; |
| 453 | val |= S3C64XX_SPI_MODE_CH_TSZ_WORD; | ||
| 437 | break; | 454 | break; |
| 438 | case 16: | 455 | case 16: |
| 439 | val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD; | 456 | val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD; |
| 457 | val |= S3C64XX_SPI_MODE_CH_TSZ_HALFWORD; | ||
| 440 | break; | 458 | break; |
| 441 | default: | 459 | default: |
| 442 | val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE; | 460 | val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE; |
| 461 | val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; | ||
| 443 | break; | 462 | break; |
| 444 | } | 463 | } |
| 445 | val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; /* Always 8bits wide */ | ||
| 446 | 464 | ||
| 447 | writel(val, regs + S3C64XX_SPI_MODE_CFG); | 465 | writel(val, regs + S3C64XX_SPI_MODE_CFG); |
| 448 | 466 | ||
| @@ -629,6 +647,14 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd, | |||
| 629 | bpw = xfer->bits_per_word ? : spi->bits_per_word; | 647 | bpw = xfer->bits_per_word ? : spi->bits_per_word; |
| 630 | speed = xfer->speed_hz ? : spi->max_speed_hz; | 648 | speed = xfer->speed_hz ? : spi->max_speed_hz; |
| 631 | 649 | ||
| 650 | if (xfer->len % (bpw / 8)) { | ||
| 651 | dev_err(&spi->dev, | ||
| 652 | "Xfer length(%u) not a multiple of word size(%u)\n", | ||
| 653 | xfer->len, bpw / 8); | ||
| 654 | status = -EIO; | ||
| 655 | goto out; | ||
| 656 | } | ||
| 657 | |||
| 632 | if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { | 658 | if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { |
| 633 | sdd->cur_bpw = bpw; | 659 | sdd->cur_bpw = bpw; |
| 634 | sdd->cur_speed = speed; | 660 | sdd->cur_speed = speed; |
