Linux SPI subsystem development
 help / color / mirror / Atom feed
* [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support
@ 2026-08-17 23:32 Jonathan Santos
  2026-08-17 23:32 ` [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support Jonathan Santos
                   ` (5 more replies)
  0 siblings, 6 replies; 22+ messages in thread
From: Jonathan Santos @ 2026-08-17 23:32 UTC (permalink / raw)
  To: linux-spi, linux-kernel
  Cc: Jonathan Santos, dlechner, nuno.sa, michael.hennerich, broonie,
	jonath4nns, marcelo.schmitt1, andriy.shevchenko

This series adds support to multi-CS devices and ancillary device with
lanes, to enable the multi-device setup described in [1],  where multiple
AD7768-1 ADCs are wired to the same controller in a synchronized sampling
configuration, and the limitation noted in [2], where no SPI controller 
completely handles logical chip selects beyond the first one.

The first part of the set addresses multi-CS support. Some SPI controllers
can assert multiple chip selects simultaneously, but the existing code
hardcoded CS index 0 in both spi_set_cs() and of_spi_parse_dt(),
preventing this from working. The spi device name pattern is modified to
include all active CS lines, so multi-CS devices are distinguishable in
sysfs.

The second part introduces spi_new_ancillary_device_with_lane() and its
devm variant, used here to create subdevices that binds the CS with a 
correspondent rx and tx lane from the parent device. With that we can 
handle each device individually when there are separate data lanes.

The last part uses the above infrastructure in the AD7768-1 driver to
support aggregating multiple chips as a single IIO device. The number of
sub-devices is derived from spi->num_rx_lanes. IIO channels are
allocated dynamically, buffered capture is restricted to the full-device
scan mask, and SPI offload mode enables SPI_MULTI_LANE_MODE_STRIPE to
interleave samples from all lanes into the DMA stream.

---
v3 summary:
* Added new patch to document the properties for multidevice support on 
  ad7768-1 bindings.
* Refactored "spi: introduce SPI ancillary device with lanes" patch
  to reduce duplicated code using helper functions.
* Modified channel mask allocation on ad7768_parse_aaf_gain() to get 
  a static value, Since we assume the family is single channel. Added a 
  comment explaining.
* Link to v2: https://lore.kernel.org/linux-spi/cover.1785725359.git.Jonathan.Santos@analog.com/T/#t

v2 summary:
* Removed the per-transfer CS mask patches, the devices will be 
  individually handled by the ancillary device feature.
* Removed dynamic multilane selection patches. The lane is bound to the 
  CS using the new spi_new_ancillary_device_with_lane() feature.
* Included a use case patch modifying the AD7768-1 driver to support 
  multidevice aggregation.
* Link to v1: https://lore.kernel.org/linux-spi/cover.1783729282.git.Jonathan.Santos@analog.com/T/#t

OBS: The ancillary device approach was chosen over per-transfer CS masks
because it has better integrattion with regmap. Both approaches require
multiple regmap instances, but the CS mask approach would additionally
require custom read/write functions to route transfers to the correct CS,
while ancillary devices handle this more transparently.

David suggested adding an ancillary device field to spi_message, I guess to
enable dynamic CS-lane selection. For now, using one ancillary device per 
chip for individual access and the main SPI device for simultaneous access
seems to be sufficient. The dynamic approach can be implemented in the future
if needed.

---

[1]: https://lore.kernel.org/linux-iio/af0EGv172ZMl%2F6N5@JSANTO12-L01.ad.analog.com/T/#t
[2]: https://lore.kernel.org/all/20250915183725.219473-1-jonas.gorski@gmail.com/

Jonathan Santos (6):
  dt-bindings: iio: adc: ad7768-1: Document multidevice support
  spi: support simultaneous assertion of multiple CS
  spi: expand device name to include all CS lines for multi-CS devices
  spi: introduce SPI ancillary device with lanes
  spi: spi-engine-ex: Add support for multi-CS devices
  iio: adc: ad7768-1: add support for multiple chip aggregation

 .../bindings/iio/adc/adi,ad7768-1.yaml        |  78 +++++++++-
 drivers/iio/adc/ad7768-1.c                    | 100 +++++++++++--
 drivers/spi/spi-axi-spi-engine.c              |  22 ++-
 drivers/spi/spi.c                             | 135 +++++++++++++++---
 include/linux/spi/spi.h                       |   8 ++
 5 files changed, 305 insertions(+), 38 deletions(-)


base-commit: 350d1fb9204b13c5f95e511e98b8bcb47574d425
-- 
2.34.1


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support
  2026-08-17 23:32 [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support Jonathan Santos
@ 2026-08-17 23:32 ` Jonathan Santos
  2026-08-18  6:46   ` Krzysztof Kozlowski
  2026-08-18 15:02   ` David Lechner
  2026-08-17 23:32 ` [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS Jonathan Santos
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 22+ messages in thread
From: Jonathan Santos @ 2026-08-17 23:32 UTC (permalink / raw)
  To: linux-spi, linux-kernel
  Cc: Jonathan Santos, dlechner, nuno.sa, michael.hennerich, broonie,
	jonath4nns, marcelo.schmitt1, andriy.shevchenko

The AD7768-1 family supports aggregating up to four devices on a single
SPI controller, with each device occupying a dedicated CS line and a
single data lane.

Extend the `reg` property to accept up to 4 entries (one per device).

Add `spi-rx-bus-width` property to declare the per-device lane count.
Since each lane is bound to one CS, the number of entries must match
`reg`. Make it required when `reg` has more than one entry.

Add an example for a four ADAQ7768-1 aggregation, with shared DRDY and
SYNC_IN pin.

Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
Changes in v3:
* New patch.
---
 .../bindings/iio/adc/adi,ad7768-1.yaml        | 78 ++++++++++++++++++-
 1 file changed, 77 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
index dfa2d7fa9fb3..804793a56d1d 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
@@ -26,7 +26,10 @@ properties:
       - adi,adaq7769-1
 
   reg:
-    maxItems: 1
+    minItems: 1
+    maxItems: 4
+    description:
+      Chip select number. For multi-device setups, one entry per device.
 
   clocks:
     maxItems: 1
@@ -109,6 +112,12 @@ properties:
   reset-gpios:
     maxItems: 1
 
+  spi-rx-bus-width:
+    description:
+      Bus width per CS. For multi-device setups (multiple reg entries), one
+      entry per device must be provided. Required when reg has more than
+      one entry.
+
   spi-cpol: true
 
   spi-cpha: true
@@ -203,6 +212,15 @@ allOf:
       properties:
         pga-gpios: false
 
+  # spi-rx-bus-width is required for multi-device setups
+  - if:
+      properties:
+        reg:
+          minItems: 2
+    then:
+      required:
+        - spi-rx-bus-width
+
 unevaluatedProperties: false
 
 examples:
@@ -244,4 +262,62 @@ examples:
             };
         };
     };
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/iio/adc/adi,ad7768-1.h>
+    /*
+     * Four ADAQ7768-1 devices aggregated on a single SPI controller.
+     * Each device occupies one CS and one data lane; DRDY and SYNC_IN
+     * pins are wired together across all four devices.
+     */
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@0 {
+            compatible = "adi,adaq7768-1";
+            reg = <0>, <1>, <2>, <3>;
+            spi-max-frequency = <2000000>;
+            spi-rx-bus-width = <1>, <1>, <1>, <1>;
+            spi-cpol;
+            spi-cpha;
+            vref-supply = <&adc_vref>;
+            pga-gpios = <&gpio 10 GPIO_ACTIVE_HIGH>,
+                        <&gpio 11 GPIO_ACTIVE_HIGH>,
+                        <&gpio 12 GPIO_ACTIVE_HIGH>;
+            interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+            interrupt-parent = <&gpio>;
+            #trigger-source-cells = <1>;
+            adi,sync-in-gpios = <&gpio 22 GPIO_ACTIVE_LOW>;
+            reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
+            clocks = <&ad7768_mclk>;
+            clock-names = "mclk";
+            gpio-controller;
+            #gpio-cells = <2>;
+            #io-channel-cells = <1>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            channel@0 {
+                reg = <0>;
+                label = "channel_0";
+            };
+
+            channel@1 {
+                reg = <1>;
+                label = "channel_1";
+            };
+
+            channel@2 {
+                reg = <2>;
+                label = "channel_2";
+            };
+
+            channel@3 {
+                reg = <3>;
+                label = "channel_3";
+            };
+        };
+    };
 ...
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS
  2026-08-17 23:32 [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support Jonathan Santos
  2026-08-17 23:32 ` [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support Jonathan Santos
@ 2026-08-17 23:32 ` Jonathan Santos
  2026-08-18  6:39   ` Andy Shevchenko
  2026-08-18 16:06   ` David Lechner
  2026-08-17 23:32 ` [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices Jonathan Santos
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 22+ messages in thread
From: Jonathan Santos @ 2026-08-17 23:32 UTC (permalink / raw)
  To: linux-spi, linux-kernel
  Cc: Jonathan Santos, dlechner, nuno.sa, michael.hennerich, broonie,
	jonath4nns, marcelo.schmitt1, andriy.shevchenko

Some SPI controllers allow multiple CS lines to be toggled at the same
time. The existing code always used CS index 0 when tracking the last
active CS in spi_set_cs(), and unconditionally set cs_index_mask to
BIT(0) when parsing DT, both forcing the single CS usage.

Modify spi_set_cs() to iterate last_cs[] using each logical CS index
instead of always reading index 0. Modify of_spi_parse_dt() to build
cs_index_mask from all parsed CS entries rather than hardcoding BIT(0),
so the controller correctly identifies which CS lines belong to a device
when asserting them simultaneously.

Board info, ACPI, and ancillary device paths are not updated here.
Board info would require an API change to accept an array of CS values
and is left for a follow-up when we have a use case for this. Ancillary
devices are by design single-CS, so multi-CS is not a current use case for
them. ACPI represents the CS as a 64-bit integer with no established
convention for encoding multiple CS indices yet, so any extension there
would require a separate specification effort.

Acked-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
Changes in v3:
* None.

Changes in v2:
* Include Summary describind why the other SPI paths were not addressed
  here.
---
 drivers/spi/spi.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index d9e6b4b87c89..55fb96fea243 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1090,7 +1090,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
 	spi->controller->last_cs_index_mask = spi->cs_index_mask;
 	for (idx = 0; idx < SPI_DEVICE_CS_CNT_MAX; idx++) {
 		if (enable && idx < spi->num_chipselect)
-			spi->controller->last_cs[idx] = spi_get_chipselect(spi, 0);
+			spi->controller->last_cs[idx] = spi_get_chipselect(spi, idx);
 		else
 			spi->controller->last_cs[idx] = SPI_INVALID_CS;
 	}
@@ -2594,10 +2594,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
 		spi_set_chipselect(spi, idx, cs[idx]);
 
 	/*
-	 * By default spi->chip_select[0] will hold the physical CS number,
-	 * so set bit 0 in spi->cs_index_mask.
+	 * Set cs_index_mask to indicate which logical CS indices are active.
+	 * Each bit corresponds to a logical CS index in the spi->chip_select array.
 	 */
-	spi->cs_index_mask = BIT(0);
+	for (idx = 0; idx < rc; idx++)
+		spi->cs_index_mask |= BIT(idx);
 
 	/* Device speed */
 	if (!of_property_read_u32(nc, "spi-max-frequency", &value))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices
  2026-08-17 23:32 [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support Jonathan Santos
  2026-08-17 23:32 ` [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support Jonathan Santos
  2026-08-17 23:32 ` [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS Jonathan Santos
@ 2026-08-17 23:32 ` Jonathan Santos
  2026-08-18  6:45   ` Andy Shevchenko
  2026-08-17 23:33 ` [PATCH v3 4/6] spi: introduce SPI ancillary device with lanes Jonathan Santos
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 22+ messages in thread
From: Jonathan Santos @ 2026-08-17 23:32 UTC (permalink / raw)
  To: linux-spi, linux-kernel
  Cc: Jonathan Santos, dlechner, nuno.sa, michael.hennerich, broonie,
	jonath4nns, marcelo.schmitt1, andriy.shevchenko

The device name for SPI devices was formatted as <controller>.<cs0>,
always using only the first chip-select index, ignoring the remaining CS
lines.

Change the naming format to <controller>.<cs0>+<cs1>+... so that all
active chip-selects are reflected in the device name. Single-CS devices
are not affected since the loop only appends extra indices when
num_chipselect is greater than one.

Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
Changes in v3:
* replaced `int idx = 1` by `unsigned int idx = 1` in the for loop.

Changes in v2:
* New patch.
---
 drivers/spi/spi.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 55fb96fea243..9ccfa5be557b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -594,6 +594,8 @@ static void spi_dev_set_name(struct spi_device *spi)
 {
 	struct device *dev = &spi->dev;
 	struct fwnode_handle *fwnode = dev_fwnode(dev);
+	char cs_str[32];
+	int cs_len;
 
 	if (is_acpi_device_node(fwnode)) {
 		dev_set_name(dev, "spi-%s", acpi_dev_name(to_acpi_device_node(fwnode)));
@@ -605,8 +607,12 @@ static void spi_dev_set_name(struct spi_device *spi)
 		return;
 	}
 
-	dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev),
-		     spi_get_chipselect(spi, 0));
+	cs_len = scnprintf(cs_str, sizeof(cs_str), "%u", spi_get_chipselect(spi, 0));
+	for (unsigned int idx = 1; idx < spi->num_chipselect; idx++)
+		cs_len += scnprintf(cs_str + cs_len, sizeof(cs_str) - cs_len,
+				    "+%u", spi_get_chipselect(spi, idx));
+
+	dev_set_name(&spi->dev, "%s.%s", dev_name(&spi->controller->dev), cs_str);
 }
 
 /*
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 4/6] spi: introduce SPI ancillary device with lanes
  2026-08-17 23:32 [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support Jonathan Santos
                   ` (2 preceding siblings ...)
  2026-08-17 23:32 ` [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices Jonathan Santos
@ 2026-08-17 23:33 ` Jonathan Santos
  2026-08-18  6:53   ` Andy Shevchenko
  2026-08-17 23:33 ` [PATCH v3 5/6] spi: spi-engine-ex: Add support for multi-CS devices Jonathan Santos
  2026-08-17 23:33 ` [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation Jonathan Santos
  5 siblings, 1 reply; 22+ messages in thread
From: Jonathan Santos @ 2026-08-17 23:33 UTC (permalink / raw)
  To: linux-spi, linux-kernel
  Cc: Jonathan Santos, dlechner, nuno.sa, michael.hennerich, broonie,
	jonath4nns, marcelo.schmitt1, andriy.shevchenko

The existing spi_new_ancillary_device() creates an ancillary SPI device
but does not consider the parent's lane map. In multi-device setups where
each sub-device's chip-select is bound to a dedicated data lane, there is
no way to bind an ancillary device to an arbitrary lane index.

Introduce spi_new_ancillary_device_with_lane() and
devm_spi_new_ancillary_device_with_lane(), which accept rx_lane_idx and
tx_lane_idx parameters to select a specific lane from the parent's
rx_lane_map and tx_lane_map respectively. The resulting ancillary device
is registered with a single RX and TX lane, keeping it independent from
the other sub-devices sharing the same controller.

Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
Changes in v3:
* Refactored code using helper function to reduce duplicated code.

Changes in v2:
* New patch.
---
 drivers/spi/spi.c       | 116 +++++++++++++++++++++++++++++++++++-----
 include/linux/spi/spi.h |   8 +++
 2 files changed, 110 insertions(+), 14 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 9ccfa5be557b..174507696f1f 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2692,20 +2692,12 @@ static void of_register_spi_devices(struct spi_controller *ctlr)
 static void of_register_spi_devices(struct spi_controller *ctlr) { }
 #endif
 
-/**
- * spi_new_ancillary_device() - Register ancillary SPI device
- * @spi:         Pointer to the main SPI device registering the ancillary device
- * @chip_select: Chip Select of the ancillary device
- *
- * Register an ancillary SPI device; for example some chips have a chip-select
- * for normal device usage and another one for setup/firmware upload.
- *
- * This may only be called from main SPI device's probe routine.
- *
- * Return: 0 on success; negative errno on failure
- */
-struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
-					     u8 chip_select)
+#define SPI_UNDEFINED_LANE	-1
+
+static struct spi_device *__spi_new_ancillary_device(struct spi_device *spi,
+						     u8 chip_select,
+						     int rx_lane_idx,
+						     int tx_lane_idx)
 {
 	struct spi_controller *ctlr = spi->controller;
 	struct spi_device *ancillary;
@@ -2732,6 +2724,21 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
 	 */
 	ancillary->cs_index_mask = BIT(0);
 
+	if (rx_lane_idx >= spi->num_rx_lanes || tx_lane_idx >= spi->num_tx_lanes) {
+		rc = -EINVAL;
+		goto err_out;
+	}
+
+	if (rx_lane_idx != SPI_UNDEFINED_LANE) {
+		ancillary->rx_lane_map[0] = spi->rx_lane_map[rx_lane_idx];
+		ancillary->num_rx_lanes = 1;
+	}
+
+	if (tx_lane_idx != SPI_UNDEFINED_LANE) {
+		ancillary->tx_lane_map[0] = spi->tx_lane_map[tx_lane_idx];
+		ancillary->num_tx_lanes = 1;
+	}
+
 	WARN_ON(!mutex_is_locked(&ctlr->add_lock));
 
 	/* Register the new device, passing the parent to skip CS conflict check */
@@ -2747,8 +2754,53 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
 	spi_dev_put(ancillary);
 	return ERR_PTR(rc);
 }
