]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
spi: dw: Allow bits_per_word to be configured by device drivers
authorBoon Khai Ng <boon.khai.ng@altera.com>
Thu, 12 Mar 2026 04:46:33 +0000 (12:46 +0800)
committerTom Rini <trini@konsulko.com>
Mon, 20 Jul 2026 19:16:10 +0000 (13:16 -0600)
The DesignWare SPI controller supports configurable bits_per_word
(typically 4-32 bits), but this was previously hardcoded to 8 bits
in the driver initialization.

This patch enables bits_per_word to be set dynamically by upper-level
device drivers, matching the approach used in Linux. The controller
reads the bits_per_word value from the spi_slave structure during
each transfer, allowing different SPI devices on the same bus to use
different word sizes.

Implementation details:
 - Read slave->bits_per_word in dw_spi_xfer() before each transfer
 - Validate requested value against controller capabilities (4 to max_xfer)
 - Default to 8 bits if not set (maintains backward compatibility)

This follows the Linux model where spi_device drivers set bits_per_word,
and the controller driver reads it in the transfer function. Device
drivers can now set slave->bits_per_word before calling spi_xfer().

Example usage in device driver:
 slave->bits_per_word = 16;
 spi_xfer(slave, ...);

Backward compatible: Existing drivers that don't set bits_per_word
will continue to work with the default 8-bit transfers.

Signed-off-by: Boon Khai Ng <boon.khai.ng@altera.com>
drivers/spi/designware_spi.c
include/spi.h

index b520c727900d847dbbc01c214e9d703c428b58b0..0df9a4f5abd0c6c0e7405d99e28c9aeab48446c9 100644 (file)
@@ -497,6 +497,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
 {
        struct udevice *bus = dev->parent;
        struct dw_spi_priv *priv = dev_get_priv(bus);
+       struct spi_slave *slave = dev_get_parent_priv(dev);
        const u8 *tx = dout;
        u8 *rx = din;
        int ret = 0;
@@ -504,6 +505,17 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
        u32 val;
        u32 cs;
 
+       /* Get bits_per_word from slave (set by device driver) */
+       if (slave->bits_per_word >= 4 && slave->bits_per_word <= priv->max_xfer) {
+               priv->bits_per_word = slave->bits_per_word;
+       } else if (slave->bits_per_word == 0) {
+               priv->bits_per_word = 8;  /* Default if not set */
+       } else {
+               dev_warn(dev, "Invalid bits_per_word %u, using 8\n",
+                        slave->bits_per_word);
+               priv->bits_per_word = 8;
+       }
+
        /* spi core configured to do 8 bit transfers */
        if (bitlen % 8) {
                dev_err(dev, "Non byte aligned SPI transfer.\n");
index 7eaf0aa69b8b3ec0a9e7bc32ad3028c7f69eb258..97096a7752621578dea094df5e39ccdcf165427d 100644 (file)
@@ -161,6 +161,7 @@ struct spi_slave {
        unsigned int max_write_size;
        void *memory_map;
 
+       u8 bits_per_word;
        u8 flags;
 #define SPI_XFER_BEGIN         BIT(0)  /* Assert CS before transfer */
 #define SPI_XFER_END           BIT(1)  /* Deassert CS after transfer */