[PATCH 2/2] spi: qcom-geni: Use GPIO to notify master of SPI target activity
Praveen Talari <[email protected]> Thu, 06 Aug 2026 15:43:45 +0530
| Newsgroups | org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-spi |
|---|---|
| Message-ID | <20260806-use_gpio_to_notify_master_of_spi_target_activity-v1-2-c363a9b5df69@oss.qualcomm.com> |
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 device 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 GPIO is optional and requested only when target mode is enabled, using devm_gpiod_get_index_optional() so targets without this signal continue to work unchanged. Signed-off-by: Praveen Talari <[email protected]> --- 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..ffb8871a55d8 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, "device", 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