mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jonathan Santos <Jonathan.Santos@analog.com>
To: <linux-spi@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Cc: Jonathan Santos <Jonathan.Santos@analog.com>,
	<dlechner@baylibre.com>, <nuno.sa@analog.com>,
	<michael.hennerich@analog.com>, <broonie@kernel.org>,
	<jonath4nns@gmail.com>, <marcelo.schmitt1@gmail.com>,
	<andy@kernel.org>
Subject: [PATCH 3/6] spi: spi-engine-ex: Add support for multi-CS devices
Date: Tue, 14 Jul 2026 02:56:16 -0300	[thread overview]
Message-ID: <844bb5dbe3a4f40f12575bc50b4e65875fa33d3c.1783729282.git.Jonathan.Santos@analog.com> (raw)
In-Reply-To: <cover.1783729282.git.Jonathan.Santos@analog.com>

The AXI SPI Engine controller hardcoded CS index 0 when generating
assert commands, so only the first chip select was being toggled even
when a device declared multiple CS lines in the device tree.

Modify spi_engine_gen_cs() to accept a cs_select_mask argument and
iterate all bits set in the effective mask (the intersection of
xfer->cs_select_mask with spi->cs_index_mask, falling back to
spi->cs_index_mask when the transfer mask is 0). Update
spi_engine_compile_message() to pass each transfer's cs_select_mask
at every CS transition, including cs_change and cs_select_mask
change boundaries between consecutive transfers.

Likewise, modify spi_engine_setup() replacing the single-index CS
assert with a for_each_set_bit() loop over cs_index_mask.

Set SPI_CONTROLLER_MULTI_CS flag in the probe path so the core
multi-CS path in spi_set_cs() is activated for this controller.

Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
---
 drivers/spi/spi-axi-spi-engine.c | 44 ++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 02bbc5d0cfc5..f2d0a6dd593b 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))
@@ -279,12 +280,17 @@ 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)
+		struct spi_device *spi, bool assert, unsigned long xfer_cs_mask)
 {
+	unsigned long cs_index_mask = !xfer_cs_mask
+		? spi->cs_index_mask
+		: spi->cs_index_mask & xfer_cs_mask;
 	unsigned int mask = 0xff;
+	unsigned int cs_bit;
 
 	if (assert)
-		mask ^= BIT(spi_get_chipselect(spi, 0));
+		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));
 }
@@ -406,7 +412,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
 	}
 
 	xfer = list_first_entry(&msg->transfers, struct spi_transfer, transfer_list);
-	spi_engine_gen_cs(p, dry, spi, !xfer->cs_off);
+	spi_engine_gen_cs(p, dry, spi, !xfer->cs_off, xfer->cs_select_mask);
 
 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
 		if (xfer->rx_buf || xfer->offload_flags & SPI_OFFLOAD_XFER_RX_STREAM ||
@@ -451,28 +457,33 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry,
 		spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer),
 				     inst_ns, xfer->effective_speed_hz);
 
+		struct spi_transfer *next_xfer = list_next_entry(xfer, transfer_list);
 		if (xfer->cs_change) {
 			if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
 				keep_cs = true;
 			} else {
 				if (!xfer->cs_off)
-					spi_engine_gen_cs(p, dry, spi, false);
+					spi_engine_gen_cs(p, dry, spi, false, xfer->cs_select_mask);
 
 				spi_engine_gen_sleep(p, dry, spi_delay_to_ns(
 					&xfer->cs_change_delay, xfer), inst_ns,
 					xfer->effective_speed_hz);
 
-				if (!list_next_entry(xfer, transfer_list)->cs_off)
-					spi_engine_gen_cs(p, dry, spi, true);
+				if (!next_xfer->cs_off)
+					spi_engine_gen_cs(p, dry, spi, true,
+							  next_xfer->cs_select_mask);
 			}
 		} else if (!list_is_last(&xfer->transfer_list, &msg->transfers) &&
-			   xfer->cs_off != list_next_entry(xfer, transfer_list)->cs_off) {
-			spi_engine_gen_cs(p, dry, spi, xfer->cs_off);
+			   xfer->cs_off != next_xfer->cs_off) {
+			spi_engine_gen_cs(p, dry, spi, xfer->cs_off, xfer->cs_select_mask);
+		} else if (!list_is_last(&xfer->transfer_list, &msg->transfers) &&
+			   xfer->cs_select_mask != next_xfer->cs_select_mask) {
+			spi_engine_gen_cs(p, dry, spi, true, next_xfer->cs_select_mask);
 		}
 	}
 
 	if (!keep_cs)
-		spi_engine_gen_cs(p, dry, spi, false);
+		spi_engine_gen_cs(p, dry, spi, false, 0);
 
 	/*
 	 * Restore clockdiv to default so that future gen_sleep commands don't
@@ -886,12 +897,18 @@ 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 +1239,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


  parent reply	other threads:[~2026-07-14  2:56 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-14  5:55 [PATCH 0/6] spi: add multi-CS and per-transfer lane mask support Jonathan Santos
2026-07-14  5:55 ` [PATCH 1/6] spi: support simultaneous assertion of multiple CS Jonathan Santos
2026-07-14  9:06   ` Andy Shevchenko
2026-07-14  9:08   ` Nuno Sá
2026-07-14  5:56 ` [PATCH 2/6] spi: add per-transfer CS mask Jonathan Santos
2026-07-14  9:12   ` Nuno Sá
2026-07-14  9:23   ` Andy Shevchenko
2026-07-14  5:56 ` Jonathan Santos [this message]
2026-07-14  9:17   ` [PATCH 3/6] spi: spi-engine-ex: Add support for multi-CS devices Andy Shevchenko
2026-07-14  5:56 ` [PATCH 4/6] spi: Documentation: multiple-data-lanes: describe rx and tx lane mask Jonathan Santos
2026-07-14  5:56 ` [PATCH 5/6] spi: add rx and tx lane mask to spi_transfer struct Jonathan Santos
2026-07-14  9:22   ` Nuno Sá
2026-07-14  9:26   ` Andy Shevchenko
2026-07-14 15:18   ` David Lechner
2026-07-15 10:23     ` Nuno Sá
2026-07-14  5:57 ` [PATCH 6/6] spi: axi-spi-engine: add support for dynamic multi-lane selection Jonathan Santos
2026-07-14 10:29   ` Nuno Sá
2026-07-14  8:57 ` [PATCH 0/6] spi: add multi-CS and per-transfer lane mask support Andy Shevchenko
2026-07-14 14:09   ` David Lechner
2026-07-14 14:26     ` Andy Shevchenko
2026-07-14 14:44       ` David Lechner
2026-07-14 10:29 ` Nuno Sá
2026-07-14 15:02   ` David Lechner
2026-07-16 16:50     ` Jonathan Santos
2026-07-20 23:10       ` David Lechner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=844bb5dbe3a4f40f12575bc50b4e65875fa33d3c.1783729282.git.Jonathan.Santos@analog.com \
    --to=jonathan.santos@analog.com \
    --cc=andy@kernel.org \
    --cc=broonie@kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=jonath4nns@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=marcelo.schmitt1@gmail.com \
    --cc=michael.hennerich@analog.com \
    --cc=nuno.sa@analog.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®