diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 198f062da3706fd89127176c0f5367ec0171b96d..cd37697850cf14faf57182a302e966402d0d56e8 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; }