Commit 467ce769 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'spi-fix-v4.7-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "A few small driver-specific fixes for SPI, all in the normal important
  if you hit them category especially the rockchip driver fix which
  addresses a race which has been exposed more frequently with some
  recent performance improvements"

* tag 'spi-fix-v4.7-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: sunxi: fix transfer timeout
  spi: sun4i: fix FIFO limit
  spi: rockchip: Signal unfinished DMA transfers
  spi: spi-ti-qspi: Suspend the queue before removing the device
parents a2b0db5b 2a9b27b3
...@@ -578,7 +578,7 @@ static int rockchip_spi_transfer_one( ...@@ -578,7 +578,7 @@ static int rockchip_spi_transfer_one(
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
int ret = 1; int ret = 0;
struct rockchip_spi *rs = spi_master_get_devdata(master); struct rockchip_spi *rs = spi_master_get_devdata(master);
WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
...@@ -627,6 +627,8 @@ static int rockchip_spi_transfer_one( ...@@ -627,6 +627,8 @@ static int rockchip_spi_transfer_one(
spi_enable_chip(rs, 1); spi_enable_chip(rs, 1);
ret = rockchip_spi_prepare_dma(rs); ret = rockchip_spi_prepare_dma(rs);
} }
/* successful DMA prepare means the transfer is in progress */
ret = ret ? ret : 1;
} else { } else {
spi_enable_chip(rs, 1); spi_enable_chip(rs, 1);
ret = rockchip_spi_pio_transfer(rs); ret = rockchip_spi_pio_transfer(rs);
......
...@@ -173,13 +173,17 @@ static int sun4i_spi_transfer_one(struct spi_master *master, ...@@ -173,13 +173,17 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
{ {
struct sun4i_spi *sspi = spi_master_get_devdata(master); struct sun4i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout; unsigned int mclk_rate, div, timeout;
unsigned int start, end, tx_time;
unsigned int tx_len = 0; unsigned int tx_len = 0;
int ret = 0; int ret = 0;
u32 reg; u32 reg;
/* We don't support transfer larger than the FIFO */ /* We don't support transfer larger than the FIFO */
if (tfr->len > SUN4I_FIFO_DEPTH) if (tfr->len > SUN4I_FIFO_DEPTH)
return -EINVAL; return -EMSGSIZE;
if (tfr->tx_buf && tfr->len >= SUN4I_FIFO_DEPTH)
return -EMSGSIZE;
reinit_completion(&sspi->done); reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf; sspi->tx_buf = tfr->tx_buf;
...@@ -269,8 +273,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master, ...@@ -269,8 +273,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len)); sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len)); sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
/* Fill the TX FIFO */ /*
sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); * Fill the TX FIFO
* Filling the FIFO fully causes timeout for some reason
* at least on spi2 on A10s
*/
sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
/* Enable the interrupts */ /* Enable the interrupts */
sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC); sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
...@@ -279,9 +287,16 @@ static int sun4i_spi_transfer_one(struct spi_master *master, ...@@ -279,9 +287,16 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH); sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
start = jiffies;
timeout = wait_for_completion_timeout(&sspi->done, timeout = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(1000)); msecs_to_jiffies(tx_time));
end = jiffies;
if (!timeout) { if (!timeout) {
dev_warn(&master->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz,
jiffies_to_msecs(end - start), tx_time);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto out; goto out;
} }
......
...@@ -160,6 +160,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -160,6 +160,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
{ {
struct sun6i_spi *sspi = spi_master_get_devdata(master); struct sun6i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout; unsigned int mclk_rate, div, timeout;
unsigned int start, end, tx_time;
unsigned int tx_len = 0; unsigned int tx_len = 0;
int ret = 0; int ret = 0;
u32 reg; u32 reg;
...@@ -269,9 +270,16 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -269,9 +270,16 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH); sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
start = jiffies;
timeout = wait_for_completion_timeout(&sspi->done, timeout = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(1000)); msecs_to_jiffies(tx_time));
end = jiffies;
if (!timeout) { if (!timeout) {
dev_warn(&master->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz,
jiffies_to_msecs(end - start), tx_time);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto out; goto out;
} }
......
...@@ -646,6 +646,13 @@ static int ti_qspi_probe(struct platform_device *pdev) ...@@ -646,6 +646,13 @@ static int ti_qspi_probe(struct platform_device *pdev)
static int ti_qspi_remove(struct platform_device *pdev) static int ti_qspi_remove(struct platform_device *pdev)
{ {
struct ti_qspi *qspi = platform_get_drvdata(pdev);
int rc;
rc = spi_master_suspend(qspi->master);
if (rc)
return rc;
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment