diff options
| author | Mugunthan V N <mugunthanvnm@ti.com> | 2015-02-17 14:03:51 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2015-02-21 04:29:09 -0500 |
| commit | 006110476478c69c399d0cd25888eefab0e69267 (patch) | |
| tree | 629e830087284cec4134234dff0fe67f0a2062a4 | |
| parent | 66886337bf2a523aef76cff84c846335db5f85f9 (diff) | |
drivers: spi: ti-qspi: wait for busy bit clear before data write/read
Data corruption is seen while reading/writing large data from/to qspi
device because the data register is over written or read before data
is ready which is denoted by busy bit in status register. SO adding
a busy bit check before writing/reading data to/from qspi device.
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
| -rw-r--r-- | drivers/spi/spi-ti-qspi.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 884a716e50cb..5c0616870358 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c | |||
| @@ -101,6 +101,7 @@ struct ti_qspi { | |||
| 101 | #define QSPI_FLEN(n) ((n - 1) << 0) | 101 | #define QSPI_FLEN(n) ((n - 1) << 0) |
| 102 | 102 | ||
| 103 | /* STATUS REGISTER */ | 103 | /* STATUS REGISTER */ |
| 104 | #define BUSY 0x01 | ||
| 104 | #define WC 0x02 | 105 | #define WC 0x02 |
| 105 | 106 | ||
| 106 | /* INTERRUPT REGISTER */ | 107 | /* INTERRUPT REGISTER */ |
| @@ -199,6 +200,21 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi) | |||
| 199 | ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG); | 200 | ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG); |
| 200 | } | 201 | } |
| 201 | 202 | ||
| 203 | static inline u32 qspi_is_busy(struct ti_qspi *qspi) | ||
| 204 | { | ||
| 205 | u32 stat; | ||
| 206 | unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; | ||
| 207 | |||
| 208 | stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); | ||
| 209 | while ((stat & BUSY) && time_after(timeout, jiffies)) { | ||
| 210 | cpu_relax(); | ||
| 211 | stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); | ||
| 212 | } | ||
| 213 | |||
| 214 | WARN(stat & BUSY, "qspi busy\n"); | ||
| 215 | return stat & BUSY; | ||
| 216 | } | ||
| 217 | |||
| 202 | static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) | 218 | static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) |
| 203 | { | 219 | { |
| 204 | int wlen, count; | 220 | int wlen, count; |
| @@ -211,6 +227,9 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) | |||
| 211 | wlen = t->bits_per_word >> 3; /* in bytes */ | 227 | wlen = t->bits_per_word >> 3; /* in bytes */ |
| 212 | 228 | ||
| 213 | while (count) { | 229 | while (count) { |
| 230 | if (qspi_is_busy(qspi)) | ||
| 231 | return -EBUSY; | ||
| 232 | |||
| 214 | switch (wlen) { | 233 | switch (wlen) { |
| 215 | case 1: | 234 | case 1: |
| 216 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", | 235 | dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", |
| @@ -266,6 +285,9 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) | |||
| 266 | 285 | ||
| 267 | while (count) { | 286 | while (count) { |
| 268 | dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); | 287 | dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); |
| 288 | if (qspi_is_busy(qspi)) | ||
| 289 | return -EBUSY; | ||
| 290 | |||
| 269 | ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); | 291 | ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); |
| 270 | if (!wait_for_completion_timeout(&qspi->transfer_complete, | 292 | if (!wait_for_completion_timeout(&qspi->transfer_complete, |
| 271 | QSPI_COMPLETION_TIMEOUT)) { | 293 | QSPI_COMPLETION_TIMEOUT)) { |
