Allow dynamic configuration of the SPI word length. This is required
for controllers and slaves that need to operate with non-standard
word lengths, such as 9-bit wide transfers.

Signed-off-by: Dario Binacchi <[email protected]>
Reviewed-by: Simon Glass <[email protected]>

---

Changes in v3:
- Add Reviewed-by tag of Simon Glass
- Store the default value in struct dm_spi_slave_plat and copy it
  in struct spi_slave

 drivers/spi/spi-uclass.c | 22 +++++++++++++++++++++-
 include/spi.h            | 14 ++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 49b584c648d6..f70c04994252 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -91,6 +91,20 @@ void dm_spi_release_bus(struct udevice *dev)
                ops->release_bus(dev);
 }
 
+int dm_spi_set_wordlen(struct udevice *dev, unsigned int wordlen)
+{
+       struct udevice *bus = dev->parent;
+       struct dm_spi_ops *ops = spi_get_ops(bus);
+
+       if (bus->uclass->uc_drv->id != UCLASS_SPI)
+               return -EOPNOTSUPP;
+
+       if (!ops->set_wordlen)
+               return -ENOSYS;
+
+       return ops->set_wordlen(dev, wordlen);
+}
+
 int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
                const void *dout, void *din, unsigned long flags)
 {
@@ -144,6 +158,11 @@ int spi_set_speed(struct spi_slave *slave, uint hz)
        return ret;
 }
 
+int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen)
+{
+       return dm_spi_set_wordlen(slave->dev, wordlen);
+}
+
 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
             const void *dout, void *din, unsigned long flags)
 {
@@ -215,7 +234,7 @@ static int spi_child_pre_probe(struct udevice *dev)
 
        slave->max_hz = plat->max_hz;
        slave->mode = plat->mode;
-       slave->wordlen = SPI_DEFAULT_WORDLEN;
+       slave->wordlen = plat->wordlen;
 
        return 0;
 }
@@ -582,6 +601,7 @@ int spi_slave_of_to_plat(struct udevice *dev, struct 
dm_spi_slave_plat *plat)
        }
 
        plat->mode = mode;
+       plat->wordlen = SPI_DEFAULT_WORDLEN;
 
        return 0;
 }
diff --git a/include/spi.h b/include/spi.h
index 2783200d663e..5a98b1cad65e 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -77,11 +77,13 @@ struct dm_spi_bus {
  * @cs:                Chip select number (0..n-1)
  * @max_hz:    Maximum bus speed that this slave can tolerate
  * @mode:      SPI mode to use for this device (see SPI mode flags)
+ * @wordlen:   Word length in bits to use for this device
  */
 struct dm_spi_slave_plat {
        unsigned int cs[SPI_CS_CNT_MAX];
        uint max_hz;
        uint mode;
+       unsigned int wordlen;
 };
 
 /**
@@ -729,6 +731,18 @@ int dm_spi_claim_bus(struct udevice *dev);
  */
 void dm_spi_release_bus(struct udevice *dev);
 
+/**
+ * Set the word length for SPI transactions
+ *
+ * Set the word length (number of bits per word) for SPI transactions.
+ *
+ * @slave:     The SPI slave
+ * @wordlen:   The number of bits in a word
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+int dm_spi_set_wordlen(struct udevice *dev, unsigned int wordlen);
+
 /**
  * SPI transfer
  *
-- 
2.43.0

Reply via email to