+
+/**
+ * spi_new_ancillary_device() - Register ancillary SPI device
+ * @spi:         Pointer to the main SPI device registering the ancillary device
+ * @chip_select: Chip Select of the ancillary device
+ *
+ * Register an ancillary SPI device; for example some chips have a chip-select
+ * for normal device usage and another one for setup/firmware upload.
+ *
+ * This may only be called from main SPI device's probe routine.
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
+					    u8 chip_select)
+{
+	return __spi_new_ancillary_device(spi, chip_select,
+					  SPI_UNDEFINED_LANE,
+					  SPI_UNDEFINED_LANE);
+}
 EXPORT_SYMBOL_GPL(spi_new_ancillary_device);
 
+/**
+ * spi_new_ancillary_device_with_lane() - Register ancillary SPI device bound to specific lane
+ * @spi:          Pointer to the main SPI device registering the ancillary device
+ * @chip_select:  Chip Select of the ancillary device
+ * @rx_lane_idx:  Lane index within the parent's rx_lane_map
+ * @tx_lane_idx:  Lane index within the parent's tx_lane_map
+ *
+ * Like spi_new_ancillary_device(), but additionally binds the ancillary device
+ * to a single lane from the parent's lane map. Use this in multi-device setups
+ * where each sub-device is physically wired to a dedicated CS and a dedicated
+ * data lane.
+ *
+ * This may only be called from main SPI device's probe routine.
+ *
+ * Return: Pointer to new ancillary device on success; ERR_PTR on failure
+ */
+struct spi_device *spi_new_ancillary_device_with_lane(struct spi_device *spi,
+						      u8 chip_select,
+						      unsigned int rx_lane_idx,
+						      unsigned int tx_lane_idx)
+{
+	return __spi_new_ancillary_device(spi, chip_select, rx_lane_idx, tx_lane_idx);
+}
+EXPORT_SYMBOL_GPL(spi_new_ancillary_device_with_lane);
+
 static void devm_spi_unregister_device(void *spi)
 {
 	spi_unregister_device(spi);
@@ -2789,6 +2841,42 @@ struct spi_device *devm_spi_new_ancillary_device(struct spi_device *spi,
 }
 EXPORT_SYMBOL_GPL(devm_spi_new_ancillary_device);
 
+/**
+ * devm_spi_new_ancillary_device_with_lane() - Register managed ancillary SPI device bound to a lane
+ * @spi:         Pointer to the main SPI device registering the ancillary device
+ * @chip_select: Chip Select of the ancillary device
+ * @rx_lane_idx: Per-device lane index within the parent's rx_lane_map
+ * @tx_lane_idx: Per-device lane index within the parent's tx_lane_map
+ *
+ * Managed version of spi_new_ancillary_device_with_lane(). The ancillary device
+ * will be unregistered automatically when the parent SPI device is unregistered.
+ *
+ * This may only be called from main SPI device's probe routine.
+ *
+ * Return: Pointer to new ancillary device on success; ERR_PTR on failure
+ */
+struct spi_device *devm_spi_new_ancillary_device_with_lane(struct spi_device *spi,
+							   u8 chip_select,
+							   unsigned int rx_lane_idx,
+							   unsigned int tx_lane_idx)
+{
+	struct spi_device *ancillary;
+	int ret;
+
+	ancillary = spi_new_ancillary_device_with_lane(spi, chip_select,
+						       rx_lane_idx, tx_lane_idx);
+	if (IS_ERR(ancillary))
+		return ancillary;
+
+	ret = devm_add_action_or_reset(&spi->dev, devm_spi_unregister_device,
+				       ancillary);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return ancillary;
+}
+EXPORT_SYMBOL_GPL(devm_spi_new_ancillary_device_with_lane);
+
 #ifdef CONFIG_ACPI
 struct acpi_spi_lookup {
 	struct spi_controller 	*ctlr;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 4c285d3ede1d..91c9e2d2e7e3 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -385,6 +385,14 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
 
 extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
 extern struct spi_device *devm_spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
+extern struct spi_device *spi_new_ancillary_device_with_lane(struct spi_device *spi,
+							     u8 chip_select,
+							     unsigned int rx_lane_idx,
+							     unsigned int tx_lane_idx);
+extern struct spi_device *devm_spi_new_ancillary_device_with_lane(struct spi_device *spi,
+								  u8 chip_select,
+								  unsigned int rx_lane_idx,
+								  unsigned int tx_lane_idx);
 
 /* Use a define to avoid include chaining to get THIS_MODULE */
 #define spi_register_driver(driver) \
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 5/6] spi: spi-engine-ex: Add support for multi-CS devices
  2026-08-17 23:32 [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support Jonathan Santos
                   ` (3 preceding siblings ...)
  2026-08-17 23:33 ` [PATCH v3 4/6] spi: introduce SPI ancillary device with lanes Jonathan Santos
@ 2026-08-17 23:33 ` Jonathan Santos
  2026-08-18  7:01   ` Andy Shevchenko
  2026-08-17 23:33 ` [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation Jonathan Santos
  5 siblings, 1 reply; 22+ messages in thread
From: Jonathan Santos @ 2026-08-17 23:33 UTC (permalink / raw)
  To: linux-spi, linux-kernel
  Cc: Jonathan Santos, dlechner, nuno.sa, michael.hennerich, broonie,
	jonath4nns, marcelo.schmitt1, andriy.shevchenko

The SPI Engine controller only handled the first chip select when
asserting CS lines and configuring CS polarity inversion, ignoring
additional CS indices present in cs_index_mask.

Update spi_engine_gen_cs() to iterate over all set bits in
cs_index_mask and toggle each corresponding CS line in the assert mask.
Update spi_engine_setup() likewise so that SPI_CS_HIGH polarity is
applied to every active CS index rather than only index 0.

Set SPI_CONTROLLER_MULTI_CS in the controller flags to reflect the
capability to the SPI core.

Acked-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
Changes in v3:
* None.

Changes in v2:
* Adaptation of the patch
  "spi: spi-engine-ex: Add support for multi-CS devices" from v1,
  discarding the per transfer CS mask and keeping the Multi-CS support
  only.
---
 drivers/spi/spi-axi-spi-engine.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 02bbc5d0cfc5..8a2cae81aea6 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -46,6 +46,7 @@
 #define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK	0xec
 
 #define SPI_ENGINE_MAX_NUM_OFFLOADS		32
+#define SPI_ENGINE_MAX_CS			8
 
 #define SPI_ENGINE_REG_OFFLOAD_CTRL(x)		(0x100 + SPI_ENGINE_MAX_NUM_OFFLOADS * (x))
 #define SPI_ENGINE_REG_OFFLOAD_STATUS(x)	(0x104 + SPI_ENGINE_MAX_NUM_OFFLOADS * (x))
@@ -281,10 +282,14 @@ static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
 static void spi_engine_gen_cs(struct spi_engine_program *p, bool dry,
 		struct spi_device *spi, bool assert)
 {
+	unsigned long cs_index_mask = spi->cs_index_mask;
 	unsigned int mask = 0xff;
+	unsigned int cs_bit;
 
-	if (assert)
-		mask ^= BIT(spi_get_chipselect(spi, 0));
+	if (assert) {
+		for_each_set_bit(cs_bit, &cs_index_mask, SPI_ENGINE_MAX_CS)
+			mask ^= BIT(spi_get_chipselect(spi, cs_bit));
+	}
 
 	spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_ASSERT(0, mask));
 }
@@ -886,12 +891,16 @@ static int spi_engine_setup(struct spi_device *device)
 {
 	struct spi_controller *host = device->controller;
 	struct spi_engine *spi_engine = spi_controller_get_devdata(host);
+	unsigned long cs_index_mask = device->cs_index_mask;
 	unsigned int reg;
+	u32 cs_bit;
 
-	if (device->mode & SPI_CS_HIGH)
-		spi_engine->cs_inv |= BIT(spi_get_chipselect(device, 0));
-	else
-		spi_engine->cs_inv &= ~BIT(spi_get_chipselect(device, 0));
+	for_each_set_bit(cs_bit, &cs_index_mask, SPI_ENGINE_MAX_CS) {
+		if (device->mode & SPI_CS_HIGH)
+			spi_engine->cs_inv |= BIT(spi_get_chipselect(device, cs_bit));
+		else
+			spi_engine->cs_inv &= ~BIT(spi_get_chipselect(device, cs_bit));
+	}
 
 	writel_relaxed(SPI_ENGINE_CMD_SYNC(0),
 		       spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
@@ -1222,6 +1231,7 @@ static int spi_engine_probe(struct platform_device *pdev)
 	host->unoptimize_message = spi_engine_unoptimize_message;
 	host->get_offload = spi_engine_get_offload;
 	host->put_offload = spi_engine_put_offload;
+	host->flags |= SPI_CONTROLLER_MULTI_CS;
 	host->num_chipselect = 8;
 
 	if (adi_axi_pcore_ver_gteq(version, 1, 2)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation
  2026-08-17 23:32 [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support Jonathan Santos
                   ` (4 preceding siblings ...)
  2026-08-17 23:33 ` [PATCH v3 5/6] spi: spi-engine-ex: Add support for multi-CS devices Jonathan Santos
@ 2026-08-17 23:33 ` Jonathan Santos
  2026-08-18  7:10   ` Andy Shevchenko
  2026-08-18 16:17   ` Nuno Sá
  5 siblings, 2 replies; 22+ messages in thread
From: Jonathan Santos @ 2026-08-17 23:33 UTC (permalink / raw)
  To: linux-spi, linux-kernel
  Cc: Jonathan Santos, dlechner, nuno.sa, michael.hennerich, broonie,
	jonath4nns, marcelo.schmitt1, andriy.shevchenko

The AD7768-1 family is a single-channel ADC, but it is designed to allow
connecting multiple devices to the same SPI controller, each on a
dedicated CS and data lane, clocked synchronously, and sharing SDO and
SCLK. The number of aggregated devices are derived from
spi->num_rx_lanes, assuming all parts are single lane.

The DRDY pins are combined to trigger the data interrupt when all
devices are ready, and since the synchronization pins are tied, they
stay in synchrony.

To reflect the multidevice setup, IIO channels are dynamically set
based on the number of devices. Restrict buffered capture to the
all-channels scan mask, since all devices sample in lockstep. Register
an ancillary SPI device per lane for individual direct reads, and enable
SPI_MULTI_LANE_MODE_STRIPE in offload mode to interleave samples from all
lanes into the DMA stream.

Since all devices must be in sync, all configurations that affects the
sampling rate are unified, so they always have the same sampling
frequency.

Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
Changes in v3:
* Modified channel mask allocation on ad7768_parse_aaf_gain() to get 
  a static value, Since we assume the family is single channel. Added a 
  comment explaining.

Changes in v2:
* New patch.
---
 drivers/iio/adc/ad7768-1.c | 100 +++++++++++++++++++++++++++++++++----
 1 file changed, 89 insertions(+), 11 deletions(-)

diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index e9060c1bbe6f..deff36165ed1 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -120,7 +120,8 @@
 
 #define AD7768_TRIGGER_SOURCE_SYNC_IDX 0
 
-#define AD7768_MAX_CHANNELS 1
+#define AD7768_MAX_CHANNELS	1
+#define AD7768_MAX_AGGR_DEVICES	4
 
 #define ADAQ7768_PGA_PINS 3
 
@@ -300,10 +301,12 @@ struct ad7768_chip_info {
 
 struct ad7768_state {
 	struct spi_device *spi;
+	struct spi_device *spi_anc[AD7768_MAX_AGGR_DEVICES];
 	struct spi_offload *offload;
 	struct spi_offload_trigger *offload_trigger;
 	struct regmap *regmap;
 	struct regmap *regmap24;
+	struct regmap *regmap24_anc[AD7768_MAX_AGGR_DEVICES];
 	int vref_uv;
 	struct regulator_dev *vcm_rdev;
 	unsigned int vcm_output_sel;
@@ -322,11 +325,12 @@ struct ad7768_state {
 	struct gpio_descs *pga_gpios;
 	struct gpio_desc *gpio_sync_in;
 	struct gpio_desc *gpio_reset;
-	const char *labels[AD7768_MAX_CHANNELS];
+	const char *labels[AD7768_MAX_CHANNELS * AD7768_MAX_AGGR_DEVICES];
 	struct gpio_chip gpiochip;
 	struct spi_transfer offload_xfer;
 	struct spi_message offload_msg;
 	const struct ad7768_chip_info *chip;
+	u8 num_devices;
 	bool en_spi_sync;
 	struct mutex pga_lock; /* protect device internal state (PGA) */
 	/*
@@ -335,7 +339,7 @@ struct ad7768_state {
 	 */
 	union {
 		struct {
-			__be32 chan;
+			__be32 chan[AD7768_MAX_AGGR_DEVICES];
 			aligned_s64 timestamp;
 		} scan;
 		__be32 d32;
@@ -478,7 +482,7 @@ static int ad7768_set_mode(struct ad7768_state *st,
 				 AD7768_CONV_MODE_MSK, AD7768_CONV_MODE(mode));
 }
 
-static int ad7768_scan_direct(struct iio_dev *indio_dev)
+static int ad7768_scan_direct(struct iio_dev *indio_dev, unsigned int chan)
 {
 	struct ad7768_state *st = iio_priv(indio_dev);
 	int readval, ret;
@@ -492,9 +496,15 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
 	if (!ret)
 		return -ETIMEDOUT;
 
-	ret = regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &readval);
-	if (ret)
-		return ret;
+	if (st->num_devices > 1) {
+		ret = regmap_read(st->regmap24_anc[chan], AD7768_REG24_ADC_DATA, &readval);
+		if (ret)
+			return ret;
+	} else {
+		ret = regmap_read(st->regmap24, AD7768_REG24_ADC_DATA, &readval);
+		if (ret)
+			return ret;
+	}
 
 	/*
 	 * When the decimation rate is set to x8, the ADC data precision is
@@ -989,7 +999,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
 		if (!iio_device_claim_direct(indio_dev))
 			return -EBUSY;
 
-		ret = ad7768_scan_direct(indio_dev);
+		ret = ad7768_scan_direct(indio_dev, chan->channel);
 
 		iio_device_release_direct(indio_dev);
 		if (ret < 0)
@@ -1391,6 +1401,8 @@ static int ad7768_offload_buffer_postenable(struct iio_dev *indio_dev)
 	st->offload_xfer.len = spi_bpw_to_bytes(scan_type->realbits);
 	st->offload_xfer.bits_per_word = scan_type->realbits;
 	st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+	if (st->num_devices > 1)
+		st->offload_xfer.multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE;
 
 	spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1);
 	st->offload_msg.offload = st->offload;
@@ -1694,6 +1706,56 @@ static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st)
 	return 0;
 }
 
+static int ad7768_probe_multidevices(struct iio_dev *indio_dev)
+{
+	struct ad7768_state *st = iio_priv(indio_dev);
+	struct device *dev = indio_dev->dev.parent;
+	struct iio_chan_spec *channels;
+	unsigned long *masks;
+	u8 cs;
+	int i;
+
+	indio_dev->num_channels = st->num_devices * st->chip->num_channels;
+	channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels), GFP_KERNEL);
+	if (!channels)
+		return -ENOMEM;
+
+	for (i = 0; i < st->num_devices; i++) {
+		struct iio_chan_spec *chan = &channels[i];
+
+		*chan = *st->chip->channel_spec;
+		chan->channel = i;
+		chan->scan_index = i;
+	}
+
+	indio_dev->channels = channels;
+
+	/* One mask entry, considering single channel ADCs, plus a zero terminator */
+	masks = devm_kcalloc(dev, 2, sizeof(*masks), GFP_KERNEL);
+	if (!masks)
+		return -ENOMEM;
+
+	masks[0] = GENMASK(st->num_devices - 1, 0);
+	indio_dev->available_scan_masks = masks;
+
+	/* Setup ancillary SPI devices for single device access  */
+	for (i = 0; i < st->num_devices; i++) {
+		cs = spi_get_chipselect(st->spi, i);
+		st->spi_anc[i] = devm_spi_new_ancillary_device_with_lane(st->spi,
+									 cs, i, 0);
+		if (IS_ERR(st->spi_anc[i]))
+			return dev_err_probe(dev, PTR_ERR(st->spi_anc[i]),
+					     "failed to register ancillary device\n");
+
+		st->regmap24_anc[i] = devm_regmap_init_spi(st->spi_anc[i],
+							   &ad7768_regmap24_config);
+		if (IS_ERR(st->regmap24_anc[i]))
+			return PTR_ERR(st->regmap24_anc[i]);
+	}
+
+	return 0;
+}
+
 static bool ad7768_offload_trigger_match(struct spi_offload_trigger *trigger,
 					 enum spi_offload_trigger_type type,
 					 u64 *args, u32 nargs)
@@ -1830,6 +1892,15 @@ static int ad7768_probe(struct spi_device *spi)
 
 	st->chip = spi_get_device_match_data(spi);
 	st->spi = spi;
+	/*
+	 * This family is composed of single-lane devices, so we assume that
+	 * each lane is bound to a different device.
+	 */
+	st->num_devices = spi->num_rx_lanes;
+	if (st->num_devices > AD7768_MAX_AGGR_DEVICES)
+		return dev_err_probe(&spi->dev, -EINVAL,
+				     "Too many devices (%u), max %d supported\n",
+				     st->num_devices, AD7768_MAX_AGGR_DEVICES);
 
 	st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config);
 	if (IS_ERR(st->regmap))
@@ -1853,11 +1924,18 @@ static int ad7768_probe(struct spi_device *spi)
 
 	st->mclk_freq = clk_get_rate(st->mclk);
 
-	indio_dev->channels = st->chip->channel_spec;
-	indio_dev->num_channels = st->chip->num_channels;
 	indio_dev->name = st->chip->name;
 	indio_dev->info = &ad7768_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
+	if (st->num_devices > 1) {
+		ret = ad7768_probe_multidevices(indio_dev);
+		if (ret)
+			return dev_err_probe(&spi->dev, ret,
+					     "Failed to configure multidevice\n");
+	} else {
+		indio_dev->channels = st->chip->channel_spec;
+		indio_dev->num_channels = st->chip->num_channels;
+	}
 
 	/* Register VCM output regulator */
 	if (st->chip->has_vcm_regulator) {
@@ -1889,7 +1967,7 @@ static int ad7768_probe(struct spi_device *spi)
 			return ret;
 	}
 
-	ret = ad7768_set_channel_label(indio_dev, st->chip->num_channels);
+	ret = ad7768_set_channel_label(indio_dev, st->num_devices);
 	if (ret)
 		return ret;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS
  2026-08-17 23:32 ` [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS Jonathan Santos
@ 2026-08-18  6:39   ` Andy Shevchenko
  2026-08-18 16:06   ` David Lechner
  1 sibling, 0 replies; 22+ messages in thread
From: Andy Shevchenko @ 2026-08-18  6:39 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: linux-spi, linux-kernel, dlechner, nuno.sa, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1

On Mon, Aug 17, 2026 at 08:32:43PM -0300, Jonathan Santos wrote:
> Some SPI controllers allow multiple CS lines to be toggled at the same
> time. The existing code always used CS index 0 when tracking the last
> active CS in spi_set_cs(), and unconditionally set cs_index_mask to
> BIT(0) when parsing DT, both forcing the single CS usage.
> 
> Modify spi_set_cs() to iterate last_cs[] using each logical CS index
> instead of always reading index 0. Modify of_spi_parse_dt() to build
> cs_index_mask from all parsed CS entries rather than hardcoding BIT(0),
> so the controller correctly identifies which CS lines belong to a device
> when asserting them simultaneously.
> 
> Board info, ACPI, and ancillary device paths are not updated here.
> Board info would require an API change to accept an array of CS values
> and is left for a follow-up when we have a use case for this. Ancillary
> devices are by design single-CS, so multi-CS is not a current use case for
> them. ACPI represents the CS as a 64-bit integer with no established
> convention for encoding multiple CS indices yet, so any extension there
> would require a separate specification effort.

...

>  	/*
> -	 * By default spi->chip_select[0] will hold the physical CS number,
> -	 * so set bit 0 in spi->cs_index_mask.
> +	 * Set cs_index_mask to indicate which logical CS indices are active.
> +	 * Each bit corresponds to a logical CS index in the spi->chip_select array.
>  	 */
> -	spi->cs_index_mask = BIT(0);
> +	for (idx = 0; idx < rc; idx++)
> +		spi->cs_index_mask |= BIT(idx);

Maybe I'm missing something, but isn't it a simple mask, and for-loop is not
required?

	spi->cs_index_mask = BIT(rc + 1) - 1;

OR

	spi->cs_index_mask = GENMASK(rc, 0); // This is better as it supports rc to be 32 or 64


-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices
  2026-08-17 23:32 ` [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices Jonathan Santos
@ 2026-08-18  6:45   ` Andy Shevchenko
  2026-08-18 16:14     ` Nuno Sá
  0 siblings, 1 reply; 22+ messages in thread
From: Andy Shevchenko @ 2026-08-18  6:45 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: linux-spi, linux-kernel, dlechner, nuno.sa, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1

On Mon, Aug 17, 2026 at 08:32:57PM -0300, Jonathan Santos wrote:
> The device name for SPI devices was formatted as <controller>.<cs0>,
> always using only the first chip-select index, ignoring the remaining CS
> lines.
> 
> Change the naming format to <controller>.<cs0>+<cs1>+... so that all
> active chip-selects are reflected in the device name. Single-CS devices
> are not affected since the loop only appends extra indices when
> num_chipselect is greater than one.

...

> -	dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev),
> -		     spi_get_chipselect(spi, 0));
> +	cs_len = scnprintf(cs_str, sizeof(cs_str), "%u", spi_get_chipselect(spi, 0));
> +	for (unsigned int idx = 1; idx < spi->num_chipselect; idx++)
> +		cs_len += scnprintf(cs_str + cs_len, sizeof(cs_str) - cs_len,
> +				    "+%u", spi_get_chipselect(spi, idx));

So, if this won't support sparse CS list, I would just go with a standard range:

	dev_set_name(&spi->dev, "%s.%u-%u", dev_name(&spi->controller->dev),
		     spi_get_chipselect(spi, 0), spi_get_chipselect(spi, 0) + spi->num_chipselect - 1);

(yes, need a variation for num_chipselect == 1, but I leave the rest for you)

Note, I do not see that we are expecting to see the sparse CS list here. It
would make too complex logic to follow. So, range approach is KISS in my opinion.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support
  2026-08-17 23:32 ` [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support Jonathan Santos
@ 2026-08-18  6:46   ` Krzysztof Kozlowski
  2026-08-18 13:35     ` David Lechner
  2026-08-18 15:02   ` David Lechner
  1 sibling, 1 reply; 22+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-18  6:46 UTC (permalink / raw)
  To: Jonathan Santos, linux-spi, linux-kernel
  Cc: dlechner, nuno.sa, michael.hennerich, broonie, jonath4nns,
	marcelo.schmitt1, andriy.shevchenko

On 18/08/2026 01:32, Jonathan Santos wrote:
> The AD7768-1 family supports aggregating up to four devices on a single
> SPI controller, with each device occupying a dedicated CS line and a
> single data lane.
> 
> Extend the `reg` property to accept up to 4 entries (one per device).
> 
> Add `spi-rx-bus-width` property to declare the per-device lane count.
> Since each lane is bound to one CS, the number of entries must match
> `reg`. Make it required when `reg` has more than one entry.
> 
> Add an example for a four ADAQ7768-1 aggregation, with shared DRDY and
> SYNC_IN pin.
> 
> Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> ---
> Changes in v3:
> * New patch.

Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.

Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.

You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time.

Please kindly resend and include all necessary To/Cc entries.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 4/6] spi: introduce SPI ancillary device with lanes
  2026-08-17 23:33 ` [PATCH v3 4/6] spi: introduce SPI ancillary device with lanes Jonathan Santos
@ 2026-08-18  6:53   ` Andy Shevchenko
  0 siblings, 0 replies; 22+ messages in thread
From: Andy Shevchenko @ 2026-08-18  6:53 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: linux-spi, linux-kernel, dlechner, nuno.sa, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1

On Mon, Aug 17, 2026 at 08:33:12PM -0300, Jonathan Santos wrote:
> The existing spi_new_ancillary_device() creates an ancillary SPI device
> but does not consider the parent's lane map. In multi-device setups where
> each sub-device's chip-select is bound to a dedicated data lane, there is
> no way to bind an ancillary device to an arbitrary lane index.
> 
> Introduce spi_new_ancillary_device_with_lane() and
> devm_spi_new_ancillary_device_with_lane(), which accept rx_lane_idx and
> tx_lane_idx parameters to select a specific lane from the parent's
> rx_lane_map and tx_lane_map respectively. The resulting ancillary device
> is registered with a single RX and TX lane, keeping it independent from
> the other sub-devices sharing the same controller.


...

>  extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
>  extern struct spi_device *devm_spi_new_ancillary_device(struct spi_device *spi, u8 chip_select);
> +extern struct spi_device *spi_new_ancillary_device_with_lane(struct spi_device *spi,
> +							     u8 chip_select,
> +							     unsigned int rx_lane_idx,
> +							     unsigned int tx_lane_idx);
> +extern struct spi_device *devm_spi_new_ancillary_device_with_lane(struct spi_device *spi,
> +								  u8 chip_select,
> +								  unsigned int rx_lane_idx,
> +								  unsigned int tx_lane_idx);

Can we stop using legacy 'extern' for the function declarations?

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 5/6] spi: spi-engine-ex: Add support for multi-CS devices
  2026-08-17 23:33 ` [PATCH v3 5/6] spi: spi-engine-ex: Add support for multi-CS devices Jonathan Santos
@ 2026-08-18  7:01   ` Andy Shevchenko
  0 siblings, 0 replies; 22+ messages in thread
