From c0e3ec7f08b8a63444f345bf357d9071da645b8c Mon Sep 17 00:00:00 2001 From: Declan Snyder Date: Mon, 19 May 2025 14:43:18 -0500 Subject: [PATCH] spi_nxp_lpspi: Add maximum wait time of fifo empty Instead of waiting forever and potentially allowing infinite loop on ISR, wait some arbitrary amount of cycles to error out if it isn't happening. Still make this configurable for debugging purposes. Signed-off-by: Declan Snyder --- drivers/spi/spi_nxp_lpspi/Kconfig | 13 +++++++++++++ drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c | 5 ++++- .../spi/spi_nxp_lpspi/spi_nxp_lpspi_common.c | 18 +++++++++++++++--- drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h | 2 +- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi_nxp_lpspi/Kconfig b/drivers/spi/spi_nxp_lpspi/Kconfig index aabb4d51ce7..1d9ce8a770a 100644 --- a/drivers/spi/spi_nxp_lpspi/Kconfig +++ b/drivers/spi/spi_nxp_lpspi/Kconfig @@ -36,4 +36,17 @@ config SPI_MCUX_LPSPI_CPU This has lower latency than DMA-based driver but over the longer transfers will likely have less bandwidth and use more CPU time. +config SPI_NXP_LPSPI_TXFIFO_WAIT_CYCLES + int "Number of CPU cycles to wait on TX fifo empty" + default 0 if DEBUG + default 10000 + help + This option most likely does not need changed. + The drivers tend to need to wait on confirming the transmit command + is consumed by the hardware by checking of the TX fifo is emptied. + This option gives a maximum number of CPU cycles to wait on that check. + The special value of 0 means infinite, which can be useful for debugging + for if there is some programming error that causes TX fifo not to empty. + The default of 10000 is arbitrary. + endif # SPI_MCUX_LPSPI diff --git a/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c b/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c index bedf112f9c6..8f37d90164d 100644 --- a/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c +++ b/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c @@ -337,7 +337,10 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg base->TCR |= LPSPI_TCR_CONT_MASK; } /* tcr is written to tx fifo */ - lpspi_wait_tx_fifo_empty(dev); + ret = lpspi_wait_tx_fifo_empty(dev); + if (ret) { + return ret; + } /* start the transfer sequence which are handled by irqs */ lpspi_next_tx_fill(dev); diff --git a/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_common.c b/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_common.c index 078a619d2f9..53df267c4ed 100644 --- a/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_common.c +++ b/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_common.c @@ -60,12 +60,24 @@ static inline clock_ip_name_t lpspi_get_clock(LPSPI_Type *const base) } #endif -void lpspi_wait_tx_fifo_empty(const struct device *dev) +int lpspi_wait_tx_fifo_empty(const struct device *dev) { LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + int arbitrary_cycle_limit = CONFIG_SPI_NXP_LPSPI_TXFIFO_WAIT_CYCLES; + bool limit_wait = arbitrary_cycle_limit > 0; - while (LPSPI_GetTxFifoCount(base) != 0) { + while (FIELD_GET(LPSPI_FSR_TXCOUNT_MASK, base->FSR) != 0) { + if (!limit_wait) { + continue; + } + + if (arbitrary_cycle_limit-- < 0) { + LOG_WRN("Failed waiting for TX fifo empty"); + return -EIO; + } } + + return 0; } int spi_lpspi_release(const struct device *dev, const struct spi_config *spi_cfg) @@ -185,7 +197,7 @@ int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cf base->CR |= LPSPI_CR_DBGEN_MASK; } - return 0; + return lpspi_wait_tx_fifo_empty(dev); } static void lpspi_module_system_init(LPSPI_Type *base) diff --git a/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h b/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h index ec985367a02..58e72f105e3 100644 --- a/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h +++ b/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h @@ -68,7 +68,7 @@ int spi_nxp_init_common(const struct device *dev); /* common api function for now */ int spi_lpspi_release(const struct device *dev, const struct spi_config *spi_cfg); -void lpspi_wait_tx_fifo_empty(const struct device *dev); +int lpspi_wait_tx_fifo_empty(const struct device *dev); #define SPI_LPSPI_IRQ_FUNC_LP_FLEXCOMM(n) \ nxp_lp_flexcomm_setirqhandler(DEVICE_DT_GET(DT_INST_PARENT(n)), DEVICE_DT_INST_GET(n), \