|
@@ -261,15 +261,25 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
|
|
chcfg |= S3C64XX_SPI_CH_TXCH_ON;
|
|
chcfg |= S3C64XX_SPI_CH_TXCH_ON;
|
|
if (dma_mode) {
|
|
if (dma_mode) {
|
|
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
|
|
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
|
|
- s3c2410_dma_config(sdd->tx_dmach, 1);
|
|
|
|
|
|
+ s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8);
|
|
s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
|
|
s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
|
|
xfer->tx_dma, xfer->len);
|
|
xfer->tx_dma, xfer->len);
|
|
s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
|
|
s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
|
|
} else {
|
|
} else {
|
|
- unsigned char *buf = (unsigned char *) xfer->tx_buf;
|
|
|
|
- int i = 0;
|
|
|
|
- while (i < xfer->len)
|
|
|
|
- writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA);
|
|
|
|
|
|
+ switch (sdd->cur_bpw) {
|
|
|
|
+ case 32:
|
|
|
|
+ iowrite32_rep(regs + S3C64XX_SPI_TX_DATA,
|
|
|
|
+ xfer->tx_buf, xfer->len / 4);
|
|
|
|
+ break;
|
|
|
|
+ case 16:
|
|
|
|
+ iowrite16_rep(regs + S3C64XX_SPI_TX_DATA,
|
|
|
|
+ xfer->tx_buf, xfer->len / 2);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ iowrite8_rep(regs + S3C64XX_SPI_TX_DATA,
|
|
|
|
+ xfer->tx_buf, xfer->len);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -286,7 +296,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
|
|
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
|
|
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
|
|
| S3C64XX_SPI_PACKET_CNT_EN,
|
|
| S3C64XX_SPI_PACKET_CNT_EN,
|
|
regs + S3C64XX_SPI_PACKET_CNT);
|
|
regs + S3C64XX_SPI_PACKET_CNT);
|
|
- s3c2410_dma_config(sdd->rx_dmach, 1);
|
|
|
|
|
|
+ s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8);
|
|
s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
|
|
s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
|
|
xfer->rx_dma, xfer->len);
|
|
xfer->rx_dma, xfer->len);
|
|
s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
|
|
s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
|
|
@@ -366,20 +376,26 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- unsigned char *buf;
|
|
|
|
- int i;
|
|
|
|
-
|
|
|
|
/* If it was only Tx */
|
|
/* If it was only Tx */
|
|
if (xfer->rx_buf == NULL) {
|
|
if (xfer->rx_buf == NULL) {
|
|
sdd->state &= ~TXBUSY;
|
|
sdd->state &= ~TXBUSY;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- i = 0;
|
|
|
|
- buf = xfer->rx_buf;
|
|
|
|
- while (i < xfer->len)
|
|
|
|
- buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA);
|
|
|
|
-
|
|
|
|
|
|
+ switch (sdd->cur_bpw) {
|
|
|
|
+ case 32:
|
|
|
|
+ ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
|
|
|
|
+ xfer->rx_buf, xfer->len / 4);
|
|
|
|
+ break;
|
|
|
|
+ case 16:
|
|
|
|
+ ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
|
|
|
|
+ xfer->rx_buf, xfer->len / 2);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
|
|
|
|
+ xfer->rx_buf, xfer->len);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
sdd->state &= ~RXBUSY;
|
|
sdd->state &= ~RXBUSY;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -434,15 +450,17 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
|
switch (sdd->cur_bpw) {
|
|
switch (sdd->cur_bpw) {
|
|
case 32:
|
|
case 32:
|
|
val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
|
|
val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
|
|
|
|
+ val |= S3C64XX_SPI_MODE_CH_TSZ_WORD;
|
|
break;
|
|
break;
|
|
case 16:
|
|
case 16:
|
|
val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
|
|
val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
|
|
|
|
+ val |= S3C64XX_SPI_MODE_CH_TSZ_HALFWORD;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
|
|
val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
|
|
|
|
+ val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; /* Always 8bits wide */
|
|
|
|
|
|
|
|
writel(val, regs + S3C64XX_SPI_MODE_CFG);
|
|
writel(val, regs + S3C64XX_SPI_MODE_CFG);
|
|
|
|
|
|
@@ -629,6 +647,14 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
|
|
bpw = xfer->bits_per_word ? : spi->bits_per_word;
|
|
bpw = xfer->bits_per_word ? : spi->bits_per_word;
|
|
speed = xfer->speed_hz ? : spi->max_speed_hz;
|
|
speed = xfer->speed_hz ? : spi->max_speed_hz;
|
|
|
|
|
|
|
|
+ if (xfer->len % (bpw / 8)) {
|
|
|
|
+ dev_err(&spi->dev,
|
|
|
|
+ "Xfer length(%u) not a multiple of word size(%u)\n",
|
|
|
|
+ xfer->len, bpw / 8);
|
|
|
|
+ status = -EIO;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
|
|
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
|
|
sdd->cur_bpw = bpw;
|
|
sdd->cur_bpw = bpw;
|
|
sdd->cur_speed = speed;
|
|
sdd->cur_speed = speed;
|