Commit 4d676fc5 authored by Bob Liu's avatar Bob Liu Committed by Grant Likely

spi/bfin_spi: support for multiples of 8bits with hardware CS

We can do multiples of 8bit transfers when using the hardware CS and a
little bit of magic, so make it work.
Signed-off-by: default avatarBob Liu <lliubbo@gmail.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent b214b7bb
...@@ -425,6 +425,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) ...@@ -425,6 +425,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
struct bfin_spi_slave_data *chip = drv_data->cur_chip; struct bfin_spi_slave_data *chip = drv_data->cur_chip;
struct spi_message *msg = drv_data->cur_msg; struct spi_message *msg = drv_data->cur_msg;
int n_bytes = drv_data->n_bytes; int n_bytes = drv_data->n_bytes;
int loop = 0;
/* wait until transfer finished. */ /* wait until transfer finished. */
while (!(read_STAT(drv_data) & BIT_STAT_RXS)) while (!(read_STAT(drv_data) & BIT_STAT_RXS))
...@@ -435,10 +436,15 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) ...@@ -435,10 +436,15 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
/* last read */ /* last read */
if (drv_data->rx) { if (drv_data->rx) {
dev_dbg(&drv_data->pdev->dev, "last read\n"); dev_dbg(&drv_data->pdev->dev, "last read\n");
if (n_bytes == 2) if (n_bytes % 2) {
*(u16 *) (drv_data->rx) = read_RDBR(drv_data); u16 *buf = (u16 *)drv_data->rx;
else if (n_bytes == 1) for (loop = 0; loop < n_bytes / 2; loop++)
*(u8 *) (drv_data->rx) = read_RDBR(drv_data); *buf++ = read_RDBR(drv_data);
} else {
u8 *buf = (u8 *)drv_data->rx;
for (loop = 0; loop < n_bytes; loop++)
*buf++ = read_RDBR(drv_data);
}
drv_data->rx += n_bytes; drv_data->rx += n_bytes;
} }
...@@ -458,29 +464,53 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) ...@@ -458,29 +464,53 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
if (drv_data->rx && drv_data->tx) { if (drv_data->rx && drv_data->tx) {
/* duplex */ /* duplex */
dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n"); dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n");
if (drv_data->n_bytes == 2) { if (n_bytes % 2) {
*(u16 *) (drv_data->rx) = read_RDBR(drv_data); u16 *buf = (u16 *)drv_data->rx;
write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); u16 *buf2 = (u16 *)drv_data->tx;
} else if (drv_data->n_bytes == 1) { for (loop = 0; loop < n_bytes / 2; loop++) {
*(u8 *) (drv_data->rx) = read_RDBR(drv_data); *buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); write_TDBR(drv_data, *buf2++);
}
} else {
u8 *buf = (u8 *)drv_data->rx;
u8 *buf2 = (u8 *)drv_data->tx;
for (loop = 0; loop < n_bytes; loop++) {
*buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, *buf2++);
}
} }
} else if (drv_data->rx) { } else if (drv_data->rx) {
/* read */ /* read */
dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n"); dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n");
if (drv_data->n_bytes == 2) if (n_bytes % 2) {
*(u16 *) (drv_data->rx) = read_RDBR(drv_data); u16 *buf = (u16 *)drv_data->rx;
else if (drv_data->n_bytes == 1) for (loop = 0; loop < n_bytes / 2; loop++) {
*(u8 *) (drv_data->rx) = read_RDBR(drv_data); *buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, chip->idle_tx_val);
}
} else {
u8 *buf = (u8 *)drv_data->rx;
for (loop = 0; loop < n_bytes; loop++) {
*buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, chip->idle_tx_val); write_TDBR(drv_data, chip->idle_tx_val);
}
}
} else if (drv_data->tx) { } else if (drv_data->tx) {
/* write */ /* write */
dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n"); dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n");
bfin_spi_dummy_read(drv_data); if (n_bytes % 2) {
if (drv_data->n_bytes == 2) u16 *buf = (u16 *)drv_data->tx;
write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); for (loop = 0; loop < n_bytes / 2; loop++) {
else if (drv_data->n_bytes == 1) read_RDBR(drv_data);
write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); write_TDBR(drv_data, *buf++);
}
} else {
u8 *buf = (u8 *)drv_data->tx;
for (loop = 0; loop < n_bytes; loop++) {
read_RDBR(drv_data);
write_TDBR(drv_data, *buf++);
}
}
} }
if (drv_data->tx) if (drv_data->tx)
...@@ -651,16 +681,16 @@ static void bfin_spi_pump_transfers(unsigned long data) ...@@ -651,16 +681,16 @@ static void bfin_spi_pump_transfers(unsigned long data)
/* Bits per word setup */ /* Bits per word setup */
bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word; bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word;
if (bits_per_word == 8) { if ((bits_per_word > 0) && (bits_per_word % 16 == 0)) {
drv_data->n_bytes = 1; drv_data->n_bytes = bits_per_word/8;
drv_data->len = transfer->len;
cr_width = 0;
drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
} else if (bits_per_word == 16) {
drv_data->n_bytes = 2;
drv_data->len = (transfer->len) >> 1; drv_data->len = (transfer->len) >> 1;
cr_width = BIT_CTL_WORDSIZE; cr_width = BIT_CTL_WORDSIZE;
drv_data->ops = &bfin_bfin_spi_transfer_ops_u16; drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
} else if ((bits_per_word > 0) && (bits_per_word % 8 == 0)) {
drv_data->n_bytes = bits_per_word/8;
drv_data->len = transfer->len;
cr_width = 0;
drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
} else { } else {
dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n"); dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n");
message->status = -EINVAL; message->status = -EINVAL;
...@@ -815,10 +845,19 @@ static void bfin_spi_pump_transfers(unsigned long data) ...@@ -815,10 +845,19 @@ static void bfin_spi_pump_transfers(unsigned long data)
if (drv_data->tx == NULL) if (drv_data->tx == NULL)
write_TDBR(drv_data, chip->idle_tx_val); write_TDBR(drv_data, chip->idle_tx_val);
else { else {
if (bits_per_word == 8) int loop;
write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); if (bits_per_word % 16 == 0) {
else u16 *buf = (u16 *)drv_data->tx;
write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); for (loop = 0; loop < bits_per_word / 16;
loop++) {
write_TDBR(drv_data, *buf++);
}
} else if (bits_per_word % 8 == 0) {
u8 *buf = (u8 *)drv_data->tx;
for (loop = 0; loop < bits_per_word / 8; loop++)
write_TDBR(drv_data, *buf++);
}
drv_data->tx += drv_data->n_bytes; drv_data->tx += drv_data->n_bytes;
} }
...@@ -1031,7 +1070,7 @@ static int bfin_spi_setup(struct spi_device *spi) ...@@ -1031,7 +1070,7 @@ static int bfin_spi_setup(struct spi_device *spi)
chip->ctl_reg &= bfin_ctl_reg; chip->ctl_reg &= bfin_ctl_reg;
} }
if (spi->bits_per_word != 8 && spi->bits_per_word != 16) { if (spi->bits_per_word % 8) {
dev_err(&spi->dev, "%d bits_per_word is not supported\n", dev_err(&spi->dev, "%d bits_per_word is not supported\n",
spi->bits_per_word); spi->bits_per_word);
goto error; goto error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment