[PATCH v1] spi: dw: Allow bits_per_word to be configured by device drivers

Boon Khai Ng boon.khai.ng at altera.com
Thu Mar 12 05:46:33 CET 2026


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 at altera.com>
---
 drivers/spi/designware_spi.c | 12 ++++++++++++
 include/spi.h                |  1 +
 2 files changed, 13 insertions(+)

diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index b520c727900..0df9a4f5abd 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -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");
diff --git a/include/spi.h b/include/spi.h
index 95e7d5b1556..035d50f6b3a 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -159,6 +159,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 */
-- 
2.43.7



More information about the U-Boot mailing list