[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