summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/davinci_spi.c96
1 files changed, 41 insertions, 55 deletions
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 198f062..cd37697 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -91,6 +91,10 @@
#define SPIFLG_BITERR_MASK BIT(4)
#define SPIFLG_OVRRUN_MASK BIT(6)
#define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24)
+#define SPIFLG_ERROR_MASK (SPIFLG_DLEN_ERR_MASK \
+ | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \
+ | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \
+ | SPIFLG_OVRRUN_MASK)
#define SPIINT_DMA_REQ_EN BIT(16)
@@ -601,10 +605,10 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t)
{
struct davinci_spi *davinci_spi;
- int status, count, ret;
- u8 conv;
+ int ret;
+ int rcount, wcount;
u32 tx_data, data1_reg_val;
- u32 buf_val, flg_val;
+ u32 errors = 0;
struct davinci_spi_platform_data *pdata;
davinci_spi = spi_master_get_devdata(spi->master);
@@ -612,70 +616,51 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t)
davinci_spi->tx = t->tx_buf;
davinci_spi->rx = t->rx_buf;
-
- /* convert len to words based on bits_per_word */
- conv = davinci_spi->bytes_per_word[spi->chip_select];
- data1_reg_val = ioread32(davinci_spi->base + SPIDAT1);
+ wcount = t->len / davinci_spi->bytes_per_word[spi->chip_select];
+ rcount = wcount;
ret = davinci_spi_bufs_prep(spi, davinci_spi);
if (ret)
return ret;
+ data1_reg_val = ioread32(davinci_spi->base + SPIDAT1);
+
/* Enable SPI */
set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
- count = t->len / conv;
-
clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
- /* Determine the command to execute READ or WRITE */
- if (t->tx_buf) {
+ /* start the transfer */
+ wcount--;
+ tx_data = davinci_spi->get_tx(davinci_spi);
+ data1_reg_val &= 0xFFFF0000;
+ data1_reg_val |= tx_data & 0xFFFF;
+ iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
- while (1) {
- tx_data = davinci_spi->get_tx(davinci_spi);
+ while (rcount > 0 || wcount > 0) {
- data1_reg_val &= ~(0xFFFF);
- data1_reg_val |= (0xFFFF & tx_data);
-
- buf_val = ioread32(davinci_spi->base + SPIBUF);
- if ((buf_val & SPIBUF_TXFULL_MASK) == 0) {
- iowrite32(data1_reg_val,
- davinci_spi->base + SPIDAT1);
-
- count--;
- }
- while (ioread32(davinci_spi->base + SPIBUF)
- & SPIBUF_RXEMPTY_MASK)
- cpu_relax();
-
- /* getting the returned byte */
- if (t->rx_buf) {
- buf_val = ioread32(davinci_spi->base + SPIBUF);
- davinci_spi->get_rx(buf_val, davinci_spi);
- }
- if (count <= 0)
- break;
- }
- } else {
- while (1) {
- /* keeps the serial clock going */
- if ((ioread32(davinci_spi->base + SPIBUF)
- & SPIBUF_TXFULL_MASK) == 0)
- iowrite32(data1_reg_val,
- davinci_spi->base + SPIDAT1);
+ u32 buf, status;
- while (ioread32(davinci_spi->base + SPIBUF) &
- SPIBUF_RXEMPTY_MASK)
- cpu_relax();
+ buf = ioread32(davinci_spi->base + SPIBUF);
- flg_val = ioread32(davinci_spi->base + SPIFLG);
- buf_val = ioread32(davinci_spi->base + SPIBUF);
+ if (!(buf & SPIBUF_RXEMPTY_MASK)) {
+ davinci_spi->get_rx(buf & 0xFFFF, davinci_spi);
+ rcount--;
+ }
- davinci_spi->get_rx(buf_val, davinci_spi);
+ status = ioread32(davinci_spi->base + SPIFLG);
- count--;
- if (count <= 0)
- break;
+ if (unlikely(status & SPIFLG_ERROR_MASK)) {
+ errors = status & SPIFLG_ERROR_MASK;
+ break;
+ }
+
+ if (wcount > 0 && !(buf & SPIBUF_TXFULL_MASK)) {
+ wcount--;
+ tx_data = davinci_spi->get_tx(davinci_spi);
+ data1_reg_val &= ~0xFFFF;
+ data1_reg_val |= 0xFFFF & tx_data;
+ iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
}
}
@@ -683,11 +668,12 @@ static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t)
* Check for bit error, desync error,parity error,timeout error and
* receive overflow errors
*/
- status = ioread32(davinci_spi->base + SPIFLG);
-
- ret = davinci_spi_check_error(davinci_spi, status);
- if (ret != 0)
+ if (errors) {
+ ret = davinci_spi_check_error(davinci_spi, errors);
+ WARN(!ret, "%s: error reported but no error found!\n",
+ dev_name(&spi->dev));
return ret;
+ }
return t->len;
}
OpenPOWER on IntegriCloud