On 2/21/26 10:42, Dario Binacchi wrote:
> Implement the set_wordlen operation to allow dynamic bus width
> configuration. This is required for peripherals with non-standard
> requirements, such as display panels that need 9-bit word transfers
> during the initialization and setup phase.
>
> Signed-off-by: Dario Binacchi <[email protected]>
> ---
>
> (no changes since v1)
>
> drivers/spi/stm32_spi.c | 62 +++++++++++++++++++++++++++++++++++++----
> 1 file changed, 57 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c
> index adba97915cd3..39ea69c68174 100644
> --- a/drivers/spi/stm32_spi.c
> +++ b/drivers/spi/stm32_spi.c
> @@ -192,6 +192,11 @@ static void stm32_spi_read_rxfifo(struct udevice *bus)
> log_debug("%d bytes left\n", priv->rx_len);
> }
>
> +static bool stm32_spi_is_enabled(void __iomem *base)
> +{
> + return !!(readl(base + STM32_SPI_CR1) & SPI_CR1_SPE);
> +}
> +
In stm32_spi_stopxfer(), we first check if SPI is enabled,
stm32_spi_is_enabled() can be used
to replace the existing code:
static void stm32_spi_stopxfer(struct udevice *dev)
{
struct stm32_spi_plat *plat = dev_get_plat(dev);
void __iomem *base = plat->base;
u32 cr1, sr;
int ret;
dev_dbg(dev, "\n");
cr1 = readl(base + STM32_SPI_CR1);
if (!(cr1 & SPI_CR1_SPE))
return;
> static int stm32_spi_enable(void __iomem *base)
> {
> log_debug("\n");
> @@ -381,6 +386,44 @@ static int stm32_spi_set_speed(struct udevice *bus, uint
> hz)
> return 0;
> }
>
> +static int _stm32_spi_set_wordlen(struct udevice *bus, unsigned int wordlen)
> +{
> + struct stm32_spi_priv *priv = dev_get_priv(bus);
> + struct stm32_spi_plat *plat = dev_get_plat(bus);
> + void __iomem *base = plat->base;
> + bool spi_enabled;
> +
> + if ((wordlen - 1) < SPI_CFG1_DSIZE_MIN ||
> + (wordlen - 1) > SPI_CFG1_DSIZE) {
> + dev_err(bus, "Cannot set wordlen to %u [%d - %d]\n",
> + wordlen, SPI_CFG1_DSIZE_MIN + 1,
> + SPI_CFG1_DSIZE + 1);
> + return -EINVAL;
> + }
> +
> + spi_enabled = stm32_spi_is_enabled(plat->base);
> + if (spi_enabled)
> + stm32_spi_disable(plat->base);
> +
> + dev_dbg(bus, "bits_per_word=%d\n", wordlen);
> +
> + priv->cur_bpw = wordlen;
> + clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE,
> + priv->cur_bpw - 1);
> +
> + if (spi_enabled)
> + stm32_spi_enable(plat->base);
> +
> + return 0;
> +}
> +
> +static int stm32_spi_set_wordlen(struct udevice *slave, unsigned int wordlen)
> +{
> + struct udevice *bus = dev_get_parent(slave);
> +
> + return _stm32_spi_set_wordlen(bus, wordlen);
> +}
> +
> static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen,
> const void *dout, void *din, unsigned long flags)
> {
> @@ -394,11 +437,19 @@ static int stm32_spi_xfer(struct udevice *slave,
> unsigned int bitlen,
> u32 xferlen;
> u32 mode;
> int xfer_status = 0;
> + int nb_words;
>
> xferlen = bitlen / 8;
>
> - if (xferlen <= SPI_CR2_TSIZE)
> - writel(xferlen, base + STM32_SPI_CR2);
> + if (priv->cur_bpw <= 8)
> + nb_words = xferlen;
> + else if (priv->cur_bpw <= 16)
> + nb_words = DIV_ROUND_UP(xferlen * 8, 16);
> + else
> + nb_words = DIV_ROUND_UP(xferlen * 8, 32);
> +
> + if (nb_words <= SPI_CR2_TSIZE)
> + writel(nb_words, base + STM32_SPI_CR2);
> else
> return -EMSGSIZE;
>
> @@ -406,6 +457,8 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned
> int bitlen,
> priv->rx_buf = din;
> priv->tx_len = priv->tx_buf ? xferlen : 0;
> priv->rx_len = priv->rx_buf ? xferlen : 0;
> + dev_dbg(bus, "bitlen: %d, xferlen: %d, nb_words: %d\n",
> + bitlen, xferlen, nb_words);
>
> mode = SPI_FULL_DUPLEX;
> if (!priv->tx_buf)
> @@ -567,9 +620,7 @@ static int stm32_spi_probe(struct udevice *dev)
> priv->fifo_size = stm32_spi_get_fifo_size(dev);
> priv->cur_mode = SPI_FULL_DUPLEX;
> priv->cur_xferlen = 0;
> - priv->cur_bpw = SPI_DEFAULT_WORDLEN;
> - clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE,
> - priv->cur_bpw - 1);
> + _stm32_spi_set_wordlen(dev, SPI_DEFAULT_WORDLEN);
>
> for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) {
> if (!dm_gpio_is_valid(&plat->cs_gpios[i]))
> @@ -630,6 +681,7 @@ static const struct dm_spi_ops stm32_spi_ops = {
> .release_bus = stm32_spi_release_bus,
> .set_mode = stm32_spi_set_mode,
> .set_speed = stm32_spi_set_speed,
> + .set_wordlen = stm32_spi_set_wordlen,
> .xfer = stm32_spi_xfer,
> };
>