[PATCH v2 2/2] spi: qcom-geni: Use GPIO to notify master of SPI target activity
From: Praveen Talari
Date: Mon Aug 17 2026 - 13:18:47 EST
When operating in SPI target mode, the GENI controller relies on an
external GPIO to notify the SPI master about the target's active state.
Add support for an optional ready GPIO that is asserted when a target
transfer begins and deasserted when the transfer completes, is aborted,
or hits a timeout. This allows the target to explicitly signal its
availability to the master and ensures the GPIO is released in all error
and completion paths, preventing the master from observing a stale or
incorrect target-ready indication.
The ready GPIO is intentionally made optional and is requested only
when target mode is enabled. This preserves existing behaviour for
systems that do not require the signal and avoids regressions on
deployed platforms where the GPIO is already controlled from userspace.
Targets without a ready GPIO continue to operate unchanged by using
devm_gpiod_get_index_optional().
Signed-off-by: Praveen Talari <praveen.talari@xxxxxxxxxxxxxxxx>
---
drivers/spi/spi-geni-qcom.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index d262206ed663..5ebbeac70382 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -8,6 +8,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/dma/qcom-gpi-dma.h>
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/log2.h>
@@ -113,6 +114,7 @@ struct spi_geni_master {
struct dma_chan *rx;
int cur_xfer_mode;
const struct geni_spi_desc *dev_data;
+ struct gpio_desc *target_gpio;
};
static void spi_slv_setup(struct spi_geni_master *mas)
@@ -171,6 +173,9 @@ static void handle_se_timeout(struct spi_controller *spi)
xfer = mas->cur_xfer;
mas->cur_xfer = NULL;
+ if (spi->target && mas->target_gpio)
+ gpiod_set_value(mas->target_gpio, 0);
+
/* The controller doesn't support the Cancel commnand in target mode */
if (!spi->target) {
reinit_completion(&mas->cancel_done);
@@ -928,8 +933,12 @@ static int spi_geni_transfer_one(struct spi_controller *spi,
if (mas->cur_xfer_mode == GENI_SE_FIFO || mas->cur_xfer_mode == GENI_SE_DMA) {
ret = setup_se_xfer(xfer, mas, slv->mode, spi);
/* SPI framework expects +ve ret code to wait for transfer complete */
- if (!ret)
+ if (!ret) {
+ if (spi->target && mas->target_gpio)
+ gpiod_set_value(mas->target_gpio, 1);
ret = 1;
+ }
+
return ret;
}
return setup_gsi_xfer(xfer, mas, slv, spi);
@@ -969,6 +978,8 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
if (mas->cur_xfer) {
spi_finalize_current_transfer(spi);
mas->cur_xfer = NULL;
+ if (spi->target && mas->target_gpio)
+ gpiod_set_value(mas->target_gpio, 0);
/*
* If this happens, then a CMD_DONE came before all the
* Tx buffer bytes were sent out. This is unusual, log
@@ -1012,6 +1023,8 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
if (!mas->tx_rem_bytes && !mas->rx_rem_bytes && xfer) {
spi_finalize_current_transfer(spi);
mas->cur_xfer = NULL;
+ if (spi->target && mas->target_gpio)
+ gpiod_set_value(mas->target_gpio, 0);
}
}
@@ -1116,8 +1129,16 @@ static int spi_geni_probe(struct platform_device *pdev)
init_completion(&mas->rx_reset_done);
spin_lock_init(&mas->lock);
- if (spi->target)
+ if (spi->target) {
spi->target_abort = spi_geni_target_abort;
+ mas->target_gpio = devm_gpiod_get_index_optional(dev, "ready", 0,
+ GPIOD_OUT_LOW);
+ if (IS_ERR(mas->target_gpio)) {
+ dev_err(dev, "Failed to request GPIO: %ld\n",
+ PTR_ERR(mas->target_gpio));
+ mas->target_gpio = NULL;
+ }
+ }
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
--
2.34.1