* [PATCH v5 1/9] spi: dt-bindings: change spi-{rx,tx}-bus-width to arrays
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-12 17:45 ` [PATCH v5 2/9] spi: dt-bindings: add spi-{tx,rx}-lane-map properties David Lechner
` (7 subsequent siblings)
8 siblings, 0 replies; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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, Jonathan Cameron
Change spi-rx-bus-width and spi-tx-bus-width properties from single
uint32 values to arrays of uint32 values. This allows describing SPI
peripherals connected to controllers that have multiple data lanes for
receiving or transmitting two or more words in parallel.
Each index in the array corresponds to a physical data lane (one or more
wires depending on the bus width). Additional mapping properties will be
needed in cases where a lane on the controller or peripheral is skipped.
Bindings that make use of this property are updated in the same commit
to avoid validation errors.
The adi,ad4030 binding can now better describe the chips multi-lane
capabilities, so that binding is refined and gets a new example.
Converting from single uint32 to array of uint32 does not break .dts/
.dtb files since there is no difference between specifying a single
uint32 value and an array with a single uint32 value in devicetree.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v5 changes:
- Added change for andestech,ae350-spi.yaml (recently new file).
v4 changes:
- New patch to replace data-lanes property patch.
In v3, Rob suggested possibly splitting the spi-controller.yaml file
to have a way to make most SPI controllers have maxItems: 1 for these
properties. I would like to avoid that because it doesn't seem scalable,
e.g. if we need another similar split in the future, the number of
combinations would grow exponentially (factorially?). I have an idea to
instead do this using $dynamicAnchor and $dynamicRef, but dt-schema
doesn't currently support that. So I propose we do the best we can for
now with the current dt-schema and make further improvements later.
Also, in v3, I suggested that we could have leading 0s in the arrays
to indicate unused lanes. But after further consideration, I think it's
better to have separate lane-mapping properties for that purpose. It
will be easier to explain and parse and be a bit more flexible that way.
---
.../bindings/display/panel/sitronix,st7789v.yaml | 5 +--
.../devicetree/bindings/iio/adc/adi,ad4030.yaml | 42 +++++++++++++++++++++-
.../devicetree/bindings/iio/adc/adi,ad4695.yaml | 5 +--
.../bindings/spi/allwinner,sun4i-a10-spi.yaml | 6 ++--
.../bindings/spi/allwinner,sun6i-a31-spi.yaml | 6 ++--
.../bindings/spi/andestech,ae350-spi.yaml | 6 ++--
.../bindings/spi/nvidia,tegra210-quad.yaml | 6 ++--
.../bindings/spi/spi-peripheral-props.yaml | 26 ++++++++++----
8 files changed, 83 insertions(+), 19 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml
index 0ce2ea13583d..c35d4f2ab9a4 100644
--- a/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml
+++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7789v.yaml
@@ -34,8 +34,9 @@ properties:
spi-cpol: true
spi-rx-bus-width:
- minimum: 0
- maximum: 1
+ items:
+ minimum: 0
+ maximum: 1
dc-gpios:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4030.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4030.yaml
index 54e7349317b7..e22d518135f2 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad4030.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4030.yaml
@@ -37,7 +37,15 @@ properties:
maximum: 102040816
spi-rx-bus-width:
- enum: [1, 2, 4]
+ maxItems: 2
+ # all lanes must have the same width
+ oneOf:
+ - contains:
+ const: 1
+ - contains:
+ const: 2
+ - contains:
+ const: 4
vdd-5v-supply: true
vdd-1v8-supply: true
@@ -88,6 +96,18 @@ oneOf:
unevaluatedProperties: false
+allOf:
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad4030-24
+ - adi,ad4032-24
+ then:
+ properties:
+ spi-rx-bus-width:
+ maxItems: 1
+
examples:
- |
#include <dt-bindings/gpio/gpio.h>
@@ -108,3 +128,23 @@ examples:
reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
};
};
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "adi,ad4630-24";
+ reg = <0>;
+ spi-max-frequency = <80000000>;
+ spi-rx-bus-width = <4>, <4>;
+ vdd-5v-supply = <&supply_5V>;
+ vdd-1v8-supply = <&supply_1_8V>;
+ vio-supply = <&supply_1_8V>;
+ ref-supply = <&supply_5V>;
+ cnv-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml
index cbde7a0505d2..ae8d0b5f328b 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad4695.yaml
@@ -38,8 +38,9 @@ properties:
spi-cpha: true
spi-rx-bus-width:
- minimum: 1
- maximum: 4
+ items:
+ minimum: 1
+ maximum: 4
avdd-supply:
description: Analog power supply.
diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
index e1ab3f523ad6..a34e6471dbe8 100644
--- a/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/allwinner,sun4i-a10-spi.yaml
@@ -55,10 +55,12 @@ patternProperties:
maximum: 4
spi-rx-bus-width:
- const: 1
+ items:
+ - const: 1
spi-tx-bus-width:
- const: 1
+ items:
+ - const: 1
required:
- compatible
diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
index 1b91d1566c95..a6067030c5ed 100644
--- a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
@@ -81,10 +81,12 @@ patternProperties:
maximum: 4
spi-rx-bus-width:
- const: 1
+ items:
+ - const: 1
spi-tx-bus-width:
- const: 1
+ items:
+ - const: 1
required:
- compatible
diff --git a/Documentation/devicetree/bindings/spi/andestech,ae350-spi.yaml b/Documentation/devicetree/bindings/spi/andestech,ae350-spi.yaml
index 78093468dd5e..8e441742cee6 100644
--- a/Documentation/devicetree/bindings/spi/andestech,ae350-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/andestech,ae350-spi.yaml
@@ -45,10 +45,12 @@ patternProperties:
properties:
spi-rx-bus-width:
- enum: [1, 4]
+ items:
+ - enum: [1, 4]
spi-tx-bus-width:
- enum: [1, 4]
+ items:
+ - enum: [1, 4]
allOf:
- $ref: spi-controller.yaml#
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml
index 8b3640280559..909c204b8adf 100644
--- a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml
+++ b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad.yaml
@@ -54,10 +54,12 @@ patternProperties:
properties:
spi-rx-bus-width:
- enum: [1, 2, 4]
+ items:
+ - enum: [1, 2, 4]
spi-tx-bus-width:
- enum: [1, 2, 4]
+ items:
+ - enum: [1, 2, 4]
required:
- compatible
diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
index 8b6e8fc009db..59ddead7da14 100644
--- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
@@ -64,9 +64,16 @@ properties:
description:
Bus width to the SPI bus used for read transfers.
If 0 is provided, then no RX will be possible on this device.
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 4, 8]
- default: 1
+
+ Some SPI peripherals and controllers may have multiple data lanes for
+ receiving two or more words at the same time. If this is the case, each
+ index in the array represents the lane on both the SPI peripheral and
+ controller. Additional mapping properties may be needed if a lane is
+ skipped on either side.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ items:
+ enum: [0, 1, 2, 4, 8]
+ default: [1]
spi-rx-delay-us:
description:
@@ -81,9 +88,16 @@ properties:
description:
Bus width to the SPI bus used for write transfers.
If 0 is provided, then no TX will be possible on this device.
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 4, 8]
- default: 1
+
+ Some SPI peripherals and controllers may have multiple data lanes for
+ transmitting two or more words at the same time. If this is the case, each
+ index in the array represents the lane on both the SPI peripheral and
+ controller. Additional mapping properties may be needed if a lane is
+ skipped on either side.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ items:
+ enum: [0, 1, 2, 4, 8]
+ default: [1]
spi-tx-delay-us:
description:
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH v5 2/9] spi: dt-bindings: add spi-{tx,rx}-lane-map properties
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
2026-01-12 17:45 ` [PATCH v5 1/9] spi: dt-bindings: change spi-{rx,tx}-bus-width to arrays David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-14 8:57 ` Jonathan Cameron
2026-01-12 17:45 ` [PATCH v5 3/9] spi: support controllers with multiple data lanes David Lechner
` (6 subsequent siblings)
8 siblings, 1 reply; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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-tx-lane-map and spi-rx-lane-map properties to the SPI peripheral
device tree binding. These properties allow specifying the mapping of
peripheral data lanes to controller data lanes. This is needed e.g. when
some lanes are skipped on the controller side so that the controller
can correctly route data to/from the peripheral.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v5 changes:
- Use SDI/SDO terminology in descriptions. (Fixes incorrect use of TX/RX
when describing the peripheral lanes.)
v4 changes:
- This replaces the data-lanes property from the previous revision. Now
there are separate properties for tx and rx lane maps. And instead of
being the primary property for determining the number of lanes, this
is only needed in special cases where the mapping is non-trivial.
---
.../devicetree/bindings/spi/spi-peripheral-props.yaml | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
index 59ddead7da14..880a9f624566 100644
--- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
@@ -75,6 +75,13 @@ properties:
enum: [0, 1, 2, 4, 8]
default: [1]
+ spi-rx-lane-map:
+ description: Mapping of peripheral SDO lanes to controller SDI lanes.
+ Each index in the array represents a peripheral SDO lane, and the value
+ at that index represents the corresponding controller SDI lane.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ default: [0, 1, 2, 3, 4, 5, 6, 7]
+
spi-rx-delay-us:
description:
Delay, in microseconds, after a read transfer.
@@ -99,6 +106,13 @@ properties:
enum: [0, 1, 2, 4, 8]
default: [1]
+ spi-tx-lane-map:
+ description: Mapping of peripheral SDI lanes to controller SDO lanes.
+ Each index in the array represents a peripheral SDI lane, and the value
+ at that index represents the corresponding controller SDO lane.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ default: [0, 1, 2, 3, 4, 5, 6, 7]
+
spi-tx-delay-us:
description:
Delay, in microseconds, after a write transfer.
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v5 2/9] spi: dt-bindings: add spi-{tx,rx}-lane-map properties
2026-01-12 17:45 ` [PATCH v5 2/9] spi: dt-bindings: add spi-{tx,rx}-lane-map properties David Lechner
@ 2026-01-14 8:57 ` Jonathan Cameron
0 siblings, 0 replies; 26+ messages in thread
From: Jonathan Cameron @ 2026-01-14 8:57 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 Mon, 12 Jan 2026 11:45:20 -0600
David Lechner <dlechner@baylibre.com> wrote:
> Add spi-tx-lane-map and spi-rx-lane-map properties to the SPI peripheral
> device tree binding. These properties allow specifying the mapping of
> peripheral data lanes to controller data lanes. This is needed e.g. when
> some lanes are skipped on the controller side so that the controller
> can correctly route data to/from the peripheral.
>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: David Lechner <dlechner@baylibre.com>
LGTM
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> ---
>
> v5 changes:
> - Use SDI/SDO terminology in descriptions. (Fixes incorrect use of TX/RX
> when describing the peripheral lanes.)
>
> v4 changes:
> - This replaces the data-lanes property from the previous revision. Now
> there are separate properties for tx and rx lane maps. And instead of
> being the primary property for determining the number of lanes, this
> is only needed in special cases where the mapping is non-trivial.
> ---
> .../devicetree/bindings/spi/spi-peripheral-props.yaml | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
> index 59ddead7da14..880a9f624566 100644
> --- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
> +++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
> @@ -75,6 +75,13 @@ properties:
> enum: [0, 1, 2, 4, 8]
> default: [1]
>
> + spi-rx-lane-map:
> + description: Mapping of peripheral SDO lanes to controller SDI lanes.
> + Each index in the array represents a peripheral SDO lane, and the value
> + at that index represents the corresponding controller SDI lane.
> + $ref: /schemas/types.yaml#/definitions/uint32-array
> + default: [0, 1, 2, 3, 4, 5, 6, 7]
> +
> spi-rx-delay-us:
> description:
> Delay, in microseconds, after a read transfer.
> @@ -99,6 +106,13 @@ properties:
> enum: [0, 1, 2, 4, 8]
> default: [1]
>
> + spi-tx-lane-map:
> + description: Mapping of peripheral SDI lanes to controller SDO lanes.
> + Each index in the array represents a peripheral SDI lane, and the value
> + at that index represents the corresponding controller SDO lane.
> + $ref: /schemas/types.yaml#/definitions/uint32-array
> + default: [0, 1, 2, 3, 4, 5, 6, 7]
> +
> spi-tx-delay-us:
> description:
> Delay, in microseconds, after a write transfer.
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
2026-01-12 17:45 ` [PATCH v5 1/9] spi: dt-bindings: change spi-{rx,tx}-bus-width to arrays David Lechner
2026-01-12 17:45 ` [PATCH v5 2/9] spi: dt-bindings: add spi-{tx,rx}-lane-map properties David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-12 19:07 ` Andy Shevchenko
2026-01-14 9:05 ` Jonathan Cameron
2026-01-12 17:45 ` [PATCH v5 4/9] spi: add multi_lane_mode field to struct spi_transfer David Lechner
` (5 subsequent siblings)
8 siblings, 2 replies; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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 lanes.
(A data lane in this context means lines connected to a serializer, so a
controller with two data lanes 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_lanes
to something greater than 1. Peripherals indicate which lane they are
connected to via device tree (ACPI support can be added if needed).
The spi-{tx,rx}-bus-width DT properties can now be arrays. The length of
the array indicates the number of data lanes, and each element indicates
the bus width of that lane. For now, we restrict all lanes to have the
same bus width to keep things simple. Support for an optional controller
lane mapping property is also implemented.
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v5 changes:
- Use of_property_read_variable_u32_array() for lane maps.
v4 changes:
- Update for changes in devicetree bindings.
- Don't put new fields in the middle of CS fields.
- Dropped acks since this was a significant rework.
v3 changes:
* Renamed "buses" to "lanes" to reflect devicetree property name change.
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 | 116 +++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/spi/spi.h | 22 +++++++++
2 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e25df9990f82..5c3f9ba3f606 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2370,7 +2370,53 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
spi->mode |= SPI_CS_HIGH;
/* Device DUAL/QUAD mode */
- if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
+
+ rc = of_property_read_variable_u32_array(nc, "spi-tx-lane-map",
+ spi->tx_lane_map, 1,
+ ARRAY_SIZE(spi->tx_lane_map));
+ if (rc == -EINVAL) {
+ /* Default lane map */
+ for (idx = 0; idx < ARRAY_SIZE(spi->tx_lane_map); idx++)
+ spi->tx_lane_map[idx] = idx;
+ } else if (rc < 0) {
+ dev_err(&ctlr->dev,
+ "failed to read spi-tx-lane-map property: %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_count_u32_elems(nc, "spi-tx-bus-width");
+ if (rc < 0 && rc != -EINVAL) {
+ dev_err(&ctlr->dev,
+ "failed to read spi-tx-bus-width property: %d\n", rc);
+ return rc;
+ }
+
+ if (rc == -EINVAL) {
+ /* Default when property is not present. */
+ spi->num_tx_lanes = 1;
+ } else {
+ u32 first_value;
+
+ spi->num_tx_lanes = rc;
+
+ for (idx = 0; idx < spi->num_tx_lanes; idx++) {
+ of_property_read_u32_index(nc, "spi-tx-bus-width", idx,
+ &value);
+
+ /*
+ * For now, we only support all lanes having the same
+ * width so we can keep using the existing mode flags.
+ */
+ if (!idx)
+ first_value = value;
+ else if (first_value != value) {
+ dev_err(&ctlr->dev,
+ "spi-tx-bus-width has inconsistent values: first %d vs later %d\n",
+ first_value, value);
+ return -EINVAL;
+ }
+ }
+
switch (value) {
case 0:
spi->mode |= SPI_NO_TX;
@@ -2394,7 +2440,62 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
}
}
- if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
+ for (idx = 0; idx < spi->num_tx_lanes; idx++) {
+ if (spi->tx_lane_map[idx] >= spi->controller->num_data_lanes) {
+ dev_err(&ctlr->dev,
+ "spi-tx-lane-map has invalid value %d (num_data_lanes=%d)\n",
+ spi->tx_lane_map[idx],
+ spi->controller->num_data_lanes);
+ return -EINVAL;
+ }
+ }
+
+ rc = of_property_read_variable_u32_array(nc, "spi-rx-lane-map",
+ spi->rx_lane_map, 1,
+ ARRAY_SIZE(spi->rx_lane_map));
+ if (rc == -EINVAL) {
+ /* Default lane map */
+ for (idx = 0; idx < ARRAY_SIZE(spi->rx_lane_map); idx++)
+ spi->rx_lane_map[idx] = idx;
+ } else if (rc < 0) {
+ dev_err(&ctlr->dev,
+ "failed to read spi-rx-lane-map property: %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_count_u32_elems(nc, "spi-rx-bus-width");
+ if (rc < 0 && rc != -EINVAL) {
+ dev_err(&ctlr->dev,
+ "failed to read spi-rx-bus-width property: %d\n", rc);
+ return rc;
+ }
+
+ if (rc == -EINVAL) {
+ /* Default when property is not present. */
+ spi->num_rx_lanes = 1;
+ } else {
+ u32 first_value;
+
+ spi->num_rx_lanes = rc;
+
+ for (idx = 0; idx < spi->num_rx_lanes; idx++) {
+ of_property_read_u32_index(nc, "spi-rx-bus-width", idx,
+ &value);
+
+ /*
+ * For now, we only support all lanes having the same
+ * width so we can keep using the existing mode flags.
+ */
+ if (!idx)
+ first_value = value;
+ else if (first_value != value) {
+ dev_err(&ctlr->dev,
+ "spi-rx-bus-width has inconsistent values: first %d vs later %d\n",
+ first_value, value);
+ return -EINVAL;
+ }
+ }
+
switch (value) {
case 0:
spi->mode |= SPI_NO_RX;
@@ -2418,6 +2519,16 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
}
}
+ for (idx = 0; idx < spi->num_rx_lanes; idx++) {
+ if (spi->rx_lane_map[idx] >= spi->controller->num_data_lanes) {
+ dev_err(&ctlr->dev,
+ "spi-rx-lane-map has invalid value %d (num_data_lanes=%d)\n",
+ spi->rx_lane_map[idx],
+ spi->controller->num_data_lanes);
+ return -EINVAL;
+ }
+ }
+
if (spi_controller_is_target(ctlr)) {
if (!of_node_name_eq(nc, "slave")) {
dev_err(&ctlr->dev, "%pOF is not called 'slave'\n",
@@ -3066,6 +3177,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_lanes = 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 cb2c2df31089..7aff60ab257e 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 lanes supported per spi device */
+#define SPI_DEVICE_DATA_LANE_CNT_MAX 8
+
struct dma_chan;
struct software_node;
struct ptp_system_timestamp;
@@ -174,6 +177,10 @@ extern void spi_transfer_cs_change_delay_exec(struct spi_message *msg,
* @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)
+ * @tx_lane_map: Map of peripheral lanes (index) to controller lanes (value).
+ * @num_tx_lanes: Number of transmit lanes wired up.
+ * @rx_lane_map: Map of peripheral lanes (index) to controller lanes (value).
+ * @num_rx_lanes: Number of receive lanes wired up.
*
* A @spi_device is used to interchange data between an SPI target device
* (usually a discrete chip) and CPU memory.
@@ -242,6 +249,12 @@ struct spi_device {
struct gpio_desc *cs_gpiod[SPI_DEVICE_CS_CNT_MAX]; /* Chip select gpio desc */
+ /* Multi-lane SPI controller support. */
+ u32 tx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
+ u32 num_tx_lanes;
+ u32 rx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
+ u32 num_rx_lanes;
+
/*
* Likely need more hooks for more protocol options affecting how
* the controller talks to each chip, like:
@@ -401,6 +414,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_lanes: Number of data lanes 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 +590,14 @@ struct spi_controller {
*/
u16 num_chipselect;
+ /*
+ * Some specialized SPI controllers can have more than one physical
+ * data lane interface per controller (each having it's own serializer).
+ * This specifies the number of data lanes in that case. Other
+ * controllers do not need to set this (defaults to 1).
+ */
+ u16 num_data_lanes;
+
/* 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] 26+ messages in thread* Re: [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-12 17:45 ` [PATCH v5 3/9] spi: support controllers with multiple data lanes David Lechner
@ 2026-01-12 19:07 ` Andy Shevchenko
2026-01-12 19:11 ` Mark Brown
2026-01-14 9:05 ` Jonathan Cameron
1 sibling, 1 reply; 26+ messages in thread
From: Andy Shevchenko @ 2026-01-12 19:07 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 Mon, Jan 12, 2026 at 11:45:21AM -0600, David Lechner wrote:
> Add support for SPI controllers with multiple physical SPI data lanes.
> (A data lane in this context means lines connected to a serializer, so a
> controller with two data lanes 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_lanes
> to something greater than 1. Peripherals indicate which lane they are
> connected to via device tree (ACPI support can be added if needed).
>
> The spi-{tx,rx}-bus-width DT properties can now be arrays. The length of
> the array indicates the number of data lanes, and each element indicates
> the bus width of that lane. For now, we restrict all lanes to have the
> same bus width to keep things simple. Support for an optional controller
> lane mapping property is also implemented.
...
> struct spi_device {
> + /* Multi-lane SPI controller support. */
> + u32 tx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> + u32 num_tx_lanes;
> + u32 rx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> + u32 num_rx_lanes;
This adds 72 bytes in _each_ instance of spi_device on the platforms that do
not use the feature and might not ever use it. Can we move to the pointer
and allocate the mentioned fields separately, please?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-12 19:07 ` Andy Shevchenko
@ 2026-01-12 19:11 ` Mark Brown
2026-01-12 19:35 ` Andy Shevchenko
0 siblings, 1 reply; 26+ messages in thread
From: Mark Brown @ 2026-01-12 19:11 UTC (permalink / raw)
To: Andy Shevchenko
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: 630 bytes --]
On Mon, Jan 12, 2026 at 09:07:17PM +0200, Andy Shevchenko wrote:
> On Mon, Jan 12, 2026 at 11:45:21AM -0600, David Lechner wrote:
> > + /* Multi-lane SPI controller support. */
> > + u32 tx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> > + u32 num_tx_lanes;
> > + u32 rx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> > + u32 num_rx_lanes;
> This adds 72 bytes in _each_ instance of spi_device on the platforms that do
> not use the feature and might not ever use it. Can we move to the pointer
> and allocate the mentioned fields separately, please?
Do we have real systems where we have enough SPI devices for anyone to
care?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-12 19:11 ` Mark Brown
@ 2026-01-12 19:35 ` Andy Shevchenko
2026-01-16 23:12 ` David Lechner
0 siblings, 1 reply; 26+ messages in thread
From: Andy Shevchenko @ 2026-01-12 19:35 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 Mon, Jan 12, 2026 at 07:11:26PM +0000, Mark Brown wrote:
> On Mon, Jan 12, 2026 at 09:07:17PM +0200, Andy Shevchenko wrote:
> > On Mon, Jan 12, 2026 at 11:45:21AM -0600, David Lechner wrote:
...
> > > + /* Multi-lane SPI controller support. */
> > > + u32 tx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> > > + u32 num_tx_lanes;
> > > + u32 rx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> > > + u32 num_rx_lanes;
>
> > This adds 72 bytes in _each_ instance of spi_device on the platforms that do
> > not use the feature and might not ever use it. Can we move to the pointer
> > and allocate the mentioned fields separately, please?
>
> Do we have real systems where we have enough SPI devices for anyone to
> care?
Define "enough" :-) To me even dozen of devices is enough (it gets almost a 1kB
of space) esp. if we are talking about quite low profile embedded systems.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-12 19:35 ` Andy Shevchenko
@ 2026-01-16 23:12 ` David Lechner
2026-01-19 7:44 ` Andy Shevchenko
0 siblings, 1 reply; 26+ messages in thread
From: David Lechner @ 2026-01-16 23:12 UTC (permalink / raw)
To: Andy Shevchenko, 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 1/12/26 1:35 PM, Andy Shevchenko wrote:
> On Mon, Jan 12, 2026 at 07:11:26PM +0000, Mark Brown wrote:
>> On Mon, Jan 12, 2026 at 09:07:17PM +0200, Andy Shevchenko wrote:
>>> On Mon, Jan 12, 2026 at 11:45:21AM -0600, David Lechner wrote:
>
> ...
>
>>>> + /* Multi-lane SPI controller support. */
>>>> + u32 tx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
>>>> + u32 num_tx_lanes;
>>>> + u32 rx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
>>>> + u32 num_rx_lanes;
>>
>>> This adds 72 bytes in _each_ instance of spi_device on the platforms that do
>>> not use the feature and might not ever use it. Can we move to the pointer
>>> and allocate the mentioned fields separately, please?
>>
>> Do we have real systems where we have enough SPI devices for anyone to
>> care?
>
> Define "enough" :-) To me even dozen of devices is enough (it gets almost a 1kB
> of space) esp. if we are talking about quite low profile embedded systems.
>
We could make it u8 and save the same amount (on 64-bit systems) while avoiding
the extra complexity of separate allocation.
I'm not particularly keen on requiring `/bits/ 8` in the devicetree though since
it is unusual and often trips people up.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-16 23:12 ` David Lechner
@ 2026-01-19 7:44 ` Andy Shevchenko
0 siblings, 0 replies; 26+ messages in thread
From: Andy Shevchenko @ 2026-01-19 7:44 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 Fri, Jan 16, 2026 at 05:12:09PM -0600, David Lechner wrote:
> On 1/12/26 1:35 PM, Andy Shevchenko wrote:
> > On Mon, Jan 12, 2026 at 07:11:26PM +0000, Mark Brown wrote:
> >> On Mon, Jan 12, 2026 at 09:07:17PM +0200, Andy Shevchenko wrote:
> >>> On Mon, Jan 12, 2026 at 11:45:21AM -0600, David Lechner wrote:
...
> >>>> + /* Multi-lane SPI controller support. */
> >>>> + u32 tx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> >>>> + u32 num_tx_lanes;
> >>>> + u32 rx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
> >>>> + u32 num_rx_lanes;
> >>
> >>> This adds 72 bytes in _each_ instance of spi_device on the platforms that do
> >>> not use the feature and might not ever use it. Can we move to the pointer
> >>> and allocate the mentioned fields separately, please?
> >>
> >> Do we have real systems where we have enough SPI devices for anyone to
> >> care?
> >
> > Define "enough" :-) To me even dozen of devices is enough (it gets almost a 1kB
> > of space) esp. if we are talking about quite low profile embedded systems.
>
> We could make it u8 and save the same amount (on 64-bit systems) while avoiding
> the extra complexity of separate allocation.
Have you run `pahole` on this, btw? How big is it right now and do you fit
(aligned) with cache lines with this fields?
> I'm not particularly keen on requiring `/bits/ 8` in the devicetree though since
> it is unusual and often trips people up.
It can be transformed (to a smaller one) after reading
to a local (bigger) array.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-12 17:45 ` [PATCH v5 3/9] spi: support controllers with multiple data lanes David Lechner
2026-01-12 19:07 ` Andy Shevchenko
@ 2026-01-14 9:05 ` Jonathan Cameron
2026-01-16 22:20 ` David Lechner
1 sibling, 1 reply; 26+ messages in thread
From: Jonathan Cameron @ 2026-01-14 9:05 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 Mon, 12 Jan 2026 11:45:21 -0600
David Lechner <dlechner@baylibre.com> wrote:
> Add support for SPI controllers with multiple physical SPI data lanes.
> (A data lane in this context means lines connected to a serializer, so a
> controller with two data lanes 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_lanes
> to something greater than 1. Peripherals indicate which lane they are
> connected to via device tree (ACPI support can be added if needed).
>
> The spi-{tx,rx}-bus-width DT properties can now be arrays. The length of
> the array indicates the number of data lanes, and each element indicates
> the bus width of that lane. For now, we restrict all lanes to have the
> same bus width to keep things simple. Support for an optional controller
> lane mapping property is also implemented.
>
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
>
> v5 changes:
> - Use of_property_read_variable_u32_array() for lane maps.
For this, I think you need to check for short maps.
>
> v4 changes:
> - Update for changes in devicetree bindings.
> - Don't put new fields in the middle of CS fields.
> - Dropped acks since this was a significant rework.
>
> v3 changes:
> * Renamed "buses" to "lanes" to reflect devicetree property name change.
>
> 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 | 116 +++++++++++++++++++++++++++++++++++++++++++++++-
> include/linux/spi/spi.h | 22 +++++++++
> 2 files changed, 136 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index e25df9990f82..5c3f9ba3f606 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -2370,7 +2370,53 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
> spi->mode |= SPI_CS_HIGH;
>
> /* Device DUAL/QUAD mode */
> - if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
> +
> + rc = of_property_read_variable_u32_array(nc, "spi-tx-lane-map",
> + spi->tx_lane_map, 1,
> + ARRAY_SIZE(spi->tx_lane_map));
This reads 'up to' the ARRAY_SIZE(spi->tx_lane_map)
If it is short, what is the right thing to do? I'd either expect a check
for that or for rc to be stashed somewhere if positive for later use.
If the intent is for short the default of 0 is fine, then if it's a lot
short we'll end up with repeated mappings to 0 which makes little sense.
> + if (rc == -EINVAL) {
> + /* Default lane map */
> + for (idx = 0; idx < ARRAY_SIZE(spi->tx_lane_map); idx++)
> + spi->tx_lane_map[idx] = idx;
> + } else if (rc < 0) {
> + dev_err(&ctlr->dev,
> + "failed to read spi-tx-lane-map property: %d\n", rc);
> + return rc;
> + }
> +
> + rc = of_property_count_u32_elems(nc, "spi-tx-bus-width");
> + if (rc < 0 && rc != -EINVAL) {
> + dev_err(&ctlr->dev,
> + "failed to read spi-tx-bus-width property: %d\n", rc);
> + return rc;
> + }
> +
> + if (rc == -EINVAL) {
> + /* Default when property is not present. */
> + spi->num_tx_lanes = 1;
> + } else {
> + u32 first_value;
> +
> + spi->num_tx_lanes = rc;
> +
> + for (idx = 0; idx < spi->num_tx_lanes; idx++) {
> + of_property_read_u32_index(nc, "spi-tx-bus-width", idx,
> + &value);
Probably want a sanity check on return value of that even though we are fairly sure
it won't fail.
> +
> + /*
> + * For now, we only support all lanes having the same
> + * width so we can keep using the existing mode flags.
> + */
> + if (!idx)
> + first_value = value;
> + else if (first_value != value) {
> + dev_err(&ctlr->dev,
> + "spi-tx-bus-width has inconsistent values: first %d vs later %d\n",
> + first_value, value);
> + return -EINVAL;
> + }
> + }
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v5 3/9] spi: support controllers with multiple data lanes
2026-01-14 9:05 ` Jonathan Cameron
@ 2026-01-16 22:20 ` David Lechner
0 siblings, 0 replies; 26+ messages in thread
From: David Lechner @ 2026-01-16 22:20 UTC (permalink / raw)
To: Jonathan Cameron
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 1/14/26 3:05 AM, Jonathan Cameron wrote:
> On Mon, 12 Jan 2026 11:45:21 -0600
> David Lechner <dlechner@baylibre.com> wrote:
>
>> Add support for SPI controllers with multiple physical SPI data lanes.
>> (A data lane in this context means lines connected to a serializer, so a
>> controller with two data lanes 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_lanes
>> to something greater than 1. Peripherals indicate which lane they are
>> connected to via device tree (ACPI support can be added if needed).
>>
>> The spi-{tx,rx}-bus-width DT properties can now be arrays. The length of
>> the array indicates the number of data lanes, and each element indicates
>> the bus width of that lane. For now, we restrict all lanes to have the
>> same bus width to keep things simple. Support for an optional controller
>> lane mapping property is also implemented.
>>
>> Signed-off-by: David Lechner <dlechner@baylibre.com>
>> ---
>>
>> v5 changes:
>> - Use of_property_read_variable_u32_array() for lane maps.
> For this, I think you need to check for short maps.
>>
>> v4 changes:
>> - Update for changes in devicetree bindings.
>> - Don't put new fields in the middle of CS fields.
>> - Dropped acks since this was a significant rework.
>>
>> v3 changes:
>> * Renamed "buses" to "lanes" to reflect devicetree property name change.
>>
>> 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 | 116 +++++++++++++++++++++++++++++++++++++++++++++++-
>> include/linux/spi/spi.h | 22 +++++++++
>> 2 files changed, 136 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
>> index e25df9990f82..5c3f9ba3f606 100644
>> --- a/drivers/spi/spi.c
>> +++ b/drivers/spi/spi.c
>> @@ -2370,7 +2370,53 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
>> spi->mode |= SPI_CS_HIGH;
>>
>> /* Device DUAL/QUAD mode */
>> - if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
>> +
>> + rc = of_property_read_variable_u32_array(nc, "spi-tx-lane-map",
>> + spi->tx_lane_map, 1,
>> + ARRAY_SIZE(spi->tx_lane_map));
>
> This reads 'up to' the ARRAY_SIZE(spi->tx_lane_map)
> If it is short, what is the right thing to do? I'd either expect a check
> for that or for rc to be stashed somewhere if positive for later use.
> If the intent is for short the default of 0 is fine, then if it's a lot
> short we'll end up with repeated mappings to 0 which makes little sense.
The right thing would be to make sure that spi-tx-lane-map and
spi-tx-bus-width are the same size. I suppose we could reorder it
and call of_property_count_u32_elems(nc, "spi-tx-bus-width") first
to avoid needing to do the variable read.
>
>
>> + if (rc == -EINVAL) {
>> + /* Default lane map */
>> + for (idx = 0; idx < ARRAY_SIZE(spi->tx_lane_map); idx++)
>> + spi->tx_lane_map[idx] = idx;
>> + } else if (rc < 0) {
>> + dev_err(&ctlr->dev,
>> + "failed to read spi-tx-lane-map property: %d\n", rc);
>> + return rc;
>> + }
>> +
>> + rc = of_property_count_u32_elems(nc, "spi-tx-bus-width");
>> + if (rc < 0 && rc != -EINVAL) {
>> + dev_err(&ctlr->dev,
>> + "failed to read spi-tx-bus-width property: %d\n", rc);
>> + return rc;
>> + }
>> +
>> + if (rc == -EINVAL) {
>> + /* Default when property is not present. */
>> + spi->num_tx_lanes = 1;
>> + } else {
>> + u32 first_value;
>> +
>> + spi->num_tx_lanes = rc;
>> +
>> + for (idx = 0; idx < spi->num_tx_lanes; idx++) {
>> + of_property_read_u32_index(nc, "spi-tx-bus-width", idx,
>> + &value);
>
> Probably want a sanity check on return value of that even though we are fairly sure
> it won't fail.
I figured that if of_property_count_u32_elems() succeeded then this could not
possibly fail. But OK, why not be extra careful.
>
>> +
>> + /*
>> + * For now, we only support all lanes having the same
>> + * width so we can keep using the existing mode flags.
>> + */
>> + if (!idx)
>> + first_value = value;
>> + else if (first_value != value) {
>> + dev_err(&ctlr->dev,
>> + "spi-tx-bus-width has inconsistent values: first %d vs later %d\n",
>> + first_value, value);
>> + return -EINVAL;
>> + }
>> + }
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v5 4/9] spi: add multi_lane_mode field to struct spi_transfer
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
` (2 preceding siblings ...)
2026-01-12 17:45 ` [PATCH v5 3/9] spi: support controllers with multiple data lanes David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-14 9:06 ` Jonathan Cameron
2026-01-12 17:45 ` [PATCH v5 5/9] spi: Documentation: add page on multi-lane support David Lechner
` (4 subsequent siblings)
8 siblings, 1 reply; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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_lane_mode field to struct spi_transfer to allow
peripherals that support multiple SPI lanes to be used with a single
SPI controller.
This requires both the peripheral and the controller to have multiple
serializers connected to separate data lanes. It could also be used with
a single controller and multiple peripherals that are functioning as a
single logical device (similar to parallel memories).
Acked-by: Nuno Sá <nuno.sa@analog.com>
Acked-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v4 changes:
* Shortened commit message (useful info will be in docs instead).
* Added whitespace to create clear grouping of macros and the field.
v3 changes:
* Renamed "buses" to "lanes" to reflect devicetree property name change.
---
include/linux/spi/spi.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 7aff60ab257e..eba7ae8466ac 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -981,6 +981,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_lane_mode: How to serialize data on multiple lanes. One of the
+ * SPI_MULTI_LANE_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.
@@ -1117,6 +1119,12 @@ struct spi_transfer {
unsigned cs_change:1;
unsigned tx_nbits:4;
unsigned rx_nbits:4;
+
+#define SPI_MULTI_LANE_MODE_SINGLE 0 /* only use single lane */
+#define SPI_MULTI_LANE_MODE_STRIPE 1 /* one data word per lane */
+#define SPI_MULTI_LANE_MODE_MIRROR 2 /* same word sent on all lanes */
+ unsigned multi_lane_mode: 2;
+
unsigned timestamped:1;
bool dtr_mode;
#define SPI_NBITS_SINGLE 0x01 /* 1-bit transfer */
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v5 4/9] spi: add multi_lane_mode field to struct spi_transfer
2026-01-12 17:45 ` [PATCH v5 4/9] spi: add multi_lane_mode field to struct spi_transfer David Lechner
@ 2026-01-14 9:06 ` Jonathan Cameron
0 siblings, 0 replies; 26+ messages in thread
From: Jonathan Cameron @ 2026-01-14 9:06 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 Mon, 12 Jan 2026 11:45:22 -0600
David Lechner <dlechner@baylibre.com> wrote:
> Add a new multi_lane_mode field to struct spi_transfer to allow
> peripherals that support multiple SPI lanes to be used with a single
> SPI controller.
>
> This requires both the peripheral and the controller to have multiple
> serializers connected to separate data lanes. It could also be used with
> a single controller and multiple peripherals that are functioning as a
> single logical device (similar to parallel memories).
>
> Acked-by: Nuno Sá <nuno.sa@analog.com>
> Acked-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> Signed-off-by: David Lechner <dlechner@baylibre.com>
Fwiw looks fine to me (and so a tag mostly so I don't read it again in v6
if that happens!)
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> ---
>
> v4 changes:
> * Shortened commit message (useful info will be in docs instead).
> * Added whitespace to create clear grouping of macros and the field.
>
> v3 changes:
> * Renamed "buses" to "lanes" to reflect devicetree property name change.
> ---
> include/linux/spi/spi.h | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
> index 7aff60ab257e..eba7ae8466ac 100644
> --- a/include/linux/spi/spi.h
> +++ b/include/linux/spi/spi.h
> @@ -981,6 +981,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_lane_mode: How to serialize data on multiple lanes. One of the
> + * SPI_MULTI_LANE_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.
> @@ -1117,6 +1119,12 @@ struct spi_transfer {
> unsigned cs_change:1;
> unsigned tx_nbits:4;
> unsigned rx_nbits:4;
> +
> +#define SPI_MULTI_LANE_MODE_SINGLE 0 /* only use single lane */
> +#define SPI_MULTI_LANE_MODE_STRIPE 1 /* one data word per lane */
> +#define SPI_MULTI_LANE_MODE_MIRROR 2 /* same word sent on all lanes */
> + unsigned multi_lane_mode: 2;
> +
> unsigned timestamped:1;
> bool dtr_mode;
> #define SPI_NBITS_SINGLE 0x01 /* 1-bit transfer */
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v5 5/9] spi: Documentation: add page on multi-lane support
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
` (3 preceding siblings ...)
2026-01-12 17:45 ` [PATCH v5 4/9] spi: add multi_lane_mode field to struct spi_transfer David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-14 9:10 ` Jonathan Cameron
2026-01-12 17:45 ` [PATCH v5 6/9] spi: dt-bindings: adi,axi-spi-engine: add " David Lechner
` (3 subsequent siblings)
8 siblings, 1 reply; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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 page to Documentation/spi/ describing how multi-lane SPI
support works. This is uncommon functionality so it deserves its own
documentation page.
Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v5 changes:
* Fix tx/rx typo in stripe mode example.
v4 changes:
* New patch in v4.
---
Documentation/spi/index.rst | 1 +
Documentation/spi/multiple-data-lanes.rst | 217 ++++++++++++++++++++++++++++++
2 files changed, 218 insertions(+)
diff --git a/Documentation/spi/index.rst b/Documentation/spi/index.rst
index 824ce42ed4f0..2c89b1ee39e2 100644
--- a/Documentation/spi/index.rst
+++ b/Documentation/spi/index.rst
@@ -9,6 +9,7 @@ Serial Peripheral Interface (SPI)
spi-summary
spidev
+ multiple-data-lanes
butterfly
spi-lm70llp
spi-sc18is602
diff --git a/Documentation/spi/multiple-data-lanes.rst b/Documentation/spi/multiple-data-lanes.rst
new file mode 100644
index 000000000000..96d6997ecf77
--- /dev/null
+++ b/Documentation/spi/multiple-data-lanes.rst
@@ -0,0 +1,217 @@
+====================================
+SPI devices with multiple data lanes
+====================================
+
+Some specialized SPI controllers and peripherals support multiple data lanes
+that allow reading more than one word at a time in parallel. This is different
+from dual/quad/octal SPI where multiple bits of a single word are transferred
+simultaneously.
+
+For example, controllers that support parallel flash memories have this feature
+as do some simultaneous-sampling ADCs where each channel has its own data lane.
+
+---------------------
+Describing the wiring
+---------------------
+
+The ``spi-tx-bus-width`` and ``spi-rx-bus-width`` properties in the devicetree
+are used to describe how many data lanes are connected between the controller
+and how wide each lane is. The number of items in the array indicates how many
+lanes there are, and the value of each item indicates how many bits wide that
+lane is.
+
+For example, a dual-simultaneous-sampling ADC with two 4-bit lanes might be
+wired up like this::
+
+ +--------------+ +----------+
+ | SPI | | AD4630 |
+ | Controller | | ADC |
+ | | | |
+ | CS0 |--->| CS |
+ | SCK |--->| SCK |
+ | SDO |--->| SDI |
+ | | | |
+ | SDIA0 |<---| SDOA0 |
+ | SDIA1 |<---| SDOA1 |
+ | SDIA2 |<---| SDOA2 |
+ | SDIA3 |<---| SDOA3 |
+ | | | |
+ | SDIB0 |<---| SDOB0 |
+ | SDIB1 |<---| SDOB1 |
+ | SDIB2 |<---| SDOB2 |
+ | SDIB3 |<---| SDOB3 |
+ | | | |
+ +--------------+ +----------+
+
+It is described in a devicetree like this::
+
+ spi {
+ compatible = "my,spi-controller";
+
+ ...
+
+ adc@0 {
+ compatible = "adi,ad4630";
+ reg = <0>;
+ ...
+ spi-rx-bus-width = <4>, <4>; /* 2 lanes of 4 bits each */
+ ...
+ };
+ };
+
+In most cases, lanes will be wired up symmetrically (A to A, B to B, etc). If
+this isn't the case, extra ``spi-rx-bus-width`` and ``spi-tx-bus-width``
+properties are needed to provide a mapping between controller lanes and the
+physical lane wires.
+
+Here is an example where a multi-lane SPI controller has each lane wired to
+separate single-lane peripherals::
+
+ +--------------+ +----------+
+ | SPI | | Thing 1 |
+ | Controller | | |
+ | | | |
+ | CS0 |--->| CS |
+ | SDO0 |--->| SDI |
+ | SDI0 |<---| SDO |
+ | SCLK0 |--->| SCLK |
+ | | | |
+ | | +----------+
+ | |
+ | | +----------+
+ | | | Thing 2 |
+ | | | |
+ | CS1 |--->| CS |
+ | SDO1 |--->| SDI |
+ | SDI1 |<---| SDO |
+ | SCLK1 |--->| SCLK |
+ | | | |
+ +--------------+ +----------+
+
+This is described in a devicetree like this::
+
+ spi {
+ compatible = "my,spi-controller";
+
+ ...
+
+ thing1@0 {
+ compatible = "my,thing1";
+ reg = <0>;
+ ...
+ };
+
+ thing2@1 {
+ compatible = "my,thing2";
+ reg = <1>;
+ ...
+ spi-tx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for tx wire */
+ spi-rx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for rx wire */
+ ...
+ };
+ };
+
+
+The default values of ``spi-rx-bus-width`` and ``spi-tx-bus-width`` are ``<1>``,
+so these properties can still be omitted even when ``spi-rx-lane-map`` and
+``spi-tx-lane-map`` are used.
+
+----------------------------
+Usage in a peripheral driver
+----------------------------
+
+These types of SPI controllers generally do not support arbitrary use of the
+multiple lanes. Instead, they operate in one of a few defined modes. Peripheral
+drivers should set the :c:type:`struct spi_transfer.multi_lane_mode <spi_transfer>`
+field to indicate which mode they want to use for a given transfer.
+
+The possible values for this field have the following semantics:
+
+- :c:macro:`SPI_MULTI_BUS_MODE_SINGLE`: Only use the first lane. Other lanes are
+ ignored. This means that it is operating just like a conventional SPI
+ peripheral. This is the default, so it does not need to be explicitly set.
+
+ Example::
+
+ tx_buf[0] = 0x88;
+
+ struct spi_transfer xfer = {
+ .tx_buf = tx_buf,
+ .len = 1,
+ };
+
+ spi_sync_transfer(spi, &xfer, 1);
+
+ Assuming the controller is sending the MSB first, the sequence of bits
+ sent over the tx wire would be (right-most bit is sent first)::
+
+ controller > data bits > peripheral
+ ---------- ---------------- ----------
+ SDO 0 0-0-0-1-0-0-0-1 SDI 0
+
+- :c:macro:`SPI_MULTI_BUS_MODE_MIRROR`: Send a single data word over all of the
+ lanes 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_lane_mode = SPI_MULTI_BUS_MODE_MIRROR,
+ };
+
+ spi_sync_transfer(spi, &xfer, 1);
+
+ The data is mirrored on each tx wire::
+
+ 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
+
+- :c:macro:`SPI_MULTI_BUS_MODE_STRIPE`: Send or receive two different data words
+ at the same time, one on each lane. This means that the buffer needs to be
+ sized to hold data for all lanes. Data is interleaved in the buffer, with
+ the first word corresponding to lane 0, the second to lane 1, and so on.
+ Once the last lane is used, the next word in the buffer corresponds to lane
+ 0 again. Accordingly, the buffer size must be a multiple of the number of
+ lanes. This mode works for both reads and writes.
+
+ Example::
+
+ struct spi_transfer xfer = {
+ .rx_buf = rx_buf,
+ .len = 2,
+ .multi_lane_mode = SPI_MULTI_BUS_MODE_STRIPE,
+ };
+
+ spi_sync_transfer(spi, &xfer, 1);
+
+ Each rx wire has a different data word sent simultaneously::
+
+ 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).
+
+
+-----------------------------
+SPI controller driver support
+-----------------------------
+
+To support multiple data lanes, SPI controller drivers need to set
+:c:type:`struct spi_controller.num_data_lanes <spi_controller>` to a value
+greater than 1.
+
+Then the part of the driver that handles SPI transfers needs to check the
+:c:type:`struct spi_transfer.multi_lane_mode <spi_transfer>` field and implement
+the appropriate behavior for each supported mode and return an error for
+unsupported modes.
+
+The core SPI code should handle the rest.
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v5 5/9] spi: Documentation: add page on multi-lane support
2026-01-12 17:45 ` [PATCH v5 5/9] spi: Documentation: add page on multi-lane support David Lechner
@ 2026-01-14 9:10 ` Jonathan Cameron
2026-01-16 22:35 ` David Lechner
0 siblings, 1 reply; 26+ messages in thread
From: Jonathan Cameron @ 2026-01-14 9: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 Mon, 12 Jan 2026 11:45:23 -0600
David Lechner <dlechner@baylibre.com> wrote:
> Add a new page to Documentation/spi/ describing how multi-lane SPI
> support works. This is uncommon functionality so it deserves its own
> documentation page.
>
> Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> Signed-off-by: David Lechner <dlechner@baylibre.com>
Hi David,
A few things inline.
> diff --git a/Documentation/spi/multiple-data-lanes.rst b/Documentation/spi/multiple-data-lanes.rst
> new file mode 100644
> index 000000000000..96d6997ecf77
> --- /dev/null
> +++ b/Documentation/spi/multiple-data-lanes.rst
...
> +---------------------
> +Describing the wiring
> +---------------------
> +
> +The ``spi-tx-bus-width`` and ``spi-rx-bus-width`` properties in the devicetree
> +are used to describe how many data lanes are connected between the controller
> +and how wide each lane is. The number of items in the array indicates how many
> +lanes there are, and the value of each item indicates how many bits wide that
> +lane is.
> +
> +For example, a dual-simultaneous-sampling ADC with two 4-bit lanes might be
> +wired up like this::
> +
> + +--------------+ +----------+
> + | SPI | | AD4630 |
> + | Controller | | ADC |
> + | | | |
> + | CS0 |--->| CS |
> + | SCK |--->| SCK |
> + | SDO |--->| SDI |
> + | | | |
> + | SDIA0 |<---| SDOA0 |
> + | SDIA1 |<---| SDOA1 |
> + | SDIA2 |<---| SDOA2 |
> + | SDIA3 |<---| SDOA3 |
> + | | | |
> + | SDIB0 |<---| SDOB0 |
> + | SDIB1 |<---| SDOB1 |
> + | SDIB2 |<---| SDOB2 |
> + | SDIB3 |<---| SDOB3 |
> + | | | |
> + +--------------+ +----------+
> +
> +It is described in a devicetree like this::
> +
> + spi {
> + compatible = "my,spi-controller";
> +
> + ...
> +
> + adc@0 {
> + compatible = "adi,ad4630";
> + reg = <0>;
> + ...
> + spi-rx-bus-width = <4>, <4>; /* 2 lanes of 4 bits each */
> + ...
> + };
> + };
> +
> +In most cases, lanes will be wired up symmetrically (A to A, B to B, etc). If
> +this isn't the case, extra ``spi-rx-bus-width`` and ``spi-tx-bus-width``
Wrong properties. They are those sizes but spi-tx-lane-map and spi-rx-lane-map
> +properties are needed to provide a mapping between controller lanes and the
> +physical lane wires.
> +
> +Here is an example where a multi-lane SPI controller has each lane wired to
> +separate single-lane peripherals::
> +
> + +--------------+ +----------+
> + | SPI | | Thing 1 |
> + | Controller | | |
> + | | | |
> + | CS0 |--->| CS |
> + | SDO0 |--->| SDI |
> + | SDI0 |<---| SDO |
> + | SCLK0 |--->| SCLK |
> + | | | |
> + | | +----------+
> + | |
> + | | +----------+
> + | | | Thing 2 |
> + | | | |
> + | CS1 |--->| CS |
> + | SDO1 |--->| SDI |
> + | SDI1 |<---| SDO |
> + | SCLK1 |--->| SCLK |
> + | | | |
> + +--------------+ +----------+
> +
> +This is described in a devicetree like this::
> +
> + spi {
> + compatible = "my,spi-controller";
> +
> + ...
> +
> + thing1@0 {
> + compatible = "my,thing1";
> + reg = <0>;
> + ...
> + };
> +
> + thing2@1 {
> + compatible = "my,thing2";
> + reg = <1>;
> + ...
> + spi-tx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for tx wire */
> + spi-rx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for rx wire */
Whilst simple I'd kind of expect a multi lane case as the example, or this and
the multilane one? For me the comment that follows is sufficient for the 1 lane
offset case you have here.
> + ...
> + };
> + };
> +
> +
> +The default values of ``spi-rx-bus-width`` and ``spi-tx-bus-width`` are ``<1>``,
> +so these properties can still be omitted even when ``spi-rx-lane-map`` and
> +``spi-tx-lane-map`` are used.
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v5 5/9] spi: Documentation: add page on multi-lane support
2026-01-14 9:10 ` Jonathan Cameron
@ 2026-01-16 22:35 ` David Lechner
2026-01-19 10:11 ` Jonathan Cameron
0 siblings, 1 reply; 26+ messages in thread
From: David Lechner @ 2026-01-16 22:35 UTC (permalink / raw)
To: Jonathan Cameron
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 1/14/26 3:10 AM, Jonathan Cameron wrote:
> On Mon, 12 Jan 2026 11:45:23 -0600
> David Lechner <dlechner@baylibre.com> wrote:
>
>> Add a new page to Documentation/spi/ describing how multi-lane SPI
>> support works. This is uncommon functionality so it deserves its own
>> documentation page.
>>
...
>> +
>> +For example, a dual-simultaneous-sampling ADC with two 4-bit lanes might be
>> +wired up like this::
>> +
>> + +--------------+ +----------+
>> + | SPI | | AD4630 |
>> + | Controller | | ADC |
>> + | | | |
>> + | CS0 |--->| CS |
>> + | SCK |--->| SCK |
>> + | SDO |--->| SDI |
>> + | | | |
>> + | SDIA0 |<---| SDOA0 |
>> + | SDIA1 |<---| SDOA1 |
>> + | SDIA2 |<---| SDOA2 |
>> + | SDIA3 |<---| SDOA3 |
>> + | | | |
>> + | SDIB0 |<---| SDOB0 |
>> + | SDIB1 |<---| SDOB1 |
>> + | SDIB2 |<---| SDOB2 |
>> + | SDIB3 |<---| SDOB3 |
>> + | | | |
>> + +--------------+ +----------+
>> +
>> +It is described in a devicetree like this::
>> +
>> + spi {
>> + compatible = "my,spi-controller";
>> +
>> + ...
>> +
>> + adc@0 {
>> + compatible = "adi,ad4630";
>> + reg = <0>;
>> + ...
>> + spi-rx-bus-width = <4>, <4>; /* 2 lanes of 4 bits each */
>> + ...
>> + };
>> + };
...
>> +properties are needed to provide a mapping between controller lanes and the
>> +physical lane wires.
>> +
>> +Here is an example where a multi-lane SPI controller has each lane wired to
>> +separate single-lane peripherals::
>> +
>> + +--------------+ +----------+
>> + | SPI | | Thing 1 |
>> + | Controller | | |
>> + | | | |
>> + | CS0 |--->| CS |
>> + | SDO0 |--->| SDI |
>> + | SDI0 |<---| SDO |
>> + | SCLK0 |--->| SCLK |
>> + | | | |
>> + | | +----------+
>> + | |
>> + | | +----------+
>> + | | | Thing 2 |
>> + | | | |
>> + | CS1 |--->| CS |
>> + | SDO1 |--->| SDI |
>> + | SDI1 |<---| SDO |
>> + | SCLK1 |--->| SCLK |
>> + | | | |
>> + +--------------+ +----------+
>> +
>> +This is described in a devicetree like this::
>> +
>> + spi {
>> + compatible = "my,spi-controller";
>> +
>> + ...
>> +
>> + thing1@0 {
>> + compatible = "my,thing1";
>> + reg = <0>;
>> + ...
>> + };
>> +
>> + thing2@1 {
>> + compatible = "my,thing2";
>> + reg = <1>;
>> + ...
>> + spi-tx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for tx wire */
>> + spi-rx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for rx wire */
>
> Whilst simple I'd kind of expect a multi lane case as the example, or this and
> the multilane one? For me the comment that follows is sufficient for the 1 lane
> offset case you have here.
I thought that is what I did. I have one example that shows multiple lanes (ADC)
and one example that shows the map (Thing 1/2).
But I guess you mean that you want a 3rd example that show both the map and
multiple lanes at the same time?
I chose these two examples because they came from real-world use cases that
drove adding this feature. We didn't have a real-world case yet that used
both the map and multiple lanes at the same time so I didn't include that.
>
>> + ...
>> + };
>> + };
>> +
>> +
>> +The default values of ``spi-rx-bus-width`` and ``spi-tx-bus-width`` are ``<1>``,
>> +so these properties can still be omitted even when ``spi-rx-lane-map`` and
>> +``spi-tx-lane-map`` are used.
>
>
>
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v5 5/9] spi: Documentation: add page on multi-lane support
2026-01-16 22:35 ` David Lechner
@ 2026-01-19 10:11 ` Jonathan Cameron
2026-01-23 20:00 ` David Lechner
0 siblings, 1 reply; 26+ messages in thread
From: Jonathan Cameron @ 2026-01-19 10:11 UTC (permalink / raw)
To: David Lechner
Cc: Jonathan Cameron, 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 Fri, 16 Jan 2026 16:35:13 -0600
David Lechner <dlechner@baylibre.com> wrote:
> On 1/14/26 3:10 AM, Jonathan Cameron wrote:
> > On Mon, 12 Jan 2026 11:45:23 -0600
> > David Lechner <dlechner@baylibre.com> wrote:
> >
> >> Add a new page to Documentation/spi/ describing how multi-lane SPI
> >> support works. This is uncommon functionality so it deserves its own
> >> documentation page.
> >>
>
> ...
>
> >> +
> >> +For example, a dual-simultaneous-sampling ADC with two 4-bit lanes might be
> >> +wired up like this::
> >> +
> >> + +--------------+ +----------+
> >> + | SPI | | AD4630 |
> >> + | Controller | | ADC |
> >> + | | | |
> >> + | CS0 |--->| CS |
> >> + | SCK |--->| SCK |
> >> + | SDO |--->| SDI |
> >> + | | | |
> >> + | SDIA0 |<---| SDOA0 |
> >> + | SDIA1 |<---| SDOA1 |
> >> + | SDIA2 |<---| SDOA2 |
> >> + | SDIA3 |<---| SDOA3 |
> >> + | | | |
> >> + | SDIB0 |<---| SDOB0 |
> >> + | SDIB1 |<---| SDOB1 |
> >> + | SDIB2 |<---| SDOB2 |
> >> + | SDIB3 |<---| SDOB3 |
> >> + | | | |
> >> + +--------------+ +----------+
> >> +
> >> +It is described in a devicetree like this::
> >> +
> >> + spi {
> >> + compatible = "my,spi-controller";
> >> +
> >> + ...
> >> +
> >> + adc@0 {
> >> + compatible = "adi,ad4630";
> >> + reg = <0>;
> >> + ...
> >> + spi-rx-bus-width = <4>, <4>; /* 2 lanes of 4 bits each */
> >> + ...
> >> + };
> >> + };
>
>
> ...
>
> >> +properties are needed to provide a mapping between controller lanes and the
> >> +physical lane wires.
> >> +
> >> +Here is an example where a multi-lane SPI controller has each lane wired to
> >> +separate single-lane peripherals::
> >> +
> >> + +--------------+ +----------+
> >> + | SPI | | Thing 1 |
> >> + | Controller | | |
> >> + | | | |
> >> + | CS0 |--->| CS |
> >> + | SDO0 |--->| SDI |
> >> + | SDI0 |<---| SDO |
> >> + | SCLK0 |--->| SCLK |
> >> + | | | |
> >> + | | +----------+
> >> + | |
> >> + | | +----------+
> >> + | | | Thing 2 |
> >> + | | | |
> >> + | CS1 |--->| CS |
> >> + | SDO1 |--->| SDI |
> >> + | SDI1 |<---| SDO |
> >> + | SCLK1 |--->| SCLK |
> >> + | | | |
> >> + +--------------+ +----------+
> >> +
> >> +This is described in a devicetree like this::
> >> +
> >> + spi {
> >> + compatible = "my,spi-controller";
> >> +
> >> + ...
> >> +
> >> + thing1@0 {
> >> + compatible = "my,thing1";
> >> + reg = <0>;
> >> + ...
> >> + };
> >> +
> >> + thing2@1 {
> >> + compatible = "my,thing2";
> >> + reg = <1>;
> >> + ...
> >> + spi-tx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for tx wire */
> >> + spi-rx-lane-map = <1>; /* lane 0 is not used, lane 1 is used for rx wire */
> >
> > Whilst simple I'd kind of expect a multi lane case as the example, or this and
> > the multilane one? For me the comment that follows is sufficient for the 1 lane
> > offset case you have here.
>
> I thought that is what I did. I have one example that shows multiple lanes (ADC)
> and one example that shows the map (Thing 1/2).
>
> But I guess you mean that you want a 3rd example that show both the map and
> multiple lanes at the same time?
Oops. No. I was arguing....
>
> I chose these two examples because they came from real-world use cases that
> drove adding this feature. We didn't have a real-world case yet that used
> both the map and multiple lanes at the same time so I didn't include that.
>
> >
> >> + ...
> >> + };
> >> + };
> >> +
> >> +
> >> +The default values of ``spi-rx-bus-width`` and ``spi-tx-bus-width`` are ``<1>``,
> >> +so these properties can still be omitted even when ``spi-rx-lane-map`` and
> >> +``spi-tx-lane-map`` are used.
This comment is enough to allow you to drop the first example entirely and
just have the 2nd.
Jonathan
> >
> >
> >
>
>
>
^ permalink raw reply [flat|nested] 26+ messages in thread* Re: [PATCH v5 5/9] spi: Documentation: add page on multi-lane support
2026-01-19 10:11 ` Jonathan Cameron
@ 2026-01-23 20:00 ` David Lechner
0 siblings, 0 replies; 26+ messages in thread
From: David Lechner @ 2026-01-23 20:00 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Jonathan Cameron, 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 1/19/26 4:11 AM, Jonathan Cameron wrote:
> On Fri, 16 Jan 2026 16:35:13 -0600
> David Lechner <dlechner@baylibre.com> wrote:
>
>> On 1/14/26 3:10 AM, Jonathan Cameron wrote:
>>> On Mon, 12 Jan 2026 11:45:23 -0600
>>> David Lechner <dlechner@baylibre.com> wrote:
>>>
...
>>> Whilst simple I'd kind of expect a multi lane case as the example, or this and
>>> the multilane one? For me the comment that follows is sufficient for the 1 lane
>>> offset case you have here.
>>
>> I thought that is what I did. I have one example that shows multiple lanes (ADC)
>> and one example that shows the map (Thing 1/2).
>>
>> But I guess you mean that you want a 3rd example that show both the map and
>> multiple lanes at the same time?
> Oops. No. I was arguing....
>>
>> I chose these two examples because they came from real-world use cases that
>> drove adding this feature. We didn't have a real-world case yet that used
>> both the map and multiple lanes at the same time so I didn't include that.
>>
>>>
>>>> + ...
>>>> + };
>>>> + };
>>>> +
>>>> +
>>>> +The default values of ``spi-rx-bus-width`` and ``spi-tx-bus-width`` are ``<1>``,
>>>> +so these properties can still be omitted even when ``spi-rx-lane-map`` and
>>>> +``spi-tx-lane-map`` are used.
>
> This comment is enough to allow you to drop the first example entirely and
> just have the 2nd.
>
> Jonathan
>
I still like having two examples of real-world uses cases since they are solving
two very different problems. It think combining these into one contrived example
would make it more difficult to see that.
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v5 6/9] spi: dt-bindings: adi,axi-spi-engine: add multi-lane support
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
` (4 preceding siblings ...)
2026-01-12 17:45 ` [PATCH v5 5/9] spi: Documentation: add page on multi-lane support David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-14 9:11 ` Jonathan Cameron
2026-01-12 17:45 ` [PATCH v5 7/9] spi: axi-spi-engine: support SPI_MULTI_LANE_MODE_STRIPE David Lechner
` (2 subsequent siblings)
8 siblings, 1 reply; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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
Extend the ADI AXI SPI engine binding for multiple data lanes. This SPI
controller has a capability to read multiple data words at the same
time (e.g. for use with simultaneous sampling ADCs). The current FPGA
implementation can support up to 8 data lanes at a time (depending on a
compile-time configuration option).
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v4 changes:
- Update to use spi-{tx,rx}-bus-width properties.
---
.../devicetree/bindings/spi/adi,axi-spi-engine.yaml | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml b/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml
index 4b3828eda6cb..0f2448371f17 100644
--- a/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml
+++ b/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml
@@ -70,6 +70,21 @@ required:
unevaluatedProperties: false
+patternProperties:
+ "^.*@[0-9a-f]+":
+ type: object
+
+ properties:
+ spi-rx-bus-width:
+ maxItems: 8
+ items:
+ enum: [0, 1]
+
+ spi-tx-bus-width:
+ maxItems: 8
+ items:
+ enum: [0, 1]
+
examples:
- |
spi@44a00000 {
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [PATCH v5 6/9] spi: dt-bindings: adi,axi-spi-engine: add multi-lane support
2026-01-12 17:45 ` [PATCH v5 6/9] spi: dt-bindings: adi,axi-spi-engine: add " David Lechner
@ 2026-01-14 9:11 ` Jonathan Cameron
0 siblings, 0 replies; 26+ messages in thread
From: Jonathan Cameron @ 2026-01-14 9:11 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 Mon, 12 Jan 2026 11:45:24 -0600
David Lechner <dlechner@baylibre.com> wrote:
> Extend the ADI AXI SPI engine binding for multiple data lanes. This SPI
> controller has a capability to read multiple data words at the same
> time (e.g. for use with simultaneous sampling ADCs). The current FPGA
> implementation can support up to 8 data lanes at a time (depending on a
> compile-time configuration option).
>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: David Lechner <dlechner@baylibre.com>
LGTM
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> ---
> v4 changes:
> - Update to use spi-{tx,rx}-bus-width properties.
> ---
> .../devicetree/bindings/spi/adi,axi-spi-engine.yaml | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml b/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml
> index 4b3828eda6cb..0f2448371f17 100644
> --- a/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml
> +++ b/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml
> @@ -70,6 +70,21 @@ required:
>
> unevaluatedProperties: false
>
> +patternProperties:
> + "^.*@[0-9a-f]+":
> + type: object
> +
> + properties:
> + spi-rx-bus-width:
> + maxItems: 8
> + items:
> + enum: [0, 1]
> +
> + spi-tx-bus-width:
> + maxItems: 8
> + items:
> + enum: [0, 1]
> +
> examples:
> - |
> spi@44a00000 {
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v5 7/9] spi: axi-spi-engine: support SPI_MULTI_LANE_MODE_STRIPE
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
` (5 preceding siblings ...)
2026-01-12 17:45 ` [PATCH v5 6/9] spi: dt-bindings: adi,axi-spi-engine: add " David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-14 9:16 ` Jonathan Cameron
2026-01-12 17:45 ` [PATCH v5 8/9] dt-bindings: iio: adc: adi,ad7380: add spi-rx-bus-width property David Lechner
2026-01-12 17:45 ` [PATCH v5 9/9] iio: adc: ad7380: add support for multiple SPI lanes David Lechner
8 siblings, 1 reply; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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_LANE_MODE_STRIPE to the AXI SPI engine driver.
The v2.0.0 version of the AXI SPI Engine IP core supports multiple
lanes. This can be used with SPI_MULTI_LANE_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.
Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v4 changes:
* Update for core SPI API changes.
v3 changes:
* Renamed "buses" to "lanes" to reflect devicetree property name change.
v2 changes:
* Fixed off-by-one in SPI_ENGINE_REG_DATA_WIDTH_NUM_OF_SDIO_MASK GENMASK
---
drivers/spi/spi-axi-spi-engine.c | 145 +++++++++++++++++++++++++++++++++++++--
1 file changed, 141 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index e06f412190fd..3028e6112909 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(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
@@ -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_LANE_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,11 @@ struct spi_engine_offload {
unsigned long flags;
unsigned int offload_num;
unsigned int spi_mode_config;
+ unsigned int multi_lane_mode;
+ u8 rx_primary_lane_mask;
+ u8 tx_primary_lane_mask;
+ u8 rx_all_lanes_mask;
+ u8 tx_all_lanes_mask;
u8 bits_per_word;
};
@@ -165,6 +179,25 @@ struct spi_engine {
bool offload_requires_sync;
};
+static void spi_engine_primary_lane_flag(struct spi_device *spi,
+ u8 *rx_lane_flags, u8 *tx_lane_flags)
+{
+ *rx_lane_flags = BIT(spi->rx_lane_map[0]);
+ *tx_lane_flags = BIT(spi->tx_lane_map[0]);
+}
+
+static void spi_engine_all_lanes_flags(struct spi_device *spi,
+ u8 *rx_lane_flags, u8 *tx_lane_flags)
+{
+ int i;
+
+ for (i = 0; i < spi->num_rx_lanes; i++)
+ *rx_lane_flags |= BIT(spi->rx_lane_map[i]);
+
+ for (i = 0; i < spi->num_tx_lanes; i++)
+ *tx_lane_flags |= BIT(spi->tx_lane_map[i]);
+}
+
static void spi_engine_program_add_cmd(struct spi_engine_program *p,
bool dry, uint16_t cmd)
{
@@ -193,7 +226,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 +237,9 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
else
len = xfer->len / 4;
+ if (xfer->multi_lane_mode == SPI_MULTI_LANE_MODE_STRIPE)
+ len /= num_lanes;
+
while (len) {
unsigned int n = min(len, 256U);
unsigned int flags = 0;
@@ -269,6 +305,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_lane_mode = SPI_ENGINE_MULTI_BUS_MODE_UNKNOWN;
u8 min_bits_per_word = U8_MAX;
u8 max_bits_per_word = 0;
@@ -284,6 +321,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_lane_mode) {
+ case SPI_MULTI_LANE_MODE_SINGLE:
+ case SPI_MULTI_LANE_MODE_STRIPE:
+ break;
+ default:
+ /* Other modes, like mirror not supported */
+ return -EINVAL;
+ }
+
+ /* If all xfers have the same multi-lane mode, we can optimize. */
+ if (multi_lane_mode == SPI_ENGINE_MULTI_BUS_MODE_UNKNOWN)
+ multi_lane_mode = xfer->multi_lane_mode;
+ else if (multi_lane_mode != xfer->multi_lane_mode)
+ multi_lane_mode = SPI_ENGINE_MULTI_BUS_MODE_CONFLICTING;
+ }
}
/*
@@ -297,6 +352,14 @@ 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_lane_mode = multi_lane_mode;
+ spi_engine_primary_lane_flag(msg->spi,
+ &priv->rx_primary_lane_mask,
+ &priv->tx_primary_lane_mask);
+ spi_engine_all_lanes_flags(msg->spi,
+ &priv->rx_all_lanes_mask,
+ &priv->tx_all_lanes_mask);
}
return 0;
@@ -310,6 +373,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_lane_mode = SPI_MULTI_LANE_MODE_SINGLE;
bool keep_cs = false;
u8 bits_per_word = 0;
@@ -334,6 +398,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_lane_mode = priv->multi_lane_mode;
} else {
spi_engine_program_add_cmd(p, dry,
SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
@@ -344,6 +409,28 @@ 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_lane_mode != prev_multi_lane_mode) {
+ u8 tx_lane_flags, rx_lane_flags;
+
+ if (xfer->multi_lane_mode == SPI_MULTI_LANE_MODE_STRIPE)
+ spi_engine_all_lanes_flags(spi, &rx_lane_flags,
+ &tx_lane_flags);
+ else
+ spi_engine_primary_lane_flag(spi, &rx_lane_flags,
+ &tx_lane_flags);
+
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+ rx_lane_flags));
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+ tx_lane_flags));
+ }
+ prev_multi_lane_mode = xfer->multi_lane_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 +447,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_rx_lanes);
spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer),
inst_ns, xfer->effective_speed_hz);
@@ -394,6 +481,19 @@ 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 lane mode unless offload disable will restore it later. */
+ if (prev_multi_lane_mode == SPI_MULTI_LANE_MODE_STRIPE &&
+ (!msg->offload || priv->multi_lane_mode != SPI_MULTI_LANE_MODE_STRIPE)) {
+ u8 rx_lane_flags, tx_lane_flags;
+
+ spi_engine_primary_lane_flag(spi, &rx_lane_flags, &tx_lane_flags);
+
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK, rx_lane_flags));
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK, tx_lane_flags));
+ }
}
static void spi_engine_xfer_next(struct spi_message *msg,
@@ -799,6 +899,19 @@ 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_lanes > 1) {
+ u8 rx_lane_flags, tx_lane_flags;
+
+ spi_engine_primary_lane_flag(device, &rx_lane_flags, &tx_lane_flags);
+
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+ rx_lane_flags),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+ tx_lane_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 +1015,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_lane_mode == SPI_MULTI_LANE_MODE_STRIPE) {
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+ priv->rx_all_lanes_mask),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+ priv->tx_all_lanes_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 +1051,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-lane mode. */
+ if (priv->multi_lane_mode == SPI_MULTI_LANE_MODE_STRIPE) {
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDI_MASK,
+ priv->rx_primary_lane_mask),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_SDO_MASK,
+ priv->tx_primary_lane_mask),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+ }
}
static struct dma_chan
@@ -973,7 +1105,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 +1174,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 +1182,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 +1231,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_lanes = 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] 26+ messages in thread* Re: [PATCH v5 7/9] spi: axi-spi-engine: support SPI_MULTI_LANE_MODE_STRIPE
2026-01-12 17:45 ` [PATCH v5 7/9] spi: axi-spi-engine: support SPI_MULTI_LANE_MODE_STRIPE David Lechner
@ 2026-01-14 9:16 ` Jonathan Cameron
2026-01-16 22:43 ` David Lechner
0 siblings, 1 reply; 26+ messages in thread
From: Jonathan Cameron @ 2026-01-14 9:16 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 Mon, 12 Jan 2026 11:45:25 -0600
David Lechner <dlechner@baylibre.com> wrote:
> Add support for SPI_MULTI_LANE_MODE_STRIPE to the AXI SPI engine driver.
>
> The v2.0.0 version of the AXI SPI Engine IP core supports multiple
> lanes. This can be used with SPI_MULTI_LANE_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.
>
> Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
> Signed-off-by: David Lechner <dlechner@baylibre.com>
Hi David,
I kind of hope ADI make their versions backwards compatible (or at
least try to) so the version check might be a bit over the top.
Anyhow, not my problem and the code is nice and clean.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v5 7/9] spi: axi-spi-engine: support SPI_MULTI_LANE_MODE_STRIPE
2026-01-14 9:16 ` Jonathan Cameron
@ 2026-01-16 22:43 ` David Lechner
0 siblings, 0 replies; 26+ messages in thread
From: David Lechner @ 2026-01-16 22:43 UTC (permalink / raw)
To: Jonathan Cameron
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 1/14/26 3:16 AM, Jonathan Cameron wrote:
> On Mon, 12 Jan 2026 11:45:25 -0600
> David Lechner <dlechner@baylibre.com> wrote:
>
>> Add support for SPI_MULTI_LANE_MODE_STRIPE to the AXI SPI engine driver.
>>
>> The v2.0.0 version of the AXI SPI Engine IP core supports multiple
>> lanes. This can be used with SPI_MULTI_LANE_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.
>>
>> Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
>> Signed-off-by: David Lechner <dlechner@baylibre.com>
> Hi David,
>
> I kind of hope ADI make their versions backwards compatible (or at
> least try to) so the version check might be a bit over the top.
FWIW, I was the one that actually pushed for the FPGA IP block major
version change. There wasn't a default value for the new bit fields
that worked in every case, so there wasn't a way to make it fully
backwards compatible with older drivers that don't set those bits.
>
> Anyhow, not my problem and the code is nice and clean.
>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v5 8/9] dt-bindings: iio: adc: adi,ad7380: add spi-rx-bus-width property
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
` (6 preceding siblings ...)
2026-01-12 17:45 ` [PATCH v5 7/9] spi: axi-spi-engine: support SPI_MULTI_LANE_MODE_STRIPE David Lechner
@ 2026-01-12 17:45 ` David Lechner
2026-01-12 17:45 ` [PATCH v5 9/9] iio: adc: ad7380: add support for multiple SPI lanes David Lechner
8 siblings, 0 replies; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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-rx-bus-width 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.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v4 changes:
* Change to use spi-rx-bus-width property instead of spi-lanes.
v3 changes:
* Renamed "buses" to "lanes" to reflect devicetree property name change.
---
.../devicetree/bindings/iio/adc/adi,ad7380.yaml | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
index b91bfb16ed6b..396e1a1aa805 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml
@@ -62,6 +62,11 @@ properties:
spi-cpol: true
spi-cpha: true
+ spi-rx-bus-width:
+ maxItems: 4
+ items:
+ maximum: 1
+
vcc-supply:
description: A 3V to 3.6V supply that powers the chip.
@@ -160,6 +165,23 @@ patternProperties:
unevaluatedProperties: false
allOf:
+ # 2-channel chips only have two SDO lines
+ - if:
+ properties:
+ compatible:
+ enum:
+ - adi,ad7380
+ - adi,ad7381
+ - adi,ad7383
+ - adi,ad7384
+ - adi,ad7386
+ - adi,ad7387
+ - adi,ad7388
+ then:
+ properties:
+ spi-rx-bus-width:
+ maxItems: 2
+
# pseudo-differential chips require common mode voltage supplies,
# true differential chips don't use them
- if:
@@ -284,6 +306,7 @@ examples:
spi-cpol;
spi-cpha;
spi-max-frequency = <80000000>;
+ spi-rx-bus-width = <1>, <1>, <1>, <1>;
interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio0>;
--
2.43.0
^ permalink raw reply related [flat|nested] 26+ messages in thread* [PATCH v5 9/9] iio: adc: ad7380: add support for multiple SPI lanes
2026-01-12 17:45 [PATCH v5 0/9] spi: add multi-lane support David Lechner
` (7 preceding siblings ...)
2026-01-12 17:45 ` [PATCH v5 8/9] dt-bindings: iio: adc: adi,ad7380: add spi-rx-bus-width property David Lechner
@ 2026-01-12 17:45 ` David Lechner
8 siblings, 0 replies; 26+ messages in thread
From: David Lechner @ 2026-01-12 17:45 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 lanes 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 lane. 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.
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
---
v5 changes:
* Include the number of SDO lines in the error message.
v4 changes:
* Update for core SPI API changes.
v3 changes:
* Renamed "buses" to "lanes" to reflect devicetree property name change.
v2 changes:
* Move st->seq_xfer[3].multi_lane_mode = SPI_MULTI_BUS_MODE_STRIPE;
to probe().
---
drivers/iio/adc/ad7380.c | 51 ++++++++++++++++++++++++++++++++++++------------
1 file changed, 38 insertions(+), 13 deletions(-)
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index bfd908deefc0..ca411371816f 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
/*
@@ -888,6 +882,8 @@ struct ad7380_state {
bool resolution_boost_enabled;
unsigned int ch;
bool seq;
+ /* How many SDO lines are wired up. */
+ u8 num_sdo_lines;
unsigned int vref_mv;
unsigned int vcm_mv[MAX_NUM_CHANNELS];
unsigned int gain_milli[MAX_NUM_CHANNELS];
@@ -1084,7 +1080,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->num_sdo_lines;
return spi_sync_transfer(st->spi, &xfer, 1);
}
@@ -1113,7 +1109,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->num_sdo_lines;
if (st->seq) {
xfer[0].delay.value = xfer[1].delay.value = t_convert;
@@ -1198,6 +1194,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->num_sdo_lines > 1)
+ xfer->multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
spi_message_init_with_transfers(&st->offload_msg, xfer, 1);
st->offload_msg.offload = st->offload;
@@ -1793,6 +1791,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 +1814,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->num_sdo_lines) {
+ 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 +1854,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;
+ st->num_sdo_lines / st->chip_info->num_simult_channels;
st->sample_freq_range[0] = 1; /* min */
st->sample_freq_range[1] = 1; /* step */
@@ -1887,6 +1899,13 @@ static int ad7380_probe(struct spi_device *spi)
if (!st->chip_info)
return dev_err_probe(dev, -EINVAL, "missing match data\n");
+ st->num_sdo_lines = spi->num_rx_lanes;
+
+ if (st->num_sdo_lines < 1 || st->num_sdo_lines > st->chip_info->num_simult_channels)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid number of SDO lines (%d)\n",
+ st->num_sdo_lines);
+
ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies,
st->chip_info->supplies);
@@ -2010,6 +2029,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 (st->num_sdo_lines > 1)
+ st->normal_xfer[1].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
spi_message_init_with_transfers(&st->normal_msg, st->normal_xfer,
ARRAY_SIZE(st->normal_xfer));
@@ -2031,6 +2052,10 @@ 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 (st->num_sdo_lines > 1) {
+ st->seq_xfer[2].multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
+ st->seq_xfer[3].multi_lane_mode = SPI_MULTI_LANE_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] 26+ messages in thread