Skip to content

Commit

Permalink
spi: sirf: provide a shortcut for spi command-data mode
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Qipan Li authored and Mark Brown committed Mar 3, 2014
1 parent 71aa2e3 commit eeb7139
Showing 1 changed file with 50 additions and 0 deletions.
50 changes: 50 additions & 0 deletions drivers/spi/spi-sirf.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))

#define SIRFSOC_MAX_CMD_BYTES 4

struct sirfsoc_spi {
struct spi_bitbang bitbang;
struct completion rx_done;
Expand Down Expand Up @@ -161,6 +163,12 @@ struct sirfsoc_spi {
void *dummypage;
int word_width; /* in bytes */

/*
* if tx size is not more than 4 and rx size is NULL, use
* command model
*/
bool tx_by_cmd;

int chipselect[0];
};

Expand Down Expand Up @@ -259,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)

writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);

if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
complete(&sspi->tx_done);
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
return IRQ_HANDLED;
}

/* Error Conditions */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
spi_stat & SIRFSOC_SPI_TX_UFLOW) {
Expand Down Expand Up @@ -309,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)

writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);

/*
* fill tx_buf into command register and wait for its completion
*/
if (sspi->tx_by_cmd) {
u32 cmd;
memcpy(&cmd, sspi->tx, t->len);

if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
cmd = cpu_to_be32(cmd) >>
((SIRFSOC_MAX_CMD_BYTES - t->len) * 8);
if (sspi->word_width == 2 && t->len == 4 &&
(!(spi->mode & SPI_LSB_FIRST)))
cmd = ((cmd & 0xffff) << 16) | (cmd >> 16);

writel(cmd, sspi->base + SIRFSOC_SPI_CMD);
writel(SIRFSOC_SPI_FRM_END_INT_EN,
sspi->base + SIRFSOC_SPI_INT_EN);
writel(SIRFSOC_SPI_CMD_TX_EN,
sspi->base + SIRFSOC_SPI_TX_RX_EN);

if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
dev_err(&spi->dev, "transfer timeout\n");
return 0;
}

return t->len;
}

if (sspi->left_tx_word == 1) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_ENA_AUTO_CLR,
Expand Down Expand Up @@ -509,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);
writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);

if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) {
regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) |
SIRFSOC_SPI_CMD_MODE);
sspi->tx_by_cmd = true;
} else {
regval &= ~SIRFSOC_SPI_CMD_MODE;
sspi->tx_by_cmd = false;
}
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);

if (IS_DMA_VALID(t)) {
Expand Down

0 comments on commit eeb7139

Please sign in to comment.