diff options
author | Qipan Li <Qipan.Li@csr.com> | 2014-02-28 23:38:17 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-03-02 22:22:20 -0500 |
commit | eeb7139524d1851c29b5c02b3dcd6679299a104e (patch) | |
tree | 330b91bd194e8024559ad597b0a1c905f53168db /drivers/spi | |
parent | 71aa2e3207ad3249b4a7ceff7ca775a08341fdcb (diff) |
spi: sirf: provide a shortcut for spi command-data mode
there are many SPI clients which use the following protocal:
step 1: send command bytes to clients(rx buffer is empty)
step 2: send data bytes to clients or receive data bytes from
clients.
SiRFprimaII provides a shortcut for this kind of SPI transfer.
when tx buf is less or equal than 4 bytes and rx buf is null
in a transfer, we think it as 'command' data and use hardware
command register for the transfer.
here we can save some CPU loading than doing both tx and rx
for a normal transfer.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-sirf.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index dc962a17f373..a72b8f87a156 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c | |||
@@ -131,6 +131,8 @@ | |||
131 | #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \ | 131 | #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \ |
132 | ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) | 132 | ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) |
133 | 133 | ||
134 | #define SIRFSOC_MAX_CMD_BYTES 4 | ||
135 | |||
134 | struct sirfsoc_spi { | 136 | struct sirfsoc_spi { |
135 | struct spi_bitbang bitbang; | 137 | struct spi_bitbang bitbang; |
136 | struct completion rx_done; | 138 | struct completion rx_done; |
@@ -161,6 +163,12 @@ struct sirfsoc_spi { | |||
161 | void *dummypage; | 163 | void *dummypage; |
162 | int word_width; /* in bytes */ | 164 | int word_width; /* in bytes */ |
163 | 165 | ||
166 | /* | ||
167 | * if tx size is not more than 4 and rx size is NULL, use | ||
168 | * command model | ||
169 | */ | ||
170 | bool tx_by_cmd; | ||
171 | |||
164 | int chipselect[0]; | 172 | int chipselect[0]; |
165 | }; | 173 | }; |
166 | 174 | ||
@@ -259,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) | |||
259 | 267 | ||
260 | writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); | 268 | writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); |
261 | 269 | ||
270 | if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { | ||
271 | complete(&sspi->tx_done); | ||
272 | writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); | ||
273 | return IRQ_HANDLED; | ||
274 | } | ||
275 | |||
262 | /* Error Conditions */ | 276 | /* Error Conditions */ |
263 | if (spi_stat & SIRFSOC_SPI_RX_OFLOW || | 277 | if (spi_stat & SIRFSOC_SPI_RX_OFLOW || |
264 | spi_stat & SIRFSOC_SPI_TX_UFLOW) { | 278 | spi_stat & SIRFSOC_SPI_TX_UFLOW) { |
@@ -309,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) | |||
309 | 323 | ||
310 | writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); | 324 | writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); |
311 | 325 | ||
326 | /* | ||
327 | * fill tx_buf into command register and wait for its completion | ||
328 | */ | ||
329 | if (sspi->tx_by_cmd) { | ||
330 | u32 cmd; | ||
331 | memcpy(&cmd, sspi->tx, t->len); | ||
332 | |||
333 | if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) | ||
334 | cmd = cpu_to_be32(cmd) >> | ||
335 | ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); | ||
336 | if (sspi->word_width == 2 && t->len == 4 && | ||
337 | (!(spi->mode & SPI_LSB_FIRST))) | ||
338 | cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); | ||
339 | |||
340 | writel(cmd, sspi->base + SIRFSOC_SPI_CMD); | ||
341 | writel(SIRFSOC_SPI_FRM_END_INT_EN, | ||
342 | sspi->base + SIRFSOC_SPI_INT_EN); | ||
343 | writel(SIRFSOC_SPI_CMD_TX_EN, | ||
344 | sspi->base + SIRFSOC_SPI_TX_RX_EN); | ||
345 | |||
346 | if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { | ||
347 | dev_err(&spi->dev, "transfer timeout\n"); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | return t->len; | ||
352 | } | ||
353 | |||
312 | if (sspi->left_tx_word == 1) { | 354 | if (sspi->left_tx_word == 1) { |
313 | writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | | 355 | writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | |
314 | SIRFSOC_SPI_ENA_AUTO_CLR, | 356 | SIRFSOC_SPI_ENA_AUTO_CLR, |
@@ -509,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) | |||
509 | writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL); | 551 | writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL); |
510 | writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); | 552 | writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); |
511 | 553 | ||
554 | if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) { | ||
555 | regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) | | ||
556 | SIRFSOC_SPI_CMD_MODE); | ||
557 | sspi->tx_by_cmd = true; | ||
558 | } else { | ||
559 | regval &= ~SIRFSOC_SPI_CMD_MODE; | ||
560 | sspi->tx_by_cmd = false; | ||
561 | } | ||
512 | writel(regval, sspi->base + SIRFSOC_SPI_CTRL); | 562 | writel(regval, sspi->base + SIRFSOC_SPI_CTRL); |
513 | 563 | ||
514 | if (IS_DMA_VALID(t)) { | 564 | if (IS_DMA_VALID(t)) { |