Skip to content

Commit

Permalink
spi/rockchip: fix bug that cause spi transfer timed out in DMA duplex…
Browse files Browse the repository at this point in the history
… mode

In rx mode, dma must be prepared before spi is enabled.
But in tx and tr mode, spi must be enabled first.

Signed-off-by: Addy Ke <addy.ke@rock-chips.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Addy Ke authored and Mark Brown committed Oct 15, 2014
1 parent f9cfd52 commit c28be31
Showing 1 changed file with 23 additions and 11 deletions.
34 changes: 23 additions & 11 deletions drivers/spi/spi-rockchip.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@ static int rockchip_spi_unprepare_message(struct spi_master *master,

spin_unlock_irqrestore(&rs->lock, flags);

spi_enable_chip(rs, 0);

return 0;
}

Expand Down Expand Up @@ -384,6 +386,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
if (rs->tx)
wait_for_idle(rs);

spi_enable_chip(rs, 0);

return 0;
}

Expand All @@ -395,8 +399,10 @@ static void rockchip_spi_dma_rxcb(void *data)
spin_lock_irqsave(&rs->lock, flags);

rs->state &= ~RXBUSY;
if (!(rs->state & TXBUSY))
if (!(rs->state & TXBUSY)) {
spi_enable_chip(rs, 0);
spi_finalize_current_transfer(rs->master);
}

spin_unlock_irqrestore(&rs->lock, flags);
}
Expand Down Expand Up @@ -512,8 +518,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
div = max_t(u32, rs->max_freq / rs->speed, 1);
div = (div + 1) & 0xfffe;

spi_enable_chip(rs, 0);

writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);

writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
Expand All @@ -527,16 +531,14 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
spi_set_clk(rs, div);

dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);

spi_enable_chip(rs, 1);
}

static int rockchip_spi_transfer_one(
struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
int ret = 0;
int ret = 1;
struct rockchip_spi *rs = spi_master_get_devdata(master);

WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
Expand Down Expand Up @@ -568,17 +570,27 @@ static int rockchip_spi_transfer_one(
rs->tmode = CR0_XFM_RO;

/* we need prepare dma before spi was enabled */
if (master->can_dma && master->can_dma(master, spi, xfer)) {
if (master->can_dma && master->can_dma(master, spi, xfer))
rs->use_dma = 1;
rockchip_spi_prepare_dma(rs);
} else {
else
rs->use_dma = 0;
}

rockchip_spi_config(rs);

if (!rs->use_dma)
if (rs->use_dma) {
if (rs->tmode == CR0_XFM_RO) {
/* rx: dma must be prepared first */
rockchip_spi_prepare_dma(rs);
spi_enable_chip(rs, 1);
} else {
/* tx or tr: spi must be enabled first */
spi_enable_chip(rs, 1);
rockchip_spi_prepare_dma(rs);
}
} else {
spi_enable_chip(rs, 1);
ret = rockchip_spi_pio_transfer(rs);
}

return ret;
}
Expand Down

0 comments on commit c28be31

Please sign in to comment.