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 /drivers/spi | |
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>
Diffstat (limited to 'drivers/spi')
-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; |