[PATCH v2 2/2] spi: qcom-geni: Use GPIO to notify master of SPI target activity
Praveen Talari <[email protected]>
| Newsgroups | org.kernel.vger.linux-spi,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260817-use_gpio_to_notify_master_of_spi_target_activity-v2-2-94d1eff3175f@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 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 <[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..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