From: Andy Shevchenko @ 2026-08-18  7:01 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: linux-spi, linux-kernel, dlechner, nuno.sa, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1

On Mon, Aug 17, 2026 at 08:33:26PM -0300, Jonathan Santos wrote:
> The SPI Engine controller only handled the first chip select when
> asserting CS lines and configuring CS polarity inversion, ignoring
> additional CS indices present in cs_index_mask.
> 
> Update spi_engine_gen_cs() to iterate over all set bits in
> cs_index_mask and toggle each corresponding CS line in the assert mask.
> Update spi_engine_setup() likewise so that SPI_CS_HIGH polarity is
> applied to every active CS index rather than only index 0.
> 
> Set SPI_CONTROLLER_MULTI_CS in the controller flags to reflect the
> capability to the SPI core.

...

> +		for_each_set_bit(cs_bit, &cs_index_mask, SPI_ENGINE_MAX_CS)
> +			mask ^= BIT(spi_get_chipselect(spi, cs_bit));

> +	for_each_set_bit(cs_bit, &cs_index_mask, SPI_ENGINE_MAX_CS) {
> +		if (device->mode & SPI_CS_HIGH)
> +			spi_engine->cs_inv |= BIT(spi_get_chipselect(device, cs_bit));
> +		else
> +			spi_engine->cs_inv &= ~BIT(spi_get_chipselect(device, cs_bit));
> +	}

Looking at these two I would rather see a helper

unsigned long spi_get_chipselect_bits(..., unsigned long index_mask)

With that the above becomes for-loop free.

		mask ^= spi_get_chipselect_bits(spi, cs_index_mask);

and

	if (device->mode & SPI_CS_HIGH)
		spi_engine->cs_inv |= spi_get_chipselect_bits(device, cs_index_mask));
	else
		spi_engine->cs_inv &= ~spi_get_chipselect_bits(device, cs_index_mask));

respectively.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation
  2026-08-17 23:33 ` [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation Jonathan Santos
@ 2026-08-18  7:10   ` Andy Shevchenko
  2026-08-18 16:17   ` Nuno Sá
  1 sibling, 0 replies; 22+ messages in thread
From: Andy Shevchenko @ 2026-08-18  7:10 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: linux-spi, linux-kernel, dlechner, nuno.sa, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1

On Mon, Aug 17, 2026 at 08:33:41PM -0300, Jonathan Santos wrote:
> The AD7768-1 family is a single-channel ADC, but it is designed to allow
> connecting multiple devices to the same SPI controller, each on a
> dedicated CS and data lane, clocked synchronously, and sharing SDO and
> SCLK. The number of aggregated devices are derived from
> spi->num_rx_lanes, assuming all parts are single lane.
> 
> The DRDY pins are combined to trigger the data interrupt when all
> devices are ready, and since the synchronization pins are tied, they
> stay in synchrony.
> 
> To reflect the multidevice setup, IIO channels are dynamically set
> based on the number of devices. Restrict buffered capture to the
> all-channels scan mask, since all devices sample in lockstep. Register
> an ancillary SPI device per lane for individual direct reads, and enable
> SPI_MULTI_LANE_MODE_STRIPE in offload mode to interleave samples from all
> lanes into the DMA stream.
> 
> Since all devices must be in sync, all configurations that affects the
> sampling rate are unified, so they always have the same sampling
> frequency.

...

> +	struct spi_device *spi_anc[AD7768_MAX_AGGR_DEVICES];

> +	struct regmap *regmap24_anc[AD7768_MAX_AGGR_DEVICES];

Yeah, this will be enormous memory consumption...

...

> +static int ad7768_probe_multidevices(struct iio_dev *indio_dev)
> +{
> +	struct ad7768_state *st = iio_priv(indio_dev);
> +	struct device *dev = indio_dev->dev.parent;
> +	struct iio_chan_spec *channels;
> +	unsigned long *masks;
> +	u8 cs;
> +	int i;

Why is 'i' signed?

> +	indio_dev->num_channels = st->num_devices * st->chip->num_channels;

This wants to have size_mul() from overflow.h to follow what allocator is using
beneath.

> +	channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels), GFP_KERNEL);
> +	if (!channels)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < st->num_devices; i++) {
> +		struct iio_chan_spec *chan = &channels[i];
> +
> +		*chan = *st->chip->channel_spec;
> +		chan->channel = i;
> +		chan->scan_index = i;
> +	}
> +
> +	indio_dev->channels = channels;
> +
> +	/* One mask entry, considering single channel ADCs, plus a zero terminator */
> +	masks = devm_kcalloc(dev, 2, sizeof(*masks), GFP_KERNEL);
> +	if (!masks)
> +		return -ENOMEM;

Isn't this devm_bitmap_zalloc()? Yes, it might require to reconsider the design
of the masks.

> +	masks[0] = GENMASK(st->num_devices - 1, 0);

bitmap_set() (needs bitmap.h)

> +	indio_dev->available_scan_masks = masks;
> +
> +	/* Setup ancillary SPI devices for single device access  */
> +	for (i = 0; i < st->num_devices; i++) {
> +		cs = spi_get_chipselect(st->spi, i);
> +		st->spi_anc[i] = devm_spi_new_ancillary_device_with_lane(st->spi,
> +									 cs, i, 0);
> +		if (IS_ERR(st->spi_anc[i]))
> +			return dev_err_probe(dev, PTR_ERR(st->spi_anc[i]),
> +					     "failed to register ancillary device\n");
> +
> +		st->regmap24_anc[i] = devm_regmap_init_spi(st->spi_anc[i],
> +							   &ad7768_regmap24_config);
> +		if (IS_ERR(st->regmap24_anc[i]))
> +			return PTR_ERR(st->regmap24_anc[i]);
> +	}
> +
> +	return 0;
> +}

...

> +	if (st->num_devices > 1) {
> +		ret = ad7768_probe_multidevices(indio_dev);
> +		if (ret)
> +			return dev_err_probe(&spi->dev, ret,

Having

	struct device *dev = &spi->dev;

may help here and elsewhere to make code neater.

> +					     "Failed to configure multidevice\n");
> +	} else {
> +		indio_dev->channels = st->chip->channel_spec;
> +		indio_dev->num_channels = st->chip->num_channels;
> +	}

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support
  2026-08-18  6:46   ` Krzysztof Kozlowski
