aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorJassi Brar <jassi.brar@samsung.com>2010-09-29 04:31:33 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-09-29 04:31:33 -0400
commit0c92ecf10d9fb80b1798d2a9adfdea17f8f5e6d9 (patch)
treed8b4f864e8d037542301be4088fd0048e46d2097 /drivers/spi
parentb42a81ca0fa7b3b442a0731ffc4e7db44464b5f2 (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.c56
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;