* [PATCH 0/6] spi: add multi-bus support
@ 2025-10-14 22:02 David Lechner
  2025-10-14 22:02 ` [PATCH 1/6] dt-bindings: spi: Add spi-buses property David Lechner
                   ` (5 more replies)
  0 siblings, 6 replies; 33+ messages in thread
From: David Lechner @ 2025-10-14 22:02 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio,
	David Lechner
This series is adding support for SPI controllers and peripherals that
have multiple SPI data buses.
This series covers this specific use case:
+--------------+    +---------+
| SPI          |    | SPI     |
| Controller   |    | ADC     |
|              |    |         |
|          CS0 |--->| CS      |
|         SCLK |--->| SCLK    |
|          SDO |--->| SDI     |
|         SDI0 |<---| SDOA    |
|         SDI1 |<---| SDOB    |
|         SDI2 |<---| SDOC    |
|         SDI3 |<---| SDOD    |
+--------------+     +--------+
The ADC is a simultaneous sampling ADC that can convert 4 samples at the
same time. It has 4 data output lines (SDOA-D) that each contain the
data of one of the 4 channels. So it requires a SPI controller with 4
separate deserializers in order to receive all of the information at the
same time.
This should also work for the use case in [1] as well. (Some of the
patches in this series were already submitted there). In that case the
SPI controller is used kind of like it is two separate SPI controllers,
each with its own chip select, clock, and data lines.
[1]: https://lore.kernel.org/linux-spi/20250616220054.3968946-1-sean.anderson@linux.dev/
The DT bindings are a fairly straight-forward mapping of which pins on
the peripheral are connected to which pins on the controller. The SPI
core code parses this and makes the information available to drivers.
When a peripheral driver sees that multiple data buses are wired up, it
can chose to use them when sending messages.
The SPI message API is a bit higher-level than just specifying the
number of data lines for a SPI transfer though. I did some research on
other SPI controllers that have this feature. They tend to be the kind
meant for connecting to two flash memory chips at the same time but can
be used more generically as well. They generally have the option to
either use one bus at a time (Sean's use case), or can mirror the same
data on multiple buses (no users of this yet) or can perform striping
of a single data FIFO/DMA stream to/from the two buses (our use case).
For now, the API assumes that if you want to do mirror/striping, then
you want to use all available data buses. Otherwise, it just uses the
first data bus for "normal" SPI transfers.
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
David Lechner (6):
      dt-bindings: spi: Add spi-buses property
      spi: Support multi-bus controllers
      spi: add multi_bus_mode field to struct spi_transfer
      spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
      dt-bindings: iio: adc: adi,ad7380: add spi-buses property
      iio: adc: ad7380: Add support for multiple SPI buses
 .../devicetree/bindings/iio/adc/adi,ad7380.yaml    |  22 ++++
 .../bindings/spi/spi-peripheral-props.yaml         |  11 ++
 drivers/iio/adc/ad7380.c                           |  41 ++++---
 drivers/spi/spi-axi-spi-engine.c                   | 128 ++++++++++++++++++++-
 drivers/spi/spi.c                                  |  28 ++++-
 include/linux/spi/spi.h                            |  23 ++++
 6 files changed, 235 insertions(+), 18 deletions(-)
---
base-commit: 40d3910fa7980ad3c211837f1a0ded5dfa36779a
change-id: 20250815-spi-add-multi-bus-support-1b35d05c54f6
Best regards,
-- 
David Lechner <dlechner@baylibre.com>
^ permalink raw reply	[flat|nested] 33+ messages in thread
* [PATCH 1/6] dt-bindings: spi: Add spi-buses property
  2025-10-14 22:02 [PATCH 0/6] spi: add multi-bus support David Lechner
@ 2025-10-14 22:02 ` David Lechner
  2025-10-21 14:21   ` Rob Herring
  2025-10-14 22:02 ` [PATCH 2/6] spi: Support multi-bus controllers David Lechner
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 33+ messages in thread
From: David Lechner @ 2025-10-14 22:02 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio,
	David Lechner
Add a spi-buses property to the spi-peripheral-props binding to allow
specifying the SPI data bus or buses that a peripheral is connected to
in cases where the SPI controller has more than one physical SPI data
bus.
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
This patch has been seen before in a different series from Sean [1].
[1]: https://lore.kernel.org/linux-spi/20250616220054.3968946-2-sean.anderson@linux.dev/
Changes:
* Added maxItems. (8 is the most I've seen so far on an ADC)
* Tweaked the description a bit.
---
 .../devicetree/bindings/spi/spi-peripheral-props.yaml         | 11 +++++++++++
 1 file changed, 11 insertions(+)
diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
index 8b6e8fc009dbdc80978f3afef84ddc688ade4348..91c9de3ae10bbad76cd4f57d0789b1161ebc7a18 100644
--- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
@@ -89,6 +89,17 @@ properties:
     description:
       Delay, in microseconds, after a write transfer.
 
+  spi-buses:
+    description:
+      Array of bus numbers that describes which SPI buses of the controller are
+      connected to the peripheral. This only applies to peripherals connected
+      to specialized SPI controllers that have multiple SPI buses (each with
+      its own serializer) on a single controller.
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 1
+    maxItems: 8
+    default: [0]
+
   stacked-memories:
     description: Several SPI memories can be wired in stacked mode.
       This basically means that either a device features several chip
-- 
2.43.0
^ permalink raw reply related	[flat|nested] 33+ messages in thread
* [PATCH 2/6] spi: Support multi-bus controllers
  2025-10-14 22:02 [PATCH 0/6] spi: add multi-bus support David Lechner
  2025-10-14 22:02 ` [PATCH 1/6] dt-bindings: spi: Add spi-buses property David Lechner
@ 2025-10-14 22:02 ` David Lechner
  2025-10-15 10:06   ` Nuno Sá
  2025-10-15 20:16   ` Marcelo Schmitt
  2025-10-14 22:02 ` [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer David Lechner
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 33+ messages in thread
From: David Lechner @ 2025-10-14 22:02 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio,
	David Lechner
Add support for SPI controllers with multiple physical SPI data buses.
(A data bus in this context means lines connected to a serializer, so a
controller with two data buses would have two serializers in a single
controller).
This is common in the type of controller that can be used with parallel
flash memories, but can be used for general purpose SPI as well.
To indicate support, a controller just needs to set ctlr->num_data_bus
to something greater than 1. Peripherals indicate which bus they are
connected to via device tree (ACPI support can be added if needed).
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
This patch has been seen in a different series [1] by Sean before:
[1]: https://lore.kernel.org/linux-spi/20250616220054.3968946-4-sean.anderson@linux.dev/
Changes:
* Use u8 array instead of bitfield so that the order of the mapping is
  preserved. (Now looks very much like chip select mapping.)
* Added doc strings for added fields.
* Tweaked the comments.
---
 drivers/spi/spi.c       | 28 +++++++++++++++++++++++++++-
 include/linux/spi/spi.h | 17 +++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 2e0647a06890290e1c9dc4a347a0864329795b08..84e5d5057eb41f1a522c4870265d78feb41109c8 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2354,7 +2354,7 @@ static void of_spi_parse_dt_cs_delay(struct device_node *nc,
 static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
 			   struct device_node *nc)
 {
-	u32 value, cs[SPI_DEVICE_CS_CNT_MAX];
+	u32 value, buses[SPI_DEVICE_DATA_BUS_CNT_MAX], cs[SPI_DEVICE_CS_CNT_MAX];
 	int rc, idx;
 
 	/* Mode (clock phase/polarity/etc.) */
@@ -2446,6 +2446,31 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
 	for (idx = 0; idx < rc; idx++)
 		spi_set_chipselect(spi, idx, cs[idx]);
 
+	rc = of_property_read_variable_u32_array(nc, "spi-buses", buses, 1,
+						 ARRAY_SIZE(buses));
+	if (rc < 0 && rc != -EINVAL) {
+		dev_err(&ctlr->dev, "%pOF has invalid 'spi-buses' property (%d)\n",
+			nc, rc);
+		return rc;
+	}
+
+	if (rc == -EINVAL) {
+		/* Default when property is omitted. */
+		spi->num_data_bus = 1;
+	} else {
+		for (idx = 0; idx < rc; idx++) {
+			if (buses[idx] >= ctlr->num_data_bus) {
+				dev_err(&ctlr->dev,
+					"%pOF has out of range 'spi-buses' property (%d/%d)\n",
+					nc, buses[idx], ctlr->num_data_bus);
+				return -EINVAL;
+			}
+			spi->data_bus[idx] = buses[idx];
+		}
+
+		spi->num_data_bus = rc;
+	}
+
 	/*
 	 * By default spi->chip_select[0] will hold the physical CS number,
 	 * so set bit 0 in spi->cs_index_mask.
@@ -3054,6 +3079,7 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
 	mutex_init(&ctlr->add_lock);
 	ctlr->bus_num = -1;
 	ctlr->num_chipselect = 1;
+	ctlr->num_data_bus = 1;
 	ctlr->target = target;
 	if (IS_ENABLED(CONFIG_SPI_SLAVE) && target)
 		ctlr->dev.class = &spi_target_class;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index cb2c2df3108999a73b67ef4a7b0d2cb07adfc669..c314194d4e7e2b396795ece10e142118ca05f4eb 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -23,6 +23,9 @@
 /* Max no. of CS supported per spi device */
 #define SPI_DEVICE_CS_CNT_MAX 4
 
+/* Max no. of data buses supported per spi device */
+#define SPI_DEVICE_DATA_BUS_CNT_MAX 8
+
 struct dma_chan;
 struct software_node;
 struct ptp_system_timestamp;
@@ -171,6 +174,9 @@ extern void spi_transfer_cs_change_delay_exec(struct spi_message *msg,
  * @chip_select: Array of physical chipselect, spi->chipselect[i] gives
  *	the corresponding physical CS for logical CS i.
  * @num_chipselect: Number of physical chipselects used.
+ * @data_bus: Array of physical data buses. This is only used with specialized
+ * controllers that support multiple data buses.
+ * @num_data_bus: Number of physical data buses used.
  * @cs_index_mask: Bit mask of the active chipselect(s) in the chipselect array
  * @cs_gpiod: Array of GPIO descriptors of the corresponding chipselect lines
  *	(optional, NULL when not using a GPIO line)
@@ -231,6 +237,8 @@ struct spi_device {
 
 	u8			chip_select[SPI_DEVICE_CS_CNT_MAX];
 	u8			num_chipselect;
+	u8			data_bus[SPI_DEVICE_DATA_BUS_CNT_MAX];
+	u8			num_data_bus;
 
 	/*
 	 * Bit mask of the chipselect(s) that the driver need to use from
@@ -401,6 +409,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
  *	SPI targets, and are numbered from zero to num_chipselects.
  *	each target has a chipselect signal, but it's common that not
  *	every chipselect is connected to a target.
+ * @num_data_bus: Number of data buses supported by this controller. Default is 1.
  * @dma_alignment: SPI controller constraint on DMA buffers alignment.
  * @mode_bits: flags understood by this controller driver
  * @buswidth_override_bits: flags to override for this controller driver
@@ -576,6 +585,14 @@ struct spi_controller {
 	 */
 	u16			num_chipselect;
 
+	/*
+	 * Some specialized SPI controllers can have more than one physical
+	 * bus interface per controller (each having it's own serializer). This
+	 * specifies the number of buses in that case. Other controllers do not
+	 * need to set this (defaults to 1).
+	 */
+	u16			num_data_bus;
+
 	/* Some SPI controllers pose alignment requirements on DMAable
 	 * buffers; let protocol drivers know about these requirements.
 	 */
-- 
2.43.0
^ permalink raw reply related	[flat|nested] 33+ messages in thread
* [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-14 22:02 [PATCH 0/6] spi: add multi-bus support David Lechner
  2025-10-14 22:02 ` [PATCH 1/6] dt-bindings: spi: Add spi-buses property David Lechner
  2025-10-14 22:02 ` [PATCH 2/6] spi: Support multi-bus controllers David Lechner
@ 2025-10-14 22:02 ` David Lechner
  2025-10-15 10:16   ` Nuno Sá
  2025-10-15 20:21   ` Marcelo Schmitt
  2025-10-14 22:02 ` [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE David Lechner
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 33+ messages in thread
From: David Lechner @ 2025-10-14 22:02 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio,
	David Lechner
Add a new multi_bus_mode field to struct spi_transfer to allow
peripherals that support multiple SPI buses to be used with a single
SPI controller.
This requires both the peripheral and the controller to have multiple
serializers connected to separate data buses. It could also be used with
a single controller and multiple peripherals that are functioning as a
single logical device (similar to parallel memories).
The possible values for this field have the following semantics:
- SPI_MULTI_BUS_MODE_SINGLE: Only use the first bus. This means that it
    it is operating just like a conventional SPI bus. It is the default
    value so that existing drivers do not need to be modified.
    Example:
        tx_buf[0] = 0x88;
        struct spi_transfer xfer = {
            .tx_buf = tx_buf,
            .len = 1,
        };
        spi_sync_transfer(spi, &xfer, 1);
        controller    > data bits >     peripheral
        ----------   ----------------   ----------
            SDO 0    0-0-0-1-0-0-0-1    SDI 0
- SPI_MULTI_BUS_MODE_MIRROR: Send a single data word over all of the
    buses at the same time. This only makes sense for writes and not
    for reads.
    Example:
        tx_buf[0] = 0x88;
        struct spi_transfer xfer = {
            .tx_buf = tx_buf,
            .len = 1,
            .multi_bus_mode = SPI_MULTI_BUS_MODE_MIRROR,
        };
        spi_sync_transfer(spi, &xfer, 1);
        controller    > data bits >     peripheral
        ----------   ----------------   ----------
            SDO 0    0-0-0-1-0-0-0-1    SDI 0
            SDO 1    0-0-0-1-0-0-0-1    SDI 1
- SPI_MULTI_BUS_MODE_STRIPE: Send or receive two different data words at
    the same time, one on each bus.
    Example:
        struct spi_transfer xfer = {
            .rx_buf = rx_buf,
            .len = 2, /* must be multiple of number of buses */
            .multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE,
        };
        spi_sync_transfer(spi, &xfer, 1);
        controller    < data bits <     peripheral
        ----------   ----------------   ----------
            SDI 0    0-0-0-1-0-0-0-1    SDO 0
            SDI 1    1-0-0-0-1-0-0-0    SDO 1
        After the transfer, rx_buf[0] == 0x11 (word from SDO 0) and
        rx_buf[1] == 0x88 (word from SDO 1). If the transfer was longer,
        the data would continue in an alternating fashion.
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 include/linux/spi/spi.h | 6 ++++++
 1 file changed, 6 insertions(+)
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index c314194d4e7e2b396795ece10e142118ca05f4eb..7d22ef5077d1229cac2574831f80092c591b972f 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -976,6 +976,8 @@ struct spi_res {
  *      (SPI_NBITS_SINGLE) is used.
  * @rx_nbits: number of bits used for reading. If 0 the default
  *      (SPI_NBITS_SINGLE) is used.
+ * @multi_bus_mode: How to serialize data on multiple buses. One of the
+ *      SPI_MULTI_BUS_MODE_* values.
  * @len: size of rx and tx buffers (in bytes)
  * @speed_hz: Select a speed other than the device default for this
  *      transfer. If 0 the default (from @spi_device) is used.
@@ -1112,6 +1114,10 @@ struct spi_transfer {
 	unsigned	cs_change:1;
 	unsigned	tx_nbits:4;
 	unsigned	rx_nbits:4;
+	unsigned	multi_bus_mode: 2;
+#define SPI_MULTI_BUS_MODE_SINGLE	0 /* only use single bus */
+#define SPI_MULTI_BUS_MODE_STRIPE	1 /* one data word per bus */
+#define SPI_MULTI_BUS_MODE_MIRROR	2 /* same word sent on all buses */
 	unsigned	timestamped:1;
 	bool		dtr_mode;
 #define	SPI_NBITS_SINGLE	0x01 /* 1-bit transfer */
-- 
2.43.0
^ permalink raw reply related	[flat|nested] 33+ messages in thread
* [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
  2025-10-14 22:02 [PATCH 0/6] spi: add multi-bus support David Lechner
                   ` (2 preceding siblings ...)
  2025-10-14 22:02 ` [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer David Lechner
@ 2025-10-14 22:02 ` David Lechner
  2025-10-15 10:30   ` Nuno Sá
  2025-10-15 20:53   ` Marcelo Schmitt
  2025-10-14 22:02 ` [PATCH 5/6] dt-bindings: iio: adc: adi,ad7380: add spi-buses property David Lechner
  2025-10-14 22:02 ` [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses David Lechner
  5 siblings, 2 replies; 33+ messages in thread
From: David Lechner @ 2025-10-14 22:02 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio,
	David Lechner
Add support for SPI_MULTI_BUS_MODE_STRIPE to the AXI SPI engine driver.
The v2.0.0 version of the AXI SPI Engine IP core supports multiple
buses. This can be used with SPI_MULTI_BUS_MODE_STRIPE to support
reading from simultaneous sampling ADCs that have a separate SDO line
for each analog channel. This allows reading all channels at the same
time to increase throughput.
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 drivers/spi/spi-axi-spi-engine.c | 128 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 124 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index e06f412190fd243161a0b3df992f26157531f6a1..707e5108efec41f7eff608a09fcebd9d28fa2d70 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -23,6 +23,9 @@
 #include <linux/spi/spi.h>
 #include <trace/events/spi.h>
 
+#define SPI_ENGINE_REG_DATA_WIDTH		0x0C
+#define   SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK	GENMASK(24, 16)
+#define   SPI_ENGINE_REG_DATA_WIDTH_MASK		GENMASK(15, 0)
 #define SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH	0x10
 #define SPI_ENGINE_REG_RESET			0x40
 
@@ -75,6 +78,8 @@
 #define SPI_ENGINE_CMD_REG_CLK_DIV		0x0
 #define SPI_ENGINE_CMD_REG_CONFIG		0x1
 #define SPI_ENGINE_CMD_REG_XFER_BITS		0x2
+#define SPI_ENGINE_CMD_REG_SDI_MASK		0x3
+#define SPI_ENGINE_CMD_REG_SDO_MASK		0x4
 
 #define SPI_ENGINE_MISC_SYNC			0x0
 #define SPI_ENGINE_MISC_SLEEP			0x1
@@ -105,6 +110,10 @@
 #define SPI_ENGINE_OFFLOAD_CMD_FIFO_SIZE	16
 #define SPI_ENGINE_OFFLOAD_SDO_FIFO_SIZE	16
 
+/* Extending SPI_MULTI_BUS_MODE values for optimizing messages. */
+#define SPI_ENGINE_MULTI_BUS_MODE_UNKNOWN	-1
+#define SPI_ENGINE_MULTI_BUS_MODE_CONFLICTING	-2
+
 struct spi_engine_program {
 	unsigned int length;
 	uint16_t instructions[] __counted_by(length);
@@ -142,6 +151,9 @@ struct spi_engine_offload {
 	unsigned long flags;
 	unsigned int offload_num;
 	unsigned int spi_mode_config;
+	unsigned int multi_bus_mode;
+	u8 primary_bus_mask;
+	u8 all_bus_mask;
 	u8 bits_per_word;
 };
 
@@ -165,6 +177,22 @@ struct spi_engine {
 	bool offload_requires_sync;
 };
 
+static u8 spi_engine_primary_bus_flag(struct spi_device *spi)
+{
+	return BIT(spi->data_bus[0]);
+}
+
+static u8 spi_engine_all_bus_flags(struct spi_device *spi)
+{
+	u8 flags = 0;
+	int i;
+
+	for (i = 0; i < spi->num_data_bus; i++)
+		flags |= BIT(spi->data_bus[i]);
+
+	return flags;
+}
+
 static void spi_engine_program_add_cmd(struct spi_engine_program *p,
 	bool dry, uint16_t cmd)
 {
@@ -193,7 +221,7 @@ static unsigned int spi_engine_get_config(struct spi_device *spi)
 }
 
 static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
-	struct spi_transfer *xfer)
+				struct spi_transfer *xfer, u32 num_lanes)
 {
 	unsigned int len;
 
@@ -204,6 +232,9 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
 	else
 		len = xfer->len / 4;
 
+	if (xfer->multi_bus_mode == SPI_MULTI_BUS_MODE_STRIPE)
+		len /= num_lanes;
+
 	while (len) {
 		unsigned int n = min(len, 256U);
 		unsigned int flags = 0;
@@ -269,6 +300,7 @@ static int spi_engine_precompile_message(struct spi_message *msg)
 {
 	unsigned int clk_div, max_hz = msg->spi->controller->max_speed_hz;
 	struct spi_transfer *xfer;
+	int multi_bus_mode = SPI_ENGINE_MULTI_BUS_MODE_UNKNOWN;
 	u8 min_bits_per_word = U8_MAX;
 	u8 max_bits_per_word = 0;
 
@@ -284,6 +316,24 @@ static int spi_engine_precompile_message(struct spi_message *msg)
 			min_bits_per_word = min(min_bits_per_word, xfer->bits_per_word);
 			max_bits_per_word = max(max_bits_per_word, xfer->bits_per_word);
 		}
+
+		if (xfer->rx_buf || xfer->offload_flags & SPI_OFFLOAD_XFER_RX_STREAM ||
+		    xfer->tx_buf || xfer->offload_flags & SPI_OFFLOAD_XFER_TX_STREAM) {
+			switch (xfer->multi_bus_mode) {
+			case SPI_MULTI_BUS_MODE_SINGLE:
+			case SPI_MULTI_BUS_MODE_STRIPE:
+				break;
+			default:
+				/* Other modes, like mirror not supported */
+				return -EINVAL;
+			}
+
+			/* If all xfers have the same multi-bus mode, we can optimize. */
+			if (multi_bus_mode == SPI_ENGINE_MULTI_BUS_MODE_UNKNOWN)
+				multi_bus_mode = xfer->multi_bus_mode;
+			else if (multi_bus_mode != xfer->multi_bus_mode)
+				multi_bus_mode = SPI_ENGINE_MULTI_BUS_MODE_CONFLICTING;
+		}
 	}
 
 	/*
@@ -297,6 +347,10 @@ static int spi_engine_precompile_message(struct spi_message *msg)
 			priv->bits_per_word = min_bits_per_word;
 		else
 			priv->bits_per_word = 0;
+
+		priv->multi_bus_mode = multi_bus_mode;
+		priv->primary_bus_mask = spi_engine_primary_bus_flag(msg->spi);
+		priv->all_bus_mask = spi_engine_all_bus_flags(msg->spi);
 	}
 
 	return 0;
@@ -310,6 +364,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
 	struct spi_engine_offload *priv;
 	struct spi_transfer *xfer;
 	int clk_div, new_clk_div, inst_ns;
+	int prev_multi_bus_mode = SPI_MULTI_BUS_MODE_SINGLE;
 	bool keep_cs = false;
 	u8 bits_per_word = 0;
 
@@ -334,6 +389,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
 		 * in the same way.
 		 */
 		bits_per_word = priv->bits_per_word;
+		prev_multi_bus_mode = priv->multi_bus_mode;
 	} else {
 		spi_engine_program_add_cmd(p, dry,
 			SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
@@ -344,6 +400,24 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
 	spi_engine_gen_cs(p, dry, spi, !xfer->cs_off);
 
 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		if (xfer->rx_buf || xfer->offload_flags & SPI_OFFLOAD_XFER_RX_STREAM ||
+		    xfer->tx_buf || xfer->offload_flags & SPI_OFFLOAD_XFER_TX_STREAM) {
+			if (xfer->multi_bus_mode != prev_multi_bus_mode) {
+				u8 bus_flags = spi_engine_primary_bus_flag(spi);
+
+				if (xfer->multi_bus_mode == SPI_MULTI_BUS_MODE_STRIPE)
+					bus_flags = spi_engine_all_bus_flags(spi);
+
+				spi_engine_program_add_cmd(p, dry,
+					SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+							     bus_flags));
+				spi_engine_program_add_cmd(p, dry,
+					SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+							     bus_flags));
+			}
+			prev_multi_bus_mode = xfer->multi_bus_mode;
+		}
+
 		new_clk_div = host->max_speed_hz / xfer->effective_speed_hz;
 		if (new_clk_div != clk_div) {
 			clk_div = new_clk_div;
@@ -360,7 +434,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
 					bits_per_word));
 		}
 
-		spi_engine_gen_xfer(p, dry, xfer);
+		spi_engine_gen_xfer(p, dry, xfer, spi->num_data_bus);
 		spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer),
 				     inst_ns, xfer->effective_speed_hz);
 
@@ -394,6 +468,17 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
 	if (clk_div != 1)
 		spi_engine_program_add_cmd(p, dry,
 			SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CLK_DIV, 0));
+
+	/* Restore single bus mode unless offload disable will restore it later. */
+	if (prev_multi_bus_mode == SPI_MULTI_BUS_MODE_STRIPE &&
+	    (!msg->offload || priv->multi_bus_mode != SPI_MULTI_BUS_MODE_STRIPE)) {
+		u8 bus_flags = spi_engine_primary_bus_flag(spi);
+
+		spi_engine_program_add_cmd(p, dry,
+			SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK, bus_flags));
+		spi_engine_program_add_cmd(p, dry,
+			SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK, bus_flags));
+	}
 }
 
 static void spi_engine_xfer_next(struct spi_message *msg,
@@ -799,6 +884,17 @@ static int spi_engine_setup(struct spi_device *device)
 	writel_relaxed(SPI_ENGINE_CMD_CS_INV(spi_engine->cs_inv),
 		       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
 
+	if (host->num_data_bus > 1) {
+		u8 bus_flags = spi_engine_primary_bus_flag(device);
+
+		writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+						    bus_flags),
+			       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+		writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+						    bus_flags),
+			       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+	}
+
 	/*
 	 * In addition to setting the flags, we have to do a CS assert command
 	 * to make the new setting actually take effect.
@@ -902,6 +998,15 @@ static int spi_engine_trigger_enable(struct spi_offload *offload)
 						    priv->bits_per_word),
 			       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
 
+	if (priv->multi_bus_mode == SPI_MULTI_BUS_MODE_STRIPE) {
+		writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+						    priv->all_bus_mask),
+			       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+		writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+						    priv->all_bus_mask),
+			       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+	}
+
 	writel_relaxed(SPI_ENGINE_CMD_SYNC(1),
 		spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
 
@@ -929,6 +1034,16 @@ static void spi_engine_trigger_disable(struct spi_offload *offload)
 	reg &= ~SPI_ENGINE_OFFLOAD_CTRL_ENABLE;
 	writel_relaxed(reg, spi_engine->base +
 			    SPI_ENGINE_REG_OFFLOAD_CTRL(priv->offload_num));
+
+	/* Restore single-bus mode. */
+	if (priv->multi_bus_mode == SPI_MULTI_BUS_MODE_STRIPE) {
+		writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+						    priv->primary_bus_mask),
+			       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+		writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+						    priv->primary_bus_mask),
+			       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+	}
 }
 
 static struct dma_chan
@@ -973,7 +1088,7 @@ static int spi_engine_probe(struct platform_device *pdev)
 {
 	struct spi_engine *spi_engine;
 	struct spi_controller *host;
-	unsigned int version;
+	unsigned int version, data_width_reg_val;
 	int irq, ret;
 
 	irq = platform_get_irq(pdev, 0);
@@ -1042,7 +1157,7 @@ static int spi_engine_probe(struct platform_device *pdev)
 		return PTR_ERR(spi_engine->base);
 
 	version = readl(spi_engine->base + ADI_AXI_REG_VERSION);
-	if (ADI_AXI_PCORE_VER_MAJOR(version) != 1) {
+	if (ADI_AXI_PCORE_VER_MAJOR(version) > 2) {
 		dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%u\n",
 			ADI_AXI_PCORE_VER_MAJOR(version),
 			ADI_AXI_PCORE_VER_MINOR(version),
@@ -1050,6 +1165,8 @@ static int spi_engine_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	data_width_reg_val = readl(spi_engine->base + SPI_ENGINE_REG_DATA_WIDTH);
+
 	if (adi_axi_pcore_ver_gteq(version, 1, 1)) {
 		unsigned int sizes = readl(spi_engine->base +
 				SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH);
@@ -1097,6 +1214,9 @@ static int spi_engine_probe(struct platform_device *pdev)
 	}
 	if (adi_axi_pcore_ver_gteq(version, 1, 3))
 		host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH;
+	if (adi_axi_pcore_ver_gteq(version, 2, 0))
+		host->num_data_bus = FIELD_GET(SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK,
+					       data_width_reg_val);
 
 	if (host->max_speed_hz == 0)
 		return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0");
-- 
2.43.0
^ permalink raw reply related	[flat|nested] 33+ messages in thread
* [PATCH 5/6] dt-bindings: iio: adc: adi,ad7380: add spi-buses property
  2025-10-14 22:02 [PATCH 0/6] spi: add multi-bus support David Lechner
                   ` (3 preceding siblings ...)
  2025-10-14 22:02 ` [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE David Lechner
@ 2025-10-14 22:02 ` David Lechner
  2025-10-14 22:02 ` [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses David Lechner
  5 siblings, 0 replies; 33+ messages in thread
From: David Lechner @ 2025-10-14 22:02 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio,
	David Lechner
Add spi-buses property to describe how many SDO lines are wired up on
the ADC. These chips are simultaneous sampling ADCs and have one SDO
line per channel, either 2 or 4 total depending on the part number.
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 .../devicetree/bindings/iio/adc/adi,ad7380.yaml    | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
index 8dae89ecb64d723dcf2b4af1e0505fc5db49595b..78002bdaa795800a3927570d639e7f8eda9206c2 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
@@ -63,6 +63,10 @@ properties:
   spi-cpol: true
   spi-cpha: true
 
+  spi-buses:
+    minItems: 1
+    maxItems: 4
+
   vcc-supply:
     description: A 3V to 3.6V supply that powers the chip.
 
@@ -246,6 +250,22 @@ allOf:
       patternProperties:
         "^channel@[0-3]$": false
 
+  # 2-channel chip can only have up to 2 buses
+  - if:
+      properties:
+        compatible:
+          enum:
+            - adi,ad7380
+            - adi,ad7381
+            - adi,ad7386
+            - adi,ad7387
+            - adi,ad7388
+            - adi,ad7389
+    then:
+      properties:
+        spi-buses:
+          maxItems: 2
+
 examples:
   - |
     #include <dt-bindings/interrupt-controller/irq.h>
@@ -261,6 +281,7 @@ examples:
             spi-cpol;
             spi-cpha;
             spi-max-frequency = <80000000>;
+            spi-buses = <0>, <1>;
 
             interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
             interrupt-parent = <&gpio0>;
@@ -285,6 +306,7 @@ examples:
             spi-cpol;
             spi-cpha;
             spi-max-frequency = <80000000>;
+            spi-buses = <0>, <1>, <2>, <3>;
 
             interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
             interrupt-parent = <&gpio0>;
-- 
2.43.0
^ permalink raw reply related	[flat|nested] 33+ messages in thread
* [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses
  2025-10-14 22:02 [PATCH 0/6] spi: add multi-bus support David Lechner
                   ` (4 preceding siblings ...)
  2025-10-14 22:02 ` [PATCH 5/6] dt-bindings: iio: adc: adi,ad7380: add spi-buses property David Lechner
@ 2025-10-14 22:02 ` David Lechner
  2025-10-15 10:36   ` Nuno Sá
  2025-10-18 18:10   ` Jonathan Cameron
  5 siblings, 2 replies; 33+ messages in thread
From: David Lechner @ 2025-10-14 22:02 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio,
	David Lechner
Add support for multiple SPI buses to increase throughput. The AD7380
family of ADCs have multiple SDO lines on the chip that can be used to
read each channel on a separate SPI bus. If wired up to a SPI controller
that supports it, the driver will now take advantage of this feature.
This allows reaching the maximum sample rate advertised in the datasheet
when combined with SPI offloading.
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 drivers/iio/adc/ad7380.c | 41 ++++++++++++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 13 deletions(-)
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index bfd908deefc0f40b42bd8a44bfce7a2510b2fdf1..36abe95852006a81f7e31f8034699e59292af79e 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -77,8 +77,7 @@
 #define AD7380_CONFIG1_REFSEL		BIT(1)
 #define AD7380_CONFIG1_PMODE		BIT(0)
 
-#define AD7380_CONFIG2_SDO2		GENMASK(9, 8)
-#define AD7380_CONFIG2_SDO		BIT(8)
+#define AD7380_CONFIG2_SDO		GENMASK(9, 8)
 #define AD7380_CONFIG2_RESET		GENMASK(7, 0)
 
 #define AD7380_CONFIG2_RESET_SOFT	0x3C
@@ -92,11 +91,6 @@
 #define T_CONVERT_X_NS 500		/* xth conversion start time (oversampling) */
 #define T_POWERUP_US 5000		/* Power up */
 
-/*
- * AD738x support several SDO lines to increase throughput, but driver currently
- * supports only 1 SDO line (standard SPI transaction)
- */
-#define AD7380_NUM_SDO_LINES		1
 #define AD7380_DEFAULT_GAIN_MILLI	1000
 
 /*
@@ -1084,7 +1078,7 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch)
 	if (oversampling_ratio > 1)
 		xfer.delay.value = T_CONVERT_0_NS +
 			T_CONVERT_X_NS * (oversampling_ratio - 1) *
-			st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
+			st->chip_info->num_simult_channels / st->spi->num_data_bus;
 
 	return spi_sync_transfer(st->spi, &xfer, 1);
 }
@@ -1113,7 +1107,7 @@ static int ad7380_update_xfers(struct ad7380_state *st,
 	if (oversampling_ratio > 1)
 		t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS *
 			(oversampling_ratio - 1) *
-			st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES;
+			st->chip_info->num_simult_channels / st->spi->num_data_bus;
 
 	if (st->seq) {
 		xfer[0].delay.value = xfer[1].delay.value = t_convert;
@@ -1124,6 +1118,7 @@ static int ad7380_update_xfers(struct ad7380_state *st,
 			AD7380_SPI_BYTES(scan_type) *
 			st->chip_info->num_simult_channels;
 		xfer[3].rx_buf = xfer[2].rx_buf + xfer[2].len;
+		xfer[3].multi_bus_mode = xfer[2].multi_bus_mode;
 		/* Additional delay required here when oversampling is enabled */
 		if (oversampling_ratio > 1)
 			xfer[2].delay.value = t_convert;
@@ -1198,6 +1193,8 @@ static int ad7380_init_offload_msg(struct ad7380_state *st,
 	xfer->bits_per_word = scan_type->realbits;
 	xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
 	xfer->len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels;
+	if (st->spi->num_data_bus > 1)
+		xfer->multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE;
 
 	spi_message_init_with_transfers(&st->offload_msg, xfer, 1);
 	st->offload_msg.offload = st->offload;
@@ -1793,6 +1790,7 @@ static const struct iio_info ad7380_info = {
 
 static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
 {
+	u32 sdo;
 	int ret;
 
 	/* perform hard reset */
@@ -1815,11 +1813,24 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en)
 	st->ch = 0;
 	st->seq = false;
 
-	/* SPI 1-wire mode */
+	/* SDO field has an irregular mapping. */
+	switch (st->spi->num_data_bus) {
+	case 1:
+		sdo = 1;
+		break;
+	case 2:
+		sdo = 0;
+		break;
+	case 4:
+		sdo = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2,
 				  AD7380_CONFIG2_SDO,
-				  FIELD_PREP(AD7380_CONFIG2_SDO,
-					     AD7380_NUM_SDO_LINES));
+				  FIELD_PREP(AD7380_CONFIG2_SDO, sdo));
 }
 
 static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
@@ -1842,7 +1853,7 @@ static int ad7380_probe_spi_offload(struct iio_dev *indio_dev,
 				     "failed to get offload trigger\n");
 
 	sample_rate = st->chip_info->max_conversion_rate_hz *
-		      AD7380_NUM_SDO_LINES / st->chip_info->num_simult_channels;
+		      spi->num_data_bus / st->chip_info->num_simult_channels;
 
 	st->sample_freq_range[0] = 1; /* min */
 	st->sample_freq_range[1] = 1; /* step */
@@ -2010,6 +2021,8 @@ static int ad7380_probe(struct spi_device *spi)
 	st->normal_xfer[0].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
 	st->normal_xfer[0].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
 	st->normal_xfer[1].rx_buf = st->scan_data;
+	if (spi->num_data_bus > 1)
+		st->normal_xfer[1].multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE;
 
 	spi_message_init_with_transfers(&st->normal_msg, st->normal_xfer,
 					ARRAY_SIZE(st->normal_xfer));
@@ -2031,6 +2044,8 @@ static int ad7380_probe(struct spi_device *spi)
 	st->seq_xfer[2].cs_change = 1;
 	st->seq_xfer[2].cs_change_delay.value = st->chip_info->timing_specs->t_csh_ns;
 	st->seq_xfer[2].cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
+	if (spi->num_data_bus > 1)
+		st->seq_xfer[2].multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE;
 
 	spi_message_init_with_transfers(&st->seq_msg, st->seq_xfer,
 					ARRAY_SIZE(st->seq_xfer));
-- 
2.43.0
^ permalink raw reply related	[flat|nested] 33+ messages in thread
* Re: [PATCH 2/6] spi: Support multi-bus controllers
  2025-10-14 22:02 ` [PATCH 2/6] spi: Support multi-bus controllers David Lechner
@ 2025-10-15 10:06   ` Nuno Sá
  2025-10-15 20:16   ` Marcelo Schmitt
  1 sibling, 0 replies; 33+ messages in thread
From: Nuno Sá @ 2025-10-15 10:06 UTC (permalink / raw)
  To: David Lechner, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> Add support for SPI controllers with multiple physical SPI data buses.
> (A data bus in this context means lines connected to a serializer, so a
> controller with two data buses would have two serializers in a single
> controller).
> 
> This is common in the type of controller that can be used with parallel
> flash memories, but can be used for general purpose SPI as well.
> 
> To indicate support, a controller just needs to set ctlr->num_data_bus
> to something greater than 1. Peripherals indicate which bus they are
> connected to via device tree (ACPI support can be added if needed).
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
LGTM,
Acked-by: Nuno Sá <nuno.sa@analog.com>
> 
> This patch has been seen in a different series [1] by Sean before:
> 
> [1]:
> https://lore.kernel.org/linux-spi/20250616220054.3968946-4-sean.anderson@linux.dev/
> 
> Changes:
> * Use u8 array instead of bitfield so that the order of the mapping is
>   preserved. (Now looks very much like chip select mapping.)
> * Added doc strings for added fields.
> * Tweaked the comments.
> ---
>  drivers/spi/spi.c       | 28 +++++++++++++++++++++++++++-
>  include/linux/spi/spi.h | 17 +++++++++++++++++
>  2 files changed, 44 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index
> 2e0647a06890290e1c9dc4a347a0864329795b08..84e5d5057eb41f1a522c4870265d78feb411
> 09c8 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -2354,7 +2354,7 @@ static void of_spi_parse_dt_cs_delay(struct device_node
> *nc,
>  static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device
> *spi,
>  			   struct device_node *nc)
>  {
> -	u32 value, cs[SPI_DEVICE_CS_CNT_MAX];
> +	u32 value, buses[SPI_DEVICE_DATA_BUS_CNT_MAX],
> cs[SPI_DEVICE_CS_CNT_MAX];
>  	int rc, idx;
>  
>  	/* Mode (clock phase/polarity/etc.) */
> @@ -2446,6 +2446,31 @@ static int of_spi_parse_dt(struct spi_controller *ctlr,
> struct spi_device *spi,
>  	for (idx = 0; idx < rc; idx++)
>  		spi_set_chipselect(spi, idx, cs[idx]);
>  
> +	rc = of_property_read_variable_u32_array(nc, "spi-buses", buses, 1,
> +						 ARRAY_SIZE(buses));
> +	if (rc < 0 && rc != -EINVAL) {
> +		dev_err(&ctlr->dev, "%pOF has invalid 'spi-buses' property
> (%d)\n",
> +			nc, rc);
> +		return rc;
> +	}
> +
> +	if (rc == -EINVAL) {
> +		/* Default when property is omitted. */
> +		spi->num_data_bus = 1;
> +	} else {
> +		for (idx = 0; idx < rc; idx++) {
> +			if (buses[idx] >= ctlr->num_data_bus) {
> +				dev_err(&ctlr->dev,
> +					"%pOF has out of range 'spi-buses'
> property (%d/%d)\n",
> +					nc, buses[idx], ctlr->num_data_bus);
> +				return -EINVAL;
> +			}
> +			spi->data_bus[idx] = buses[idx];
> +		}
> +
> +		spi->num_data_bus = rc;
> +	}
> +
>  	/*
>  	 * By default spi->chip_select[0] will hold the physical CS number,
>  	 * so set bit 0 in spi->cs_index_mask.
> @@ -3054,6 +3079,7 @@ struct spi_controller *__spi_alloc_controller(struct
> device *dev,
>  	mutex_init(&ctlr->add_lock);
>  	ctlr->bus_num = -1;
>  	ctlr->num_chipselect = 1;
> +	ctlr->num_data_bus = 1;
>  	ctlr->target = target;
>  	if (IS_ENABLED(CONFIG_SPI_SLAVE) && target)
>  		ctlr->dev.class = &spi_target_class;
> diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
> index
> cb2c2df3108999a73b67ef4a7b0d2cb07adfc669..c314194d4e7e2b396795ece10e142118ca05
> f4eb 100644
> --- a/include/linux/spi/spi.h
> +++ b/include/linux/spi/spi.h
> @@ -23,6 +23,9 @@
>  /* Max no. of CS supported per spi device */
>  #define SPI_DEVICE_CS_CNT_MAX 4
>  
> +/* Max no. of data buses supported per spi device */
> +#define SPI_DEVICE_DATA_BUS_CNT_MAX 8
> +
>  struct dma_chan;
>  struct software_node;
>  struct ptp_system_timestamp;
> @@ -171,6 +174,9 @@ extern void spi_transfer_cs_change_delay_exec(struct
> spi_message *msg,
>   * @chip_select: Array of physical chipselect, spi->chipselect[i] gives
>   *	the corresponding physical CS for logical CS i.
>   * @num_chipselect: Number of physical chipselects used.
> + * @data_bus: Array of physical data buses. This is only used with
> specialized
> + * controllers that support multiple data buses.
> + * @num_data_bus: Number of physical data buses used.
>   * @cs_index_mask: Bit mask of the active chipselect(s) in the chipselect
> array
>   * @cs_gpiod: Array of GPIO descriptors of the corresponding chipselect lines
>   *	(optional, NULL when not using a GPIO line)
> @@ -231,6 +237,8 @@ struct spi_device {
>  
>  	u8			chip_select[SPI_DEVICE_CS_CNT_MAX];
>  	u8			num_chipselect;
> +	u8			data_bus[SPI_DEVICE_DATA_BUS_CNT_MAX];
> +	u8			num_data_bus;
>  
>  	/*
>  	 * Bit mask of the chipselect(s) that the driver need to use from
> @@ -401,6 +409,7 @@ extern struct spi_device *spi_new_ancillary_device(struct
> spi_device *spi, u8 ch
>   *	SPI targets, and are numbered from zero to num_chipselects.
>   *	each target has a chipselect signal, but it's common that not
>   *	every chipselect is connected to a target.
> + * @num_data_bus: Number of data buses supported by this controller. Default
> is 1.
>   * @dma_alignment: SPI controller constraint on DMA buffers alignment.
>   * @mode_bits: flags understood by this controller driver
>   * @buswidth_override_bits: flags to override for this controller driver
> @@ -576,6 +585,14 @@ struct spi_controller {
>  	 */
>  	u16			num_chipselect;
>  
> +	/*
> +	 * Some specialized SPI controllers can have more than one physical
> +	 * bus interface per controller (each having it's own serializer).
> This
> +	 * specifies the number of buses in that case. Other controllers do
> not
> +	 * need to set this (defaults to 1).
> +	 */
> +	u16			num_data_bus;
> +
>  	/* Some SPI controllers pose alignment requirements on DMAable
>  	 * buffers; let protocol drivers know about these requirements.
>  	 */
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-14 22:02 ` [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer David Lechner
@ 2025-10-15 10:16   ` Nuno Sá
  2025-10-15 12:01     ` Mark Brown
  2025-10-15 20:21   ` Marcelo Schmitt
  1 sibling, 1 reply; 33+ messages in thread
From: Nuno Sá @ 2025-10-15 10:16 UTC (permalink / raw)
  To: David Lechner, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> Add a new multi_bus_mode field to struct spi_transfer to allow
> peripherals that support multiple SPI buses to be used with a single
> SPI controller.
> 
> This requires both the peripheral and the controller to have multiple
> serializers connected to separate data buses. It could also be used with
> a single controller and multiple peripherals that are functioning as a
> single logical device (similar to parallel memories).
> 
> The possible values for this field have the following semantics:
> 
> - SPI_MULTI_BUS_MODE_SINGLE: Only use the first bus. This means that it
>     it is operating just like a conventional SPI bus. It is the default
>     value so that existing drivers do not need to be modified.
> 
>     Example:
>         tx_buf[0] = 0x88;
> 
>         struct spi_transfer xfer = {
>             .tx_buf = tx_buf,
>             .len = 1,
>         };
> 
>         spi_sync_transfer(spi, &xfer, 1);
> 
>         controller    > data bits >     peripheral
>         ----------   ----------------   ----------
>             SDO 0    0-0-0-1-0-0-0-1    SDI 0
> 
> - SPI_MULTI_BUS_MODE_MIRROR: Send a single data word over all of the
>     buses at the same time. This only makes sense for writes and not
>     for reads.
> 
>     Example:
>         tx_buf[0] = 0x88;
> 
>         struct spi_transfer xfer = {
>             .tx_buf = tx_buf,
>             .len = 1,
>             .multi_bus_mode = SPI_MULTI_BUS_MODE_MIRROR,
>         };
> 
>         spi_sync_transfer(spi, &xfer, 1);
> 
>         controller    > data bits >     peripheral
>         ----------   ----------------   ----------
>             SDO 0    0-0-0-1-0-0-0-1    SDI 0
>             SDO 1    0-0-0-1-0-0-0-1    SDI 1
> 
> - SPI_MULTI_BUS_MODE_STRIPE: Send or receive two different data words at
>     the same time, one on each bus.
> 
>     Example:
>         struct spi_transfer xfer = {
>             .rx_buf = rx_buf,
>             .len = 2, /* must be multiple of number of buses */
>             .multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE,
>         };
> 
>         spi_sync_transfer(spi, &xfer, 1);
> 
>         controller    < data bits <     peripheral
>         ----------   ----------------   ----------
>             SDI 0    0-0-0-1-0-0-0-1    SDO 0
>             SDI 1    1-0-0-0-1-0-0-0    SDO 1
Out of curiosity, how does this work for devices like AD4030 where the same word
is kind of interleaved between SDO lines? I guess it works the same (in terms of
SW) and is up to some IP core (typically in the FPGA) to "re-assemble" the word?
> 
>         After the transfer, rx_buf[0] == 0x11 (word from SDO 0) and
>         rx_buf[1] == 0x88 (word from SDO 1). If the transfer was longer,
>         the data would continue in an alternating fashion.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
Looks good anyways,
Acked-by: Nuno Sá <nuno.sa@analog.com>
>  include/linux/spi/spi.h | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
> index
> c314194d4e7e2b396795ece10e142118ca05f4eb..7d22ef5077d1229cac2574831f80092c591b
> 972f 100644
> --- a/include/linux/spi/spi.h
> +++ b/include/linux/spi/spi.h
> @@ -976,6 +976,8 @@ struct spi_res {
>   *      (SPI_NBITS_SINGLE) is used.
>   * @rx_nbits: number of bits used for reading. If 0 the default
>   *      (SPI_NBITS_SINGLE) is used.
> + * @multi_bus_mode: How to serialize data on multiple buses. One of the
> + *      SPI_MULTI_BUS_MODE_* values.
>   * @len: size of rx and tx buffers (in bytes)
>   * @speed_hz: Select a speed other than the device default for this
>   *      transfer. If 0 the default (from @spi_device) is used.
> @@ -1112,6 +1114,10 @@ struct spi_transfer {
>  	unsigned	cs_change:1;
>  	unsigned	tx_nbits:4;
>  	unsigned	rx_nbits:4;
> +	unsigned	multi_bus_mode: 2;
> +#define SPI_MULTI_BUS_MODE_SINGLE	0 /* only use single bus */
> +#define SPI_MULTI_BUS_MODE_STRIPE	1 /* one data word per bus */
> +#define SPI_MULTI_BUS_MODE_MIRROR	2 /* same word sent on all buses */
>  	unsigned	timestamped:1;
>  	bool		dtr_mode;
>  #define	SPI_NBITS_SINGLE	0x01 /* 1-bit transfer */
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
  2025-10-14 22:02 ` [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE David Lechner
@ 2025-10-15 10:30   ` Nuno Sá
  2025-10-15 12:03     ` Mark Brown
  2025-10-15 16:29     ` David Lechner
  2025-10-15 20:53   ` Marcelo Schmitt
  1 sibling, 2 replies; 33+ messages in thread
From: Nuno Sá @ 2025-10-15 10:30 UTC (permalink / raw)
  To: David Lechner, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> Add support for SPI_MULTI_BUS_MODE_STRIPE to the AXI SPI engine driver.
> 
> The v2.0.0 version of the AXI SPI Engine IP core supports multiple
> buses. This can be used with SPI_MULTI_BUS_MODE_STRIPE to support
> reading from simultaneous sampling ADCs that have a separate SDO line
> for each analog channel. This allows reading all channels at the same
> time to increase throughput.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
>  drivers/spi/spi-axi-spi-engine.c | 128 +++++++++++++++++++++++++++++++++++++-
> -
>  1 file changed, 124 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-
> engine.c
> index
> e06f412190fd243161a0b3df992f26157531f6a1..707e5108efec41f7eff608a09fcebd9d28fa
> 2d70 100644
> --- a/drivers/spi/spi-axi-spi-engine.c
> +++ b/drivers/spi/spi-axi-spi-engine.c
> @@ -23,6 +23,9 @@
>  #include <linux/spi/spi.h>
>  #include <trace/events/spi.h>
>  
> +#define SPI_ENGINE_REG_DATA_WIDTH		0x0C
> +#define   SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK	GENMASK(24, 16)
> +#define   SPI_ENGINE_REG_DATA_WIDTH_MASK		GENMASK(15, 0)
>  #define SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH	0x10
>  #define SPI_ENGINE_REG_RESET			0x40
>  
> @@ -75,6 +78,8 @@
>  #define SPI_ENGINE_CMD_REG_CLK_DIV		0x0
>  #define SPI_ENGINE_CMD_REG_CONFIG		0x1
>  #define SPI_ENGINE_CMD_REG_XFER_BITS		0x2
> +#define SPI_ENGINE_CMD_REG_SDI_MASK		0x3
> +#define SPI_ENGINE_CMD_REG_SDO_MASK		0x4
>  
>  #define SPI_ENGINE_MISC_SYNC			0x0
>  #define SPI_ENGINE_MISC_SLEEP			0x1
> @@ -105,6 +110,10 @@
>  #define SPI_ENGINE_OFFLOAD_CMD_FIFO_SIZE	16
>  #define SPI_ENGINE_OFFLOAD_SDO_FIFO_SIZE	16
>  
> +/* Extending SPI_MULTI_BUS_MODE values for optimizing messages. */
> +#define SPI_ENGINE_MULTI_BUS_MODE_UNKNOWN	-1
> +#define SPI_ENGINE_MULTI_BUS_MODE_CONFLICTING	-2
> +
>  struct spi_engine_program {
>  	unsigned int length;
>  	uint16_t instructions[] __counted_by(length);
> @@ -142,6 +151,9 @@ struct spi_engine_offload {
>  	unsigned long flags;
>  	unsigned int offload_num;
>  	unsigned int spi_mode_config;
> +	unsigned int multi_bus_mode;
> +	u8 primary_bus_mask;
> +	u8 all_bus_mask;
>  	u8 bits_per_word;
>  };
>  
> @@ -165,6 +177,22 @@ struct spi_engine {
>  	bool offload_requires_sync;
>  };
>  
> +static u8 spi_engine_primary_bus_flag(struct spi_device *spi)
> +{
> +	return BIT(spi->data_bus[0]);
> +}
> +
> +static u8 spi_engine_all_bus_flags(struct spi_device *spi)
> +{
> +	u8 flags = 0;
> +	int i;
> +
> +	for (i = 0; i < spi->num_data_bus; i++)
> +		flags |= BIT(spi->data_bus[i]);
> +
> +	return flags;
> +}
> +
>  static void spi_engine_program_add_cmd(struct spi_engine_program *p,
>  	bool dry, uint16_t cmd)
>  {
> @@ -193,7 +221,7 @@ static unsigned int spi_engine_get_config(struct
> spi_device *spi)
>  }
>  
>  static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
> -	struct spi_transfer *xfer)
> +				struct spi_transfer *xfer, u32 num_lanes)
>  {
>  	unsigned int len;
>  
> @@ -204,6 +232,9 @@ static void spi_engine_gen_xfer(struct spi_engine_program
> *p, bool dry,
>  	else
>  		len = xfer->len / 4;
>  
> +	if (xfer->multi_bus_mode == SPI_MULTI_BUS_MODE_STRIPE)
> +		len /= num_lanes;
> +
>  	while (len) {
>  		unsigned int n = min(len, 256U);
>  		unsigned int flags = 0;
> @@ -269,6 +300,7 @@ static int spi_engine_precompile_message(struct
> spi_message *msg)
>  {
>  	unsigned int clk_div, max_hz = msg->spi->controller->max_speed_hz;
>  	struct spi_transfer *xfer;
> +	int multi_bus_mode = SPI_ENGINE_MULTI_BUS_MODE_UNKNOWN;
>  	u8 min_bits_per_word = U8_MAX;
>  	u8 max_bits_per_word = 0;
>  
> @@ -284,6 +316,24 @@ static int spi_engine_precompile_message(struct
> spi_message *msg)
>  			min_bits_per_word = min(min_bits_per_word, xfer-
> >bits_per_word);
>  			max_bits_per_word = max(max_bits_per_word, xfer-
> >bits_per_word);
>  		}
> +
> +		if (xfer->rx_buf || xfer->offload_flags &
> SPI_OFFLOAD_XFER_RX_STREAM ||
> +		    xfer->tx_buf || xfer->offload_flags &
> SPI_OFFLOAD_XFER_TX_STREAM) {
I'm a bit confused by this condition. It looks like setting priv->multi_bus_mode
(and the other fields) only matters for msg->offload but the above will be true
for regular rx/tx messages, right? Or am i missing something?
If so, I wonder why doing this for all transfers if we only care about
multi_bus_mode for offload messages. I guess you want to validate
xfer->multi_bus_mode? I would then just take the switch() out of the condition
(I mean trying to setup a no data xfer with an invalid bus_mode should also be
seen as invalid IMO) and then use the offload conditions (or maybe simply msg-
>offload?) for the multi_bus_mode handling. To me, it makes the intent more
clear.
 
- Nuno Sá
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses
  2025-10-14 22:02 ` [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses David Lechner
@ 2025-10-15 10:36   ` Nuno Sá
  2025-10-15 18:46     ` David Lechner
  2025-10-18 18:10   ` Jonathan Cameron
  1 sibling, 1 reply; 33+ messages in thread
From: Nuno Sá @ 2025-10-15 10:36 UTC (permalink / raw)
  To: David Lechner, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> Add support for multiple SPI buses to increase throughput. The AD7380
> family of ADCs have multiple SDO lines on the chip that can be used to
> read each channel on a separate SPI bus. If wired up to a SPI controller
> that supports it, the driver will now take advantage of this feature.
> This allows reaching the maximum sample rate advertised in the datasheet
> when combined with SPI offloading.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
One minor thing. With it,
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
>  drivers/iio/adc/ad7380.c | 41 ++++++++++++++++++++++++++++-------------
>  1 file changed, 28 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
> index
> bfd908deefc0f40b42bd8a44bfce7a2510b2fdf1..36abe95852006a81f7e31f8034699e59292a
> f79e 100644
> --- a/drivers/iio/adc/ad7380.c
> +++ b/drivers/iio/adc/ad7380.c
> @@ -77,8 +77,7 @@
>  #define AD7380_CONFIG1_REFSEL		BIT(1)
>  #define AD7380_CONFIG1_PMODE		BIT(0)
>  
> -#define AD7380_CONFIG2_SDO2		GENMASK(9, 8)
> -#define AD7380_CONFIG2_SDO		BIT(8)
> +#define AD7380_CONFIG2_SDO		GENMASK(9, 8)
>  #define AD7380_CONFIG2_RESET		GENMASK(7, 0)
>  
>  #define AD7380_CONFIG2_RESET_SOFT	0x3C
> @@ -92,11 +91,6 @@
>  #define T_CONVERT_X_NS 500		/* xth conversion start time
> (oversampling) */
>  #define T_POWERUP_US 5000		/* Power up */
>  
> -/*
> - * AD738x support several SDO lines to increase throughput, but driver
> currently
> - * supports only 1 SDO line (standard SPI transaction)
> - */
> -#define AD7380_NUM_SDO_LINES		1
>  #define AD7380_DEFAULT_GAIN_MILLI	1000
>  
>  /*
> @@ -1084,7 +1078,7 @@ static int ad7380_set_ch(struct ad7380_state *st,
> unsigned int ch)
>  	if (oversampling_ratio > 1)
>  		xfer.delay.value = T_CONVERT_0_NS +
>  			T_CONVERT_X_NS * (oversampling_ratio - 1) *
> -			st->chip_info->num_simult_channels /
> AD7380_NUM_SDO_LINES;
> +			st->chip_info->num_simult_channels / st->spi-
> >num_data_bus;
>  
>  	return spi_sync_transfer(st->spi, &xfer, 1);
>  }
> @@ -1113,7 +1107,7 @@ static int ad7380_update_xfers(struct ad7380_state *st,
>  	if (oversampling_ratio > 1)
>  		t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS *
>  			(oversampling_ratio - 1) *
> -			st->chip_info->num_simult_channels /
> AD7380_NUM_SDO_LINES;
> +			st->chip_info->num_simult_channels / st->spi-
> >num_data_bus;
>  
>  	if (st->seq) {
>  		xfer[0].delay.value = xfer[1].delay.value = t_convert;
> @@ -1124,6 +1118,7 @@ static int ad7380_update_xfers(struct ad7380_state *st,
>  			AD7380_SPI_BYTES(scan_type) *
>  			st->chip_info->num_simult_channels;
>  		xfer[3].rx_buf = xfer[2].rx_buf + xfer[2].len;
> +		xfer[3].multi_bus_mode = xfer[2].multi_bus_mode;
Why not doing the above once during probe?
- Nuno Sá
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-15 10:16   ` Nuno Sá
@ 2025-10-15 12:01     ` Mark Brown
  2025-10-15 14:43       ` Nuno Sá
  0 siblings, 1 reply; 33+ messages in thread
From: Mark Brown @ 2025-10-15 12:01 UTC (permalink / raw)
  To: Nuno Sá
  Cc: David Lechner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
[-- Attachment #1: Type: text/plain, Size: 642 bytes --]
On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
> On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> >         controller    < data bits <     peripheral
> >         ----------   ----------------   ----------
> >             SDI 0    0-0-0-1-0-0-0-1    SDO 0
> >             SDI 1    1-0-0-0-1-0-0-0    SDO 1
> Out of curiosity, how does this work for devices like AD4030 where the same word
> is kind of interleaved between SDO lines? I guess it works the same (in terms of
> SW) and is up to some IP core (typically in the FPGA) to "re-assemble" the word?
So combined with the existing parallel SPI support?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
  2025-10-15 10:30   ` Nuno Sá
@ 2025-10-15 12:03     ` Mark Brown
  2025-10-15 16:29     ` David Lechner
  1 sibling, 0 replies; 33+ messages in thread
From: Mark Brown @ 2025-10-15 12:03 UTC (permalink / raw)
  To: Nuno Sá
  Cc: David Lechner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
[-- Attachment #1: Type: text/plain, Size: 752 bytes --]
On Wed, Oct 15, 2025 at 11:30:39AM +0100, Nuno Sá wrote:
> On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> > Add support for SPI_MULTI_BUS_MODE_STRIPE to the AXI SPI engine driver.
> > 
> > The v2.0.0 version of the AXI SPI Engine IP core supports multiple
> > buses. This can be used with SPI_MULTI_BUS_MODE_STRIPE to support
> > reading from simultaneous sampling ADCs that have a separate SDO line
> > for each analog channel. This allows reading all channels at the same
> > time to increase throughput.
Please delete unneeded context from mails when replying.  Doing this
makes it much easier to find your reply in the message, helping ensure
it won't be missed by people scrolling through the irrelevant quoted
material.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-15 12:01     ` Mark Brown
@ 2025-10-15 14:43       ` Nuno Sá
  2025-10-15 15:18         ` Mark Brown
  0 siblings, 1 reply; 33+ messages in thread
From: Nuno Sá @ 2025-10-15 14:43 UTC (permalink / raw)
  To: Mark Brown
  Cc: David Lechner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
> On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
> > On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> 
> > >         controller    < data bits <     peripheral
> > >         ----------   ----------------   ----------
> > >             SDI 0    0-0-0-1-0-0-0-1    SDO 0
> > >             SDI 1    1-0-0-0-1-0-0-0    SDO 1
> 
> > Out of curiosity, how does this work for devices like AD4030 where the same
> > word
> > is kind of interleaved between SDO lines? I guess it works the same (in
> > terms of
> > SW) and is up to some IP core (typically in the FPGA) to "re-assemble" the
> > word?
> 
> So combined with the existing parallel SPI support?
Not sure if this is meant for me :). parallel SPI is for parallel memories and
the spi_device multi cs support stuff right? I tried to track it down but it's
not clear if there are any users already upstream (qspi zynqmp and the nor
flashes). It looks like it's not in yet but not sure.
Anyways, IIUC, it seems we could indeed see the device I mentioned as a parallel
kind of thing as we have one bit per lane per sclk. However, the multi_cs
concept does not apply (so I think it would be misleading to try and hack it
around with tweaking cs_index_mask and related APIs).
Given the current API, maybe it makes sense to add (in the future) a
SPI_MULTI_BUS_MODE_PARALLEL or David already intends to support it in the
current STRIPE mode and I'm misunderstanding.
- Nuno Sá
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-15 14:43       ` Nuno Sá
@ 2025-10-15 15:18         ` Mark Brown
  2025-10-15 16:15           ` David Lechner
  0 siblings, 1 reply; 33+ messages in thread
From: Mark Brown @ 2025-10-15 15:18 UTC (permalink / raw)
  To: Nuno Sá
  Cc: David Lechner, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
[-- Attachment #1: Type: text/plain, Size: 1693 bytes --]
On Wed, Oct 15, 2025 at 03:43:09PM +0100, Nuno Sá wrote:
> On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
> > On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
> > > On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> > > >         controller    < data bits <     peripheral
> > > >         ----------   ----------------   ----------
> > > >             SDI 0    0-0-0-1-0-0-0-1    SDO 0
> > > >             SDI 1    1-0-0-0-1-0-0-0    SDO 1
> > > Out of curiosity, how does this work for devices like AD4030 where the same
> > > word
> > > is kind of interleaved between SDO lines? I guess it works the same (in
> > > terms of
> > > SW) and is up to some IP core (typically in the FPGA) to "re-assemble" the
> > > word?
> > So combined with the existing parallel SPI support?
> Not sure if this is meant for me :). parallel SPI is for parallel memories and
> the spi_device multi cs support stuff right? I tried to track it down but it's
> not clear if there are any users already upstream (qspi zynqmp and the nor
> flashes). It looks like it's not in yet but not sure.
There's multi-CS stuff but what I was thinking about was the stuff for
parallel memories, I was trying to clarify what cases you were talking
about with "interleaved between SDO lines".
> Anyways, IIUC, it seems we could indeed see the device I mentioned as a parallel
> kind of thing as we have one bit per lane per sclk. However, the multi_cs
> concept does not apply (so I think it would be misleading to try and hack it
> around with tweaking cs_index_mask and related APIs).
OK, so either just the parallel SPI or possibly that composed with this
(fun!).
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-15 15:18         ` Mark Brown
@ 2025-10-15 16:15           ` David Lechner
  2025-10-15 16:43             ` Nuno Sá
  0 siblings, 1 reply; 33+ messages in thread
From: David Lechner @ 2025-10-15 16:15 UTC (permalink / raw)
  To: Mark Brown, Nuno Sá
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On 10/15/25 10:18 AM, Mark Brown wrote:
> On Wed, Oct 15, 2025 at 03:43:09PM +0100, Nuno Sá wrote:
>> On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
>>> On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
>>>> On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> 
>>>>>         controller    < data bits <     peripheral
>>>>>         ----------   ----------------   ----------
>>>>>             SDI 0    0-0-0-1-0-0-0-1    SDO 0
>>>>>             SDI 1    1-0-0-0-1-0-0-0    SDO 1
> 
>>>> Out of curiosity, how does this work for devices like AD4030 where the same
>>>> word
The AD4030 is just one channel, so doesn't do interleaving. But you probably
meant AD4630 when it is wired up with only 1 SDO line. That line has to be shared
by both of the simultaneous converters so it alternates between sending one bit
from each word. This patch series doesn't address that case. But this series will
work for the AD4630 when it has 2 SDO lines wired up.
>>>> is kind of interleaved between SDO lines? I guess it works the same (in
>>>> terms of
>>>> SW) and is up to some IP core (typically in the FPGA) to "re-assemble" the
>>>> word?
Right, to be able to AD4630 with SPI offloading and only a single SDO line, there
would need to be an extra block in the offloading pipeline to deinterleave the bits.
> 
>>> So combined with the existing parallel SPI support?
> 
>> Not sure if this is meant for me :). parallel SPI is for parallel memories and
>> the spi_device multi cs support stuff right? I tried to track it down but it's
>> not clear if there are any users already upstream (qspi zynqmp and the nor
>> flashes). It looks like it's not in yet but not sure.
> 
> There's multi-CS stuff but what I was thinking about was the stuff for
> parallel memories, I was trying to clarify what cases you were talking
> about with "interleaved between SDO lines".
The interleaving Nuno mentioned is where one word each from the two buses
are interleaved one bit at at time and sent over a single bus, so it is
different from what this series is dealing with (multiple buses).
> 
>> Anyways, IIUC, it seems we could indeed see the device I mentioned as a parallel
>> kind of thing as we have one bit per lane per sclk. However, the multi_cs
>> concept does not apply (so I think it would be misleading to try and hack it
>> around with tweaking cs_index_mask and related APIs).
> 
> OK, so either just the parallel SPI or possibly that composed with this
> (fun!).
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
  2025-10-15 10:30   ` Nuno Sá
  2025-10-15 12:03     ` Mark Brown
@ 2025-10-15 16:29     ` David Lechner
  2025-10-16  9:11       ` Nuno Sá
  1 sibling, 1 reply; 33+ messages in thread
From: David Lechner @ 2025-10-15 16:29 UTC (permalink / raw)
  To: Nuno Sá, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On 10/15/25 5:30 AM, Nuno Sá wrote:
> On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
>> Add support for SPI_MULTI_BUS_MODE_STRIPE to the AXI SPI engine driver.
>>
...
>> +
>> +		if (xfer->rx_buf || xfer->offload_flags &
>> SPI_OFFLOAD_XFER_RX_STREAM ||
>> +		    xfer->tx_buf || xfer->offload_flags &
>> SPI_OFFLOAD_XFER_TX_STREAM) {
> 
> I'm a bit confused by this condition. It looks like setting priv->multi_bus_mode
> (and the other fields) only matters for msg->offload but the above will be true
> for regular rx/tx messages, right? Or am i missing something?
You are correct.
> 
> If so, I wonder why doing this for all transfers if we only care about
> multi_bus_mode for offload messages. I guess you want to validate
> xfer->multi_bus_mode?
Yes, this is important to validate it since we don't support all possible modes.
The mode still applies to the individual xfer even when not using SPI offloading.
> I would then just take the switch() out of the condition
> (I mean trying to setup a no data xfer with an invalid bus_mode should also be
> seen as invalid IMO) and then use the offload conditions (or maybe simply msg-
>> offload?) for the multi_bus_mode handling. To me, it makes the intent more
> clear.
It the validation only matters for xfers that send or receive data. I guess
it doesn't hurt to check the mode in non-data xfers (e.g. ones with just a delay)
but since we needed the condition anyway for the accumulator, it made sense to
me to put it inside the conditional.
I might have put an additional if (msg->offload) around the accumulator part
since it only matters when using SPI offloading, but the indent was already
getting quite deep.
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-15 16:15           ` David Lechner
@ 2025-10-15 16:43             ` Nuno Sá
  2025-10-15 18:38               ` David Lechner
  0 siblings, 1 reply; 33+ messages in thread
From: Nuno Sá @ 2025-10-15 16:43 UTC (permalink / raw)
  To: David Lechner, Mark Brown
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On Wed, 2025-10-15 at 11:15 -0500, David Lechner wrote:
> On 10/15/25 10:18 AM, Mark Brown wrote:
> > On Wed, Oct 15, 2025 at 03:43:09PM +0100, Nuno Sá wrote:
> > > On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
> > > > On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
> > > > > On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> > 
> > > > > >         controller    < data bits <     peripheral
> > > > > >         ----------   ----------------   ----------
> > > > > >             SDI 0    0-0-0-1-0-0-0-1    SDO 0
> > > > > >             SDI 1    1-0-0-0-1-0-0-0    SDO 1
> > 
> > > > > Out of curiosity, how does this work for devices like AD4030 where the same
> > > > > word
> 
> The AD4030 is just one channel, so doesn't do interleaving. But you probably
> meant AD4630 when it is wired up with only 1 SDO line. That line has to be shared
> by both of the simultaneous converters so it alternates between sending one bit
> from each word. This patch series doesn't address that case. But this series will
> work for the AD4630 when it has 2 SDO lines wired up.
> 
Hmm I didn't even remembered that one. But what I meant with interleaved was having
the same data word spread through multiple SDO lines (one bit per line) which is what
(also) happens with the devices I mentioned. And since you mentioned "...two
different data words at the same time, one on each bus...", I raised the question.
So I guess I kind of misused what interleaved typically means (even though I guess
it's not completely off :)) and was thinking more on the parallel concept Mark spoke
about.
Anyways, from your reply I see the intent is to also use the stripe mode for this and
have some kind of external IP deal with data re-order. I gave a look into the ad4630
IP core and indeed there's a data reorder IP block after the offload engine.
- Nuno Sá
> > > > 
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-15 16:43             ` Nuno Sá
@ 2025-10-15 18:38               ` David Lechner
  2025-10-16  9:08                 ` Nuno Sá
  0 siblings, 1 reply; 33+ messages in thread
From: David Lechner @ 2025-10-15 18:38 UTC (permalink / raw)
  To: Nuno Sá, Mark Brown
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On 10/15/25 11:43 AM, Nuno Sá wrote:
> On Wed, 2025-10-15 at 11:15 -0500, David Lechner wrote:
>> On 10/15/25 10:18 AM, Mark Brown wrote:
>>> On Wed, Oct 15, 2025 at 03:43:09PM +0100, Nuno Sá wrote:
>>>> On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
>>>>> On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
>>>>>> On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
>>>
>>>>>>>         controller    < data bits <     peripheral
>>>>>>>         ----------   ----------------   ----------
>>>>>>>             SDI 0    0-0-0-1-0-0-0-1    SDO 0
>>>>>>>             SDI 1    1-0-0-0-1-0-0-0    SDO 1
>>>
>>>>>> Out of curiosity, how does this work for devices like AD4030 where the same
>>>>>> word
>>
>> The AD4030 is just one channel, so doesn't do interleaving. But you probably
>> meant AD4630 when it is wired up with only 1 SDO line. That line has to be shared
>> by both of the simultaneous converters so it alternates between sending one bit
>> from each word. This patch series doesn't address that case. But this series will
>> work for the AD4630 when it has 2 SDO lines wired up.
>>
> 
> Hmm I didn't even remembered that one. But what I meant with interleaved was having
> the same data word spread through multiple SDO lines (one bit per line) which is what
> (also) happens with the devices I mentioned. And since you mentioned "...two
> different data words at the same time, one on each bus...", I raised the question.
Ah, yes, I know what you are talking about now. I didn't mention that use case in
the cover letter because I didn't want to confuse things. But actually the AD4630
can have 8 SDO lines, 4 per each data bus/ADC channel. The groups of 4 act like a
quad SPI where 4 bits of one data word are sent at the same time. Those 4 lines are
considered one "bus" since they are all connected to the same serialzer that combines
the bits into a single word. We already have support for this sort of thing in Linux.
And sure, we could mix the two together. So a SPI transfer might look like:
struct spi_transfer example = {
	rx_buf = rx_buf;
	len = 4; /* 2 x 16-bit words */
	rx_nbits = 4; /* each bus is quad SPI */
	multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE; /* 2 data buses */
	bits_per_word = 16;
};
This would result in a transfer that reads two 16-bit words in 4 SCLK cycles.
And the .dts would look like:
spi {
	adc@0 {
		compatible = "adi,ad4630-16";
		reg = <0>;
		...
		spi-rx-bus-width = <4>;
		spi-buses = <2>;
		...
	};
};
The AXI SPI Engine doesn't know how to do the quad SPI part yet though, so
it isn't something we could implement right now.
If we tried to do it with spi-buses = <8>; then we would end up with the
"interleaved" bits (or nibbles depending on the wiring) that requires the
extra IP block to sort out when using SPI offloading. Technically, we could
make it work, but it would require a bunch of extra hardware description that
the driver would have to interpret in order to correctly format the struct
spi_transfer. I was hoping we could avoid that and just teach the SPI Engine
how to do dual/quad SPI like other SPI controllers.
> 
> So I guess I kind of misused what interleaved typically means (even though I guess
> it's not completely off :)) and was thinking more on the parallel concept Mark spoke
> about.
> 
> Anyways, from your reply I see the intent is to also use the stripe mode for this and
> have some kind of external IP deal with data re-order. I gave a look into the ad4630
> IP core and indeed there's a data reorder IP block after the offload engine.
> 
> - Nuno Sá
> 
>>>>>
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses
  2025-10-15 10:36   ` Nuno Sá
@ 2025-10-15 18:46     ` David Lechner
  0 siblings, 0 replies; 33+ messages in thread
From: David Lechner @ 2025-10-15 18:46 UTC (permalink / raw)
  To: Nuno Sá, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On 10/15/25 5:36 AM, Nuno Sá wrote:
> On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
...
>>  
>>  	if (st->seq) {
>>  		xfer[0].delay.value = xfer[1].delay.value = t_convert;
>> @@ -1124,6 +1118,7 @@ static int ad7380_update_xfers(struct ad7380_state *st,
>>  			AD7380_SPI_BYTES(scan_type) *
>>  			st->chip_info->num_simult_channels;
>>  		xfer[3].rx_buf = xfer[2].rx_buf + xfer[2].len;
>> +		xfer[3].multi_bus_mode = xfer[2].multi_bus_mode;
> 
> Why not doing the above once during probe?
> 
There is nothing else in st->seq_xfer[3] that gets set in probe, so
I didn't really consider it. Seems like it should be fine to do as you
suggest though.
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 2/6] spi: Support multi-bus controllers
  2025-10-14 22:02 ` [PATCH 2/6] spi: Support multi-bus controllers David Lechner
  2025-10-15 10:06   ` Nuno Sá
@ 2025-10-15 20:16   ` Marcelo Schmitt
  1 sibling, 0 replies; 33+ messages in thread
From: Marcelo Schmitt @ 2025-10-15 20:16 UTC (permalink / raw)
  To: David Lechner
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
On 10/14, David Lechner wrote:
> Add support for SPI controllers with multiple physical SPI data buses.
> (A data bus in this context means lines connected to a serializer, so a
> controller with two data buses would have two serializers in a single
> controller).
> 
> This is common in the type of controller that can be used with parallel
> flash memories, but can be used for general purpose SPI as well.
> 
> To indicate support, a controller just needs to set ctlr->num_data_bus
> to something greater than 1. Peripherals indicate which bus they are
> connected to via device tree (ACPI support can be added if needed).
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
LGTM
Acked-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-14 22:02 ` [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer David Lechner
  2025-10-15 10:16   ` Nuno Sá
@ 2025-10-15 20:21   ` Marcelo Schmitt
  1 sibling, 0 replies; 33+ messages in thread
From: Marcelo Schmitt @ 2025-10-15 20:21 UTC (permalink / raw)
  To: David Lechner
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
On 10/14, David Lechner wrote:
> Add a new multi_bus_mode field to struct spi_transfer to allow
> peripherals that support multiple SPI buses to be used with a single
> SPI controller.
> 
> This requires both the peripheral and the controller to have multiple
> serializers connected to separate data buses. It could also be used with
> a single controller and multiple peripherals that are functioning as a
> single logical device (similar to parallel memories).
> 
> The possible values for this field have the following semantics:
> 
> - SPI_MULTI_BUS_MODE_SINGLE: Only use the first bus. This means that it
>     it is operating just like a conventional SPI bus. It is the default
>     value so that existing drivers do not need to be modified.
> 
>     Example:
>         tx_buf[0] = 0x88;
> 
>         struct spi_transfer xfer = {
>             .tx_buf = tx_buf,
>             .len = 1,
>         };
> 
>         spi_sync_transfer(spi, &xfer, 1);
> 
>         controller    > data bits >     peripheral
>         ----------   ----------------   ----------
>             SDO 0    0-0-0-1-0-0-0-1    SDI 0
> 
> - SPI_MULTI_BUS_MODE_MIRROR: Send a single data word over all of the
>     buses at the same time. This only makes sense for writes and not
>     for reads.
> 
>     Example:
>         tx_buf[0] = 0x88;
> 
>         struct spi_transfer xfer = {
>             .tx_buf = tx_buf,
>             .len = 1,
>             .multi_bus_mode = SPI_MULTI_BUS_MODE_MIRROR,
>         };
> 
>         spi_sync_transfer(spi, &xfer, 1);
> 
>         controller    > data bits >     peripheral
>         ----------   ----------------   ----------
>             SDO 0    0-0-0-1-0-0-0-1    SDI 0
>             SDO 1    0-0-0-1-0-0-0-1    SDI 1
> 
> - SPI_MULTI_BUS_MODE_STRIPE: Send or receive two different data words at
>     the same time, one on each bus.
> 
>     Example:
>         struct spi_transfer xfer = {
>             .rx_buf = rx_buf,
>             .len = 2, /* must be multiple of number of buses */
>             .multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE,
>         };
> 
>         spi_sync_transfer(spi, &xfer, 1);
> 
>         controller    < data bits <     peripheral
>         ----------   ----------------   ----------
>             SDI 0    0-0-0-1-0-0-0-1    SDO 0
>             SDI 1    1-0-0-0-1-0-0-0    SDO 1
> 
>         After the transfer, rx_buf[0] == 0x11 (word from SDO 0) and
>         rx_buf[1] == 0x88 (word from SDO 1). If the transfer was longer,
>         the data would continue in an alternating fashion.
> 
Can the above explanation be added to the documentation?
Maybe spi-summary.rst or a new file?
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
Nevertheless,
Acked-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
  2025-10-14 22:02 ` [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE David Lechner
  2025-10-15 10:30   ` Nuno Sá
@ 2025-10-15 20:53   ` Marcelo Schmitt
  2025-10-15 22:01     ` David Lechner
  1 sibling, 1 reply; 33+ messages in thread
From: Marcelo Schmitt @ 2025-10-15 20:53 UTC (permalink / raw)
  To: David Lechner
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
On 10/14, David Lechner wrote:
> Add support for SPI_MULTI_BUS_MODE_STRIPE to the AXI SPI engine driver.
> 
> The v2.0.0 version of the AXI SPI Engine IP core supports multiple
> buses. This can be used with SPI_MULTI_BUS_MODE_STRIPE to support
> reading from simultaneous sampling ADCs that have a separate SDO line
> for each analog channel. This allows reading all channels at the same
> time to increase throughput.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
>  drivers/spi/spi-axi-spi-engine.c | 128 +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 124 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
> index e06f412190fd243161a0b3df992f26157531f6a1..707e5108efec41f7eff608a09fcebd9d28fa2d70 100644
> --- a/drivers/spi/spi-axi-spi-engine.c
> +++ b/drivers/spi/spi-axi-spi-engine.c
> @@ -23,6 +23,9 @@
>  #include <linux/spi/spi.h>
>  #include <trace/events/spi.h>
>  
> +#define SPI_ENGINE_REG_DATA_WIDTH		0x0C
> +#define   SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK	GENMASK(24, 16)
would it be 8-bit mask?
#define   SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK   GENMASK(23, 16)
> +#define   SPI_ENGINE_REG_DATA_WIDTH_MASK		GENMASK(15, 0)
>  #define SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH	0x10
>  #define SPI_ENGINE_REG_RESET			0x40
>  
...
>  
> +	data_width_reg_val = readl(spi_engine->base + SPI_ENGINE_REG_DATA_WIDTH);
> +
>  	if (adi_axi_pcore_ver_gteq(version, 1, 1)) {
>  		unsigned int sizes = readl(spi_engine->base +
>  				SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH);
> @@ -1097,6 +1214,9 @@ static int spi_engine_probe(struct platform_device *pdev)
>  	}
>  	if (adi_axi_pcore_ver_gteq(version, 1, 3))
>  		host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH;
> +	if (adi_axi_pcore_ver_gteq(version, 2, 0))
> +		host->num_data_bus = FIELD_GET(SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK,
> +					       data_width_reg_val);
>  
Not sure I'm following the use of DATA_WIDTH and NUM_OF_SDIO.
HDL doc [1] states NUM_OF_SDIO 'is equal with the maximum supported SDI lines in
bits'. And the code sets that to be the number of buses. That should work for
AD7380 because each AD7380 SDO bus has only one line. But, it won't support
AD4630 (or even AD4030) because each AD4630 rx bus has 4 data lines. I can't
find it in HDL, but I'd expect to also have something like NUM_OF_SDIO_PER_BUS.
Or DATA_WIDTH is the number of lines per bus and HDL doc is unclear to me?
Well, it would be nice if we can have host->num_data_bus set in a way that
minimizes diff when multiple lines per bus gets implemented (if that's not
currently supported).
[1]: https://github.com/analogdevicesinc/hdl/pull/1808/files#diff-d1274cfe2e206aa66a0ecd3da04b3e62fc5fad9e12029b34b226c6f91454d34dR77
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
  2025-10-15 20:53   ` Marcelo Schmitt
@ 2025-10-15 22:01     ` David Lechner
  0 siblings, 0 replies; 33+ messages in thread
From: David Lechner @ 2025-10-15 22:01 UTC (permalink / raw)
  To: Marcelo Schmitt
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko, Sean Anderson, linux-spi,
	devicetree, linux-kernel, linux-iio
On 10/15/25 3:53 PM, Marcelo Schmitt wrote:
> On 10/14, David Lechner wrote:
>> Add support for SPI_MULTI_BUS_MODE_STRIPE to the AXI SPI engine driver.
>>
>> The v2.0.0 version of the AXI SPI Engine IP core supports multiple
>> buses. This can be used with SPI_MULTI_BUS_MODE_STRIPE to support
>> reading from simultaneous sampling ADCs that have a separate SDO line
>> for each analog channel. This allows reading all channels at the same
>> time to increase throughput.
>>
>> Signed-off-by: David Lechner <dlechner@baylibre.com>
>> ---
>>  drivers/spi/spi-axi-spi-engine.c | 128 +++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 124 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
>> index e06f412190fd243161a0b3df992f26157531f6a1..707e5108efec41f7eff608a09fcebd9d28fa2d70 100644
>> --- a/drivers/spi/spi-axi-spi-engine.c
>> +++ b/drivers/spi/spi-axi-spi-engine.c
>> @@ -23,6 +23,9 @@
>>  #include <linux/spi/spi.h>
>>  #include <trace/events/spi.h>
>>  
>> +#define SPI_ENGINE_REG_DATA_WIDTH		0x0C
>> +#define   SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK	GENMASK(24, 16)
> would it be 8-bit mask?
> #define   SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK   GENMASK(23, 16)
Ah, good catch.
> 
>> +#define   SPI_ENGINE_REG_DATA_WIDTH_MASK		GENMASK(15, 0)
>>  #define SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH	0x10
>>  #define SPI_ENGINE_REG_RESET			0x40
>>  
> ...
>>  
>> +	data_width_reg_val = readl(spi_engine->base + SPI_ENGINE_REG_DATA_WIDTH);
>> +
>>  	if (adi_axi_pcore_ver_gteq(version, 1, 1)) {
>>  		unsigned int sizes = readl(spi_engine->base +
>>  				SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH);
>> @@ -1097,6 +1214,9 @@ static int spi_engine_probe(struct platform_device *pdev)
>>  	}
>>  	if (adi_axi_pcore_ver_gteq(version, 1, 3))
>>  		host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH;
>> +	if (adi_axi_pcore_ver_gteq(version, 2, 0))
>> +		host->num_data_bus = FIELD_GET(SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK,
>> +					       data_width_reg_val);
>>  
> Not sure I'm following the use of DATA_WIDTH and NUM_OF_SDIO.
> HDL doc [1] states NUM_OF_SDIO 'is equal with the maximum supported SDI lines in
> bits'. And the code sets that to be the number of buses. That should work for
> AD7380 because each AD7380 SDO bus has only one line. But, it won't support
> AD4630 (or even AD4030) because each AD4630 rx bus has 4 data lines. I can't
> find it in HDL, but I'd expect to also have something like NUM_OF_SDIO_PER_BUS.
> Or DATA_WIDTH is the number of lines per bus and HDL doc is unclear to me?
Right now, the HDL doesn't distinguish between the two, so we only have the
case where each "SDIO" is a separate bus. The AD4630 project has extra IP
blocks to unscramble things to simulate having 4 lines on each bus rather than
8 buses.
DATA_WIDTH has to do with how wide the bus between the SPI Engine and DMA
is, so it has nothing to do with the wiring to the peripheral.
> Well, it would be nice if we can have host->num_data_bus set in a way that
> minimizes diff when multiple lines per bus gets implemented (if that's not
> currently supported).
I agree it would be nice. However, the register name and meaning already exists
even in older versions of the IP block (as NUM_OF_SDI), so I think it would be
best to stick with the existing name. Ideally, when support for multiple wires
per bus is added, then we would compile like this: NUM_OF_SDIO=2 SDIO_BUS_WIDTH=4
rather than NUM_OF_SDIO=8 NUM_OF_SDIO_PER_BUS=4.
> 
> [1]: https://github.com/analogdevicesinc/hdl/pull/1808/files#diff-d1274cfe2e206aa66a0ecd3da04b3e62fc5fad9e12029b34b226c6f91454d34dR77
Well, the linked PR isn't merged yet, so I guess we could ask there to rename
NUM_OF_SDIO to NUM_OF_SDIO_BUS there if you think that is a better name since
it is being renamed anyway.
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-15 18:38               ` David Lechner
@ 2025-10-16  9:08                 ` Nuno Sá
  2025-10-16 15:25                   ` David Lechner
  0 siblings, 1 reply; 33+ messages in thread
From: Nuno Sá @ 2025-10-16  9:08 UTC (permalink / raw)
  To: David Lechner, Mark Brown
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On Wed, 2025-10-15 at 13:38 -0500, David Lechner wrote:
> On 10/15/25 11:43 AM, Nuno Sá wrote:
> > On Wed, 2025-10-15 at 11:15 -0500, David Lechner wrote:
> > > On 10/15/25 10:18 AM, Mark Brown wrote:
> > > > On Wed, Oct 15, 2025 at 03:43:09PM +0100, Nuno Sá wrote:
> > > > > On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
> > > > > > On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
> > > > > > > On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> > > > 
> > > > > > > >         controller    < data bits <     peripheral
> > > > > > > >         ----------   ----------------   ----------
> > > > > > > >             SDI 0    0-0-0-1-0-0-0-1    SDO 0
> > > > > > > >             SDI 1    1-0-0-0-1-0-0-0    SDO 1
> > > > 
> > > > > > > Out of curiosity, how does this work for devices like AD4030 where
> > > > > > > the same
> > > > > > > word
> > > 
> > > The AD4030 is just one channel, so doesn't do interleaving. But you
> > > probably
> > > meant AD4630 when it is wired up with only 1 SDO line. That line has to be
> > > shared
> > > by both of the simultaneous converters so it alternates between sending
> > > one bit
> > > from each word. This patch series doesn't address that case. But this
> > > series will
> > > work for the AD4630 when it has 2 SDO lines wired up.
> > > 
> > 
> > Hmm I didn't even remembered that one. But what I meant with interleaved was
> > having
> > the same data word spread through multiple SDO lines (one bit per line)
> > which is what
> > (also) happens with the devices I mentioned. And since you mentioned "...two
> > different data words at the same time, one on each bus...", I raised the
> > question.
> 
> Ah, yes, I know what you are talking about now. I didn't mention that use case
> in
> the cover letter because I didn't want to confuse things. But actually the
> AD4630
> can have 8 SDO lines, 4 per each data bus/ADC channel. The groups of 4 act
> like a
> quad SPI where 4 bits of one data word are sent at the same time. Those 4
> lines are
> considered one "bus" since they are all connected to the same serialzer that
> combines
> the bits into a single word. We already have support for this sort of thing in
> Linux.
> And sure, we could mix the two together. So a SPI transfer might look like:
> 
> struct spi_transfer example = {
> 	rx_buf = rx_buf;
> 	len = 4; /* 2 x 16-bit words */
> 	rx_nbits = 4; /* each bus is quad SPI */
> 	multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE; /* 2 data buses */
> 	bits_per_word = 16;
> };
> 
> This would result in a transfer that reads two 16-bit words in 4 SCLK cycles.
> 
> And the .dts would look like:
> 
> spi {
> 	adc@0 {
> 		compatible = "adi,ad4630-16";
> 		reg = <0>;
> 		...
> 		spi-rx-bus-width = <4>;
> 		spi-buses = <2>;
> 		...
> 	};
> };
Yes, it makes sense! I guess the above is what Mark meant in the first place.
> 
> The AXI SPI Engine doesn't know how to do the quad SPI part yet though, so
> it isn't something we could implement right now.
> 
> If we tried to do it with spi-buses = <8>; then we would end up with the
> "interleaved" bits (or nibbles depending on the wiring) that requires the
> extra IP block to sort out when using SPI offloading. Technically, we could
I think that extra block already exists today. I was thinking the idea was just:
// the case where we just have one channel with eg: 32 bits words (eg: test
patterns) 
struct spi_transfer example = {
	rx_buf = rx_buf;
	len = 1; /* 1 32bit words */
	/* 4 lanes which is actually quadspi */
	multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE; 
};
I still did not looked at how the stripe mode is implemented in the hdl IP but
maybe the above would work as we get 8 bits per lane and we do have the data
reorder IP (or at least used to have) after the offload engine. 
That said, I do see now the above is not the intended usecase for this series
and even if it works we kind of have to hack the xfer len to 1 which does not
reflect reality.
> make it work, but it would require a bunch of extra hardware description that
> the driver would have to interpret in order to correctly format the struct
> spi_transfer. I was hoping we could avoid that and just teach the SPI Engine
> how to do dual/quad SPI like other SPI controllers.
Agreed!
- Nuno Sá
> > > > > 
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE
  2025-10-15 16:29     ` David Lechner
@ 2025-10-16  9:11       ` Nuno Sá
  0 siblings, 0 replies; 33+ messages in thread
From: Nuno Sá @ 2025-10-16  9:11 UTC (permalink / raw)
  To: David Lechner, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Marcelo Schmitt, Michael Hennerich, Nuno Sá,
	Jonathan Cameron, Andy Shevchenko
  Cc: Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On Wed, 2025-10-15 at 11:29 -0500, David Lechner wrote:
> On 10/15/25 5:30 AM, Nuno Sá wrote:
> > On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> > > Add support for SPI_MULTI_BUS_MODE_STRIPE to the AXI SPI engine driver.
> > > 
> 
> ...
> 
> > > +
> > > +		if (xfer->rx_buf || xfer->offload_flags &
> > > SPI_OFFLOAD_XFER_RX_STREAM ||
> > > +		    xfer->tx_buf || xfer->offload_flags &
> > > SPI_OFFLOAD_XFER_TX_STREAM) {
> > 
> > I'm a bit confused by this condition. It looks like setting priv-
> > >multi_bus_mode
> > (and the other fields) only matters for msg->offload but the above will be
> > true
> > for regular rx/tx messages, right? Or am i missing something?
> 
> You are correct.
> 
> > 
> > If so, I wonder why doing this for all transfers if we only care about
> > multi_bus_mode for offload messages. I guess you want to validate
> > xfer->multi_bus_mode?
> 
> Yes, this is important to validate it since we don't support all possible
> modes.
> The mode still applies to the individual xfer even when not using SPI
> offloading.
> 
> > I would then just take the switch() out of the condition
> > (I mean trying to setup a no data xfer with an invalid bus_mode should also
> > be
> > seen as invalid IMO) and then use the offload conditions (or maybe simply
> > msg-
> > > offload?) for the multi_bus_mode handling. To me, it makes the intent more
> > clear.
> 
> It the validation only matters for xfers that send or receive data. I guess
> it doesn't hurt to check the mode in non-data xfers (e.g. ones with just a
> delay)
> but since we needed the condition anyway for the accumulator, it made sense to
> me to put it inside the conditional.
Sure, but note that I did said that I would tread xfers that do not send/receive
data and have an invalid mode as an error (the flag should not be there anyways)
and that's why I was suggesting taking the validation out of the condition. No
strong feelings though so fine to keep it this way.
- Nuno Sá
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-16  9:08                 ` Nuno Sá
@ 2025-10-16 15:25                   ` David Lechner
  2025-10-17 12:36                     ` Nuno Sá
  0 siblings, 1 reply; 33+ messages in thread
From: David Lechner @ 2025-10-16 15:25 UTC (permalink / raw)
  To: Nuno Sá, Mark Brown
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On 10/16/25 4:08 AM, Nuno Sá wrote:
> On Wed, 2025-10-15 at 13:38 -0500, David Lechner wrote:
>> On 10/15/25 11:43 AM, Nuno Sá wrote:
>>> On Wed, 2025-10-15 at 11:15 -0500, David Lechner wrote:
>>>> On 10/15/25 10:18 AM, Mark Brown wrote:
>>>>> On Wed, Oct 15, 2025 at 03:43:09PM +0100, Nuno Sá wrote:
>>>>>> On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
>>>>>>> On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
>>>>>>>> On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
...
>>
>> The AXI SPI Engine doesn't know how to do the quad SPI part yet though, so
>> it isn't something we could implement right now.
>>
>> If we tried to do it with spi-buses = <8>; then we would end up with the
>> "interleaved" bits (or nibbles depending on the wiring) that requires the
>> extra IP block to sort out when using SPI offloading. Technically, we could
> 
> I think that extra block already exists today. I was thinking the idea was just:
> 
> // the case where we just have one channel with eg: 32 bits words (eg: test
> patterns) 
> struct spi_transfer example = {
> 	rx_buf = rx_buf;
> 	len = 1; /* 1 32bit words */
This would still need to be len = 4; since there are 4 bytes in a
32-bit word. (If this was tx with SPI_MULTI_BUS_MODE_MIRROR, then
len = 1 would be correct, but for striping, it is still the length
of all data combined).
> 	/* 4 lanes which is actually quadspi */
> 	multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE; 
> };
This will work with the caveat that for non-offload case, the software 
will need to rearrange the bits in rx_buf into the correct order after
the spi_sync().
For example, u8 *rx_buf will contain bits of the 32-bit word in the
following order:
rx_buf[0] = b28 b24 b20 b16 b12 b8 b4 b0
rx_buf[1] = b29 b25 b21 b17 b13 b9 b5 b1
rx_buf[2] = b30 b26 b22 b18 b14 b10 b6 b2
rx_buf[3] = b31 b27 b23 b19 b15 b11 b7 b3
The correct order of course would be (assuming little endian):
rx_buf[0] = b7 b6 b5 b4 b3 b2 b1 b0
...
And for the offload case, it would require an extra IP block between
SPI and DMA to rearrange the bits in hardware. So to "do it right", the
driver should be checking for a hardware description that such an IP
block exists in the pipline before creating such a SPI xfer.
> 
> I still did not looked at how the stripe mode is implemented in the hdl IP but
> maybe the above would work as we get 8 bits per lane and we do have the data
> reorder IP (or at least used to have) after the offload engine. 
> 
> That said, I do see now the above is not the intended usecase for this series
> and even if it works we kind of have to hack the xfer len to 1 which does not
> reflect reality.
> 
>> make it work, but it would require a bunch of extra hardware description that
>> the driver would have to interpret in order to correctly format the struct
>> spi_transfer. I was hoping we could avoid that and just teach the SPI Engine
>> how to do dual/quad SPI like other SPI controllers.
> 
> Agreed!
> 
> - Nuno Sá
> 
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer
  2025-10-16 15:25                   ` David Lechner
@ 2025-10-17 12:36                     ` Nuno Sá
  0 siblings, 0 replies; 33+ messages in thread
From: Nuno Sá @ 2025-10-17 12:36 UTC (permalink / raw)
  To: David Lechner, Mark Brown
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On Thu, 2025-10-16 at 10:25 -0500, David Lechner wrote:
> On 10/16/25 4:08 AM, Nuno Sá wrote:
> > On Wed, 2025-10-15 at 13:38 -0500, David Lechner wrote:
> > > On 10/15/25 11:43 AM, Nuno Sá wrote:
> > > > On Wed, 2025-10-15 at 11:15 -0500, David Lechner wrote:
> > > > > On 10/15/25 10:18 AM, Mark Brown wrote:
> > > > > > On Wed, Oct 15, 2025 at 03:43:09PM +0100, Nuno Sá wrote:
> > > > > > > On Wed, 2025-10-15 at 13:01 +0100, Mark Brown wrote:
> > > > > > > > On Wed, Oct 15, 2025 at 11:16:01AM +0100, Nuno Sá wrote:
> > > > > > > > > On Tue, 2025-10-14 at 17:02 -0500, David Lechner wrote:
> 
> ...
> 
> > > 
> > > The AXI SPI Engine doesn't know how to do the quad SPI part yet though, so
> > > it isn't something we could implement right now.
> > > 
> > > If we tried to do it with spi-buses = <8>; then we would end up with the
> > > "interleaved" bits (or nibbles depending on the wiring) that requires the
> > > extra IP block to sort out when using SPI offloading. Technically, we
> > > could
> > 
> > I think that extra block already exists today. I was thinking the idea was
> > just:
> > 
> > // the case where we just have one channel with eg: 32 bits words (eg: test
> > patterns) 
> > struct spi_transfer example = {
> > 	rx_buf = rx_buf;
> > 	len = 1; /* 1 32bit words */
> 
> This would still need to be len = 4; since there are 4 bytes in a
> 32-bit word. (If this was tx with SPI_MULTI_BUS_MODE_MIRROR, then
> len = 1 would be correct, but for striping, it is still the length
> of all data combined).
Right, I was still thinking in the old stuff where the spi engine would always
have len = 1 (which is nok)
> 
> > 	/* 4 lanes which is actually quadspi */
> > 	multi_bus_mode = SPI_MULTI_BUS_MODE_STRIPE; 
> > };
> 
> This will work with the caveat that for non-offload case, the software 
> will need to rearrange the bits in rx_buf into the correct order after
> the spi_sync().
> 
> For example, u8 *rx_buf will contain bits of the 32-bit word in the
> following order:
> 
> rx_buf[0] = b28 b24 b20 b16 b12 b8 b4 b0
> rx_buf[1] = b29 b25 b21 b17 b13 b9 b5 b1
> rx_buf[2] = b30 b26 b22 b18 b14 b10 b6 b2
> rx_buf[3] = b31 b27 b23 b19 b15 b11 b7 b3
> 
> The correct order of course would be (assuming little endian):
> 
> 
> rx_buf[0] = b7 b6 b5 b4 b3 b2 b1 b0
I know, that's what the ad4030 driver has to do.
- Nuno Sá
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses
  2025-10-14 22:02 ` [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses David Lechner
  2025-10-15 10:36   ` Nuno Sá
@ 2025-10-18 18:10   ` Jonathan Cameron
  1 sibling, 0 replies; 33+ messages in thread
From: Jonathan Cameron @ 2025-10-18 18:10 UTC (permalink / raw)
  To: David Lechner
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Marcelo Schmitt, Michael Hennerich, Nuno Sá, Andy Shevchenko,
	Sean Anderson, linux-spi, devicetree, linux-kernel, linux-iio
On Tue, 14 Oct 2025 17:02:16 -0500
David Lechner <dlechner@baylibre.com> wrote:
> Add support for multiple SPI buses to increase throughput. The AD7380
> family of ADCs have multiple SDO lines on the chip that can be used to
> read each channel on a separate SPI bus. If wired up to a SPI controller
> that supports it, the driver will now take advantage of this feature.
> This allows reaching the maximum sample rate advertised in the datasheet
> when combined with SPI offloading.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
This seems fine to me.  I briefly looked at the rest of the series and
nothing jumped out other the many combinations of crazy that exist which
came up in the discussion,
Thanks,
Jonathan
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 1/6] dt-bindings: spi: Add spi-buses property
  2025-10-14 22:02 ` [PATCH 1/6] dt-bindings: spi: Add spi-buses property David Lechner
@ 2025-10-21 14:21   ` Rob Herring
  2025-10-21 14:59     ` David Lechner
  0 siblings, 1 reply; 33+ messages in thread
From: Rob Herring @ 2025-10-21 14:21 UTC (permalink / raw)
  To: David Lechner
  Cc: Mark Brown, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On Tue, Oct 14, 2025 at 05:02:11PM -0500, David Lechner wrote:
> Add a spi-buses property to the spi-peripheral-props binding to allow
> specifying the SPI data bus or buses that a peripheral is connected to
> in cases where the SPI controller has more than one physical SPI data
> bus.
Is there a reason why spi-rx-bus-width property doesn't work for you? 
The only thing I see would be you need to define the order of the pins 
like "data-lanes" property.
Rob
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 1/6] dt-bindings: spi: Add spi-buses property
  2025-10-21 14:21   ` Rob Herring
@ 2025-10-21 14:59     ` David Lechner
  2025-10-30 13:51       ` Rob Herring
  0 siblings, 1 reply; 33+ messages in thread
From: David Lechner @ 2025-10-21 14:59 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Brown, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On 10/21/25 9:21 AM, Rob Herring wrote:
> On Tue, Oct 14, 2025 at 05:02:11PM -0500, David Lechner wrote:
>> Add a spi-buses property to the spi-peripheral-props binding to allow
>> specifying the SPI data bus or buses that a peripheral is connected to
>> in cases where the SPI controller has more than one physical SPI data
>> bus.
> 
> Is there a reason why spi-rx-bus-width property doesn't work for you? 
> The only thing I see would be you need to define the order of the pins 
> like "data-lanes" property.
> 
> Rob
Because we can have both at the same time. In one of the other threads,
we talked about the AD4630 ADC that will require this since it has 2 data
buses each with a width of 4 (total of 8 lines).
See: https://lore.kernel.org/linux-iio/ad929fe5-be03-4628-b95a-5c3523bae0c8@baylibre.com/
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 1/6] dt-bindings: spi: Add spi-buses property
  2025-10-21 14:59     ` David Lechner
@ 2025-10-30 13:51       ` Rob Herring
  2025-10-30 22:42         ` David Lechner
  0 siblings, 1 reply; 33+ messages in thread
From: Rob Herring @ 2025-10-30 13:51 UTC (permalink / raw)
  To: David Lechner
  Cc: Mark Brown, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On Tue, Oct 21, 2025 at 09:59:22AM -0500, David Lechner wrote:
> On 10/21/25 9:21 AM, Rob Herring wrote:
> > On Tue, Oct 14, 2025 at 05:02:11PM -0500, David Lechner wrote:
> >> Add a spi-buses property to the spi-peripheral-props binding to allow
> >> specifying the SPI data bus or buses that a peripheral is connected to
> >> in cases where the SPI controller has more than one physical SPI data
> >> bus.
> > 
> > Is there a reason why spi-rx-bus-width property doesn't work for you? 
> > The only thing I see would be you need to define the order of the pins 
> > like "data-lanes" property.
> > 
> > Rob
> 
> Because we can have both at the same time. In one of the other threads,
> we talked about the AD4630 ADC that will require this since it has 2 data
> buses each with a width of 4 (total of 8 lines).
> 
> See: https://lore.kernel.org/linux-iio/ad929fe5-be03-4628-b95a-5c3523bae0c8@baylibre.com/
But it can't really be 2 independent buses/controllers unless the ADC 
has 2 completely independent interfaces, right? Surely the clock is 
shared across the 2 buses? So aren't you really just borrowing pins and 
the fifo of the 2nd controller? That seems pretty controller specific to 
support that. For example, how would you support this with spi-gpio 
(obviously kind of pointless given the bandwidth needs with 8 data 
lines) or any 2 independent instances of SPI controllers?
Rob
^ permalink raw reply	[flat|nested] 33+ messages in thread
* Re: [PATCH 1/6] dt-bindings: spi: Add spi-buses property
  2025-10-30 13:51       ` Rob Herring
@ 2025-10-30 22:42         ` David Lechner
  0 siblings, 0 replies; 33+ messages in thread
From: David Lechner @ 2025-10-30 22:42 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Brown, Krzysztof Kozlowski, Conor Dooley, Marcelo Schmitt,
	Michael Hennerich, Nuno Sá, Jonathan Cameron,
	Andy Shevchenko, Sean Anderson, linux-spi, devicetree,
	linux-kernel, linux-iio
On 10/30/25 8:51 AM, Rob Herring wrote:
> On Tue, Oct 21, 2025 at 09:59:22AM -0500, David Lechner wrote:
>> On 10/21/25 9:21 AM, Rob Herring wrote:
>>> On Tue, Oct 14, 2025 at 05:02:11PM -0500, David Lechner wrote:
>>>> Add a spi-buses property to the spi-peripheral-props binding to allow
>>>> specifying the SPI data bus or buses that a peripheral is connected to
>>>> in cases where the SPI controller has more than one physical SPI data
>>>> bus.
>>>
>>> Is there a reason why spi-rx-bus-width property doesn't work for you? 
>>> The only thing I see would be you need to define the order of the pins 
>>> like "data-lanes" property.
>>>
>>> Rob
>>
>> Because we can have both at the same time. In one of the other threads,
>> we talked about the AD4630 ADC that will require this since it has 2 data
>> buses each with a width of 4 (total of 8 lines).
>>
>> See: https://lore.kernel.org/linux-iio/ad929fe5-be03-4628-b95a-5c3523bae0c8@baylibre.com/
> 
> But it can't really be 2 independent buses/controllers unless the ADC 
> has 2 completely independent interfaces, right?
Correct.
The proposed property really only concerns the data lines (tx/rx). It doesn't
care if there is 1 or 2 SCLK lines and it doesn't care if there is only 1 CS
line.
So maybe spi-data-buses would be a better name for the property? Or
spi-data-ports (using the NXP FlexSPI controller docs terminology)?
Or spi-data-channels?
> Surely the clock is shared across the 2 buses? 
It depends on the mode of operation. In stripe or mirror mode, both
clocks would be synchronized/identical. It doesn't matter if there is
1 or two clock lines in these modes. And only one CS line is needed
in these modes - but 2 also works - these properties are independent.
It could also be used in a way where each data bus is used independently
(one at a time rather than both at the same time). In this case, it could
still work with one SCLK line as long as there were two CS lines. But if
there are two SCLK lines, then each one could operate independently in this
mode.
> So aren't you really just borrowing pins and the fifo of the 2nd controller? 
Yes, I think that is a valid way of thinking about it.
> That seems pretty controller specific to support that. 
Correct. This property could only be used with such controllers.
> For example, how would you support this with spi-gpio 
We would need to increase maxItems of several of the gpios properties.
sck-gpios could be multiple gpios to allow for more than one SCLK
line.
miso-gpios would contain spi-rx-bus-width * ARRAY_SIZE(spi-buses)
gpio phandles. mosi-gpios would be similar with tx instead of rx.
> (obviously kind of pointless given the bandwidth needs with 8 data 
> lines) or any 2 independent instances of SPI controllers?
Doing this with two separate controllers wouldn't work for cases
where only one SCLK line is wired up - unless it was a controller
that supported a peripheral-provided clock, then it might.
Performance wouldn't be great in this case either though, so I
don't expect that anyone would be tempted to do this.
To implement this, I would make a new SPI controller node that
takes the phandles of two or more SPI controllers. The peripheral
child nodes would be in this new controller node and the other
two controller nodes would not have any child nodes.
It might need some extra properties to say which data and clock
lines are actually wired up similar to the spi-gpio.
> 
> Rob
^ permalink raw reply	[flat|nested] 33+ messages in thread
end of thread, other threads:[~2025-10-30 22:42 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-14 22:02 [PATCH 0/6] spi: add multi-bus support David Lechner
2025-10-14 22:02 ` [PATCH 1/6] dt-bindings: spi: Add spi-buses property David Lechner
2025-10-21 14:21   ` Rob Herring
2025-10-21 14:59     ` David Lechner
2025-10-30 13:51       ` Rob Herring
2025-10-30 22:42         ` David Lechner
2025-10-14 22:02 ` [PATCH 2/6] spi: Support multi-bus controllers David Lechner
2025-10-15 10:06   ` Nuno Sá
2025-10-15 20:16   ` Marcelo Schmitt
2025-10-14 22:02 ` [PATCH 3/6] spi: add multi_bus_mode field to struct spi_transfer David Lechner
2025-10-15 10:16   ` Nuno Sá
2025-10-15 12:01     ` Mark Brown
2025-10-15 14:43       ` Nuno Sá
2025-10-15 15:18         ` Mark Brown
2025-10-15 16:15           ` David Lechner
2025-10-15 16:43             ` Nuno Sá
2025-10-15 18:38               ` David Lechner
2025-10-16  9:08                 ` Nuno Sá
2025-10-16 15:25                   ` David Lechner
2025-10-17 12:36                     ` Nuno Sá
2025-10-15 20:21   ` Marcelo Schmitt
2025-10-14 22:02 ` [PATCH 4/6] spi: axi-spi-engine: support SPI_MULTI_BUS_MODE_STRIPE David Lechner
2025-10-15 10:30   ` Nuno Sá
2025-10-15 12:03     ` Mark Brown
2025-10-15 16:29     ` David Lechner
2025-10-16  9:11       ` Nuno Sá
2025-10-15 20:53   ` Marcelo Schmitt
2025-10-15 22:01     ` David Lechner
2025-10-14 22:02 ` [PATCH 5/6] dt-bindings: iio: adc: adi,ad7380: add spi-buses property David Lechner
2025-10-14 22:02 ` [PATCH 6/6] iio: adc: ad7380: Add support for multiple SPI buses David Lechner
2025-10-15 10:36   ` Nuno Sá
2025-10-15 18:46     ` David Lechner
2025-10-18 18:10   ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).