diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/spi/davinci_spi.c | 77 |
1 files changed, 43 insertions, 34 deletions
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 60ba007..08f837b 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -113,7 +113,8 @@ int spi_claim_bus(struct spi_slave *slave) writel(0, &ds->regs->lvl); /* enable SPI */ - writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); + writel((readl(&ds->regs->gcr1) | + SPIGCR1_SPIENA_MASK), &ds->regs->gcr1); return 0; } @@ -131,12 +132,10 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, { struct davinci_spi_slave *ds = to_davinci_spi(slave); unsigned int len, data1_reg_val = readl(&ds->regs->dat1); - int ret, i; + unsigned int i_cnt = 0, o_cnt = 0, buf_reg_val; const u8 *txp = dout; /* dout can be NULL for read operation */ u8 *rxp = din; /* din can be NULL for write operation */ - ret = 0; - if (bitlen == 0) /* Finish any previously submitted transfers */ goto out; @@ -159,41 +158,51 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, readl(&ds->regs->buf); /* keep writing and reading 1 byte until done */ - for (i = 0; i < len; i++) { - /* wait till TXFULL is asserted */ - while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK); - - /* write the data */ - data1_reg_val &= ~0xFFFF; - if (txp) { - data1_reg_val |= *txp; - txp++; + while ((i_cnt < len) || (o_cnt < len)) { + /* read RX buffer and flags */ + buf_reg_val = readl(&ds->regs->buf); + + /* if data is available */ + if ((i_cnt < len) && + (buf_reg_val & SPIBUF_RXEMPTY_MASK) == 0) { + /* + * If there is no read buffer simply + * ignore the read character + */ + if (rxp) + *rxp++ = buf_reg_val & 0xFF; + /* increment read words count */ + i_cnt++; } /* - * Write to DAT1 is required to keep the serial transfer going. - * We just terminate when we reach the end. + * if the tx buffer is empty and there + * is still data to transmit */ - if ((i == (len - 1)) && (flags & SPI_XFER_END)) { - /* clear CS hold */ - writel(data1_reg_val & - ~(1 << SPIDAT1_CSHOLD_SHIFT), &ds->regs->dat1); - } else { - /* enable CS hold */ - data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) | + if ((o_cnt < len) && + ((buf_reg_val & SPIBUF_TXFULL_MASK) == 0)) { + /* write the data */ + data1_reg_val &= ~0xFFFF; + if (txp) + data1_reg_val |= *txp++; + /* + * Write to DAT1 is required to keep + * the serial transfer going. + * We just terminate when we reach the end. + */ + if ((o_cnt == (len - 1)) && (flags & SPI_XFER_END)) { + /* clear CS hold */ + writel(data1_reg_val & + ~(1 << SPIDAT1_CSHOLD_SHIFT), + &ds->regs->dat1); + } else { + /* enable CS hold and write TX register */ + data1_reg_val |= ((1 << SPIDAT1_CSHOLD_SHIFT) | (slave->cs << SPIDAT1_CSNR_SHIFT)); - writel(data1_reg_val, &ds->regs->dat1); - } - - /* read the data - wait for data availability */ - while (readl(&ds->regs->buf) & SPIBUF_RXEMPTY_MASK); - - if (rxp) { - *rxp = readl(&ds->regs->buf) & 0xFF; - rxp++; - } else { - /* simply drop the read character */ - readl(&ds->regs->buf); + writel(data1_reg_val, &ds->regs->dat1); + } + /* increment written words count */ + o_cnt++; } } return 0; |