From fb1ae6833a2efb11cf7c94ff36851bd2d922d0fd Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 3 Feb 2026 19:13:00 +0100 Subject: [PATCH 01/20] [nrf fromtree] spi: rtio: patch spi_rtio_copy transceive with empty buffer The spi_rtio_copy implementation incorrectly sets up a transceive sqe in place of a write or read when an empty "spacer" spi_buf is passed which is not aligned with the "opposing" spi_buf. Using transceive in these cases passes a NULL receive/transmit buffer with positive length, which is a bug. Some drivers have an additional check to clear the size if the buffer is NULL, but we should not rely on this check in drivers as it is duplicate code. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 652d2a7b2a521774a52b96219222412933556a61) (cherry picked from commit 8581142bc46068cd21ab0a9fca4fa6a76f404407) --- drivers/spi/spi_rtio.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi_rtio.c b/drivers/spi/spi_rtio.c index 4d21f092febd..4bb047081cd6 100644 --- a/drivers/spi/spi_rtio.c +++ b/drivers/spi/spi_rtio.c @@ -262,11 +262,19 @@ int spi_rtio_copy(struct rtio *r, tx_len = 0; } } else if (tx_len > rx_len) { - rtio_sqe_prep_transceive(sqe, iodev, RTIO_PRIO_NORM, - (uint8_t *)tx_buf, - (uint8_t *)rx_buf, - (uint32_t)rx_len, - NULL); + if (rx_buf) { + rtio_sqe_prep_transceive(sqe, iodev, RTIO_PRIO_NORM, + (uint8_t *)tx_buf, + (uint8_t *)rx_buf, + (uint32_t)rx_len, + NULL); + } else { + rtio_sqe_prep_write(sqe, iodev, RTIO_PRIO_NORM, + (uint8_t *)tx_buf, + (uint32_t)rx_len, + NULL); + } + tx_len -= rx_len; tx_buf += rx_len; rx++; @@ -278,11 +286,19 @@ int spi_rtio_copy(struct rtio *r, rx_len = tx_len; } } else if (rx_len > tx_len) { - rtio_sqe_prep_transceive(sqe, iodev, RTIO_PRIO_NORM, - (uint8_t *)tx_buf, - (uint8_t *)rx_buf, - (uint32_t)tx_len, - NULL); + if (tx_buf) { + rtio_sqe_prep_transceive(sqe, iodev, RTIO_PRIO_NORM, + (uint8_t *)tx_buf, + (uint8_t *)rx_buf, + (uint32_t)tx_len, + NULL); + } else { + rtio_sqe_prep_read(sqe, iodev, RTIO_PRIO_NORM, + (uint8_t *)rx_buf, + (uint32_t)tx_len, + NULL); + } + rx_len -= tx_len; rx_buf += tx_len; tx++; From 402d55ad2b2a85dfc63e8c3a938f2f6e50d42d42 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 3 Feb 2026 19:19:40 +0100 Subject: [PATCH 02/20] [nrf fromtree] spi: rtio: make the shared rtio ctx of struct spi_rtio thread safe Don't rely on drivers protecting the spi_rtio ctx from multiple threads as this is generic and could just be part of the spi_rtio context to avoid duplicate code and thus make using it safer and more efficient. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit e85a5ee98c671161687c5f7a56f6862b13e37dda) (cherry picked from commit 1d281e3e6a445195e390a36466b61309dc815e48) --- drivers/spi/spi_rtio.c | 17 +++++++++++++++++ include/zephyr/drivers/spi/rtio.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/drivers/spi/spi_rtio.c b/drivers/spi/spi_rtio.c index 4bb047081cd6..eb21dcf56512 100644 --- a/drivers/spi/spi_rtio.c +++ b/drivers/spi/spi_rtio.c @@ -352,6 +352,18 @@ static inline void spi_spin_unlock(struct spi_rtio *ctx, k_spinlock_key_t key) k_spin_unlock(&ctx->lock, key); } +/** Lock the shared rtio context used for fallback implementations */ +static inline void spi_r_lock(struct spi_rtio *ctx) +{ + (void)k_sem_take(&ctx->r_lock, K_FOREVER); +} + +/** Unlock the shared rtio context used for fallback implementations */ +static inline void spi_r_unlock(struct spi_rtio *ctx) +{ + k_sem_give(&ctx->r_lock); +} + void spi_rtio_init(struct spi_rtio *ctx, const struct device *dev) { @@ -361,6 +373,7 @@ void spi_rtio_init(struct spi_rtio *ctx, ctx->dt_spec.bus = dev; ctx->iodev.data = &ctx->dt_spec; ctx->iodev.api = &spi_iodev_api; + k_sem_init(&ctx->r_lock, 1, 1); } /** @@ -435,10 +448,13 @@ int spi_rtio_transceive(struct spi_rtio *ctx, return -EINVAL; } + spi_r_lock(ctx); + dt_spec->config = *config; ret = spi_rtio_copy(ctx->r, &ctx->iodev, tx_bufs, rx_bufs, &sqe); if (ret < 0) { + spi_r_unlock(ctx); return ret; } @@ -460,5 +476,6 @@ int spi_rtio_transceive(struct spi_rtio *ctx, ret--; } + spi_r_unlock(ctx); return err; } diff --git a/include/zephyr/drivers/spi/rtio.h b/include/zephyr/drivers/spi/rtio.h index 04d5bad8e691..0af54c49485a 100644 --- a/include/zephyr/drivers/spi/rtio.h +++ b/include/zephyr/drivers/spi/rtio.h @@ -21,6 +21,8 @@ extern "C" { struct spi_rtio { struct k_spinlock lock; struct rtio *r; + /** Thread lock for rtio instance */ + struct k_sem r_lock; struct mpsc io_q; struct rtio_iodev iodev; struct rtio_iodev_sqe *txn_head; From f76596cda6b2c2b5f3293a31a0e6559b626210b1 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 4 Feb 2026 12:32:19 +0100 Subject: [PATCH 03/20] [nrf fromtree] spi: rtio: introduce spi_rtio_transceive_cb wrapper Introduce spi_rtio_transceive_cb which is an implementation of the spi_transceive_cb API based on the spi_rtio context. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit f37a79fd5a27e2944e4d78ad8cde77e14ae0daf1) (cherry picked from commit cae13733f03d78ae090dada4a4076eb16c461558) --- drivers/spi/spi_rtio.c | 81 ++++++++++++++++++++++++++++++- include/zephyr/drivers/spi/rtio.h | 19 ++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_rtio.c b/drivers/spi/spi_rtio.c index eb21dcf56512..512898597e18 100644 --- a/drivers/spi/spi_rtio.c +++ b/drivers/spi/spi_rtio.c @@ -167,6 +167,7 @@ int spi_rtio_copy(struct rtio *r, struct rtio_iodev *iodev, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, + bool no_response, struct rtio_sqe **last_sqe) { int ret = 0; @@ -314,10 +315,14 @@ int spi_rtio_copy(struct rtio *r, } sqe->flags = RTIO_SQE_TRANSACTION; + + if (no_response) { + sqe->flags |= RTIO_SQE_NO_RESPONSE; + } } if (sqe != NULL) { - sqe->flags = 0; + sqe->flags = no_response ? RTIO_SQE_NO_RESPONSE : 0; *last_sqe = sqe; } @@ -452,7 +457,7 @@ int spi_rtio_transceive(struct spi_rtio *ctx, dt_spec->config = *config; - ret = spi_rtio_copy(ctx->r, &ctx->iodev, tx_bufs, rx_bufs, &sqe); + ret = spi_rtio_copy(ctx->r, &ctx->iodev, tx_bufs, rx_bufs, false, &sqe); if (ret < 0) { spi_r_unlock(ctx); return ret; @@ -479,3 +484,75 @@ int spi_rtio_transceive(struct spi_rtio *ctx, spi_r_unlock(ctx); return err; } + +#if CONFIG_SPI_ASYNC +static void transceive_cb_callback(struct rtio *r, + const struct rtio_sqe *sqe, + int res, + void *arg0) +{ + struct spi_rtio *ctx = arg0; + spi_callback_t cb = ctx->async_cb; + struct spi_dt_spec *dt_spec = &ctx->dt_spec; + const struct device *dev = dt_spec->bus; + void *userdata = sqe->userdata; + + /* + * We have stored the context data needed for the callback so + * we can unlock the context here + */ + spi_r_unlock(ctx); + + if (cb == NULL) { + return; + } + + cb(dev, res, userdata); +} + +int spi_rtio_transceive_cb(struct spi_rtio *ctx, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + spi_callback_t cb, + void *userdata) +{ + struct spi_dt_spec *dt_spec = &ctx->dt_spec; + struct rtio_sqe *sqe; + int ret = 0; + + if (tx_bufs == NULL && rx_bufs == NULL) { + return -EINVAL; + } + + spi_r_lock(ctx); + + dt_spec->config = *config; + + ret = spi_rtio_copy(ctx->r, &ctx->iodev, tx_bufs, rx_bufs, true, &sqe); + if (ret < 0) { + spi_r_unlock(ctx); + return ret; + } + + sqe->flags |= RTIO_SQE_CHAINED; + + sqe = rtio_sqe_acquire(ctx->r); + if (sqe == NULL) { + rtio_sqe_drop_all(ctx->r); + spi_r_unlock(ctx); + return ret; + } + + ctx->async_cb = cb; + + rtio_sqe_prep_callback_no_cqe(sqe, + transceive_cb_callback, + ctx, + userdata); + + rtio_submit(ctx->r, 0); + + return 0; +} +#endif /* CONFIG_SPI_ASYNC */ diff --git a/include/zephyr/drivers/spi/rtio.h b/include/zephyr/drivers/spi/rtio.h index 0af54c49485a..0a6bb51d09f2 100644 --- a/include/zephyr/drivers/spi/rtio.h +++ b/include/zephyr/drivers/spi/rtio.h @@ -28,6 +28,9 @@ struct spi_rtio { struct rtio_iodev_sqe *txn_head; struct rtio_iodev_sqe *txn_curr; struct spi_dt_spec dt_spec; +#if CONFIG_SPI_ASYNC + spi_callback_t async_cb; +#endif /* CONFIG_SPI_ASYNC */ }; /** @@ -50,6 +53,7 @@ struct spi_rtio { * @param[in] iodev iodev to transceive with * @param[in] tx_bufs transmit buffer set * @param[in] rx_bufs receive buffer set + * @param[in] no_response do not generate any CQEs, useful if last SQE is a callback * @param[out] last_sqe last sqe submitted, NULL if not enough memory * * @retval Number of submission queue entries @@ -59,6 +63,7 @@ int spi_rtio_copy(struct rtio *r, struct rtio_iodev *iodev, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, + bool no_response, struct rtio_sqe **last_sqe); /** @@ -100,6 +105,20 @@ int spi_rtio_transceive(struct spi_rtio *ctx, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs); +/** + * @brief Perform a SPI Transfer (transceive) and call back once done + * + * Provides a compatible API for the existing spi_transceive_cb API calling + * the caller once the operation is complete. + * For details see @ref spi_transceive_cb. + */ +int spi_rtio_transceive_cb(struct spi_rtio *ctx, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + spi_callback_t cb, + void *userdata); + /** * @brief Fallback SPI RTIO submit implementation. * From 693abada9f4c3e332efb8effe2cabff6b70509d8 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 4 Feb 2026 14:42:11 +0100 Subject: [PATCH 04/20] [nrf fromtree] spi: rtio: don't support SPI_LOCK_ON The SPI_LOCK_ON flag is not compatible with RTIO, nor is the related spi_release API. Introduce stub implementation for drivers to use which simply returns -ENOTSUP and validate SPI_LOCK_ON within the spi_rtio_transceive wrappers. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 5085a29ae085a301bb108832bfbcecf45618f65c) (cherry picked from commit 6c9e3fde69d8b964401c6440f94568cafa0d9323) --- drivers/spi/spi_rtio.c | 15 +++++++++++++++ include/zephyr/drivers/spi/rtio.h | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/spi/spi_rtio.c b/drivers/spi/spi_rtio.c index 512898597e18..5dbe44064042 100644 --- a/drivers/spi/spi_rtio.c +++ b/drivers/spi/spi_rtio.c @@ -453,6 +453,10 @@ int spi_rtio_transceive(struct spi_rtio *ctx, return -EINVAL; } + if (config->operation & SPI_LOCK_ON) { + return -EINVAL; + } + spi_r_lock(ctx); dt_spec->config = *config; @@ -525,6 +529,10 @@ int spi_rtio_transceive_cb(struct spi_rtio *ctx, return -EINVAL; } + if (config->operation & SPI_LOCK_ON) { + return -EINVAL; + } + spi_r_lock(ctx); dt_spec->config = *config; @@ -556,3 +564,10 @@ int spi_rtio_transceive_cb(struct spi_rtio *ctx, return 0; } #endif /* CONFIG_SPI_ASYNC */ + +int spi_rtio_release(const struct device *dev, const struct spi_config *config) +{ + ARG_UNUSED(dev); + ARG_UNUSED(config); + return -ENOTSUP; +} diff --git a/include/zephyr/drivers/spi/rtio.h b/include/zephyr/drivers/spi/rtio.h index 0a6bb51d09f2..1bab4d253c3f 100644 --- a/include/zephyr/drivers/spi/rtio.h +++ b/include/zephyr/drivers/spi/rtio.h @@ -119,6 +119,14 @@ int spi_rtio_transceive_cb(struct spi_rtio *ctx, spi_callback_t cb, void *userdata); +/** + * @brief Stub spi_release implementation + * + * Provides a stub implementation of the spi_release API returning -ENOTSUP as SPI_LOCKED + * is not supported with RTIO. RTIO transactions with RTIO_OP_AWAIT can be used instead. + */ +int spi_rtio_release(const struct device *dev, const struct spi_config *config); + /** * @brief Fallback SPI RTIO submit implementation. * From 8289528f90335035ed1fd30a4b1c74c27aa5921c Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 26 Mar 2026 13:25:33 +0100 Subject: [PATCH 05/20] [nrf fromtree] drivers: spi: rtio: move private spi/rtio.h to drivers/spi/spi_rtio.h Move the private spi_rtio.h header from the public path include/zephyr/drivers/spi/rtio.h the the private path drivers/spi/spi_rtio.h and update drivers to include it using a relative path. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit d99b89ff9623d29bf50f52e56a6e0e4ca6a7ae60) (cherry picked from commit f6cead6bba05fe421318dfb9f05ac0b5c8059d25) --- drivers/spi/spi_ambiq_bleif.c | 2 +- drivers/spi/spi_ambiq_spic.c | 2 +- drivers/spi/spi_b91.c | 2 +- drivers/spi/spi_bitbang.c | 2 +- drivers/spi/spi_cc13xx_cc26xx.c | 2 +- drivers/spi/spi_dw.c | 2 +- drivers/spi/spi_emul.c | 2 +- drivers/spi/spi_esp32_spim.c | 2 +- drivers/spi/spi_gd32.c | 2 +- drivers/spi/spi_grlib_spimctrl.c | 2 +- drivers/spi/spi_infineon.c | 2 +- drivers/spi/spi_litex_common.h | 2 +- drivers/spi/spi_max32.c | 2 +- drivers/spi/spi_mchp_mss.c | 2 +- drivers/spi/spi_mchp_mss_qspi.c | 2 +- drivers/spi/spi_mchp_sercom_g1.c | 2 +- drivers/spi/spi_mcux_dspi.c | 2 +- drivers/spi/spi_mcux_ecspi.c | 2 +- drivers/spi/spi_mcux_flexcomm.c | 2 +- drivers/spi/spi_mcux_flexio.c | 2 +- drivers/spi/spi_npcx_spip.c | 2 +- drivers/spi/spi_nrfx_spi.c | 2 +- drivers/spi/spi_nrfx_spim.c | 2 +- drivers/spi/spi_nrfx_spis.c | 2 +- drivers/spi/spi_numaker.c | 2 +- drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h | 2 +- drivers/spi/spi_nxp_s32.h | 2 +- drivers/spi/spi_oc_simple.c | 2 +- drivers/spi/spi_opentitan.c | 2 +- drivers/spi/spi_pl022.c | 2 +- drivers/spi/spi_psoc6.c | 2 +- drivers/spi/spi_pw.c | 2 +- drivers/spi/spi_renesas_rz.c | 2 +- drivers/spi/spi_renesas_rz_rspi.c | 2 +- drivers/spi/spi_rtio.c | 2 +- include/zephyr/drivers/spi/rtio.h => drivers/spi/spi_rtio.h | 0 drivers/spi/spi_rv32m1_lpspi.c | 2 +- drivers/spi/spi_sam.c | 2 +- drivers/spi/spi_sam0.c | 2 +- drivers/spi/spi_sedi.c | 2 +- drivers/spi/spi_sifive.h | 2 +- drivers/spi/spi_silabs_eusart.c | 2 +- drivers/spi/spi_silabs_siwx91x_gspi.c | 2 +- drivers/spi/spi_silabs_usart.c | 2 +- drivers/spi/spi_smartbond.c | 2 +- drivers/spi/spi_stm32.c | 2 +- drivers/spi/spi_test.c | 2 +- drivers/spi/spi_wch.c | 2 +- drivers/spi/spi_xec_qmspi.c | 2 +- drivers/spi/spi_xlnx_axi_quadspi.c | 2 +- drivers/spi/spi_xmc4xxx.c | 2 +- 51 files changed, 50 insertions(+), 50 deletions(-) rename include/zephyr/drivers/spi/rtio.h => drivers/spi/spi_rtio.h (100%) diff --git a/drivers/spi/spi_ambiq_bleif.c b/drivers/spi/spi_ambiq_bleif.c index 075edc4f8025..05cc22c32f75 100644 --- a/drivers/spi/spi_ambiq_bleif.c +++ b/drivers/spi/spi_ambiq_bleif.c @@ -14,7 +14,7 @@ LOG_MODULE_REGISTER(spi_ambiq_bleif); #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_ambiq_spic.c b/drivers/spi/spi_ambiq_spic.c index 7ae57bb1ca6b..c2cc44cc8bad 100644 --- a/drivers/spi/spi_ambiq_spic.c +++ b/drivers/spi/spi_ambiq_spic.c @@ -10,7 +10,7 @@ LOG_MODULE_REGISTER(spi_ambiq); #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_b91.c b/drivers/spi/spi_b91.c index 1c018d88539b..ff62712c9179 100644 --- a/drivers/spi/spi_b91.c +++ b/drivers/spi/spi_b91.c @@ -19,7 +19,7 @@ LOG_MODULE_REGISTER(spi_telink); #include -#include +#include "spi_rtio.h" #include "spi_context.h" #include diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index d19b7a5b6c44..e963c2d3ad29 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -12,7 +12,7 @@ LOG_MODULE_REGISTER(spi_bitbang); #include #include -#include +#include "spi_rtio.h" #include "spi_context.h" struct spi_bitbang_data { diff --git a/drivers/spi/spi_cc13xx_cc26xx.c b/drivers/spi/spi_cc13xx_cc26xx.c index 68a28fbadc1f..5aa74a64c78a 100644 --- a/drivers/spi/spi_cc13xx_cc26xx.c +++ b/drivers/spi/spi_cc13xx_cc26xx.c @@ -11,7 +11,7 @@ LOG_MODULE_REGISTER(spi_cc13xx_cc26xx); #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index 8025d8d28d7c..54f19efd5919 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -31,7 +31,7 @@ LOG_MODULE_REGISTER(spi_dw); #endif #include -#include +#include "spi_rtio.h" #include #include "spi_dw.h" diff --git a/drivers/spi/spi_emul.c b/drivers/spi/spi_emul.c index d040d4077e4c..a7fb805f9349 100644 --- a/drivers/spi/spi_emul.c +++ b/drivers/spi/spi_emul.c @@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(spi_emul_ctlr); #include #include #include -#include +#include "spi_rtio.h" #include /** Working data for the device */ diff --git a/drivers/spi/spi_esp32_spim.c b/drivers/spi/spi_esp32_spim.c index 4b1e549ea3b4..6aa71306523d 100644 --- a/drivers/spi/spi_esp32_spim.c +++ b/drivers/spi/spi_esp32_spim.c @@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(esp32_spi, CONFIG_SPI_LOG_LEVEL); #include #include #include -#include +#include "spi_rtio.h" #include #ifdef SOC_GDMA_SUPPORTED #include diff --git a/drivers/spi/spi_gd32.c b/drivers/spi/spi_gd32.c index acc29859f63f..9f99cd8f1a03 100644 --- a/drivers/spi/spi_gd32.c +++ b/drivers/spi/spi_gd32.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include "spi_rtio.h" #ifdef CONFIG_SPI_GD32_DMA #include #include diff --git a/drivers/spi/spi_grlib_spimctrl.c b/drivers/spi/spi_grlib_spimctrl.c index 463cd6b8c922..f9c297fee6a4 100644 --- a/drivers/spi/spi_grlib_spimctrl.c +++ b/drivers/spi/spi_grlib_spimctrl.c @@ -7,7 +7,7 @@ #define DT_DRV_COMPAT gaisler_spimctrl #include -#include +#include "spi_rtio.h" #include LOG_MODULE_REGISTER(spi_spimctrl); diff --git a/drivers/spi/spi_infineon.c b/drivers/spi/spi_infineon.c index 33bb70440853..97fd673ad744 100644 --- a/drivers/spi/spi_infineon.c +++ b/drivers/spi/spi_infineon.c @@ -15,7 +15,7 @@ LOG_MODULE_REGISTER(cat1_spi); #include #include -#include +#include "spi_rtio.h" #include #include diff --git a/drivers/spi/spi_litex_common.h b/drivers/spi/spi_litex_common.h index 14a52b0ae93b..ca078c295e57 100644 --- a/drivers/spi/spi_litex_common.h +++ b/drivers/spi/spi_litex_common.h @@ -6,7 +6,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include diff --git a/drivers/spi/spi_max32.c b/drivers/spi/spi_max32.c index ee533d46e700..8c2927b43511 100644 --- a/drivers/spi/spi_max32.c +++ b/drivers/spi/spi_max32.c @@ -13,7 +13,7 @@ #endif #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_mchp_mss.c b/drivers/spi/spi_mchp_mss.c index 336edf0ae45a..ec3ec5bb1f51 100644 --- a/drivers/spi/spi_mchp_mss.c +++ b/drivers/spi/spi_mchp_mss.c @@ -8,7 +8,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_mchp_mss_qspi.c b/drivers/spi/spi_mchp_mss_qspi.c index 33b673d046b6..a3b4da14fa05 100644 --- a/drivers/spi/spi_mchp_mss_qspi.c +++ b/drivers/spi/spi_mchp_mss_qspi.c @@ -8,7 +8,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_mchp_sercom_g1.c b/drivers/spi/spi_mchp_sercom_g1.c index 3d16c467d891..6c68c6a9f7ce 100644 --- a/drivers/spi/spi_mchp_sercom_g1.c +++ b/drivers/spi/spi_mchp_sercom_g1.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include "spi_rtio.h" #include #include #if CONFIG_SPI_MCHP_DMA_DRIVEN diff --git a/drivers/spi/spi_mcux_dspi.c b/drivers/spi/spi_mcux_dspi.c index e5211eaff840..0bd108d3531a 100644 --- a/drivers/spi/spi_mcux_dspi.c +++ b/drivers/spi/spi_mcux_dspi.c @@ -9,7 +9,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_mcux_ecspi.c b/drivers/spi/spi_mcux_ecspi.c index 8138e7fdc2a7..061e245f8def 100644 --- a/drivers/spi/spi_mcux_ecspi.c +++ b/drivers/spi/spi_mcux_ecspi.c @@ -13,7 +13,7 @@ LOG_MODULE_REGISTER(spi_mcux_ecspi, CONFIG_SPI_LOG_LEVEL); #include #include #include -#include +#include "spi_rtio.h" #include #include "spi_context.h" diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index dfbf734144ec..f0b1c0290125 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -9,7 +9,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_mcux_flexio.c b/drivers/spi/spi_mcux_flexio.c index 1f4a4ebe158b..b8bef5589e51 100644 --- a/drivers/spi/spi_mcux_flexio.c +++ b/drivers/spi/spi_mcux_flexio.c @@ -9,7 +9,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_npcx_spip.c b/drivers/spi/spi_npcx_spip.c index 8263fe9e8783..9df2dc5e9178 100644 --- a/drivers/spi/spi_npcx_spip.c +++ b/drivers/spi/spi_npcx_spip.c @@ -7,7 +7,7 @@ #define DT_DRV_COMPAT nuvoton_npcx_spip #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index 3b27a05c85f3..4e9cd84cb687 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -5,7 +5,7 @@ */ #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 7496c54958f4..075dbad20f66 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -7,7 +7,7 @@ #define DT_DRV_COMPAT nordic_nrf_spim #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_nrfx_spis.c b/drivers/spi/spi_nrfx_spis.c index 1f667fb8b289..c06c8e263f5c 100644 --- a/drivers/spi/spi_nrfx_spis.c +++ b/drivers/spi/spi_nrfx_spis.c @@ -7,7 +7,7 @@ #define DT_DRV_COMPAT nordic_nrf_spis #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_numaker.c b/drivers/spi/spi_numaker.c index dc5e0327634b..c8681c1b01d9 100644 --- a/drivers/spi/spi_numaker.c +++ b/drivers/spi/spi_numaker.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include "spi_rtio.h" #include LOG_MODULE_REGISTER(spi_numaker, CONFIG_SPI_LOG_LEVEL); 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 3bf662818eda..ee42c0dc43ce 100644 --- a/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h +++ b/drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi_priv.h @@ -8,12 +8,12 @@ #define ZEPHYR_DRIVERS_SPI_SPI_NXP_LPSPI_PRIV_H_ #include -#include #include #include #include #include +#include "../spi_rtio.h" #include "../spi_context.h" #if CONFIG_NXP_LP_FLEXCOMM diff --git a/drivers/spi/spi_nxp_s32.h b/drivers/spi/spi_nxp_s32.h index 4f6fe6a9b0c0..18ff0ef167d7 100644 --- a/drivers/spi/spi_nxp_s32.h +++ b/drivers/spi/spi_nxp_s32.h @@ -7,7 +7,7 @@ #define ZEPHYR_DRIVERS_SPI_SPI_NXP_S32_H_ #include -#include +#include "spi_rtio.h" #include #define LOG_LEVEL CONFIG_SPI_LOG_LEVEL diff --git a/drivers/spi/spi_oc_simple.c b/drivers/spi/spi_oc_simple.c index d3069366bf71..77789e719e5b 100644 --- a/drivers/spi/spi_oc_simple.c +++ b/drivers/spi/spi_oc_simple.c @@ -12,7 +12,7 @@ LOG_MODULE_REGISTER(spi_oc_simple); #include #include -#include +#include "spi_rtio.h" #include "spi_context.h" #include "spi_oc_simple.h" diff --git a/drivers/spi/spi_opentitan.c b/drivers/spi/spi_opentitan.c index efcf4d0298c4..9e9bf2d0109b 100644 --- a/drivers/spi/spi_opentitan.c +++ b/drivers/spi/spi_opentitan.c @@ -11,7 +11,7 @@ LOG_MODULE_REGISTER(spi_opentitan); #include #include -#include +#include "spi_rtio.h" #include #include diff --git a/drivers/spi/spi_pl022.c b/drivers/spi/spi_pl022.c index 9a2c493d99f8..8c47247bb862 100644 --- a/drivers/spi/spi_pl022.c +++ b/drivers/spi/spi_pl022.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_psoc6.c b/drivers/spi/spi_psoc6.c index cfbc2880d7f8..f9aa3088c634 100644 --- a/drivers/spi/spi_psoc6.c +++ b/drivers/spi/spi_psoc6.c @@ -15,7 +15,7 @@ LOG_MODULE_REGISTER(spi_psoc6); #include #include #include -#include +#include "spi_rtio.h" #include #include "spi_context.h" diff --git a/drivers/spi/spi_pw.c b/drivers/spi/spi_pw.c index cff2135976cb..ee024884df4c 100644 --- a/drivers/spi/spi_pw.c +++ b/drivers/spi/spi_pw.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include "spi_rtio.h" #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "DT need CONFIG_PCIE"); diff --git a/drivers/spi/spi_renesas_rz.c b/drivers/spi/spi_renesas_rz.c index 34dc519db6b1..28a0b47310cf 100644 --- a/drivers/spi/spi_renesas_rz.c +++ b/drivers/spi/spi_renesas_rz.c @@ -13,7 +13,7 @@ #include #include "r_spi.h" #ifdef CONFIG_SPI_RTIO -#include +#include "spi_rtio.h" #include #endif #include diff --git a/drivers/spi/spi_renesas_rz_rspi.c b/drivers/spi/spi_renesas_rz_rspi.c index 6576572f15b5..75b1dd2ac649 100644 --- a/drivers/spi/spi_renesas_rz_rspi.c +++ b/drivers/spi/spi_renesas_rz_rspi.c @@ -16,7 +16,7 @@ #include "r_dmac_b.h" #endif #ifdef CONFIG_SPI_RTIO -#include +#include "spi_rtio.h" #include #endif #include diff --git a/drivers/spi/spi_rtio.c b/drivers/spi/spi_rtio.c index 5dbe44064042..7fd38fd0c235 100644 --- a/drivers/spi/spi_rtio.c +++ b/drivers/spi/spi_rtio.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include "spi_rtio.h" #include #include diff --git a/include/zephyr/drivers/spi/rtio.h b/drivers/spi/spi_rtio.h similarity index 100% rename from include/zephyr/drivers/spi/rtio.h rename to drivers/spi/spi_rtio.h diff --git a/drivers/spi/spi_rv32m1_lpspi.c b/drivers/spi/spi_rv32m1_lpspi.c index 16f5d52e7a4f..b80cec2ac790 100644 --- a/drivers/spi/spi_rv32m1_lpspi.c +++ b/drivers/spi/spi_rv32m1_lpspi.c @@ -10,7 +10,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_sam.c b/drivers/spi/spi_sam.c index 68e726bef63b..12d2ce68df11 100644 --- a/drivers/spi/spi_sam.c +++ b/drivers/spi/spi_sam.c @@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(spi_sam); #include #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_sam0.c b/drivers/spi/spi_sam0.c index 5c48c0bbc99f..594b756e1705 100644 --- a/drivers/spi/spi_sam0.c +++ b/drivers/spi/spi_sam0.c @@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(spi_sam0); #include #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_sedi.c b/drivers/spi/spi_sedi.c index 9f6a9bc28940..dd7190a4238c 100644 --- a/drivers/spi/spi_sedi.c +++ b/drivers/spi/spi_sedi.c @@ -8,7 +8,7 @@ #include #include -#include +#include "spi_rtio.h" #include #define LOG_LEVEL CONFIG_SPI_LOG_LEVEL diff --git a/drivers/spi/spi_sifive.h b/drivers/spi/spi_sifive.h index 255f76c95fe8..4c4bcf418457 100644 --- a/drivers/spi/spi_sifive.h +++ b/drivers/spi/spi_sifive.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include "spi_rtio.h" #include #define SPI_CFG(dev) ((struct spi_sifive_cfg *) ((dev)->config)) diff --git a/drivers/spi/spi_silabs_eusart.c b/drivers/spi/spi_silabs_eusart.c index 49963776247f..1342f34c7ae3 100644 --- a/drivers/spi/spi_silabs_eusart.c +++ b/drivers/spi/spi_silabs_eusart.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_silabs_siwx91x_gspi.c b/drivers/spi/spi_silabs_siwx91x_gspi.c index 3ecea64e3b38..bfebd7b1b19a 100644 --- a/drivers/spi/spi_silabs_siwx91x_gspi.c +++ b/drivers/spi/spi_silabs_siwx91x_gspi.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_silabs_usart.c b/drivers/spi/spi_silabs_usart.c index 9e167c8e217e..40da9ae6f7f4 100644 --- a/drivers/spi/spi_silabs_usart.c +++ b/drivers/spi/spi_silabs_usart.c @@ -14,7 +14,7 @@ LOG_MODULE_REGISTER(spi_silabs_usart); #include #include #include -#include +#include "spi_rtio.h" #include #include "em_cmu.h" diff --git a/drivers/spi/spi_smartbond.c b/drivers/spi/spi_smartbond.c index 6a54eb6eec2b..fad6ab825e39 100644 --- a/drivers/spi/spi_smartbond.c +++ b/drivers/spi/spi_smartbond.c @@ -15,7 +15,7 @@ LOG_MODULE_REGISTER(spi_smartbond); #include #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_stm32.c b/drivers/spi/spi_stm32.c index 5f134e6c681c..f3fdf1c6eb24 100644 --- a/drivers/spi/spi_stm32.c +++ b/drivers/spi/spi_stm32.c @@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(spi_stm32); #include #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_test.c b/drivers/spi/spi_test.c index 081aa6bfbf5e..a5c5eb8b36de 100644 --- a/drivers/spi/spi_test.c +++ b/drivers/spi/spi_test.c @@ -11,7 +11,7 @@ #include #include -#include +#include "spi_rtio.h" #define DT_DRV_COMPAT vnd_spi diff --git a/drivers/spi/spi_wch.c b/drivers/spi/spi_wch.c index 023b87e6af0c..80a0a63eb116 100644 --- a/drivers/spi/spi_wch.c +++ b/drivers/spi/spi_wch.c @@ -13,7 +13,7 @@ LOG_MODULE_REGISTER(spi_wch); #include #include #include -#include +#include "spi_rtio.h" #include #include diff --git a/drivers/spi/spi_xec_qmspi.c b/drivers/spi/spi_xec_qmspi.c index c552377ba1c2..11f5ef8e87d0 100644 --- a/drivers/spi/spi_xec_qmspi.c +++ b/drivers/spi/spi_xec_qmspi.c @@ -13,7 +13,7 @@ LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL); #include #include #include -#include +#include "spi_rtio.h" #include #include diff --git a/drivers/spi/spi_xlnx_axi_quadspi.c b/drivers/spi/spi_xlnx_axi_quadspi.c index 33918728e8ca..ed71924ae7a4 100644 --- a/drivers/spi/spi_xlnx_axi_quadspi.c +++ b/drivers/spi/spi_xlnx_axi_quadspi.c @@ -8,7 +8,7 @@ #include #include -#include +#include "spi_rtio.h" #include #include #include diff --git a/drivers/spi/spi_xmc4xxx.c b/drivers/spi/spi_xmc4xxx.c index fc4cf86f60a5..0d68e73a7e12 100644 --- a/drivers/spi/spi_xmc4xxx.c +++ b/drivers/spi/spi_xmc4xxx.c @@ -15,7 +15,7 @@ LOG_MODULE_REGISTER(spi_xmc4xxx); #include #include #include -#include +#include "spi_rtio.h" #include #include From 2a5f3059480831d56626490fe1d43b746d0e85f1 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Wed, 4 Feb 2026 14:51:01 +0100 Subject: [PATCH 06/20] [nrf fromtree] drivers: spi: rtio: introduce nrfx spim rtio Introduce support for NRF SPIM device based on RTIO. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 6f2829ea0cc31a2705cc27ad92f9907fc603cc62) (cherry picked from commit 29813dae72b42a266637b9560247fd8e61aac31d) --- drivers/spi/CMakeLists.txt | 1 + drivers/spi/Kconfig.nrfx | 19 + drivers/spi/spi_nrfx_spim_common.c | 819 +++++++++++++++++++++++++++++ drivers/spi/spi_nrfx_spim_common.h | 219 ++++++++ drivers/spi/spi_nrfx_spim_rtio.c | 283 ++++++++++ 5 files changed, 1341 insertions(+) create mode 100644 drivers/spi/spi_nrfx_spim_common.c create mode 100644 drivers/spi/spi_nrfx_spim_common.h create mode 100644 drivers/spi/spi_nrfx_spim_rtio.c diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 2b4f8e20cda1..998098614e48 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -45,6 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_FLEXIO spi_mcux_flexio.c) zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_SPIP spi_npcx_spip.c) zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPI spi_nrfx_spi.c spi_nrfx_common.c) zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM spi_nrfx_spim.c spi_nrfx_common.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM_RTIO spi_nrfx_spim_rtio.c spi_nrfx_spim_common.c) zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIS spi_nrfx_spis.c) zephyr_library_sources_ifdef(CONFIG_SPI_NUMAKER spi_numaker.c) zephyr_library_sources_ifdef(CONFIG_SPI_OC_SIMPLE spi_oc_simple.c) diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index b391b919beff..0f072da1bf15 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -20,8 +20,27 @@ config SPI_NRFX_SPI config SPI_NRFX_SPIM def_bool y depends on DT_HAS_NORDIC_NRF_SPIM_ENABLED + depends on !SPI_RTIO select NRFX_SPIM +config SPI_NRFX_SPIM_RTIO + def_bool y + depends on DT_HAS_NORDIC_NRF_SPIM_ENABLED + depends on SPI_RTIO + select NRFX_SPIM + +if SPI_NRFX_SPIM_RTIO + +config SPI_NRFX_SPIM_RTIO_SQE_POOL_SIZE + int "Size of SQE pool size for NRFX SPIM RTIO context" + default 8 + +config SPI_NRFX_SPIM_RTIO_CQE_POOL_SIZE + int "Size of SQE pool size for NRFX SPIM RTIO context" + default 8 + +endif # SPI_NRFX_SPIM_RTIO + config SPI_NRFX_SPIS def_bool y depends on DT_HAS_NORDIC_NRF_SPIS_ENABLED diff --git a/drivers/spi/spi_nrfx_spim_common.c b/drivers/spi/spi_nrfx_spim_common.c new file mode 100644 index 000000000000..ad630083d2a9 --- /dev/null +++ b/drivers/spi/spi_nrfx_spim_common.c @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2026 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "spi_nrfx_spim_common.h" + +#include + +#ifdef CONFIG_SOC_NRF5340_CPUAPP +#include +#endif + +#define WAKE_PIN_START_FLAGS (GPIO_INPUT | GPIO_PULL_UP) +#define WAKE_PIN_STOP_FLAGS (GPIO_INPUT | GPIO_PULL_DOWN | GPIO_DISCONNECTED) + +LOG_MODULE_REGISTER(spi_nrfx_spim, CONFIG_SPI_LOG_LEVEL); + +#if SPI_NRFX_HAS_WAKE +void spi_nrfx_spim_common_wake_start(const struct device *dev, + spi_nrfx_data_common_wake_handler handler) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + + dev_data->wake_handler = handler; + + k_timer_start(&dev_data->wake_timer, + K_USEC(CONFIG_SPI_NRFX_WAKE_TIMEOUT_US), + K_FOREVER); + + gpio_pin_configure_dt(&dev_config->wake_pin, WAKE_PIN_START_FLAGS); + gpio_pin_interrupt_configure_dt(&dev_config->wake_pin, GPIO_INT_EDGE_FALLING); +} + +#else + +void spi_nrfx_spim_common_wake_start(const struct device *dev, + spi_nrfx_data_common_wake_handler handler) +{ + handler(dev); +} +#endif + +void spi_nrfx_spim_common_cs_set(const struct device *dev, const struct spi_config *spi_cfg) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + NRF_SPIM_Type *spim_reg = dev_data->spim.p_reg; + + if (spi_cfg->cs.cs_is_gpio == false && NRF_SPIM_IS_320MHZ_SPIM(spim_reg) == false) { + return; + } + + if (spi_cfg->cs.cs_is_gpio) { + gpio_pin_set_dt(&spi_cfg->cs.gpio, 1); + } else { + nrfy_spim_enable(spim_reg); + } + + k_busy_wait(spi_cfg->cs.delay); +} + +void spi_nrfx_spim_common_cs_clear(const struct device *dev, const struct spi_config *spi_cfg) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + NRF_SPIM_Type *spim_reg = dev_data->spim.p_reg; + + if (spi_cfg->cs.cs_is_gpio == false && NRF_SPIM_IS_320MHZ_SPIM(spim_reg) == false) { + return; + } + + k_busy_wait(spi_cfg->cs.delay); + + if (spi_cfg->cs.cs_is_gpio) { + gpio_pin_set_dt(&spi_cfg->cs.gpio, 0); + } else { + nrfy_spim_disable(spim_reg); + } +} + +static void evt_handler(nrfx_spim_event_t const *evt, void *data) +{ + const struct device *dev = data; + const struct spi_nrfx_common_config *dev_config = dev->config; + + dev_config->evt_handler(dev, (nrfx_spim_event_t *)evt); +} + +static void spi_config_copy(struct spi_config *des, const struct spi_config *src) +{ + memcpy(des, src, sizeof(struct spi_config)); +} + +static bool spi_config_equal(const struct spi_config *a, const struct spi_config *b) +{ + if (a->frequency != b->frequency || + a->operation != b->operation || + a->slave != b->slave || + a->cs.cs_is_gpio != b->cs.cs_is_gpio || + a->word_delay != b->word_delay) { + return false; + } + + if (a->cs.cs_is_gpio) { + if (a->cs.gpio.port != b->cs.gpio.port || + a->cs.gpio.pin != b->cs.gpio.pin || + a->cs.gpio.dt_flags != b->cs.gpio.dt_flags || + a->cs.delay != b->cs.delay) { + return false; + } + } else { + if (a->cs.setup_ns != b->cs.setup_ns || + a->cs.hold_ns != b->cs.hold_ns) { + return false; + } + } + + return true; +} + +static nrf_spim_mode_t mode_from_op(uint16_t operation) +{ + if (SPI_MODE_GET(operation) & SPI_MODE_CPOL) { + if (SPI_MODE_GET(operation) & SPI_MODE_CPHA) { + return NRF_SPIM_MODE_3; + } else { + return NRF_SPIM_MODE_2; + } + } else { + if (SPI_MODE_GET(operation) & SPI_MODE_CPHA) { + return NRF_SPIM_MODE_1; + } else { + return NRF_SPIM_MODE_0; + } + } +} + +static nrf_spim_bit_order_t bit_order_from_op(uint16_t operation) +{ + if (operation & SPI_TRANSFER_LSB) { + return NRF_SPIM_BIT_ORDER_LSB_FIRST; + } else { + return NRF_SPIM_BIT_ORDER_MSB_FIRST; + } +} + +uint32_t resolve_freq(uint32_t frequency) +{ +#if defined(CONFIG_SOC_NRF5340_CPUAPP) + /* + * On nRF5340, the 32 Mbps speed is supported by the application core + * when it is running at 128 MHz (see the Timing specifications section + * in the nRF5340 PS). + */ + if (frequency > MHZ(16) && + nrf_clock_hfclk_div_get(NRF_CLOCK) != NRF_CLOCK_HFCLK_DIV_1) { + frequency = MHZ(16); + } +#endif + + if (NRF_SPIM_HAS_PRESCALER) { + return frequency; + } + + /* Get the highest supported frequency not exceeding the requested one */ + if (frequency >= MHZ(32) && NRF_SPIM_HAS_32_MHZ_FREQ) { + return MHZ(32); + } else if (frequency >= MHZ(16) && NRF_SPIM_HAS_16_MHZ_FREQ) { + return MHZ(16); + } else if (frequency >= MHZ(8)) { + return MHZ(8); + } else if (frequency >= MHZ(4)) { + return MHZ(4); + } else if (frequency >= MHZ(2)) { + return MHZ(2); + } else if (frequency >= MHZ(1)) { + return MHZ(1); + } else if (frequency >= KHZ(500)) { + return KHZ(500); + } else if (frequency >= KHZ(250)) { + return KHZ(250); + } else { + return KHZ(125); + } +} + +#if SPI_NRFX_HAS_RAM_BUF || CONFIG_HAS_NORDIC_DMM +#if SPI_NRFX_HAS_RAM_BUF +static int prepare_tx_ram_buf(const struct device *dev, + const uint8_t **tx_buf, + size_t tx_buf_len) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + NRF_SPIM_Type *spim_reg = dev_data->spim.p_reg; + + if (nrf_dma_accessible_check(spim_reg, *tx_buf)) { + return 0; + } + + if (tx_buf_len > SPI_NRFX_RAM_BUF_SIZE) { + return -ENOSPC; + } + + memcpy(dev_config->tx_ram_buf, *tx_buf, tx_buf_len); + *tx_buf = dev_config->tx_ram_buf; + return 0; +} + +static int prepare_rx_ram_buf(const struct device *dev, + uint8_t **rx_buf, + size_t rx_buf_len) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + NRF_SPIM_Type *spim_reg = dev_data->spim.p_reg; + + if (nrf_dma_accessible_check(spim_reg, *rx_buf)) { + return 0; + } + + if (rx_buf_len > SPI_NRFX_RAM_BUF_SIZE) { + return -ENOSPC; + } + + *rx_buf = dev_config->rx_ram_buf; + return 0; +} + +static void release_rx_ram_buf(const struct device *dev, const uint8_t *rx_buf) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + + if (rx_buf == dev_data->rx_user_buf) { + return; + } + + if (rx_buf != dev_config->rx_ram_buf) { + return; + } + + memcpy(dev_data->rx_user_buf, rx_buf, dev_data->rx_user_buf_len); +} + +#else /* SPI_NRFX_HAS_RAM_BUF */ + +static int prepare_tx_ram_buf(const struct device *dev, + const uint8_t **tx_buf, + size_t tx_buf_len) +{ + ARG_UNUSED(dev); + ARG_UNUSED(tx_buf); + ARG_UNUSED(tx_buf_len); + return 0; +} + +static int prepare_rx_ram_buf(const struct device *dev, + uint8_t **rx_buf, + size_t rx_buf_len) +{ + ARG_UNUSED(dev); + ARG_UNUSED(rx_buf); + ARG_UNUSED(rx_buf_len); + return 0; +} + +static void release_rx_ram_buf(const struct device *dev, const uint8_t *rx_buf) +{ + ARG_UNUSED(dev); + ARG_UNUSED(rx_buf); +} +#endif /* SPI_NRFX_HAS_RAM_BUF */ + +#if CONFIG_HAS_NORDIC_DMM +static int prepare_tx_dmm_buf(const struct device *dev, + const uint8_t **tx_buf, + size_t tx_buf_len) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + + if (*tx_buf == NULL || tx_buf_len == 0) { + return 0; + } + + return dmm_buffer_out_prepare(dev_config->mem_reg, + (void *)*tx_buf, + tx_buf_len, + (void **)tx_buf); +} + +static int prepare_rx_dmm_buf(const struct device *dev, + uint8_t **rx_buf, + size_t rx_buf_len) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + + if (*rx_buf == NULL || rx_buf_len == 0) { + return 0; + } + + return dmm_buffer_in_prepare(dev_config->mem_reg, + *rx_buf, + rx_buf_len, + (void **)rx_buf); +} + +static void release_tx_dmm_buf(const struct device *dev, const uint8_t *tx_buf) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + + dmm_buffer_out_release(dev_config->mem_reg, (void *)tx_buf); +} + +static void release_rx_dmm_buf(const struct device *dev, const uint8_t *rx_buf) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + + dmm_buffer_in_release(dev_config->mem_reg, + dev_data->rx_user_buf, + dev_data->rx_user_buf_len, + (void *)rx_buf); +} + +#else /* CONFIG_HAS_NORDIC_DMM */ + +static int prepare_tx_dmm_buf(const struct device *dev, + const uint8_t **tx_buf, + size_t tx_buf_len) +{ + ARG_UNUSED(dev); + ARG_UNUSED(tx_buf); + ARG_UNUSED(tx_buf_len); + return 0; +} + +static int prepare_rx_dmm_buf(const struct device *dev, + uint8_t **rx_buf, + size_t rx_buf_len) +{ + ARG_UNUSED(dev); + ARG_UNUSED(rx_buf); + ARG_UNUSED(rx_buf_len); + return 0; +} + +static void release_tx_dmm_buf(const struct device *dev, const uint8_t *tx_buf) +{ + ARG_UNUSED(dev); + ARG_UNUSED(tx_buf); +} + +static void release_rx_dmm_buf(const struct device *dev, const uint8_t *rx_buf) +{ + ARG_UNUSED(dev); + ARG_UNUSED(rx_buf); +} +#endif /* CONFIG_HAS_NORDIC_DMM */ + +static int prepare_tx_buf(const struct device *dev, + const uint8_t **tx_buf, + size_t tx_buf_len) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + int ret; + + dev_data->tx_user_buf = *tx_buf; + + ret = prepare_tx_ram_buf(dev, tx_buf, tx_buf_len); + if (ret) { + return ret; + } + + ret = prepare_tx_dmm_buf(dev, tx_buf, tx_buf_len); + if (ret) { + return ret; + } + + return 0; +} + +static int prepare_rx_buf(const struct device *dev, + uint8_t **rx_buf, + size_t rx_buf_len) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + int ret; + + dev_data->rx_user_buf = *rx_buf; + dev_data->rx_user_buf_len = rx_buf_len; + + ret = prepare_rx_ram_buf(dev, rx_buf, rx_buf_len); + if (ret) { + return ret; + } + + ret = prepare_rx_dmm_buf(dev, rx_buf, rx_buf_len); + if (ret) { + return ret; + } + + return 0; +} + +static void release_tx_buf(const struct device *dev, const uint8_t *tx_buf) +{ + release_tx_dmm_buf(dev, tx_buf); +} + +static void release_rx_buf(const struct device *dev, const uint8_t *rx_buf) +{ + release_rx_ram_buf(dev, rx_buf); + release_rx_dmm_buf(dev, rx_buf); +} + +#else /* SPI_NRFX_HAS_RAM_BUF || CONFIG_HAS_NORDIC_DMM */ + +static int prepare_tx_buf(const struct device *dev, + const uint8_t **tx_buf, + size_t tx_buf_len) +{ + ARG_UNUSED(dev); + ARG_UNUSED(tx_buf); + ARG_UNUSED(tx_buf_len); + return 0; +} + +static int prepare_rx_buf(const struct device *dev, + uint8_t **rx_buf, + size_t rx_buf_len) +{ + ARG_UNUSED(dev); + ARG_UNUSED(rx_buf); + ARG_UNUSED(rx_buf_len); + return 0; +} + +static void release_tx_buf(const struct device *dev, const uint8_t *tx_buf) +{ + ARG_UNUSED(dev); + ARG_UNUSED(tx_buf); +} + +static void release_rx_buf(const struct device *dev, const uint8_t *rx_buf) +{ + ARG_UNUSED(dev); + ARG_UNUSED(rx_buf); +} +#endif /* SPI_NRFX_HAS_RAM_BUF || CONFIG_HAS_NORDIC_DMM */ + +int spi_nrfx_spim_common_transfer_start(const struct device *dev, + const uint8_t *tx_buf, + size_t tx_buf_len, + uint8_t *rx_buf, + size_t rx_buf_len) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + nrfx_spim_t *spim = &dev_data->spim; + struct nrfy_spim_xfer_desc_t xfer; + int ret; + + if (tx_buf_len > dev_config->max_transfer_len || + rx_buf_len > dev_config->max_transfer_len) { + return -EINVAL; + } + + ret = prepare_tx_buf(dev, &tx_buf, tx_buf_len); + if (ret) { + return ret; + } + + ret = prepare_rx_buf(dev, &rx_buf, rx_buf_len); + if (ret) { + release_tx_buf(dev, tx_buf); + return ret; + } + + /* Set the accessible and aligned buffers */ + xfer.p_tx_buffer = (uint8_t *)tx_buf, + xfer.tx_length = tx_buf_len, + xfer.p_rx_buffer = rx_buf, + xfer.rx_length = rx_buf_len, + + ret = nrfx_spim_xfer(spim, &xfer, 0); + if (ret) { + release_tx_buf(dev, tx_buf); + release_rx_buf(dev, rx_buf); + return ret; + } + + return 0; +} + +void spi_nrfx_spim_common_transfer_stop(const struct device *dev) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + nrfx_spim_t *spim = &dev_data->spim; + + nrfx_spim_abort(spim); +} + +void spi_nrfx_spim_common_transfer_end(const struct device *dev, + const nrfx_spim_xfer_desc_t *xfer) +{ + release_tx_buf(dev, (const uint8_t *)xfer->p_tx_buffer); + release_rx_buf(dev, (const uint8_t *)xfer->p_rx_buffer); +} + +int spi_nrfx_spim_common_configure(const struct device *dev, const struct spi_config *spi_cfg) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + nrfx_spim_config_t spim_cfg; + int ret; + + if (dev_data->configured && spi_config_equal(&dev_data->spi_cfg, spi_cfg)) { + return 0; + } + + if (spi_cfg->operation & SPI_HALF_DUPLEX) { + LOG_ERR("Half-duplex not supported"); + return -ENOTSUP; + } + + if (SPI_OP_MODE_GET(spi_cfg->operation) != SPI_OP_MODE_MASTER) { + LOG_ERR("Slave mode is not supported on %s", dev->name); + return -EINVAL; + } + + if (spi_cfg->operation & SPI_MODE_LOOP) { + LOG_ERR("Loopback mode is not supported"); + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && + (spi_cfg->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_ERR("Only single line mode is supported"); + return -EINVAL; + } + + if (SPI_WORD_SIZE_GET(spi_cfg->operation) != 8) { + LOG_ERR("Word sizes other than 8 bits are not supported"); + return -EINVAL; + } + + if (spi_cfg->frequency < KHZ(125)) { + LOG_ERR("Frequencies lower than 125 kHz are not supported"); + return -EINVAL; + } + + spim_cfg.ss_pin = NRF_SPIM_PIN_NOT_CONNECTED; + spim_cfg.orc = dev_config->orc; + spim_cfg.frequency = resolve_freq(spi_cfg->frequency); + spim_cfg.mode = mode_from_op(spi_cfg->operation); + spim_cfg.bit_order = bit_order_from_op(spi_cfg->operation); +#if NRF_SPIM_HAS_DCX + spim_cfg.dcx_pin = NRF_SPIM_PIN_NOT_CONNECTED; +#endif +#if NRF_SPIM_HAS_RXDELAY + spim_cfg.rx_delay = dev_config->rx_delay; +#endif + spim_cfg.skip_gpio_cfg = true; + spim_cfg.skip_psel_cfg = true; + + if (dev_data->configured) { + ret = nrfx_spim_reconfigure(&dev_data->spim, &spim_cfg); + } else { + ret = nrfx_spim_init(&dev_data->spim, &spim_cfg, evt_handler, (void *)dev); + } + + if (ret) { + LOG_ERR("Failed to configure nrfx driver: %d", ret); + return ret; + } + +#if defined(CONFIG_NRF52_ANOMALY_58_WORKAROUND) +#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpiote), okay) + nrfx_spim_nrf52_anomaly_58_init(&dev_data->spim, + &GPIOTE_NRFX_INST_BY_NODE(DT_NODELABEL(gpiote))); +#else +#error "GPIOTE is not enabled, anomaly 58 workaround cannot be applied for SPIM" +#endif +#endif + + spi_config_copy(&dev_data->spi_cfg, spi_cfg); + dev_data->configured = true; + return 0; +} + +static int cs_put(const struct device *dev) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + const struct gpio_dt_spec *cs_gpios = dev_config->cs_gpios; + const uint8_t cs_gpios_size = dev_config->cs_gpios_size; + int ret; + + for (size_t i = 0; i < cs_gpios_size; i++) { + ret = pm_device_runtime_put(cs_gpios[i].port); + if (ret) { + return ret; + } + } + + return 0; +} + +static int pm_suspend(const struct device *dev) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + int ret; + + if (dev_data->configured) { + nrfx_spim_uninit(&dev_data->spim); + dev_data->configured = false; + } + + ret = cs_put(dev); + if (ret) { + return ret; + } + + ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); + if (ret) { + return ret; + } + + return 0; +} + +static int cs_get(const struct device *dev) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + const struct gpio_dt_spec *cs_gpios = dev_config->cs_gpios; + const uint8_t cs_gpios_size = dev_config->cs_gpios_size; + int ret; + + for (size_t i = 0; i < cs_gpios_size; i++) { + ret = pm_device_runtime_get(cs_gpios[i].port); + if (ret) { + return ret; + } + } + + return 0; +} + +static int pm_resume(const struct device *dev) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + int ret; + + ret = cs_get(dev); + if (ret) { + return ret; + } + + ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + return 0; +} + +int spi_nrfx_spim_common_pm_action(const struct device *dev, enum pm_device_action action) +{ + int ret; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + ret = pm_suspend(dev); + break; + + case PM_DEVICE_ACTION_RESUME: + ret = pm_resume(dev); + break; + + case PM_DEVICE_ACTION_TURN_OFF: + case PM_DEVICE_ACTION_TURN_ON: + ret = -ENOTSUP; + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int cs_init(const struct device *dev) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + const struct gpio_dt_spec *cs_gpios = dev_config->cs_gpios; + const uint8_t cs_gpios_size = dev_config->cs_gpios_size; + int ret; + + for (size_t i = 0; i < cs_gpios_size; i++) { + ret = gpio_pin_configure_dt(&cs_gpios[i], GPIO_OUTPUT_INACTIVE); + if (ret) { + return ret; + } + } + + return 0; +} + +#if SPI_NRFX_HAS_WAKE +static void wake_stop(const struct device *dev) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + + gpio_pin_interrupt_configure_dt(&dev_config->wake_pin, GPIO_INT_DISABLE); + gpio_pin_configure_dt(&dev_config->wake_pin, WAKE_PIN_STOP_FLAGS); + + dev_data->wake_handler(dev_data->dev); +} + +static void wake_pin_callback_handler(const struct device *port, + struct gpio_callback *cb, + uint32_t pins) +{ + struct spi_nrfx_common_data *dev_data = + CONTAINER_OF(cb, struct spi_nrfx_common_data, wake_pin_callback); + + ARG_UNUSED(port); + ARG_UNUSED(pins); + + k_timer_stop(&dev_data->wake_timer); + + if (k_timer_status_get(&dev_data->wake_timer)) { + return; + } + + wake_stop(dev_data->dev); +} + +static void wake_timer_expired_handler(struct k_timer *timer) +{ + struct spi_nrfx_common_data *dev_data = + CONTAINER_OF(timer, struct spi_nrfx_common_data, wake_timer); + + wake_stop(dev_data->dev); +} + +static int wake_init(const struct device *dev) +{ + struct spi_nrfx_common_data *dev_data = dev->data; + const struct spi_nrfx_common_config *dev_config = dev->config; + int ret; + + ret = gpio_pin_configure_dt(&dev_config->wake_pin, WAKE_PIN_STOP_FLAGS); + if (ret) { + return ret; + } + + gpio_init_callback(&dev_data->wake_pin_callback, + wake_pin_callback_handler, + BIT(dev_config->wake_pin.pin)); + + ret = gpio_add_callback(dev_config->wake_pin.port, &dev_data->wake_pin_callback); + if (ret) { + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&dev_config->wake_pin, GPIO_INT_DISABLE); + if (ret) { + return ret; + } + + k_timer_init(&dev_data->wake_timer, wake_timer_expired_handler, NULL); + return 0; +} + +#else + +static int wake_init(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} +#endif + +int spi_nrfx_spim_common_init(const struct device *dev) +{ + const struct spi_nrfx_common_config *dev_config = dev->config; + int ret; + + dev_config->irq_connect(); + + ret = cs_init(dev); + if (ret) { + return ret; + } + + ret = wake_init(dev); + if (ret) { + return ret; + } + + ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); + if (ret) { + return ret; + } + + return 0; +} + +#ifdef CONFIG_DEVICE_DEINIT_SUPPORT +int spi_nrfx_spim_common_deinit(const struct device *dev) +{ + return pm_device_driver_deinit(dev, spi_nrfx_spim_common_pm_action); +} +#endif diff --git a/drivers/spi/spi_nrfx_spim_common.h b/drivers/spi/spi_nrfx_spim_common.h new file mode 100644 index 000000000000..6eb125b3c2f5 --- /dev/null +++ b/drivers/spi/spi_nrfx_spim_common.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2026 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SPI_NRFX_SPIM_COMMON_H_ +#define ZEPHYR_DRIVERS_SPI_NRFX_SPIM_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/** + * @cond INTERNAL_HIDDEN + */ + +#if CONFIG_SPI_NRFX_RAM_BUFFER_SIZE +#define SPI_NRFX_HAS_RAM_BUF 1 +#define SPI_NRFX_RAM_BUF_SIZE CONFIG_SPI_NRFX_RAM_BUFFER_SIZE +#endif + +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(nordic_nrf_spim, wake_gpios) +#define SPI_NRFX_HAS_WAKE 1 +#endif + +typedef void (*spi_nrfx_data_common_wake_handler)(const struct device *dev); + +typedef void (*spi_nrfx_data_common_evt_handler)(const struct device *dev, + nrfx_spim_event_t *evt); + +struct spi_nrfx_common_data { + nrfx_spim_t spim; + bool configured; + struct spi_config spi_cfg; +#if SPI_NRFX_HAS_RAM_BUF || CONFIG_HAS_NORDIC_DMM + const uint8_t *tx_user_buf; + uint8_t *rx_user_buf; + size_t rx_user_buf_len; +#endif +#if SPI_NRFX_HAS_WAKE + const struct device *dev; + struct gpio_callback wake_pin_callback; + struct k_timer wake_timer; + spi_nrfx_data_common_wake_handler wake_handler; +#endif +}; + +struct spi_nrfx_common_config { + void (*irq_connect)(void); + const struct pinctrl_dev_config *pcfg; + spi_nrfx_data_common_evt_handler evt_handler; + const struct gpio_dt_spec *cs_gpios; +#if SPI_NRFX_HAS_RAM_BUF + uint8_t *tx_ram_buf; + uint8_t *rx_ram_buf; +#endif +#if CONFIG_HAS_NORDIC_DMM + void *mem_reg; +#endif + uint32_t max_freq; + uint16_t max_transfer_len; + uint8_t orc; + uint8_t cs_gpios_size; +#if NRF_SPIM_HAS_RXDELAY + uint8_t rx_delay; +#endif +#if SPI_NRFX_HAS_WAKE + struct gpio_dt_spec wake_pin; +#endif +}; + +void spi_nrfx_spim_common_wake_start(const struct device *dev, + spi_nrfx_data_common_wake_handler handler); + +void spi_nrfx_spim_common_cs_set(const struct device *dev, const struct spi_config *spi_cfg); +void spi_nrfx_spim_common_cs_clear(const struct device *dev, const struct spi_config *spi_cfg); + +int spi_nrfx_spim_common_transfer_start(const struct device *dev, + const uint8_t *tx_buf, + size_t tx_buf_len, + uint8_t *rx_buf, + size_t rx_buf_len); + +void spi_nrfx_spim_common_transfer_stop(const struct device *dev); + +void spi_nrfx_spim_common_transfer_end(const struct device *dev, + const nrfx_spim_xfer_desc_t *xfer); + +int spi_nrfx_spim_common_configure(const struct device *dev, const struct spi_config *spi_cfg); +int spi_nrfx_spim_common_pm_action(const struct device *dev, enum pm_device_action action); + +int spi_nrfx_spim_common_init(const struct device *dev); +int spi_nrfx_spim_common_deinit(const struct device *dev); + +#define SPI_NRFX_COMMON_IRQ_DEFINE(inst, _data) \ + NRF_DT_INST_IRQ_DIRECT_DEFINE( \ + inst, \ + nrfx_spim_irq_handler, \ + _data \ + ) \ + \ + static void CONCAT(irq_connect, inst)(void) \ + { \ + NRF_DT_INST_IRQ_CONNECT( \ + inst, \ + nrfx_spim_irq_handler, \ + _data \ + ); \ + } + +#define SPI_NRFX_COMMON_RAM_BUF_DEFINE(inst) \ + IF_ENABLED( \ + SPI_NRFX_HAS_RAM_BUF, \ + ( \ + static uint8_t CONCAT(tx_ram_buf, inst)[SPI_NRFX_RAM_BUF_SIZE] \ + DMM_MEMORY_SECTION(DT_DRV_INST(inst)); \ + \ + static uint8_t CONCAT(rx_ram_buf, inst)[SPI_NRFX_RAM_BUF_SIZE] \ + DMM_MEMORY_SECTION(DT_DRV_INST(inst)); \ + ) \ + ) + +#define SPI_NRFX_COMMON_CS_GPIO_INIT(idx, inst) \ + GPIO_DT_SPEC_INST_GET_BY_IDX(inst, cs_gpios, idx) + +#define SPI_NRFX_COMMON_CS_GPIOS_DEFINE(inst) \ + static const struct gpio_dt_spec CONCAT(cs_gpios, inst)[] = { \ + LISTIFY( \ + DT_INST_PROP_LEN_OR(inst, cs_gpios, 0), \ + SPI_NRFX_COMMON_CS_GPIO_INIT, \ + (,), \ + inst \ + ) \ + } + +#define SPI_NRFX_COMMON_DEFINE(inst, _data) \ + SPI_NRFX_COMMON_IRQ_DEFINE(inst, _data) \ + SPI_NRFX_COMMON_RAM_BUF_DEFINE(inst); \ + SPI_NRFX_COMMON_CS_GPIOS_DEFINE(inst); \ + PINCTRL_DT_INST_DEFINE(inst); + +#define SPI_NRFX_COMMON_DATA_WAKE_INIT(inst) \ + IF_ENABLED( \ + SPI_NRFX_HAS_WAKE, \ + ( \ + .dev = DEVICE_DT_INST_GET(inst), \ + ) \ + ) + +#define SPI_NRFX_COMMON_DATA_INIT(inst) \ + { \ + .spim = NRFX_SPIM_INSTANCE(DT_INST_REG_ADDR(inst)), \ + SPI_NRFX_COMMON_DATA_WAKE_INIT(inst) \ + } + +#define SPI_NRFX_COMMON_CONFIG_INIT_RX_DELAY(inst) \ + IF_ENABLED( \ + NRF_SPIM_HAS_RXDELAY, \ + ( \ + .rx_delay = DT_INST_PROP_OR(inst, rx_delay, 0), \ + ) \ + ) + +#define SPI_NRFX_COMMON_CONFIG_WAKE_INIT(inst) \ + IF_ENABLED( \ + SPI_NRFX_HAS_WAKE, \ + ( \ + .wake_pin = GPIO_DT_SPEC_INST_GET_OR(inst, wake_gpios, {0}), \ + ) \ + ) + +#define SPI_NRFX_COMMON_CONFIG_RAM_BUF_INIT(inst) \ + IF_ENABLED( \ + SPI_NRFX_HAS_RAM_BUF, \ + ( \ + .tx_ram_buf = CONCAT(tx_ram_buf, inst), \ + .rx_ram_buf = CONCAT(rx_ram_buf, inst), \ + ) \ + ) + +#define SPI_NRFX_COMMON_CONFIG_MEM_REG_INIT(inst) \ + IF_ENABLED( \ + CONFIG_HAS_NORDIC_DMM, \ + ( \ + .mem_reg = DMM_DEV_TO_REG(DT_DRV_INST(inst)), \ + ) \ + ) + +#define SPI_NRFX_COMMON_CONFIG_INIT(inst, _evt_handler) \ + { \ + .irq_connect = CONCAT(irq_connect, inst), \ + .evt_handler = _evt_handler, \ + .cs_gpios = CONCAT(cs_gpios, inst), \ + .cs_gpios_size = ARRAY_SIZE(CONCAT(cs_gpios, inst)), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .max_freq = DT_INST_PROP(inst, max_frequency), \ + .max_transfer_len = BIT_MASK(DT_INST_PROP(inst, easydma_maxcnt_bits)), \ + .orc = DT_INST_PROP(inst, overrun_character), \ + SPI_NRFX_COMMON_CONFIG_INIT_RX_DELAY(inst) \ + SPI_NRFX_COMMON_CONFIG_WAKE_INIT(inst) \ + SPI_NRFX_COMMON_CONFIG_RAM_BUF_INIT(inst) \ + SPI_NRFX_COMMON_CONFIG_MEM_REG_INIT(inst) \ + } + +/** + * @endcond + */ + +#endif /* ZEPHYR_DRIVERS_SPI_NRFX_SPIM_COMMON_H_ */ diff --git a/drivers/spi/spi_nrfx_spim_rtio.c b/drivers/spi/spi_nrfx_spim_rtio.c new file mode 100644 index 000000000000..1df42b8e355b --- /dev/null +++ b/drivers/spi/spi_nrfx_spim_rtio.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2026 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_nrf_spim + +#include "spi_nrfx_spim_common.h" + +#include + +LOG_MODULE_DECLARE(spi_nrfx_spim); + +struct driver_data { + struct spi_nrfx_common_data common; +}; + +struct driver_config { + struct spi_nrfx_common_config common; + struct spi_rtio *spi_rtio_ctx; +}; + +static void iodev_end_curr(const struct device *dev); +static void iodev_start_txn(const struct device *dev); +static void iodev_end_txn(const struct device *dev, int result); + +static void iodev_await_callback(struct rtio_iodev_sqe *iodev_sqe, void *userdata) +{ + const struct device *dev = userdata; + + ARG_UNUSED(iodev_sqe); + + iodev_end_curr(dev); +} + +static void iodev_start_curr(const struct device *dev) +{ + const struct driver_config *dev_config = dev->config; + struct spi_rtio *spi_rtio_ctx = dev_config->spi_rtio_ctx; + struct rtio_sqe *sqe = &spi_rtio_ctx->txn_curr->sqe; + struct spi_dt_spec *spi_spec = sqe->iodev->data; + struct spi_config *spi_cfg = &spi_spec->config; + const uint8_t *tx_buf; + size_t tx_buf_len; + uint8_t *rx_buf; + size_t rx_buf_len; + struct rtio_iodev_sqe *iodev_sqe; + int ret; + + switch (sqe->op) { + case RTIO_OP_TX: + tx_buf = sqe->tx.buf; + tx_buf_len = sqe->tx.buf_len; + rx_buf = NULL; + rx_buf_len = 0; + break; + + case RTIO_OP_RX: + tx_buf = NULL; + tx_buf_len = 0; + rx_buf = sqe->rx.buf; + rx_buf_len = sqe->rx.buf_len; + break; + + case RTIO_OP_TINY_TX: + tx_buf = sqe->tiny_tx.buf; + tx_buf_len = sqe->tiny_tx.buf_len; + rx_buf = NULL; + rx_buf_len = 0; + break; + + case RTIO_OP_TXRX: + tx_buf = sqe->txrx.tx_buf; + tx_buf_len = sqe->txrx.buf_len; + rx_buf = sqe->txrx.rx_buf; + rx_buf_len = sqe->txrx.buf_len; + break; + + default: + tx_buf = NULL; + tx_buf_len = 0; + rx_buf = NULL; + rx_buf_len = 0; + break; + } + + switch (sqe->op) { + case RTIO_OP_TX: + case RTIO_OP_RX: + case RTIO_OP_TINY_TX: + case RTIO_OP_TXRX: + ret = spi_nrfx_spim_common_configure(dev, spi_cfg); + if (ret) { + break; + } + + ret = spi_nrfx_spim_common_transfer_start(dev, + tx_buf, + tx_buf_len, + rx_buf, + rx_buf_len); + break; + + case RTIO_OP_AWAIT: + iodev_sqe = CONTAINER_OF(sqe, struct rtio_iodev_sqe, sqe); + rtio_iodev_sqe_await_signal(iodev_sqe, iodev_await_callback, (void *)dev); + ret = 0; + break; + + default: + ret = -ENOTSUP; + break; + } + + if (ret) { + iodev_end_txn(dev, ret); + } +} + +static void iodev_start_txn(const struct device *dev) +{ + const struct driver_config *dev_config = dev->config; + struct spi_rtio *spi_rtio_ctx = dev_config->spi_rtio_ctx; + struct rtio_sqe *sqe = &spi_rtio_ctx->txn_head->sqe; + struct spi_dt_spec *spi_spec = sqe->iodev->data; + struct spi_config *spi_cfg = &spi_spec->config; + + spi_nrfx_spim_common_cs_set(dev, spi_cfg); + iodev_start_curr(dev); +} + +static void iodev_end_txn(const struct device *dev, int result) +{ + const struct driver_config *dev_config = dev->config; + struct spi_rtio *spi_rtio_ctx = dev_config->spi_rtio_ctx; + struct rtio_sqe *sqe = &spi_rtio_ctx->txn_head->sqe; + struct spi_dt_spec *spi_spec = sqe->iodev->data; + struct spi_config *spi_cfg = &spi_spec->config; + + if (spi_rtio_complete(spi_rtio_ctx, result) == false) { + if ((spi_cfg->operation & SPI_HOLD_ON_CS) == 0) { + spi_nrfx_spim_common_cs_clear(dev, spi_cfg); + } + pm_device_runtime_put(dev); + return; + } + + iodev_start_txn(dev); +} + +static void iodev_end_curr(const struct device *dev) +{ + const struct driver_config *dev_config = dev->config; + struct spi_rtio *spi_rtio_ctx = dev_config->spi_rtio_ctx; + + spi_rtio_ctx->txn_curr = rtio_txn_next(spi_rtio_ctx->txn_curr); + if (spi_rtio_ctx->txn_curr == NULL) { + iodev_end_txn(dev, 0); + return; + } + + iodev_start_curr(dev); +} + +static void spim_evt_handler(const struct device *dev, nrfx_spim_event_t *evt) +{ + spi_nrfx_spim_common_transfer_end(dev, &evt->xfer_desc); + iodev_end_curr(dev); +} + +static int driver_api_transceive(const struct device *dev, + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + const struct driver_config *dev_config = dev->config; + + return spi_rtio_transceive(dev_config->spi_rtio_ctx, spi_cfg, tx_bufs, rx_bufs); +} + +#ifdef CONFIG_SPI_ASYNC +static int driver_api_transceive_async(const struct device *dev, + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + spi_callback_t cb, + void *userdata) +{ + const struct driver_config *dev_config = dev->config; + + return spi_rtio_transceive_cb(dev_config->spi_rtio_ctx, + spi_cfg, + tx_bufs, + rx_bufs, + cb, + userdata); +} +#endif + +static void spim_wake_handler(const struct device *dev) +{ + iodev_start_txn(dev); +} + +static void driver_api_iodev_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct driver_config *dev_config = dev->config; + struct spi_rtio *spi_rtio_ctx = dev_config->spi_rtio_ctx; + + if (spi_rtio_submit(spi_rtio_ctx, iodev_sqe)) { + pm_device_runtime_get(dev); + spi_nrfx_spim_common_wake_start(dev, spim_wake_handler); + } +} + +static DEVICE_API(spi, driver_api) = { + .transceive = driver_api_transceive, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = driver_api_transceive_async, +#endif + .iodev_submit = driver_api_iodev_submit, + .release = spi_rtio_release, +}; + +static int driver_init(const struct device *dev) +{ + const struct driver_config *dev_config = dev->config; + int ret; + + ret = spi_nrfx_spim_common_init(dev); + if (ret) { + return ret; + } + + spi_rtio_init(dev_config->spi_rtio_ctx, dev); + + return pm_device_driver_init(dev, spi_nrfx_spim_common_pm_action); +} + +#ifdef CONFIG_DEVICE_DEINIT_SUPPORT +static int driver_deinit(const struct device *dev) +{ + return spi_nrfx_spim_common_deinit(dev); +} +#endif + +#define DRIVER_DEFINE(inst) \ + static struct driver_data CONCAT(data, inst) = { \ + .common = SPI_NRFX_COMMON_DATA_INIT(inst), \ + }; \ + \ + SPI_NRFX_COMMON_DEFINE(inst, &CONCAT(data, inst)); \ + \ + SPI_RTIO_DEFINE( \ + CONCAT(spi_rtio_ctx, inst), \ + CONFIG_SPI_NRFX_SPIM_RTIO_SQE_POOL_SIZE, \ + CONFIG_SPI_NRFX_SPIM_RTIO_CQE_POOL_SIZE \ + ); \ + \ + static const struct driver_config CONCAT(config, inst) = { \ + .common = SPI_NRFX_COMMON_CONFIG_INIT( \ + inst, \ + spim_evt_handler \ + ), \ + .spi_rtio_ctx = &CONCAT(spi_rtio_ctx, inst), \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, spi_nrfx_spim_common_pm_action, 1); \ + \ + SPI_DEVICE_DT_INST_DEINIT_DEFINE( \ + inst, \ + driver_init, \ + driver_deinit, \ + PM_DEVICE_DT_INST_GET(inst), \ + &CONCAT(data, inst), \ + &CONCAT(config, inst), \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &driver_api \ + ) + +DT_INST_FOREACH_STATUS_OKAY(DRIVER_DEFINE) From cf84338b875247e60cc24f205b44b6575ee42f0f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 23 Feb 2026 18:19:23 +0100 Subject: [PATCH 07/20] [nrf fromtree] drivers: spi: nrf_spim: refactor to use common code with rtio impl Refactor the nrf_spim device driver to share the common code between the nrf_spim_rtio implementation. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit e4d61fc47218a653e1e1be3bc61086d26f2eba5d) (cherry picked from commit 53b573a2076820c2e7459e085419c62fc98efe2c) --- drivers/spi/CMakeLists.txt | 2 +- drivers/spi/Kconfig.nrfx | 1 + drivers/spi/spi_nrfx_spim.c | 748 ++++++++---------------------------- 3 files changed, 162 insertions(+), 589 deletions(-) diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 998098614e48..b6642956e2d6 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -44,7 +44,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_FLEXCOMM spi_mcux_flexcomm.c) zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_FLEXIO spi_mcux_flexio.c) zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_SPIP spi_npcx_spip.c) zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPI spi_nrfx_spi.c spi_nrfx_common.c) -zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM spi_nrfx_spim.c spi_nrfx_common.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM spi_nrfx_spim.c spi_nrfx_spim_common.c) zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIM_RTIO spi_nrfx_spim_rtio.c spi_nrfx_spim_common.c) zephyr_library_sources_ifdef(CONFIG_SPI_NRFX_SPIS spi_nrfx_spis.c) zephyr_library_sources_ifdef(CONFIG_SPI_NUMAKER spi_numaker.c) diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index 0f072da1bf15..3eff3da6c864 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -49,6 +49,7 @@ config SPI_NRFX_SPIS config SPI_NRFX_RAM_BUFFER_SIZE int "Size of RAM buffers for SPIM peripherals" + default 0 if HAS_NORDIC_DMM default 8 depends on SPI_NRFX_SPIM help diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 075dbad20f66..4914a5b629a7 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -1,364 +1,98 @@ /* - * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * Copyright (c) 2026 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT nordic_nrf_spim -#include -#include "spi_rtio.h" -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SOC_NRF5340_CPUAPP -#include -#endif -#include -#include -#include +#include "spi_nrfx_spim_common.h" -#include -#include -LOG_MODULE_REGISTER(spi_nrfx_spim, CONFIG_SPI_LOG_LEVEL); +LOG_MODULE_DECLARE(spi_nrfx_spim); #include "spi_context.h" -#include "spi_nrfx_common.h" - -#if (CONFIG_SPI_NRFX_RAM_BUFFER_SIZE > 0) -#define SPI_BUFFER_IN_RAM 1 -#endif -struct spi_nrfx_data { - nrfx_spim_t spim; +struct driver_data { + struct spi_nrfx_common_data common; struct spi_context ctx; - const struct device *dev; - size_t chunk_len; - bool busy; - bool initialized; -#ifdef SPI_BUFFER_IN_RAM - uint8_t *tx_buffer; - uint8_t *rx_buffer; -#endif + struct k_sem wake_sem; }; -struct spi_nrfx_config { - uint32_t max_freq; - nrfx_spim_config_t def_config; - void (*irq_connect)(void); - uint16_t max_chunk_len; - const struct pinctrl_dev_config *pcfg; - nrfx_gpiote_t *wake_gpiote; - uint32_t wake_pin; - void *mem_reg; +struct driver_config { + struct spi_nrfx_common_config common; }; -static void event_handler(const nrfx_spim_event_t *p_event, void *p_context); - -static inline void finalize_spi_transaction(const struct device *dev, bool deactivate_cs) +static void transfer_end(const struct device *dev, int ret) { - struct spi_nrfx_data *dev_data = dev->data; - void *reg = dev_data->spim.p_reg; + struct driver_data *dev_data = dev->data; + const struct spi_config *spi_cfg = dev_data->ctx.config; - if (deactivate_cs) { - spi_context_cs_control(&dev_data->ctx, false); - } + pm_device_runtime_put(dev); - if (NRF_SPIM_IS_320MHZ_SPIM(reg) && !(dev_data->ctx.config->operation & SPI_HOLD_ON_CS)) { - nrfy_spim_disable(reg); + if (ret || (spi_cfg->operation & SPI_HOLD_ON_CS) == 0) { + spi_nrfx_spim_common_cs_clear(dev, spi_cfg); } -} -static inline uint32_t get_nrf_spim_frequency(uint32_t frequency) -{ - if (NRF_SPIM_HAS_PRESCALER) { - return frequency; - } - /* Get the highest supported frequency not exceeding the requested one. - */ - if (frequency >= MHZ(32) && NRF_SPIM_HAS_32_MHZ_FREQ) { - return MHZ(32); - } else if (frequency >= MHZ(16) && NRF_SPIM_HAS_16_MHZ_FREQ) { - return MHZ(16); - } else if (frequency >= MHZ(8)) { - return MHZ(8); - } else if (frequency >= MHZ(4)) { - return MHZ(4); - } else if (frequency >= MHZ(2)) { - return MHZ(2); - } else if (frequency >= MHZ(1)) { - return MHZ(1); - } else if (frequency >= KHZ(500)) { - return KHZ(500); - } else if (frequency >= KHZ(250)) { - return KHZ(250); - } else { - return KHZ(125); - } + spi_context_complete(&dev_data->ctx, dev, ret); } -static inline nrf_spim_mode_t get_nrf_spim_mode(uint16_t operation) +static void transfer_start(const struct device *dev) { - if (SPI_MODE_GET(operation) & SPI_MODE_CPOL) { - if (SPI_MODE_GET(operation) & SPI_MODE_CPHA) { - return NRF_SPIM_MODE_3; - } else { - return NRF_SPIM_MODE_2; - } + struct driver_data *dev_data = dev->data; + size_t chunk_len; + const uint8_t *tx_buf; + size_t tx_buf_len; + uint8_t *rx_buf; + size_t rx_buf_len; + int ret; + + chunk_len = spi_context_max_continuous_chunk(&dev_data->ctx); + if (chunk_len == 0) { + transfer_end(dev, 0); + return; + } + + if (spi_context_tx_buf_on(&dev_data->ctx)) { + tx_buf = dev_data->ctx.tx_buf; + tx_buf_len = chunk_len; } else { - if (SPI_MODE_GET(operation) & SPI_MODE_CPHA) { - return NRF_SPIM_MODE_1; - } else { - return NRF_SPIM_MODE_0; - } + tx_buf = NULL; + tx_buf_len = 0; } -} -static inline nrf_spim_bit_order_t get_nrf_spim_bit_order(uint16_t operation) -{ - if (operation & SPI_TRANSFER_LSB) { - return NRF_SPIM_BIT_ORDER_LSB_FIRST; + if (spi_context_rx_buf_on(&dev_data->ctx)) { + rx_buf = dev_data->ctx.rx_buf; + rx_buf_len = chunk_len; } else { - return NRF_SPIM_BIT_ORDER_MSB_FIRST; - } -} - -static int configure(const struct device *dev, - const struct spi_config *spi_cfg) -{ - struct spi_nrfx_data *dev_data = dev->data; - const struct spi_nrfx_config *dev_config = dev->config; - struct spi_context *ctx = &dev_data->ctx; - uint32_t max_freq = dev_config->max_freq; - nrfx_spim_config_t config; - int result; - uint32_t sck_pin; - - if (dev_data->initialized && spi_context_configured(ctx, spi_cfg)) { - /* Already configured. No need to do it again. */ - return 0; - } - - if (spi_cfg->operation & SPI_HALF_DUPLEX) { - LOG_ERR("Half-duplex not supported"); - return -ENOTSUP; - } - - if (SPI_OP_MODE_GET(spi_cfg->operation) != SPI_OP_MODE_MASTER) { - LOG_ERR("Slave mode is not supported on %s", dev->name); - return -EINVAL; - } - - if (spi_cfg->operation & SPI_MODE_LOOP) { - LOG_ERR("Loopback mode is not supported"); - return -EINVAL; - } - - if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && - (spi_cfg->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { - LOG_ERR("Only single line mode is supported"); - return -EINVAL; - } - - if (SPI_WORD_SIZE_GET(spi_cfg->operation) != 8) { - LOG_ERR("Word sizes other than 8 bits are not supported"); - return -EINVAL; - } - - if (spi_cfg->frequency < 125000) { - LOG_ERR("Frequencies lower than 125 kHz are not supported"); - return -EINVAL; - } - -#if defined(CONFIG_SOC_NRF5340_CPUAPP) - /* On nRF5340, the 32 Mbps speed is supported by the application core - * when it is running at 128 MHz (see the Timing specifications section - * in the nRF5340 PS). - */ - if (max_freq > 16000000 && - nrf_clock_hfclk_div_get(NRF_CLOCK) != NRF_CLOCK_HFCLK_DIV_1) { - max_freq = 16000000; + rx_buf = NULL; + rx_buf_len = 0; } -#endif - - config = dev_config->def_config; - - /* Limit the frequency to that supported by the SPIM instance. */ - config.frequency = get_nrf_spim_frequency(MIN(spi_cfg->frequency, - max_freq)); - config.mode = get_nrf_spim_mode(spi_cfg->operation); - config.bit_order = get_nrf_spim_bit_order(spi_cfg->operation); - sck_pin = nrfy_spim_sck_pin_get(dev_data->spim.p_reg); - - if (sck_pin != NRF_SPIM_PIN_NOT_CONNECTED) { - nrfy_gpio_pin_write(sck_pin, spi_cfg->operation & SPI_MODE_CPOL ? 1 : 0); + ret = spi_nrfx_spim_common_transfer_start(dev, + tx_buf, + tx_buf_len, + rx_buf, + rx_buf_len); + if (ret) { + transfer_end(dev, ret); + return; } - if (dev_data->initialized) { - nrfx_spim_uninit(&dev_data->spim); - dev_data->initialized = false; - } - - result = nrfx_spim_init(&dev_data->spim, &config, - event_handler, (void *)dev); - if (result < 0) { - LOG_ERR("Failed to initialize nrfx driver: %d", result); - return result; - } - -#if defined(CONFIG_NRF52_ANOMALY_58_WORKAROUND) -#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpiote), okay) - nrfx_spim_nrf52_anomaly_58_init(&dev_data->spim, - &GPIOTE_NRFX_INST_BY_NODE(DT_NODELABEL(gpiote))); -#else -#error "GPIOTE is not enabled, anomaly 58 workaround cannot be applied for SPIM" -#endif -#endif - - dev_data->initialized = true; - - ctx->config = spi_cfg; - - return 0; + spi_context_update_tx(&dev_data->ctx, 1, chunk_len); + spi_context_update_rx(&dev_data->ctx, 1, chunk_len); } -static void finish_transaction(const struct device *dev, int error) +static void spim_wake_handler(const struct device *dev) { - struct spi_nrfx_data *dev_data = dev->data; - struct spi_context *ctx = &dev_data->ctx; + struct driver_data *dev_data = dev->data; - LOG_DBG("Transaction finished with status %d", error); - - spi_context_complete(ctx, dev, error); - dev_data->busy = false; - - finalize_spi_transaction(dev, true); - -#ifdef CONFIG_SPI_ASYNC - if (ctx->asynchronous) { - pm_device_runtime_put_async(dev, K_NO_WAIT); - } -#endif + k_sem_give(&dev_data->wake_sem); } -static void transfer_next_chunk(const struct device *dev) +static void spim_evt_handler(const struct device *dev, nrfx_spim_event_t *evt) { - struct spi_nrfx_data *dev_data = dev->data; - const struct spi_nrfx_config *dev_config = dev->config; - struct spi_context *ctx = &dev_data->ctx; - int error = 0; - - size_t chunk_len = spi_context_max_continuous_chunk(ctx); - - if (chunk_len > 0) { - nrfx_spim_xfer_desc_t xfer; - const uint8_t *tx_buf = ctx->tx_buf; - uint8_t *rx_buf = ctx->rx_buf; - - if (chunk_len > dev_config->max_chunk_len) { - chunk_len = dev_config->max_chunk_len; - } - -#ifdef SPI_BUFFER_IN_RAM - if (spi_context_tx_buf_on(ctx) && - !nrf_dma_accessible_check(&dev_data->spim.p_reg, tx_buf)) { - - if (chunk_len > CONFIG_SPI_NRFX_RAM_BUFFER_SIZE) { - chunk_len = CONFIG_SPI_NRFX_RAM_BUFFER_SIZE; - } - - memcpy(dev_data->tx_buffer, tx_buf, chunk_len); - tx_buf = dev_data->tx_buffer; - } - - if (spi_context_rx_buf_on(ctx) && - !nrf_dma_accessible_check(&dev_data->spim.p_reg, rx_buf)) { - - if (chunk_len > CONFIG_SPI_NRFX_RAM_BUFFER_SIZE) { - chunk_len = CONFIG_SPI_NRFX_RAM_BUFFER_SIZE; - } - - rx_buf = dev_data->rx_buffer; - } -#endif - - dev_data->chunk_len = chunk_len; - - xfer.tx_length = spi_context_tx_buf_on(ctx) ? chunk_len : 0; - xfer.rx_length = spi_context_rx_buf_on(ctx) ? chunk_len : 0; - - error = dmm_buffer_out_prepare(dev_config->mem_reg, tx_buf, xfer.tx_length, - (void **)&xfer.p_tx_buffer); - if (error != 0) { - goto out_alloc_failed; - } - - error = dmm_buffer_in_prepare(dev_config->mem_reg, rx_buf, xfer.rx_length, - (void **)&xfer.p_rx_buffer); - if (error != 0) { - goto in_alloc_failed; - } - - error = nrfx_spim_xfer(&dev_data->spim, &xfer, 0); - if (error == 0) { - return; - } - - /* On nrfx_spim_xfer() error */ - dmm_buffer_in_release(dev_config->mem_reg, rx_buf, xfer.rx_length, - (void **)&xfer.p_rx_buffer); -in_alloc_failed: - dmm_buffer_out_release(dev_config->mem_reg, (void **)&xfer.p_tx_buffer); - } - -out_alloc_failed: - finish_transaction(dev, error); -} - -static void event_handler(const nrfx_spim_event_t *p_event, void *p_context) -{ - const struct device *dev = p_context; - struct spi_nrfx_data *dev_data = dev->data; - const struct spi_nrfx_config *dev_config = dev->config; - - if (p_event->type == NRFX_SPIM_EVENT_DONE) { - /* Chunk length is set to 0 when a transaction is aborted - * due to a timeout. - */ - if (dev_data->chunk_len == 0) { - finish_transaction(dev_data->dev, -ETIMEDOUT); - return; - } - - if (spi_context_tx_buf_on(&dev_data->ctx)) { - dmm_buffer_out_release(dev_config->mem_reg, - (void **)p_event->xfer_desc.p_tx_buffer); - } - - if (spi_context_rx_buf_on(&dev_data->ctx)) { - dmm_buffer_in_release(dev_config->mem_reg, dev_data->ctx.rx_buf, - dev_data->chunk_len, p_event->xfer_desc.p_rx_buffer); - } - -#ifdef SPI_BUFFER_IN_RAM - if (spi_context_rx_buf_on(&dev_data->ctx) && - p_event->xfer_desc.p_rx_buffer != NULL && - p_event->xfer_desc.p_rx_buffer != dev_data->ctx.rx_buf) { - (void)memcpy(dev_data->ctx.rx_buf, - dev_data->rx_buffer, - dev_data->chunk_len); - } -#endif - spi_context_update_tx(&dev_data->ctx, 1, dev_data->chunk_len); - spi_context_update_rx(&dev_data->ctx, 1, dev_data->chunk_len); - - transfer_next_chunk(dev_data->dev); - } + spi_nrfx_spim_common_transfer_end(dev, &evt->xfer_desc); + transfer_start(dev); } static int transceive(const struct device *dev, @@ -369,324 +103,162 @@ static int transceive(const struct device *dev, spi_callback_t cb, void *userdata) { - struct spi_nrfx_data *dev_data = dev->data; - const struct spi_nrfx_config *dev_config = dev->config; - void *reg = dev_data->spim.p_reg; - int error; + struct driver_data *dev_data = dev->data; + int ret; spi_context_lock(&dev_data->ctx, asynchronous, cb, userdata, spi_cfg); spi_context_buffers_setup(&dev_data->ctx, tx_bufs, rx_bufs, 1); if (!spi_context_tx_buf_on(&dev_data->ctx) && !spi_context_rx_buf_on(&dev_data->ctx)) { - spi_context_release(&dev_data->ctx, -EINVAL); - return -EINVAL; + ret = -EINVAL; + goto release_exit; } - pm_device_runtime_get(dev); - error = configure(dev, spi_cfg); - - if (error == 0) { - dev_data->busy = true; - - if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - error = spi_nrfx_wake_request(dev_config->wake_gpiote, - dev_config->wake_pin); - if (error == -ETIMEDOUT) { - LOG_WRN("Waiting for WAKE acknowledgment timed out"); - /* If timeout occurs, try to perform the transfer - * anyway, just in case the slave device was unable - * to signal that it was already awaken and prepared - * for the transfer. - */ - } - } + ret = pm_device_runtime_get(dev); + if (ret) { + goto release_exit; + } - if (NRF_SPIM_IS_320MHZ_SPIM(reg)) { - nrfy_spim_enable(reg); - } - spi_context_cs_control(&dev_data->ctx, true); - - transfer_next_chunk(dev); - - error = spi_context_wait_for_completion(&dev_data->ctx); - if (error == -ETIMEDOUT) { - /* Set the chunk length to 0 so that event_handler() - * knows that the transaction timed out and is to be - * aborted. - */ - dev_data->chunk_len = 0; - /* Abort the current transfer by deinitializing - * the nrfx driver. - */ - nrfx_spim_uninit(&dev_data->spim); - dev_data->initialized = false; - - /* Make sure the transaction is finished (it may be - * already finished if it actually did complete before - * the nrfx driver was deinitialized). - */ - finish_transaction(dev, -ETIMEDOUT); - - /* Clean up the driver state. */ -#ifdef CONFIG_MULTITHREADING - k_sem_reset(&dev_data->ctx.sync); -#else - dev_data->ctx.ready = 0; -#endif /* CONFIG_MULTITHREADING */ - } else if (error) { - finalize_spi_transaction(dev, true); - } + ret = spi_nrfx_spim_common_configure(dev, spi_cfg); + if (ret) { + goto put_release_exit; } - if (error || !(dev_data->ctx.config->operation & SPI_LOCK_ON)) { - spi_context_release(&dev_data->ctx, error); + dev_data->ctx.config = spi_cfg; + + spi_nrfx_spim_common_wake_start(dev, spim_wake_handler); + k_sem_take(&dev_data->wake_sem, K_FOREVER); + + spi_nrfx_spim_common_cs_set(dev, spi_cfg); + transfer_start(dev); + + ret = spi_context_wait_for_completion(&dev_data->ctx); + if (ret == 0) { + if (spi_cfg->operation & SPI_LOCK_ON) { + goto exit; + } else { + goto release_exit; + } } - if (error || !asynchronous) { - pm_device_runtime_put(dev); + if (ret == -ETIMEDOUT) { + spi_nrfx_spim_common_transfer_stop(dev); + spi_context_wait_for_completion(&dev_data->ctx); } - return error; + +put_release_exit: + pm_device_runtime_put(dev); + +release_exit: + spi_context_release(&dev_data->ctx, ret); + +exit: + return ret; } -static int spi_nrfx_transceive(const struct device *dev, - const struct spi_config *spi_cfg, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) +static int driver_api_transceive(const struct device *dev, + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) { return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); } #ifdef CONFIG_SPI_ASYNC -static int spi_nrfx_transceive_async(const struct device *dev, - const struct spi_config *spi_cfg, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs, - spi_callback_t cb, - void *userdata) +static int driver_api_transceive_async(const struct device *dev, + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + spi_callback_t cb, + void *userdata) { return transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata); } -#endif /* CONFIG_SPI_ASYNC */ +#endif -static int spi_nrfx_release(const struct device *dev, - const struct spi_config *spi_cfg) +static int driver_api_release(const struct device *dev, + const struct spi_config *spi_cfg) { - struct spi_nrfx_data *dev_data = dev->data; - -#ifdef CONFIG_MULTITHREADING - if (dev_data->ctx.owner != spi_cfg) { - return -EALREADY; - } -#endif + struct driver_data *dev_data = dev->data; if (!spi_context_configured(&dev_data->ctx, spi_cfg)) { - return -EINVAL; - } - - if (dev_data->busy) { - return -EBUSY; + return -EPERM; } spi_context_unlock_unconditionally(&dev_data->ctx); - finalize_spi_transaction(dev, false); - return 0; } -static DEVICE_API(spi, spi_nrfx_driver_api) = { - .transceive = spi_nrfx_transceive, +static DEVICE_API(spi, driver_api) = { + .transceive = driver_api_transceive, #ifdef CONFIG_SPI_ASYNC - .transceive_async = spi_nrfx_transceive_async, + .transceive_async = driver_api_transceive_async, #endif #ifdef CONFIG_SPI_RTIO .iodev_submit = spi_rtio_iodev_default_submit, #endif - .release = spi_nrfx_release, + .release = driver_api_release, }; -static int spim_resume(const struct device *dev) -{ - const struct spi_nrfx_config *dev_config = dev->config; - struct spi_nrfx_data *dev_data = dev->data; - (void)dev_data; - - (void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - /* nrfx_spim_init() will be called at configuration before - * the next transfer. - */ - - if (spi_context_cs_get_all(&dev_data->ctx)) { - return -EAGAIN; - } - - return 0; -} - -static void spim_suspend(const struct device *dev) -{ - const struct spi_nrfx_config *dev_config = dev->config; - struct spi_nrfx_data *dev_data = dev->data; - int err; - - if (dev_data->initialized) { - nrfx_spim_uninit(&dev_data->spim); - dev_data->initialized = false; - } - - err = spi_context_cs_put_all(&dev_data->ctx); - (void)err; - - (void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); -} - -static int spim_nrfx_pm_action(const struct device *dev, enum pm_device_action action) +static int driver_init(const struct device *dev) { - if (action == PM_DEVICE_ACTION_RESUME) { - return spim_resume(dev); - } else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) { - spim_suspend(dev); - } else { - return -ENOTSUP; - } - - return 0; -} + struct driver_data *dev_data = dev->data; + int ret; -static int spi_nrfx_init(const struct device *dev) -{ - const struct spi_nrfx_config *dev_config = dev->config; - struct spi_nrfx_data *dev_data = dev->data; - int err; - - /* Apply sleep state by default. - * If PM is disabled, the default state will be applied in pm_device_driver_init. - */ - (void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); - - if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - err = spi_nrfx_wake_init(dev_config->wake_gpiote, dev_config->wake_pin); - if (err == -ENODEV) { - LOG_ERR("Failed to allocate GPIOTE channel for WAKE"); - return err; - } - if (err == -EIO) { - LOG_ERR("Failed to configure WAKE pin"); - return err; - } + ret = spi_nrfx_spim_common_init(dev); + if (ret) { + return ret; } - dev_config->irq_connect(); - - err = spi_context_cs_configure_all(&dev_data->ctx); - if (err < 0) { - return err; - } + k_sem_init(&dev_data->wake_sem, 0, 1); spi_context_unlock_unconditionally(&dev_data->ctx); - return pm_device_driver_init(dev, spim_nrfx_pm_action); + return pm_device_driver_init(dev, spi_nrfx_spim_common_pm_action); } #ifdef CONFIG_DEVICE_DEINIT_SUPPORT -static int spi_nrfx_deinit(const struct device *dev) +static int driver_deinit(const struct device *dev) { -#if defined(CONFIG_PM_DEVICE) - enum pm_device_state state; - - /* - * PM must have suspended the device before driver can - * be deinitialized - */ - (void)pm_device_state_get(dev, &state); - return state == PM_DEVICE_STATE_SUSPENDED || - state == PM_DEVICE_STATE_OFF ? - 0 : -EBUSY; -#else - /* PM suspend implementation does everything we need */ - spim_suspend(dev); -#endif - - return 0; + return spi_nrfx_spim_common_deinit(dev); } #endif -#define SPI_NRFX_SPIM_EXTENDED_CONFIG(inst) \ - IF_ENABLED(NRFX_SPIM_EXTENDED_ENABLED, \ - (.dcx_pin = NRF_SPIM_PIN_NOT_CONNECTED, \ - COND_CODE_1(DT_INST_PROP(inst, rx_delay_supported), \ - (.rx_delay = DT_INST_PROP(inst, rx_delay),), \ - ()) \ - )) - -#define SPI_NRFX_SPIM_DEFINE(inst) \ - NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(DT_DRV_INST(inst)); \ - NRF_DT_CHECK_NODE_HAS_REQUIRED_MEMORY_REGIONS(DT_DRV_INST(inst)); \ - IF_ENABLED(SPI_BUFFER_IN_RAM, \ - (static uint8_t spim_##inst##_tx_buffer \ - [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ - DMM_MEMORY_SECTION(DT_DRV_INST(inst)); \ - static uint8_t spim_##inst##_rx_buffer \ - [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ - DMM_MEMORY_SECTION(DT_DRV_INST(inst));)) \ - static struct spi_nrfx_data spi_##inst##_data = { \ - .spim = NRFX_SPIM_INSTANCE(DT_INST_REG_ADDR(inst)), \ - IF_ENABLED(CONFIG_MULTITHREADING, \ - (SPI_CONTEXT_INIT_LOCK(spi_##inst##_data, ctx),)) \ - IF_ENABLED(CONFIG_MULTITHREADING, \ - (SPI_CONTEXT_INIT_SYNC(spi_##inst##_data, ctx),)) \ - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), ctx) \ - IF_ENABLED(SPI_BUFFER_IN_RAM, \ - (.tx_buffer = spim_##inst##_tx_buffer, \ - .rx_buffer = spim_##inst##_rx_buffer,)) \ - .dev = DEVICE_DT_GET(DT_DRV_INST(inst)), \ - .busy = false, \ - }; \ - NRF_DT_INST_IRQ_DIRECT_DEFINE( \ - inst, \ - nrfx_spim_irq_handler, \ - &CONCAT(spi_, inst, _data.spim) \ - ) \ - static void irq_connect##inst(void) \ - { \ - NRF_DT_INST_IRQ_CONNECT( \ - inst, \ - nrfx_spim_irq_handler, \ - &CONCAT(spi_, inst, _data.spim) \ - ); \ - } \ - PINCTRL_DT_INST_DEFINE(inst); \ - static const struct spi_nrfx_config spi_##inst##z_config = { \ - .max_freq = DT_INST_PROP(inst, max_frequency), \ - .def_config = { \ - .skip_gpio_cfg = true, \ - .skip_psel_cfg = true, \ - .ss_pin = NRF_SPIM_PIN_NOT_CONNECTED, \ - .orc = DT_INST_PROP(inst, overrun_character), \ - SPI_NRFX_SPIM_EXTENDED_CONFIG(inst) \ - }, \ - .irq_connect = irq_connect##inst, \ - .max_chunk_len = BIT_MASK( \ - DT_INST_PROP(inst, easydma_maxcnt_bits)), \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ - .wake_gpiote = WAKE_GPIOTE_NODE(DT_DRV_INST(inst)), \ - .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(DT_DRV_INST(inst), \ - wake_gpios, \ - WAKE_PIN_NOT_USED), \ - .mem_reg = DMM_DEV_TO_REG(DT_DRV_INST(inst)), \ - }; \ - BUILD_ASSERT(!DT_INST_NODE_HAS_PROP(inst, wake_gpios) || \ - !(DT_GPIO_FLAGS(DT_DRV_INST(inst), wake_gpios) & \ - GPIO_ACTIVE_LOW), \ - "WAKE line must be configured as active high"); \ - PM_DEVICE_DT_INST_DEFINE(inst, spim_nrfx_pm_action); \ - SPI_DEVICE_DT_INST_DEINIT_DEFINE(inst, \ - spi_nrfx_init, \ - spi_nrfx_deinit, \ - PM_DEVICE_DT_INST_GET(inst), \ - &spi_##inst##_data, \ - &spi_##inst##z_config, \ - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ - &spi_nrfx_driver_api) - -DT_INST_FOREACH_STATUS_OKAY(SPI_NRFX_SPIM_DEFINE) +#define DRIVER_DEFINE(inst) \ + static struct driver_data CONCAT(data, inst) = { \ + .common = SPI_NRFX_COMMON_DATA_INIT(inst), \ + IF_ENABLED( \ + CONFIG_MULTITHREADING, \ + (SPI_CONTEXT_INIT_LOCK(CONCAT(data, inst), ctx),) \ + ) \ + IF_ENABLED( \ + CONFIG_MULTITHREADING, \ + (SPI_CONTEXT_INIT_SYNC(CONCAT(data, inst), ctx),) \ + ) \ + }; \ + \ + SPI_NRFX_COMMON_DEFINE(inst, &CONCAT(data, inst)); \ + \ + static const struct driver_config CONCAT(config, inst) = { \ + .common = SPI_NRFX_COMMON_CONFIG_INIT( \ + inst, \ + spim_evt_handler \ + ), \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, spi_nrfx_spim_common_pm_action, 1); \ + \ + SPI_DEVICE_DT_INST_DEINIT_DEFINE( \ + inst, \ + driver_init, \ + driver_deinit, \ + PM_DEVICE_DT_INST_GET(inst), \ + &CONCAT(data, inst), \ + &CONCAT(config, inst), \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &driver_api \ + ) + +DT_INST_FOREACH_STATUS_OKAY(DRIVER_DEFINE) From 3b3597d9f48036166370d0715bd7e3b9017948b7 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Mon, 23 Feb 2026 19:12:01 +0100 Subject: [PATCH 08/20] [nrf fromtree] tests: drivers: spi_loopback: add nrf54h and nrf54l to rtio case Add nrf54h20dk and nrf54l15dk to drivers.spi.loopback.rtio test case. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 09dd50b95f68e8e857f7d3850007da3725ddcd9b) (cherry picked from commit 7defeb4b938902fc2742150bea979b30c4de2fdc) --- tests/drivers/spi/spi_loopback/testcase.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/drivers/spi/spi_loopback/testcase.yaml b/tests/drivers/spi/spi_loopback/testcase.yaml index 5dcf4c651f1c..ecdb68f09409 100644 --- a/tests/drivers/spi/spi_loopback/testcase.yaml +++ b/tests/drivers/spi/spi_loopback/testcase.yaml @@ -36,6 +36,8 @@ tests: - mimxrt1170_evk/mimxrt1176/cm7 - bg29_rb4420a - xg29_rb4412a + - nrf54h20dk/nrf54h20/cpuapp + - nrf54l15dk/nrf54l15/cpuapp integration_platforms: - robokit1 drivers.spi.mcux_dspi_dma.loopback: From 8606bdbe4dac945f04e0fd0154e4ae53955e3f2f Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 26 Feb 2026 15:54:36 +0100 Subject: [PATCH 09/20] [nrf fromtree] tests: drivers: spi_loopback: exclude nrf spim from same_buf_cmd The nrf spim peripheral uses two EasyDMA channels, one read and one write. Two channels can't access the same memory at the same time, so if the spi frequency is too high, data will he lost/corrupted. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 7e5df6d7add776a341873febf6d96e0cfc24afb1) (cherry picked from commit 5a6758f33bfe231f2665b996058d5aa562b5d1aa) --- tests/drivers/spi/spi_loopback/src/spi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/drivers/spi/spi_loopback/src/spi.c b/tests/drivers/spi/spi_loopback/src/spi.c index 5f3598ea89d0..5a4c97bc58c8 100644 --- a/tests/drivers/spi/spi_loopback/src/spi.c +++ b/tests/drivers/spi/spi_loopback/src/spi.c @@ -676,7 +676,10 @@ ZTEST(spi_loopback, test_spi_write_back) /* similar to test_spi_write_back, simulates the real common case of 1 word command */ ZTEST(spi_loopback, test_spi_same_buf_cmd) { - if (IS_ENABLED(CONFIG_SPI_STM32_DMA) || IS_ENABLED(CONFIG_DSPI_MCUX_EDMA)) { + if (IS_ENABLED(CONFIG_SPI_STM32_DMA) || + IS_ENABLED(CONFIG_DSPI_MCUX_EDMA) || + IS_ENABLED(CONFIG_SPI_NRFX_SPIM) || + IS_ENABLED(CONFIG_SPI_NRFX_SPIM_RTIO)) { ztest_test_skip(); } From 018c3d4cddeb6abf470c5a778482a8e4111daba6 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Apr 2026 13:26:15 +0200 Subject: [PATCH 10/20] [nrf fromtree] drivers: spi: spi_nrfx_spim_rtio: update spi_rtio.h include path The header at drivers/spi/rtio.h was moved to a relative path, and renamed "spi_rtio.h". Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 8ff7835ff1016d14514600867e5808db00c66200) (cherry picked from commit ae2d9d072442e8258ad6040eb78492667375dfa7) --- drivers/spi/spi_nrfx_spim_rtio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim_rtio.c b/drivers/spi/spi_nrfx_spim_rtio.c index 1df42b8e355b..83b5f8f95732 100644 --- a/drivers/spi/spi_nrfx_spim_rtio.c +++ b/drivers/spi/spi_nrfx_spim_rtio.c @@ -7,8 +7,7 @@ #define DT_DRV_COMPAT nordic_nrf_spim #include "spi_nrfx_spim_common.h" - -#include +#include "spi_rtio.h" LOG_MODULE_DECLARE(spi_nrfx_spim); From 1952aab641ea6cf67ceccfa8c5c9e50c56303a37 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Apr 2026 13:36:04 +0200 Subject: [PATCH 11/20] [nrf fromtree] drivers: spi: spi_nrfx_spim_common.c: patch pinctrl sleep state set The common pm_suspend implementation for the spi_nrfx_spim drivers unconditionally sets the sleep state. The sleep state may not be available, in which case we should not try to set it. Check CONFIG_PINCTRL_KEEP_SLEEP_STATE and only try to set sleep state if true. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 50df2d9a7797000c620bf028b8194655882962c7) (cherry picked from commit 1a4692a12811df0ccf1eef20596290ed56110799) --- drivers/spi/spi_nrfx_spim_common.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim_common.c b/drivers/spi/spi_nrfx_spim_common.c index ad630083d2a9..591cd0fe320d 100644 --- a/drivers/spi/spi_nrfx_spim_common.c +++ b/drivers/spi/spi_nrfx_spim_common.c @@ -610,9 +610,12 @@ static int cs_put(const struct device *dev) static int pm_suspend(const struct device *dev) { struct spi_nrfx_common_data *dev_data = dev->data; - const struct spi_nrfx_common_config *dev_config = dev->config; int ret; +#if CONFIG_PINCTRL_KEEP_SLEEP_STATE + const struct spi_nrfx_common_config *dev_config = dev->config; +#endif + if (dev_data->configured) { nrfx_spim_uninit(&dev_data->spim); dev_data->configured = false; @@ -623,10 +626,12 @@ static int pm_suspend(const struct device *dev) return ret; } +#if CONFIG_PINCTRL_KEEP_SLEEP_STATE ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); if (ret) { return ret; } +#endif return 0; } @@ -803,11 +808,6 @@ int spi_nrfx_spim_common_init(const struct device *dev) return ret; } - ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); - if (ret) { - return ret; - } - return 0; } From e47096a4368a801002c7be533637feacacce6ec5 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Apr 2026 13:40:55 +0200 Subject: [PATCH 12/20] [nrf fromtree] tests: drivers: spi: controller_periph: lower nrf54l15 spi22 freq The nrf54l15 SPIM22 instance does not support 16MHz, lower to 8MHz. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit a0d910e5634ba5f5beb21822eb5236dcc3ce2f43) (cherry picked from commit 4cd3ee5e096652739b870a329a88e436d6b13314) --- .../boards/nrf54l15dk_nrf54l15_cpuapp.overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54l15dk_nrf54l15_cpuapp.overlay index cf83ac20a270..e26a549a97a1 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54l15dk_nrf54l15_cpuapp.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -58,7 +58,7 @@ dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; - spi-max-frequency = ; + spi-max-frequency = ; }; }; From eaa2c7fbfe4a451e05e94cda69cb26d5ecaf3bf3 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Apr 2026 15:24:56 +0200 Subject: [PATCH 13/20] [nrf fromtree] drivers: spi: nrfx_spim_rtio: set CS after configuring SPIM Ensure SPI pins are correctly configured before setting CS, by configuring the SPIM before setting CS. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit ca9b6d4ab948938f88eb760545804b363d12b4e0) (cherry picked from commit c71efc397832077ee65aea27c301c7fb8bff9827) --- drivers/spi/spi_nrfx_spim_rtio.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim_rtio.c b/drivers/spi/spi_nrfx_spim_rtio.c index 83b5f8f95732..35990b96f231 100644 --- a/drivers/spi/spi_nrfx_spim_rtio.c +++ b/drivers/spi/spi_nrfx_spim_rtio.c @@ -21,7 +21,7 @@ struct driver_config { }; static void iodev_end_curr(const struct device *dev); -static void iodev_start_txn(const struct device *dev); +static void iodev_start_curr(const struct device *dev); static void iodev_end_txn(const struct device *dev, int result); static void iodev_await_callback(struct rtio_iodev_sqe *iodev_sqe, void *userdata) @@ -94,6 +94,8 @@ static void iodev_start_curr(const struct device *dev) break; } + spi_nrfx_spim_common_cs_set(dev, spi_cfg); + ret = spi_nrfx_spim_common_transfer_start(dev, tx_buf, tx_buf_len, @@ -117,18 +119,6 @@ static void iodev_start_curr(const struct device *dev) } } -static void iodev_start_txn(const struct device *dev) -{ - const struct driver_config *dev_config = dev->config; - struct spi_rtio *spi_rtio_ctx = dev_config->spi_rtio_ctx; - struct rtio_sqe *sqe = &spi_rtio_ctx->txn_head->sqe; - struct spi_dt_spec *spi_spec = sqe->iodev->data; - struct spi_config *spi_cfg = &spi_spec->config; - - spi_nrfx_spim_common_cs_set(dev, spi_cfg); - iodev_start_curr(dev); -} - static void iodev_end_txn(const struct device *dev, int result) { const struct driver_config *dev_config = dev->config; @@ -145,7 +135,7 @@ static void iodev_end_txn(const struct device *dev, int result) return; } - iodev_start_txn(dev); + iodev_start_curr(dev); } static void iodev_end_curr(const struct device *dev) @@ -199,7 +189,7 @@ static int driver_api_transceive_async(const struct device *dev, static void spim_wake_handler(const struct device *dev) { - iodev_start_txn(dev); + iodev_start_curr(dev); } static void driver_api_iodev_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) From 3cb8d9a189149a53a49eff18d11e526949f5eb86 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Apr 2026 17:10:28 +0200 Subject: [PATCH 14/20] [nrf fromtree] tests: spi: loopback: update SPIM error regex for nrf platforms The SPIM driver now produces the error "Failed to configure nrfx driver" rather than "Failed to initialize nrfx driver" as the driver now reconfigures the SPIM. Update testcases to match. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit e511b529e093ff091fbbdc9a185e0e6ddbaa96a3) (cherry picked from commit 8e6b539ca8bca9da01d0cb4f1ff06747520433ad) --- tests/drivers/spi/spi_loopback/testcase.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/drivers/spi/spi_loopback/testcase.yaml b/tests/drivers/spi/spi_loopback/testcase.yaml index ecdb68f09409..cf1c5a6f826f 100644 --- a/tests/drivers/spi/spi_loopback/testcase.yaml +++ b/tests/drivers/spi/spi_loopback/testcase.yaml @@ -286,7 +286,7 @@ tests: fixture: spi_loopback type: one_line regex: - - "Failed to initialize nrfx driver" + - "Failed to configure nrfx driver" drivers.spi.nrf54h_fast_8mhz: extra_args: DTC_OVERLAY_FILE="boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay" platform_allow: @@ -319,7 +319,7 @@ tests: fixture: spi_loopback type: one_line regex: - - "Failed to initialize nrfx driver" + - "Failed to configure nrfx driver" drivers.spi.nrf54l_8mhz: extra_args: EXTRA_DTC_OVERLAY_FILE="boards/nrf_at_8mhz.overlay" platform_allow: From 9ec4282b66a7ddb3129cf4f953d6e8dbc579b657 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Apr 2026 18:52:27 +0200 Subject: [PATCH 15/20] [nrf fromtree] drivers: spi: nrfx_spim: move update of buffer to after transfer Update the tx and rx buffer progress after each transfer has completed. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit ff6084fe9610f5316deefc8b38b61a4ec6783b24) (cherry picked from commit af1aae44b2cbd0b41bcf8d1946ec7b4141aa0841) --- drivers/spi/spi_nrfx_spim.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 4914a5b629a7..f7923fe5e503 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -77,9 +77,6 @@ static void transfer_start(const struct device *dev) transfer_end(dev, ret); return; } - - spi_context_update_tx(&dev_data->ctx, 1, chunk_len); - spi_context_update_rx(&dev_data->ctx, 1, chunk_len); } static void spim_wake_handler(const struct device *dev) @@ -91,7 +88,12 @@ static void spim_wake_handler(const struct device *dev) static void spim_evt_handler(const struct device *dev, nrfx_spim_event_t *evt) { + struct driver_data *dev_data = dev->data; + uint32_t len = MAX(evt->xfer_desc.tx_length, evt->xfer_desc.rx_length); + spi_nrfx_spim_common_transfer_end(dev, &evt->xfer_desc); + spi_context_update_tx(&dev_data->ctx, 1, len); + spi_context_update_rx(&dev_data->ctx, 1, len); transfer_start(dev); } From c40d9329b8157ece23782f78af4b02f278986148 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Thu, 16 Apr 2026 18:55:45 +0200 Subject: [PATCH 16/20] [nrf fromtree] drivers: spi: context: calculate total rxtx before using buffers The spi context tx_buf, rx_buf, tx_count and rx_count members are modified during the transfer. These members are currently accessed in spi_context_wait_for_completion when calculating the expected timeout, which happens concurrently with the transfer being in progress. This can lead to concurrency issues as the mentioned members may be modified independently as they are being accessed by the thread setting up the wait. Remove this potential conflict by calculating the number of bytes as part of spi_context_buffers_setup and store it, before the transfer is started. Then used the stored value when setting up the wait. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 05d6a7f770ef5a8beec216e0792dc58bff30692f) (cherry picked from commit 184948e505ef2379572abf1c66c1657efa07ac20) --- drivers/spi/spi_context.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi_context.h b/drivers/spi/spi_context.h index 25fdbf8d8ad2..e2146bff354b 100644 --- a/drivers/spi/spi_context.h +++ b/drivers/spi/spi_context.h @@ -62,6 +62,8 @@ struct spi_context { const struct spi_buf *current_rx; size_t rx_count; + size_t max_count; + const uint8_t *tx_buf; size_t tx_len; uint8_t *rx_buf; @@ -206,13 +208,8 @@ static inline int spi_context_wait_for_completion(struct spi_context *ctx) if (IS_ENABLED(CONFIG_SPI_SLAVE) && spi_context_is_slave(ctx)) { timeout = K_FOREVER; } else { - uint32_t tx_len = spi_context_total_tx_len(ctx); - uint32_t rx_len = spi_context_total_rx_len(ctx); - - timeout_ms = MAX(tx_len, rx_len) * 8 * 1000 / - ctx->config->frequency; + timeout_ms = ctx->max_count * 8 * 1000 / ctx->config->frequency; timeout_ms += CONFIG_SPI_COMPLETION_TIMEOUT_TOLERANCE; - timeout = K_MSEC(timeout_ms); } #ifdef CONFIG_MULTITHREADING @@ -495,6 +492,7 @@ void spi_context_buffers_setup(struct spi_context *ctx, &ctx->rx_len, dfs); ctx->sync_status = 0; + ctx->max_count = MAX(spi_context_total_tx_len(ctx), spi_context_total_rx_len(ctx)); #ifdef CONFIG_SPI_SLAVE ctx->recv_frames = 0; From 9a1cd0a57838f5fb4f57a1297cd4b83c208c20cd Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 17 Apr 2026 10:37:27 +0200 Subject: [PATCH 17/20] [nrf fromtree] drivers: spi: nrfx_spim_common: include gpiote_nrfx.h The gpiote_nrfx.h header is needed for a macro used when handling NRF52_ANOMALY_58 Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 0068b2f06b77ba19740601548f0048724be20efe) (cherry picked from commit da36b80dc453d39f1efbf8a964e42c829255357c) --- drivers/spi/spi_nrfx_spim_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi_nrfx_spim_common.c b/drivers/spi/spi_nrfx_spim_common.c index 591cd0fe320d..1d0910037975 100644 --- a/drivers/spi/spi_nrfx_spim_common.c +++ b/drivers/spi/spi_nrfx_spim_common.c @@ -12,6 +12,8 @@ #include #endif +#include + #define WAKE_PIN_START_FLAGS (GPIO_INPUT | GPIO_PULL_UP) #define WAKE_PIN_STOP_FLAGS (GPIO_INPUT | GPIO_PULL_DOWN | GPIO_DISCONNECTED) From c56bb601f9d2b07bc6d5e79141919a2032c59f9a Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 17 Apr 2026 17:59:58 +0200 Subject: [PATCH 18/20] [nrf fromtree] drivers: spi: nrfx_spim: patch flow so bus inits before cs is set The current flow sets CS before the SPIM peripheral actually drives the bus. This can cause SCK to be in the incorrect initial state dictated by CPOL. New flow enables SPIM after it has been configured, before CS is set, and disabled is after CS is cleared, thus the bus is driven by SPIM during the entire transfer. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 407cedc1cffd6f683a586830349173ca78edc89b) (cherry picked from commit 2297ceb1cf8616b2d8aa54d052043dfd7dade5a4) --- drivers/spi/spi_nrfx_spim_common.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi_nrfx_spim_common.c b/drivers/spi/spi_nrfx_spim_common.c index 1d0910037975..2c75471f66ae 100644 --- a/drivers/spi/spi_nrfx_spim_common.c +++ b/drivers/spi/spi_nrfx_spim_common.c @@ -50,17 +50,20 @@ void spi_nrfx_spim_common_cs_set(const struct device *dev, const struct spi_conf struct spi_nrfx_common_data *dev_data = dev->data; NRF_SPIM_Type *spim_reg = dev_data->spim.p_reg; - if (spi_cfg->cs.cs_is_gpio == false && NRF_SPIM_IS_320MHZ_SPIM(spim_reg) == false) { - return; - } + /* + * Enable the SPIM peripheral so it drives the SPI bus, ensuring correct initial bus state + * before transfer starts, and setting CS if its controlled by the SPIM peripheral. + */ + nrfy_spim_enable(spim_reg); if (spi_cfg->cs.cs_is_gpio) { gpio_pin_set_dt(&spi_cfg->cs.gpio, 1); - } else { - nrfy_spim_enable(spim_reg); } - k_busy_wait(spi_cfg->cs.delay); + /* Wait only if we control the CS pin */ + if (spi_cfg->cs.cs_is_gpio || NRF_SPIM_IS_320MHZ_SPIM(spim_reg)) { + k_busy_wait(spi_cfg->cs.delay); + } } void spi_nrfx_spim_common_cs_clear(const struct device *dev, const struct spi_config *spi_cfg) @@ -68,17 +71,20 @@ void spi_nrfx_spim_common_cs_clear(const struct device *dev, const struct spi_co struct spi_nrfx_common_data *dev_data = dev->data; NRF_SPIM_Type *spim_reg = dev_data->spim.p_reg; - if (spi_cfg->cs.cs_is_gpio == false && NRF_SPIM_IS_320MHZ_SPIM(spim_reg) == false) { - return; + /* Wait only if we control the CS pin */ + if (spi_cfg->cs.cs_is_gpio || NRF_SPIM_IS_320MHZ_SPIM(spim_reg)) { + k_busy_wait(spi_cfg->cs.delay); } - k_busy_wait(spi_cfg->cs.delay); - if (spi_cfg->cs.cs_is_gpio) { gpio_pin_set_dt(&spi_cfg->cs.gpio, 0); - } else { - nrfy_spim_disable(spim_reg); } + + /* + * Disable the SPIM peripheral so it no longer drives the SPI bus, clearing CS if its + * controlled by the SPIM peripheral. + */ + nrfy_spim_disable(spim_reg); } static void evt_handler(nrfx_spim_event_t const *evt, void *data) From ca73e642c5c4cf5875df6b2db8c59d7716a75bd4 Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 12 May 2026 11:20:36 +0200 Subject: [PATCH 19/20] [nrf fromtree] drivers: spi: nrfx_spim_common: Limit freq by max_freq of controller When configuring the nRF SPIM, the frequency needs to be limited by the max frequency of the SPIM, which is specified in the devicetree. Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit b2085e6cd6400cd8a2dadaee8328ed430a2d4b11) (cherry picked from commit e589b5a5e79fe2822ce3354b91d746afc5eba469) --- drivers/spi/spi_nrfx_spim_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_nrfx_spim_common.c b/drivers/spi/spi_nrfx_spim_common.c index 2c75471f66ae..845d1edf8ac9 100644 --- a/drivers/spi/spi_nrfx_spim_common.c +++ b/drivers/spi/spi_nrfx_spim_common.c @@ -561,7 +561,7 @@ int spi_nrfx_spim_common_configure(const struct device *dev, const struct spi_co spim_cfg.ss_pin = NRF_SPIM_PIN_NOT_CONNECTED; spim_cfg.orc = dev_config->orc; - spim_cfg.frequency = resolve_freq(spi_cfg->frequency); + spim_cfg.frequency = MIN(resolve_freq(spi_cfg->frequency), dev_config->max_freq); spim_cfg.mode = mode_from_op(spi_cfg->operation); spim_cfg.bit_order = bit_order_from_op(spi_cfg->operation); #if NRF_SPIM_HAS_DCX From 74a21487267ae5f6e4fddddeb0562d18c0e6a84c Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Fri, 1 May 2026 15:32:25 +0200 Subject: [PATCH 20/20] [nrf fromtree] tests: drivers: spi: lower nrf54l and nrf7120 SPI freq to 8MHz The nrf7120 and nrf54l SPIM21 and SPIM22 instances do not support 16MHz, and the SPIS21 only supports up to 8MHz according to the datasheet. The SPIS21 is the target device, which is what defines the spi-max-frequency, compared to the max-frequency of the bus, which does correctly set it to 8MHz for the SPIM instances. Lower the spi-max-frequency to 8MHz, and remove the nrf7120 from the 16Mhz and 32Mhz test case from testcase.yaml Signed-off-by: Bjarki Arge Andreasen (cherry picked from commit 040034b7ee44da4245cb34780a9d4194ff6356b0) (cherry picked from commit fbc1377458028323f2281716e08216b6d40e0459) --- .../boards/bl54l15_dvk_nrf54l15_cpuapp.overlay | 2 +- .../boards/bl54l15u_dvk_nrf54l15_cpuapp.overlay | 2 +- .../boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay | 2 +- .../boards/nrf54lm20dk_nrf54lm20b_cpuapp.overlay | 2 +- .../boards/nrf7120dk_nrf7120_cpuapp.overlay | 2 +- .../boards/ophelia4ev_nrf54l15_cpuapp.overlay | 2 +- tests/drivers/spi/spi_loopback/testcase.yaml | 2 -- 7 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15_dvk_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15_dvk_nrf54l15_cpuapp.overlay index ec14118e6b37..37526d41b315 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15_dvk_nrf54l15_cpuapp.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15_dvk_nrf54l15_cpuapp.overlay @@ -59,7 +59,7 @@ dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; - spi-max-frequency = ; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15u_dvk_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15u_dvk_nrf54l15_cpuapp.overlay index ec14118e6b37..37526d41b315 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15u_dvk_nrf54l15_cpuapp.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/bl54l15u_dvk_nrf54l15_cpuapp.overlay @@ -59,7 +59,7 @@ dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; - spi-max-frequency = ; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay index 0c782e8ff9cc..5003d8e3e701 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay @@ -65,7 +65,7 @@ dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; - spi-max-frequency = ; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20b_cpuapp.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20b_cpuapp.overlay index 56d1cf573d00..23cc3e1dc38d 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20b_cpuapp.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54lm20dk_nrf54lm20b_cpuapp.overlay @@ -65,7 +65,7 @@ dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; - spi-max-frequency = ; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/nrf7120dk_nrf7120_cpuapp.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/nrf7120dk_nrf7120_cpuapp.overlay index 8e9d6ce4c265..264bd06c587a 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/nrf7120dk_nrf7120_cpuapp.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/nrf7120dk_nrf7120_cpuapp.overlay @@ -58,7 +58,7 @@ dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; - spi-max-frequency = ; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/ophelia4ev_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/ophelia4ev_nrf54l15_cpuapp.overlay index 5a6b6928e056..977d9de5154b 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/ophelia4ev_nrf54l15_cpuapp.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/ophelia4ev_nrf54l15_cpuapp.overlay @@ -58,7 +58,7 @@ dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; - spi-max-frequency = ; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_loopback/testcase.yaml b/tests/drivers/spi/spi_loopback/testcase.yaml index cf1c5a6f826f..25cd348b520b 100644 --- a/tests/drivers/spi/spi_loopback/testcase.yaml +++ b/tests/drivers/spi/spi_loopback/testcase.yaml @@ -332,13 +332,11 @@ tests: extra_args: EXTRA_DTC_OVERLAY_FILE="boards/nrf_at_16mhz.overlay" platform_allow: - nrf54l15dk/nrf54l15/cpuapp - - nrf7120dk/nrf7120/cpuapp - ophelia4ev/nrf54l15/cpuapp drivers.spi.nrf54l_32mhz: extra_args: EXTRA_DTC_OVERLAY_FILE="boards/nrf_at_32mhz.overlay" platform_allow: - nrf54l15dk/nrf54l15/cpuapp - - nrf7120dk/nrf7120/cpuapp - ophelia4ev/nrf54l15/cpuapp drivers.spi.nrf54lm20_16mhz_32mhz: harness: ztest