@ 2026-08-18 13:35     ` David Lechner
  0 siblings, 0 replies; 22+ messages in thread
From: David Lechner @ 2026-08-18 13:35 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Jonathan Santos, linux-spi, linux-kernel
  Cc: nuno.sa, michael.hennerich, broonie, jonath4nns, marcelo.schmitt1,
	andriy.shevchenko

On 8/18/26 1:46 AM, Krzysztof Kozlowski wrote:
> On 18/08/2026 01:32, Jonathan Santos wrote:
>> The AD7768-1 family supports aggregating up to four devices on a single
>> SPI controller, with each device occupying a dedicated CS line and a
>> single data lane.
>>
>> Extend the `reg` property to accept up to 4 entries (one per device).
>>
>> Add `spi-rx-bus-width` property to declare the per-device lane count.
>> Since each lane is bound to one CS, the number of entries must match
>> `reg`. Make it required when `reg` has more than one entry.
>>
>> Add an example for a four ADAQ7768-1 aggregation, with shared DRDY and
>> SYNC_IN pin.
>>
>> Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
>> ---
>> Changes in v3:
>> * New patch.
> 
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC. It might happen, that command when run on an older
> kernel, gives you outdated entries. Therefore please be sure you base
> your patches on recent Linux kernel.
> 
> Tools like b4 or scripts/get_maintainer.pl provide you proper list of
> people, so fix your workflow. Tools might also fail if you work on some
> ancient tree (don't, instead use mainline) or work on fork of kernel
> (don't, instead use mainline). Just use b4 and everything should be
> fine, although remember about `b4 prep --auto-to-cc` if you added new
> patches to the patchset.
> 
> You missed at least devicetree list (maybe more), so this won't be

Also missed IIO.

> tested by automated tooling. Performing review on untested code might be
> a waste of time.
> 
> Please kindly resend and include all necessary To/Cc entries.
> 
> Best regards,
> Krzysztof


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support
  2026-08-17 23:32 ` [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support Jonathan Santos
  2026-08-18  6:46   ` Krzysztof Kozlowski
@ 2026-08-18 15:02   ` David Lechner
  2026-08-18 15:14     ` Nuno Sá
  1 sibling, 1 reply; 22+ messages in thread
From: David Lechner @ 2026-08-18 15:02 UTC (permalink / raw)
  To: Jonathan Santos, linux-spi, linux-kernel
  Cc: nuno.sa, michael.hennerich, broonie, jonath4nns, marcelo.schmitt1,
	andriy.shevchenko

On 8/17/26 6:32 PM, Jonathan Santos wrote:
> The AD7768-1 family supports aggregating up to four devices on a single
> SPI controller, with each device occupying a dedicated CS line and a
> single data lane.
> 
> Extend the `reg` property to accept up to 4 entries (one per device).
> 
> Add `spi-rx-bus-width` property to declare the per-device lane count.
> Since each lane is bound to one CS, the number of entries must match
> `reg`. Make it required when `reg` has more than one entry.
> 
I don't see why we should have to require the spi-rx-bus-width property.
It seems logical that if it is not present, then we would assume one
lane per CS. This is already how bindings work.

For example, adi,ad4080 and ge,achc have multiple CS lines and don't
require any bus width properties.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support
  2026-08-18 15:02   ` David Lechner
@ 2026-08-18 15:14     ` Nuno Sá
  2026-08-18 15:26       ` David Lechner
  0 siblings, 1 reply; 22+ messages in thread
From: Nuno Sá @ 2026-08-18 15:14 UTC (permalink / raw)
  To: David Lechner
  Cc: Jonathan Santos, linux-spi, linux-kernel, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1, andriy.shevchenko

On Tue, Aug 18, 2026 at 10:02:50AM -0500, David Lechner wrote:
> On 8/17/26 6:32 PM, Jonathan Santos wrote:
> > The AD7768-1 family supports aggregating up to four devices on a single
> > SPI controller, with each device occupying a dedicated CS line and a
> > single data lane.
> > 
> > Extend the `reg` property to accept up to 4 entries (one per device).
> > 
> > Add `spi-rx-bus-width` property to declare the per-device lane count.
> > Since each lane is bound to one CS, the number of entries must match
> > `reg`. Make it required when `reg` has more than one entry.
> > 
> I don't see why we should have to require the spi-rx-bus-width property.
> It seems logical that if it is not present, then we would assume one
> lane per CS. This is already how bindings work.
> 
> For example, adi,ad4080 and ge,achc have multiple CS lines and don't
> require any bus width properties.

Hmm that's my default then! I was the one requesting it. Basically
because of:

https://elixir.bootlin.com/linux/v7.2/source/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml#L76

So I thought that $refing spi-peripheral-props.yaml and leaving the
default value would make dtbs_check to fail if one used 

spi-rx-bus-width = <1>, <1>, <1>, <1>;

in DT. 

Won't it fail?

And if we don't give the property I believe we'll have:

https://elixir.bootlin.com/linux/v7.2/source/drivers/spi/spi.c#L2509

And given these series assumption of spi->num_rx_lanes == number of
devices (which I don't agree btw), I thought we would need to make
spi-rx-bus-width  explicit in our bindings! I still think but I might be
wrong and I'm by no means an expert on dt bindings schemas work :)

- Nuno Sá

> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support
  2026-08-18 15:14     ` Nuno Sá
@ 2026-08-18 15:26       ` David Lechner
  0 siblings, 0 replies; 22+ messages in thread
From: David Lechner @ 2026-08-18 15:26 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Jonathan Santos, linux-spi, linux-kernel, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1, andriy.shevchenko

On 8/18/26 10:14 AM, Nuno Sá wrote:
> On Tue, Aug 18, 2026 at 10:02:50AM -0500, David Lechner wrote:
>> On 8/17/26 6:32 PM, Jonathan Santos wrote:
>>> The AD7768-1 family supports aggregating up to four devices on a single
>>> SPI controller, with each device occupying a dedicated CS line and a
>>> single data lane.
>>>
>>> Extend the `reg` property to accept up to 4 entries (one per device).
>>>
>>> Add `spi-rx-bus-width` property to declare the per-device lane count.
>>> Since each lane is bound to one CS, the number of entries must match
>>> `reg`. Make it required when `reg` has more than one entry.
>>>
>> I don't see why we should have to require the spi-rx-bus-width property.
>> It seems logical that if it is not present, then we would assume one
>> lane per CS. This is already how bindings work.
>>
>> For example, adi,ad4080 and ge,achc have multiple CS lines and don't
>> require any bus width properties.
> 
> Hmm that's my default then! I was the one requesting it. Basically
> because of:
> 
> https://elixir.bootlin.com/linux/v7.2/source/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml#L76
> 
> So I thought that $refing spi-peripheral-props.yaml and leaving the
> default value would make dtbs_check to fail if one used 
> 
> spi-rx-bus-width = <1>, <1>, <1>, <1>;
> 
> in DT. 
> 
> Won't it fail?
> 
> And if we don't give the property I believe we'll have:
> 
> https://elixir.bootlin.com/linux/v7.2/source/drivers/spi/spi.c#L2509
> 
> And given these series assumption of spi->num_rx_lanes == number of
> devices (which I don't agree btw), I thought we would need to make
> spi-rx-bus-width  explicit in our bindings! I still think but I might be
> wrong and I'm by no means an expert on dt bindings schemas work :)
> 
> - Nuno Sá
> 
>>

Now that I'm reading the later patches again, it is jogging my memory.
I forgot that we want this to operate like a single multi-lane device
when reading data.

So for that part, yes, having spi-rx-bus-width kind of makes sense.

And I'm thinking that we might need a new property to indicate that
this should be treated as a composite device rather than main + 3
auxiliary. I'll reply more about that in a later patch.


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS
  2026-08-17 23:32 ` [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS Jonathan Santos
  2026-08-18  6:39   ` Andy Shevchenko
@ 2026-08-18 16:06   ` David Lechner
  2026-08-22  0:10     ` Jonathan Santos
  1 sibling, 1 reply; 22+ messages in thread
From: David Lechner @ 2026-08-18 16:06 UTC (permalink / raw)
  To: Jonathan Santos, linux-spi, linux-kernel
  Cc: nuno.sa, michael.hennerich, broonie, jonath4nns, marcelo.schmitt1,
	andriy.shevchenko

On 8/17/26 6:32 PM, Jonathan Santos wrote:
> Some SPI controllers allow multiple CS lines to be toggled at the same
> time. The existing code always used CS index 0 when tracking the last
> active CS in spi_set_cs(), and unconditionally set cs_index_mask to
> BIT(0) when parsing DT, both forcing the single CS usage.
> 
> Modify spi_set_cs() to iterate last_cs[] using each logical CS index
> instead of always reading index 0. Modify of_spi_parse_dt() to build
> cs_index_mask from all parsed CS entries rather than hardcoding BIT(0),
> so the controller correctly identifies which CS lines belong to a device
> when asserting them simultaneously.
> 
> Board info, ACPI, and ancillary device paths are not updated here.
> Board info would require an API change to accept an array of CS values
> and is left for a follow-up when we have a use case for this. Ancillary
> devices are by design single-CS, so multi-CS is not a current use case for
> them. ACPI represents the CS as a 64-bit integer with no established
> convention for encoding multiple CS indices yet, so any extension there
> would require a separate specification effort.
> 
> Acked-by: Nuno Sá <nuno.sa@analog.com>
> Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> ---
> Changes in v3:
> * None.
> 
> Changes in v2:
> * Include Summary describind why the other SPI paths were not addressed
>   here.
> ---
>  drivers/spi/spi.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index d9e6b4b87c89..55fb96fea243 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -1090,7 +1090,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
>  	spi->controller->last_cs_index_mask = spi->cs_index_mask;
>  	for (idx = 0; idx < SPI_DEVICE_CS_CNT_MAX; idx++) {
>  		if (enable && idx < spi->num_chipselect)
> -			spi->controller->last_cs[idx] = spi_get_chipselect(spi, 0);
> +			spi->controller->last_cs[idx] = spi_get_chipselect(spi, idx);
>  		else
>  			spi->controller->last_cs[idx] = SPI_INVALID_CS;
>  	}
> @@ -2594,10 +2594,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
>  		spi_set_chipselect(spi, idx, cs[idx]);
>  
>  	/*
> -	 * By default spi->chip_select[0] will hold the physical CS number,
> -	 * so set bit 0 in spi->cs_index_mask.
> +	 * Set cs_index_mask to indicate which logical CS indices are active.
> +	 * Each bit corresponds to a logical CS index in the spi->chip_select array.
>  	 */
> -	spi->cs_index_mask = BIT(0);
> +	for (idx = 0; idx < rc; idx++)
> +		spi->cs_index_mask |= BIT(idx);
>  
>  	/* Device speed */
>  	if (!of_property_read_u32(nc, "spi-max-frequency", &value))

I have the same concern that sashiko calls out here.

Existing users of multi-cs (not including spi-mem) follow the pattern
that a SPI device gets registered with the CS at index 0 and they later
create an auxiliary using the additional CS. This would cause the main
device to now assert both CS. Not what we want to happen.

If I understood (and remember) the previous explanations of this series
correctly, we have a different case for this one.

We want a main device that acts as a single composite device that asserts
all 4 CS at the same time. Then we also need 4 auxiliary devices that
only assert one CS at a time for configuring the individual chips.

So it seems to me like we need a new DT property or some way to be able to
tell the difference to decide whether we just use the first CS here or all
of them.

Perhaps another possibility would be to leave this code the way it is and
do it this way instead:
- The SPI device passed to the IIO driver is just the first chip (one CS)
- The IIO driver then registers auxiliary drivers for the other 3 chips
  (also 1 CS each)
- These 4 devices will be used individual to handle configuration.
- The IIO driver registers a separate composite device that has the
  multiple lanes and and multiple CS. Whether this using the same
  auxiliary mechanism with additional parameters or something new
  probably doesn't matter too much.
- In this way of doing things, it would not make sense to have the
  spi-rx-bus-width property in the devcietree since as far as the
  devicetree is concerned, these are more-or-less 4 separate devices
  (from the SPI point of view).  Instead, this new composite device
  registration function would be the one setting the number of lanes
  based on the number of chip selects.

---
sashiko output for reference:

--- Patch [2]: [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS ---
commit 17290644299c39d6ca397b14180cd885c5b04919
Author: Jonathan Santos <Jonathan.Santos@analog.com>
Subject: spi: support simultaneous assertion of multiple CS

This commit modifies spi_set_cs() and of_spi_parse_dt() to allow
simultaneous toggling of multiple chip select lines. It builds
cs_index_mask from all parsed CS entries instead of hardcoding
bit 0.

> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index d9e6b4b87c899..55fb96fea2432 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c

[ ... ]

> @@ -2594,10 +2594,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
>  		spi_set_chipselect(spi, idx, cs[idx]);
>  
>  	/*
> -	 * By default spi->chip_select[0] will hold the physical CS number,
> -	 * so set bit 0 in spi->cs_index_mask.
> +	 * Set cs_index_mask to indicate which logical CS indices are active.
> +	 * Each bit corresponds to a logical CS index in the spi->chip_select array.
>  	 */
> -	spi->cs_index_mask = BIT(0);
> +	for (idx = 0; idx < rc; idx++)
> +		spi->cs_index_mask |= BIT(idx);

Will this loop break backward compatibility for devices that use multiple
reg entries for independent logical chip selects?

For example, if a device has multiple reg entries and uses
spi_new_ancillary_device(), the primary device's cs_index_mask will now have
multiple bits set. During a transfer on the primary device, all of these
parsed chip selects would be asserted simultaneously.

Could this result in multiple chips driving the shared MISO line at the same
time, causing bus contention and data corruption?

>  
>  	/* Device speed */
>  	if (!of_property_read_u32(nc, "spi-max-frequency", &value))

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices
  2026-08-18  6:45   ` Andy Shevchenko
@ 2026-08-18 16:14     ` Nuno Sá
  2026-08-19  6:59       ` Andy Shevchenko
  0 siblings, 1 reply; 22+ messages in thread
From: Nuno Sá @ 2026-08-18 16:14 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Jonathan Santos, linux-spi, linux-kernel, dlechner, nuno.sa,
	michael.hennerich, broonie, jonath4nns, marcelo.schmitt1

On 2026-08-18 09:45:05+03:00, Andy Shevchenko wrote:
> On Mon, Aug 17, 2026 at 08:32:57PM -0300, Jonathan Santos wrote:
> 
> > The device name for SPI devices was formatted as <controller>.<cs0>,
> > always using only the first chip-select index, ignoring the remaining CS
> > lines.
> > 
> > Change the naming format to <controller>.<cs0>+<cs1>+... so that all
> > active chip-selects are reflected in the device name. Single-CS devices
> > are not affected since the loop only appends extra indices when
> > num_chipselect is greater than one.
> 
> ...
> 
> > -	dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev),
> > -		     spi_get_chipselect(spi, 0));
> > +	cs_len = scnprintf(cs_str, sizeof(cs_str), "%u", spi_get_chipselect(spi, 0));
> > +	for (unsigned int idx = 1; idx < spi->num_chipselect; idx++)
> > +		cs_len += scnprintf(cs_str + cs_len, sizeof(cs_str) - cs_len,
> > +				    "+%u", spi_get_chipselect(spi, idx));
> 
> So, if this won't support sparse CS list, I would just go with a standard range:
> 
> 	dev_set_name(&spi->dev, "%s.%u-%u", dev_name(&spi->controller->dev),
> 		     spi_get_chipselect(spi, 0), spi_get_chipselect(spi, 0) + spi->num_chipselect - 1);
> 

I don't think there's anything forcing cs to be contiguous. So cs4-0 does
not mean we have 0,1,2,3 and 4 which I think the above implies.

Moreover, i also don't think is guaranteed that `spi_get_chipselect(spi,
0) + spi->num_chipselect - 1)` yields a valid cs. IOW, in theory

spi_get_chipselect(spi, spi->num_chipselect - 1) might be different
than spi_get_chipselect(spi, 0) + spi->num_chipselect - 1

- Nuno Sá

> (yes, need a variation for num_chipselect == 1, but I leave the rest for you)
> 
> Note, I do not see that we are expecting to see the sparse CS list here. It
> would make too complex logic to follow. So, range approach is KISS in my opinion.



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation
  2026-08-17 23:33 ` [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation Jonathan Santos
  2026-08-18  7:10   ` Andy Shevchenko
@ 2026-08-18 16:17   ` Nuno Sá
  1 sibling, 0 replies; 22+ messages in thread
From: Nuno Sá @ 2026-08-18 16:17 UTC (permalink / raw)
  To: Jonathan Santos
  Cc: linux-spi, linux-kernel, dlechner, nuno.sa, michael.hennerich,
	broonie, jonath4nns, marcelo.schmitt1, andriy.shevchenko

On Mon, 17 Aug 2026 20:33:41 -0300, Jonathan Santos <Jonathan.Santos@analog.com> wrote:
> diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
> index e9060c1bbe6f..deff36165ed1 100644
> --- a/drivers/iio/adc/ad7768-1.c
> +++ b/drivers/iio/adc/ad7768-1.c
> @@ -1830,6 +1892,15 @@ static int ad7768_probe(struct spi_device *spi)
>  
>  	st->chip = spi_get_device_match_data(spi);
>  	st->spi = spi;
> +	/*
> +	 * This family is composed of single-lane devices, so we assume that
> +	 * each lane is bound to a different device.
> +	 */
> +	st->num_devices = spi->num_rx_lanes;

I still don't agree with the above! At the very least we should infer
st->num_devices from the number of chipselects. Anyways, won't extend
much the review for now given that David seems to have some ideas
different from the ancillary devices.

- Nuno Sá

-- 
Nuno Sá <nuno.sa@analog.com>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices
  2026-08-18 16:14     ` Nuno Sá
@ 2026-08-19  6:59       ` Andy Shevchenko
  0 siblings, 0 replies; 22+ messages in thread
From: Andy Shevchenko @ 2026-08-19  6:59 UTC (permalink / raw)
  To: Nuno Sá
  Cc: Jonathan Santos, linux-spi, linux-kernel, dlechner,
	michael.hennerich, broonie, jonath4nns, marcelo.schmitt1

On Tue, Aug 18, 2026 at 05:14:20PM +0100, Nuno Sá wrote:
> On 2026-08-18 09:45:05+03:00, Andy Shevchenko wrote:
> > On Mon, Aug 17, 2026 at 08:32:57PM -0300, Jonathan Santos wrote:

...

> > > -	dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev),
> > > -		     spi_get_chipselect(spi, 0));
> > > +	cs_len = scnprintf(cs_str, sizeof(cs_str), "%u", spi_get_chipselect(spi, 0));
> > > +	for (unsigned int idx = 1; idx < spi->num_chipselect; idx++)
> > > +		cs_len += scnprintf(cs_str + cs_len, sizeof(cs_str) - cs_len,
> > > +				    "+%u", spi_get_chipselect(spi, idx));
> > 
> > So, if this won't support sparse CS list, I would just go with a standard range:
> > 
> > 	dev_set_name(&spi->dev, "%s.%u-%u", dev_name(&spi->controller->dev),
> > 		     spi_get_chipselect(spi, 0), spi_get_chipselect(spi, 0) + spi->num_chipselect - 1);
> 
> I don't think there's anything forcing cs to be contiguous. So cs4-0 does
> not mean we have 0,1,2,3 and 4 which I think the above implies.
> 
> Moreover, i also don't think is guaranteed that `spi_get_chipselect(spi,
> 0) + spi->num_chipselect - 1)` yields a valid cs. IOW, in theory
> 
> spi_get_chipselect(spi, spi->num_chipselect - 1) might be different
> than spi_get_chipselect(spi, 0) + spi->num_chipselect - 1

So, I would expect then two things:
- following the KISS and make sure we operate on the sequential CS ranges.
- definitely add some test cases, now it's a time (I consider NAKing any
version without test cases of this rather complex mapping logic)

> > (yes, need a variation for num_chipselect == 1, but I leave the rest for you)
> > 
> > Note, I do not see that we are expecting to see the sparse CS list here. It
> > would make too complex logic to follow. So, range approach is KISS in my opinion.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS
  2026-08-18 16:06   ` David Lechner
