The serie provides a fix for the spi-stm32 driver, allowing to properly
handle 0 byte transfer (and thus being able to run spi-loopback-test).
In addition to that, important enhancements are implemented, among them,
supporting transfer larger that what the IP can setup in one go or
allowing to use the SPI bus without cs_gpio.
v2: Fix within patch 'spi: stm32: properly handle 0 byte transfer'
Reorder patches to avoid compilation issue
Alain Volmat (5):
spi: stm32: properly handle 0 byte transfer
spi: stm32: do not mandate cs_gpio
spi: stm32h7: ensure message are smaller than max size
spi: stm32: defer probe for reset
spi: stm32: make spurious and overrun interrupts visible
Amelie Delaunay (2):
spi: stm32: use bitfield macros
spi: stm32h7: replace private SPI_1HZ_NS with NSEC_PER_SEC
Etienne Carriere (1):
spi: stm32: driver uses reset controller only at init
drivers/spi/spi-stm32.c | 114 ++++++++++++++++++----------------------
1 file changed, 52 insertions(+), 62 deletions(-)
--
2.17.1
Defer the probe operation when a reset controller device is expected
but have not yet been probed.
This change replaces use of devm_reset_control_get_exclusive() with
devm_reset_control_get_optional_exclusive() as reset controller is
optional which is now explicitly stated.
Signed-off-by: Alain Volmat <[email protected]>
---
v2: reordered within the serie
drivers/spi/spi-stm32.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 561234829110..54196cecfe2e 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -1871,8 +1871,14 @@ static int stm32_spi_probe(struct platform_device *pdev)
goto err_clk_disable;
}
- rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (!IS_ERR(rst)) {
+ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+ if (rst) {
+ if (IS_ERR(rst)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(rst),
+ "failed to get reset\n");
+ goto err_clk_disable;
+ }
+
reset_control_assert(rst);
udelay(2);
reset_control_deassert(rst);
--
2.17.1
From: Amelie Delaunay <[email protected]>
To avoid defining shift and mask separately and hand-coding the bit
manipulation, use the bitfield macros.
Signed-off-by: Amelie Delaunay <[email protected]>
Signed-off-by: Alain Volmat <[email protected]>
---
v2: reordered within the serie
drivers/spi/spi-stm32.c | 54 ++++++++++++++---------------------------
1 file changed, 18 insertions(+), 36 deletions(-)
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 2b4ea4cba00b..a46132e81533 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -5,6 +5,7 @@
// Copyright (C) 2017, STMicroelectronics - All Rights Reserved
// Author(s): Amelie Delaunay <[email protected]> for STMicroelectronics.
+#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -94,27 +95,22 @@
#define STM32H7_SPI_CR1_SSI BIT(12)
/* STM32H7_SPI_CR2 bit fields */
-#define STM32H7_SPI_CR2_TSIZE_SHIFT 0
#define STM32H7_SPI_CR2_TSIZE GENMASK(15, 0)
+#define STM32H7_SPI_TSIZE_MAX GENMASK(15, 0)
/* STM32H7_SPI_CFG1 bit fields */
-#define STM32H7_SPI_CFG1_DSIZE_SHIFT 0
#define STM32H7_SPI_CFG1_DSIZE GENMASK(4, 0)
-#define STM32H7_SPI_CFG1_FTHLV_SHIFT 5
#define STM32H7_SPI_CFG1_FTHLV GENMASK(8, 5)
#define STM32H7_SPI_CFG1_RXDMAEN BIT(14)
#define STM32H7_SPI_CFG1_TXDMAEN BIT(15)
-#define STM32H7_SPI_CFG1_MBR_SHIFT 28
#define STM32H7_SPI_CFG1_MBR GENMASK(30, 28)
+#define STM32H7_SPI_CFG1_MBR_SHIFT 28
#define STM32H7_SPI_CFG1_MBR_MIN 0
#define STM32H7_SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28)
/* STM32H7_SPI_CFG2 bit fields */
-#define STM32H7_SPI_CFG2_MIDI_SHIFT 4
#define STM32H7_SPI_CFG2_MIDI GENMASK(7, 4)
-#define STM32H7_SPI_CFG2_COMM_SHIFT 17
#define STM32H7_SPI_CFG2_COMM GENMASK(18, 17)
-#define STM32H7_SPI_CFG2_SP_SHIFT 19
#define STM32H7_SPI_CFG2_SP GENMASK(21, 19)
#define STM32H7_SPI_CFG2_MASTER BIT(22)
#define STM32H7_SPI_CFG2_LSBFRST BIT(23)
@@ -140,7 +136,6 @@
#define STM32H7_SPI_SR_OVR BIT(6)
#define STM32H7_SPI_SR_MODF BIT(9)
#define STM32H7_SPI_SR_SUSP BIT(11)
-#define STM32H7_SPI_SR_RXPLVL_SHIFT 13
#define STM32H7_SPI_SR_RXPLVL GENMASK(14, 13)
#define STM32H7_SPI_SR_RXWNE BIT(15)
@@ -417,9 +412,7 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi)
stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_DSIZE);
cfg1 = readl_relaxed(spi->base + STM32H7_SPI_CFG1);
- max_bpw = (cfg1 & STM32H7_SPI_CFG1_DSIZE) >>
- STM32H7_SPI_CFG1_DSIZE_SHIFT;
- max_bpw += 1;
+ max_bpw = FIELD_GET(STM32H7_SPI_CFG1_DSIZE, cfg1) + 1;
spin_unlock_irqrestore(&spi->lock, flags);
@@ -587,8 +580,7 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi)
static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush)
{
u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
- u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >>
- STM32H7_SPI_SR_RXPLVL_SHIFT;
+ u32 rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr);
while ((spi->rx_len > 0) &&
((sr & STM32H7_SPI_SR_RXP) ||
@@ -615,8 +607,7 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush)
}
sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
- rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >>
- STM32H7_SPI_SR_RXPLVL_SHIFT;
+ rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr);
}
dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__,
@@ -1385,15 +1376,13 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi)
bpw = spi->cur_bpw - 1;
cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE;
- cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) &
- STM32H7_SPI_CFG1_DSIZE;
+ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_DSIZE, bpw);
spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen);
fthlv = spi->cur_fthlv - 1;
cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV;
- cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) &
- STM32H7_SPI_CFG1_FTHLV;
+ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_FTHLV, fthlv);
writel_relaxed(
(readl_relaxed(spi->base + STM32H7_SPI_CFG1) &
@@ -1411,8 +1400,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv)
u32 clrb = 0, setb = 0;
clrb |= spi->cfg->regs->br.mask;
- setb |= ((u32)mbrdiv << spi->cfg->regs->br.shift) &
- spi->cfg->regs->br.mask;
+ setb |= (mbrdiv << spi->cfg->regs->br.shift) & spi->cfg->regs->br.mask;
writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) &
~clrb) | setb,
@@ -1503,8 +1491,7 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
}
cfg2_clrb |= STM32H7_SPI_CFG2_COMM;
- cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) &
- STM32H7_SPI_CFG2_COMM;
+ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_COMM, mode);
writel_relaxed(
(readl_relaxed(spi->base + STM32H7_SPI_CFG2) &
@@ -1527,14 +1514,15 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
if ((len > 1) && (spi->cur_midi > 0)) {
u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed);
- u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns),
- (u32)STM32H7_SPI_CFG2_MIDI >>
- STM32H7_SPI_CFG2_MIDI_SHIFT);
+ u32 midi = min_t(u32,
+ DIV_ROUND_UP(spi->cur_midi, sck_period_ns),
+ FIELD_GET(STM32H7_SPI_CFG2_MIDI,
+ STM32H7_SPI_CFG2_MIDI));
+
dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n",
sck_period_ns, midi, midi * sck_period_ns);
- cfg2_setb |= (midi << STM32H7_SPI_CFG2_MIDI_SHIFT) &
- STM32H7_SPI_CFG2_MIDI;
+ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_MIDI, midi);
}
writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) &
@@ -1549,14 +1537,8 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
*/
static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words)
{
- u32 cr2_clrb = 0, cr2_setb = 0;
-
- if (nb_words <= (STM32H7_SPI_CR2_TSIZE >>
- STM32H7_SPI_CR2_TSIZE_SHIFT)) {
- cr2_clrb |= STM32H7_SPI_CR2_TSIZE;
- cr2_setb = nb_words << STM32H7_SPI_CR2_TSIZE_SHIFT;
- writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CR2) &
- ~cr2_clrb) | cr2_setb,
+ if (nb_words <= STM32H7_SPI_TSIZE_MAX) {
+ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, nb_words),
spi->base + STM32H7_SPI_CR2);
} else {
return -EMSGSIZE;
--
2.17.1
Ensure that messages given to transfer_one handler can actually be
handled by it. For that purpose rely on the SPI framework
spi_split_transfers_maxsize function to split messages whenever necessary.
Signed-off-by: Alain Volmat <[email protected]>
---
v2: reordered within the serie
drivers/spi/spi-stm32.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index a46132e81533..8e4db219b95d 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -1004,6 +1004,20 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
!!(spi_dev->mode & SPI_LSB_FIRST),
!!(spi_dev->mode & SPI_CS_HIGH));
+ /* On STM32H7, messages should not exceed a maximum size setted
+ * afterward via the set_number_of_data function. In order to
+ * ensure that, split large messages into several messages
+ */
+ if (spi->cfg->set_number_of_data) {
+ int ret;
+
+ ret = spi_split_transfers_maxsize(master, msg,
+ STM32H7_SPI_TSIZE_MAX,
+ GFP_KERNEL | GFP_DMA);
+ if (ret)
+ return ret;
+ }
+
spin_lock_irqsave(&spi->lock, flags);
/* CPOL, CPHA and LSB FIRST bits have common register */
--
2.17.1
We do not expect to receive spurious interrupts so rise a warning
if it happens.
RX overrun is an error condition that signals a corrupted RX
stream both in dma and in irq modes. Report the error and
abort the transfer in either cases.
Signed-off-by: Alain Volmat <[email protected]>
---
v2: identical to v1
drivers/spi/spi-stm32.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index f3a4ff60ac4b..25c076461011 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -895,8 +895,8 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
mask |= STM32H7_SPI_SR_RXP;
if (!(sr & mask)) {
- dev_dbg(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n",
- sr, ier);
+ dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n",
+ sr, ier);
spin_unlock_irqrestore(&spi->lock, flags);
return IRQ_NONE;
}
@@ -923,15 +923,8 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
}
if (sr & STM32H7_SPI_SR_OVR) {
- dev_warn(spi->dev, "Overrun: received value discarded\n");
- if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
- stm32h7_spi_read_rxfifo(spi, false);
- /*
- * If overrun is detected while using DMA, it means that
- * something went wrong, so stop the current transfer
- */
- if (spi->cur_usedma)
- end = true;
+ dev_err(spi->dev, "Overrun: RX data lost\n");
+ end = true;
}
if (sr & STM32H7_SPI_SR_EOT) {
--
2.17.1
From: Amelie Delaunay <[email protected]>
Replace SPI_1HZ_NS private constant with NSEC_PER_SEC, which is easier
to read and understand.
Signed-off-by: Amelie Delaunay <[email protected]>
Signed-off-by: Alain Volmat <[email protected]>
---
v2: identical to v1
drivers/spi/spi-stm32.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 54196cecfe2e..f3a4ff60ac4b 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -162,8 +162,6 @@
#define SPI_3WIRE_TX 3
#define SPI_3WIRE_RX 4
-#define SPI_1HZ_NS 1000000000
-
/*
* use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers
* without fifo buffers.
@@ -1525,7 +1523,7 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
if ((len > 1) && (spi->cur_midi > 0)) {
- u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed);
+ u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed);
u32 midi = min_t(u32,
DIV_ROUND_UP(spi->cur_midi, sck_period_ns),
FIELD_GET(STM32H7_SPI_CFG2_MIDI,
--
2.17.1
From: Etienne Carriere <[email protected]>
Remove reset controller device reference from the device private
structure since it is used only at probe time and can be discarded
once used to reset the SPI device.
Signed-off-by: Etienne Carriere <[email protected]>
Signed-off-by: Alain Volmat <[email protected]>
---
v2: reordered within the serie
drivers/spi/spi-stm32.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 8e4db219b95d..561234829110 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -263,7 +263,6 @@ struct stm32_spi_cfg {
* @base: virtual memory area
* @clk: hw kernel clock feeding the SPI clock generator
* @clk_rate: rate of the hw kernel clock feeding the SPI clock generator
- * @rst: SPI controller reset line
* @lock: prevent I/O concurrent access
* @irq: SPI controller interrupt line
* @fifo_size: size of the embedded fifo in bytes
@@ -289,7 +288,6 @@ struct stm32_spi {
void __iomem *base;
struct clk *clk;
u32 clk_rate;
- struct reset_control *rst;
spinlock_t lock; /* prevent I/O concurrent access */
int irq;
unsigned int fifo_size;
@@ -1811,6 +1809,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
struct spi_master *master;
struct stm32_spi *spi;
struct resource *res;
+ struct reset_control *rst;
int ret;
master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi));
@@ -1872,11 +1871,11 @@ static int stm32_spi_probe(struct platform_device *pdev)
goto err_clk_disable;
}
- spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (!IS_ERR(spi->rst)) {
- reset_control_assert(spi->rst);
+ rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (!IS_ERR(rst)) {
+ reset_control_assert(rst);
udelay(2);
- reset_control_deassert(spi->rst);
+ reset_control_deassert(rst);
}
if (spi->cfg->has_fifo)
--
2.17.1
On Fri, 5 Feb 2021 19:59:24 +0100, Alain Volmat wrote:
> The serie provides a fix for the spi-stm32 driver, allowing to properly
> handle 0 byte transfer (and thus being able to run spi-loopback-test).
>
> In addition to that, important enhancements are implemented, among them,
> supporting transfer larger that what the IP can setup in one go or
> allowing to use the SPI bus without cs_gpio.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
Thanks!
[1/8] spi: stm32: properly handle 0 byte transfer
commit: 2269f5a8b1a7b38651d62676b98182828f29d11a
[2/8] spi: stm32: do not mandate cs_gpio
commit: 8f8d0e3e33e36ba63416cad64b9a9ad6b0129eed
[3/8] spi: stm32: use bitfield macros
commit: 5a380b833ad437123dca91bf900a696709d9b6ab
[4/8] spi: stm32h7: ensure message are smaller than max size
commit: 084de5232820c9e857ccc2282c3d94f33f92a381
[5/8] spi: stm32: driver uses reset controller only at init
commit: 1c75cfd53e213044523141b464eb06813e39ecea
[6/8] spi: stm32: defer probe for reset
commit: c63b95b76e69b679b9b95014552db099eb77a4fa
[7/8] spi: stm32h7: replace private SPI_1HZ_NS with NSEC_PER_SEC
commit: e1e2093b16cb1cefe4dc483b00e73d1333260784
[8/8] spi: stm32: make spurious and overrun interrupts visible
commit: c64e7efe46b7de21937ef4b3594d9b1fc74f07df
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark