Commit 8cb61d65 authored by Mark Brown's avatar Mark Brown

Merge series "spi: stm32: various driver fixes" from Alain Volmat <alain.volmat@st.com>:

This serie is a reduced version of the serie
[spi: stm32: various driver enhancements] previously sent.

Alain Volmat (1):
  spi: stm32: always perform registers configuration prior to transfer

Amelie Delaunay (3):
  spi: stm32: fix fifo threshold level in case of short transfer
  spi: stm32: fix stm32_spi_prepare_mbr in case of odd clk_rate
  spi: stm32: fixes suspend/resume management

Antonio Borneo (1):
  spi: stm32h7: fix race condition at end of transfer

 drivers/spi/spi-stm32.c | 98 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 61 insertions(+), 37 deletions(-)

--
v2: fix conditional statement within [spi: stm32: fix fifo threshold level in case of short transfer]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
parents 0454357f 60ccb351
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
...@@ -441,7 +442,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, ...@@ -441,7 +442,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
{ {
u32 div, mbrdiv; u32 div, mbrdiv;
div = DIV_ROUND_UP(spi->clk_rate, speed_hz); /* Ensure spi->clk_rate is even */
div = DIV_ROUND_UP(spi->clk_rate & ~0x1, speed_hz);
/* /*
* SPI framework set xfer->speed_hz to master->max_speed_hz if * SPI framework set xfer->speed_hz to master->max_speed_hz if
...@@ -467,20 +469,27 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, ...@@ -467,20 +469,27 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
/** /**
* stm32h7_spi_prepare_fthlv - Determine FIFO threshold level * stm32h7_spi_prepare_fthlv - Determine FIFO threshold level
* @spi: pointer to the spi controller data structure * @spi: pointer to the spi controller data structure
* @xfer_len: length of the message to be transferred
*/ */
static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len)
{ {
u32 fthlv, half_fifo; u32 fthlv, half_fifo, packet;
/* data packet should not exceed 1/2 of fifo space */ /* data packet should not exceed 1/2 of fifo space */
half_fifo = (spi->fifo_size / 2); half_fifo = (spi->fifo_size / 2);
/* data_packet should not exceed transfer length */
if (half_fifo > xfer_len)
packet = xfer_len;
else
packet = half_fifo;
if (spi->cur_bpw <= 8) if (spi->cur_bpw <= 8)
fthlv = half_fifo; fthlv = packet;
else if (spi->cur_bpw <= 16) else if (spi->cur_bpw <= 16)
fthlv = half_fifo / 2; fthlv = packet / 2;
else else
fthlv = half_fifo / 4; fthlv = packet / 4;
/* align packet size with data registers access */ /* align packet size with data registers access */
if (spi->cur_bpw > 8) if (spi->cur_bpw > 8)
...@@ -488,6 +497,9 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) ...@@ -488,6 +497,9 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi)
else else
fthlv -= (fthlv % 4); /* multiple of 4 */ fthlv -= (fthlv % 4); /* multiple of 4 */
if (!fthlv)
fthlv = 1;
return fthlv; return fthlv;
} }
...@@ -971,8 +983,8 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) ...@@ -971,8 +983,8 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
spin_unlock_irqrestore(&spi->lock, flags); spin_unlock_irqrestore(&spi->lock, flags);
if (end) { if (end) {
spi_finalize_current_transfer(master);
stm32h7_spi_disable(spi); stm32h7_spi_disable(spi);
spi_finalize_current_transfer(master);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -1393,7 +1405,7 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi) ...@@ -1393,7 +1405,7 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi)
cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) &
STM32H7_SPI_CFG1_DSIZE; STM32H7_SPI_CFG1_DSIZE;
spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi); spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen);
fthlv = spi->cur_fthlv - 1; fthlv = spi->cur_fthlv - 1;
cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV;
...@@ -1585,39 +1597,33 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, ...@@ -1585,39 +1597,33 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
unsigned long flags; unsigned long flags;
unsigned int comm_type; unsigned int comm_type;
int nb_words, ret = 0; int nb_words, ret = 0;
int mbr;
spin_lock_irqsave(&spi->lock, flags); spin_lock_irqsave(&spi->lock, flags);
if (spi->cur_bpw != transfer->bits_per_word) { spi->cur_xferlen = transfer->len;
spi->cur_bpw = transfer->bits_per_word;
spi->cfg->set_bpw(spi);
}
if (spi->cur_speed != transfer->speed_hz) {
int mbr;
/* Update spi->cur_speed with real clock speed */ spi->cur_bpw = transfer->bits_per_word;
mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, spi->cfg->set_bpw(spi);
spi->cfg->baud_rate_div_min,
spi->cfg->baud_rate_div_max);
if (mbr < 0) {
ret = mbr;
goto out;
}
transfer->speed_hz = spi->cur_speed; /* Update spi->cur_speed with real clock speed */
stm32_spi_set_mbr(spi, mbr); mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
spi->cfg->baud_rate_div_min,
spi->cfg->baud_rate_div_max);
if (mbr < 0) {
ret = mbr;
goto out;
} }
transfer->speed_hz = spi->cur_speed;
stm32_spi_set_mbr(spi, mbr);
comm_type = stm32_spi_communication_type(spi_dev, transfer); comm_type = stm32_spi_communication_type(spi_dev, transfer);
if (spi->cur_comm != comm_type) { ret = spi->cfg->set_mode(spi, comm_type);
ret = spi->cfg->set_mode(spi, comm_type); if (ret < 0)
goto out;
if (ret < 0) spi->cur_comm = comm_type;
goto out;
spi->cur_comm = comm_type;
}
if (spi->cfg->set_data_idleness) if (spi->cfg->set_data_idleness)
spi->cfg->set_data_idleness(spi, transfer->len); spi->cfg->set_data_idleness(spi, transfer->len);
...@@ -1635,8 +1641,6 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, ...@@ -1635,8 +1641,6 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
goto out; goto out;
} }
spi->cur_xferlen = transfer->len;
dev_dbg(spi->dev, "transfer communication mode set to %d\n", dev_dbg(spi->dev, "transfer communication mode set to %d\n",
spi->cur_comm); spi->cur_comm);
dev_dbg(spi->dev, dev_dbg(spi->dev,
...@@ -1996,6 +2000,8 @@ static int stm32_spi_remove(struct platform_device *pdev) ...@@ -1996,6 +2000,8 @@ static int stm32_spi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pinctrl_pm_select_sleep_state(&pdev->dev);
return 0; return 0;
} }
...@@ -2007,13 +2013,18 @@ static int stm32_spi_runtime_suspend(struct device *dev) ...@@ -2007,13 +2013,18 @@ static int stm32_spi_runtime_suspend(struct device *dev)
clk_disable_unprepare(spi->clk); clk_disable_unprepare(spi->clk);
return 0; return pinctrl_pm_select_sleep_state(dev);
} }
static int stm32_spi_runtime_resume(struct device *dev) static int stm32_spi_runtime_resume(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
struct stm32_spi *spi = spi_master_get_devdata(master); struct stm32_spi *spi = spi_master_get_devdata(master);
int ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret)
return ret;
return clk_prepare_enable(spi->clk); return clk_prepare_enable(spi->clk);
} }
...@@ -2043,10 +2054,23 @@ static int stm32_spi_resume(struct device *dev) ...@@ -2043,10 +2054,23 @@ static int stm32_spi_resume(struct device *dev)
return ret; return ret;
ret = spi_master_resume(master); ret = spi_master_resume(master);
if (ret) if (ret) {
clk_disable_unprepare(spi->clk); clk_disable_unprepare(spi->clk);
return ret;
}
return ret; ret = pm_runtime_get_sync(dev);
if (ret) {
dev_err(dev, "Unable to power device:%d\n", ret);
return ret;
}
spi->cfg->config(spi);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
} }
#endif #endif
......
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