@ 2026-08-22  0:10     ` Jonathan Santos
  0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Santos @ 2026-08-22  0:10 UTC (permalink / raw)
  To: David Lechner
  Cc: Jonathan Santos, linux-spi, linux-kernel, nuno.sa,
	michael.hennerich, broonie, marcelo.schmitt1, andriy.shevchenko

On 08/18, David Lechner wrote:
> On 8/17/26 6:32 PM, Jonathan Santos wrote:
> > Some SPI controllers allow multiple CS lines to be toggled at the same
> > time. The existing code always used CS index 0 when tracking the last
> > active CS in spi_set_cs(), and unconditionally set cs_index_mask to
> > BIT(0) when parsing DT, both forcing the single CS usage.
> > 
> > Modify spi_set_cs() to iterate last_cs[] using each logical CS index
> > instead of always reading index 0. Modify of_spi_parse_dt() to build
> > cs_index_mask from all parsed CS entries rather than hardcoding BIT(0),
> > so the controller correctly identifies which CS lines belong to a device
> > when asserting them simultaneously.
> > 
> > Board info, ACPI, and ancillary device paths are not updated here.
> > Board info would require an API change to accept an array of CS values
> > and is left for a follow-up when we have a use case for this. Ancillary
> > devices are by design single-CS, so multi-CS is not a current use case for
> > them. ACPI represents the CS as a 64-bit integer with no established
> > convention for encoding multiple CS indices yet, so any extension there
> > would require a separate specification effort.
> > 
> > Acked-by: Nuno Sá <nuno.sa@analog.com>
> > Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
> > ---
> > Changes in v3:
> > * None.
> > 
> > Changes in v2:
> > * Include Summary describind why the other SPI paths were not addressed
> >   here.
> > ---
> >  drivers/spi/spi.c | 9 +++++----
> >  1 file changed, 5 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > index d9e6b4b87c89..55fb96fea243 100644
> > --- a/drivers/spi/spi.c
> > +++ b/drivers/spi/spi.c
> > @@ -1090,7 +1090,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
> >  	spi->controller->last_cs_index_mask = spi->cs_index_mask;
> >  	for (idx = 0; idx < SPI_DEVICE_CS_CNT_MAX; idx++) {
> >  		if (enable && idx < spi->num_chipselect)
> > -			spi->controller->last_cs[idx] = spi_get_chipselect(spi, 0);
> > +			spi->controller->last_cs[idx] = spi_get_chipselect(spi, idx);
> >  		else
> >  			spi->controller->last_cs[idx] = SPI_INVALID_CS;
> >  	}
> > @@ -2594,10 +2594,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
> >  		spi_set_chipselect(spi, idx, cs[idx]);
> >  
> >  	/*
> > -	 * By default spi->chip_select[0] will hold the physical CS number,
> > -	 * so set bit 0 in spi->cs_index_mask.
> > +	 * Set cs_index_mask to indicate which logical CS indices are active.
> > +	 * Each bit corresponds to a logical CS index in the spi->chip_select array.
> >  	 */
> > -	spi->cs_index_mask = BIT(0);
> > +	for (idx = 0; idx < rc; idx++)
> > +		spi->cs_index_mask |= BIT(idx);
> >  
> >  	/* Device speed */
> >  	if (!of_property_read_u32(nc, "spi-max-frequency", &value))
> 
> I have the same concern that sashiko calls out here.
> 
> Existing users of multi-cs (not including spi-mem) follow the pattern
> that a SPI device gets registered with the CS at index 0 and they later
> create an auxiliary using the additional CS. This would cause the main
> device to now assert both CS. Not what we want to happen.

Indeed, enalbing all CS for those cases would cause problems (like you
describe below). AD4080 would be an example.

The devicetree property seems to be a good ideia to fix this and simpler
to execute, but the composite device is interesting.

> 
> If I understood (and remember) the previous explanations of this series
> correctly, we have a different case for this one.
> 
> We want a main device that acts as a single composite device that asserts
> all 4 CS at the same time. Then we also need 4 auxiliary devices that
> only assert one CS at a time for configuring the individual chips.
> 
> So it seems to me like we need a new DT property or some way to be able to
> tell the difference to decide whether we just use the first CS here or all
> of them.
> 
> Perhaps another possibility would be to leave this code the way it is and
> do it this way instead:
> - The SPI device passed to the IIO driver is just the first chip (one CS)
> - The IIO driver then registers auxiliary drivers for the other 3 chips
>   (also 1 CS each)
> - These 4 devices will be used individual to handle configuration.
> - The IIO driver registers a separate composite device that has the
>   multiple lanes and and multiple CS. Whether this using the same
>   auxiliary mechanism with additional parameters or something new
>   probably doesn't matter too much.
> - In this way of doing things, it would not make sense to have the
>   spi-rx-bus-width property in the devcietree since as far as the
>   devicetree is concerned, these are more-or-less 4 separate devices
>   (from the SPI point of view).  Instead, this new composite device
>   registration function would be the one setting the number of lanes
>   based on the number of chip selects.
> 

My initial idea was to use the main device as the "composite" because it
holds the hw description, therefore the multi-lane would be handled by
the existing flow (that's why the spi-rx-bus-width property was
mandatory). This way each ancillary device would take the lane index
from the main device. Using the main + 3 ancillaries for individual
access and the new composite for simultaneous is a great alternative,
but removing the spi-rx-bus-width kind of excludes the information that
we are using multiple lanes for this device. Unless we document that 
"number of CS = number of lanes" on multiple-data-lanes.rst, the 
assumption is:

spi-rx-bus-width = <1>
spi-rx-lane-map = <1>

Also, it would make more sense to take the lane description from the
main device described in the DT considering cases like non-default
mapping. Or at least take it into consideration.
> ---
> sashiko output for reference:
> 
> --- Patch [2]: [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS ---
> commit 17290644299c39d6ca397b14180cd885c5b04919
> Author: Jonathan Santos <Jonathan.Santos@analog.com>
> Subject: spi: support simultaneous assertion of multiple CS
> 
> This commit modifies spi_set_cs() and of_spi_parse_dt() to allow
> simultaneous toggling of multiple chip select lines. It builds
> cs_index_mask from all parsed CS entries instead of hardcoding
> bit 0.
> 
> > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > index d9e6b4b87c899..55fb96fea2432 100644
> > --- a/drivers/spi/spi.c
> > +++ b/drivers/spi/spi.c
> 
> [ ... ]
> 
> > @@ -2594,10 +2594,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
> >  		spi_set_chipselect(spi, idx, cs[idx]);
> >  
> >  	/*
> > -	 * By default spi->chip_select[0] will hold the physical CS number,
> > -	 * so set bit 0 in spi->cs_index_mask.
> > +	 * Set cs_index_mask to indicate which logical CS indices are active.
> > +	 * Each bit corresponds to a logical CS index in the spi->chip_select array.
> >  	 */
> > -	spi->cs_index_mask = BIT(0);
> > +	for (idx = 0; idx < rc; idx++)
> > +		spi->cs_index_mask |= BIT(idx);
> 
> Will this loop break backward compatibility for devices that use multiple
> reg entries for independent logical chip selects?
> 
> For example, if a device has multiple reg entries and uses
> spi_new_ancillary_device(), the primary device's cs_index_mask will now have
> multiple bits set. During a transfer on the primary device, all of these
> parsed chip selects would be asserted simultaneously.
> 
> Could this result in multiple chips driving the shared MISO line at the same
> time, causing bus contention and data corruption?
> 

Yes, that could happen.

> >  
> >  	/* Device speed */
> >  	if (!of_property_read_u32(nc, "spi-max-frequency", &value))

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2026-08-22  0:10 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17 23:32 [PATCH v3 0/6] spi: add multi-CS and multi-chip aggregation support Jonathan Santos
2026-08-17 23:32 ` [PATCH v3 1/6] dt-bindings: iio: adc: ad7768-1: Document multidevice support Jonathan Santos
2026-08-18  6:46   ` Krzysztof Kozlowski
2026-08-18 13:35     ` David Lechner
2026-08-18 15:02   ` David Lechner
2026-08-18 15:14     ` Nuno Sá
2026-08-18 15:26       ` David Lechner
2026-08-17 23:32 ` [PATCH v3 2/6] spi: support simultaneous assertion of multiple CS Jonathan Santos
2026-08-18  6:39   ` Andy Shevchenko
2026-08-18 16:06   ` David Lechner
2026-08-22  0:10     ` Jonathan Santos
2026-08-17 23:32 ` [PATCH v3 3/6] spi: expand device name to include all CS lines for multi-CS devices Jonathan Santos
2026-08-18  6:45   ` Andy Shevchenko
2026-08-18 16:14     ` Nuno Sá
2026-08-19  6:59       ` Andy Shevchenko
2026-08-17 23:33 ` [PATCH v3 4/6] spi: introduce SPI ancillary device with lanes Jonathan Santos
2026-08-18  6:53   ` Andy Shevchenko
2026-08-17 23:33 ` [PATCH v3 5/6] spi: spi-engine-ex: Add support for multi-CS devices Jonathan Santos
2026-08-18  7:01   ` Andy Shevchenko
2026-08-17 23:33 ` [PATCH v3 6/6] iio: adc: ad7768-1: add support for multiple chip aggregation Jonathan Santos
2026-08-18  7:10   ` Andy Shevchenko
2026-08-18 16:17   ` Nuno Sá

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox