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: Bob Liu <lliubbo@gmail.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
parent
b214b7bbff
commit
4d676fc5c3
1 changed files with 71 additions and 32 deletions
|
@ -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)
|
||||||
/* 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)
|
||||||
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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
} 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)
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue