diff --git a/drivers/spi/spi_context.h b/drivers/spi/spi_context.h index a5110f52de8c6..3017010110565 100644 --- a/drivers/spi/spi_context.h +++ b/drivers/spi/spi_context.h @@ -86,7 +86,8 @@ static inline bool spi_context_is_slave(struct spi_context *ctx) return (ctx->config->operation & SPI_OP_MODE_SLAVE); } -static inline void spi_context_lock(struct spi_context *ctx, +static inline void spi_context_lock_pm(const struct device *dev, + struct spi_context *ctx, bool asynchronous, spi_callback_t callback, void *callback_data, @@ -99,6 +100,9 @@ static inline void spi_context_lock(struct spi_context *ctx, } k_sem_take(&ctx->lock, K_FOREVER); + if (dev) { + pm_device_runtime_get(dev); + } ctx->owner = spi_cfg; #ifdef CONFIG_SPI_ASYNC @@ -108,7 +112,18 @@ static inline void spi_context_lock(struct spi_context *ctx, #endif /* CONFIG_SPI_ASYNC */ } -static inline void spi_context_release(struct spi_context *ctx, int status) +static inline void spi_context_lock(struct spi_context *ctx, + bool asynchronous, + spi_callback_t callback, + void *callback_data, + const struct spi_config *spi_cfg) +{ + spi_context_lock_pm(NULL, ctx, asynchronous, + callback, callback_data, spi_cfg); +} + +static inline void spi_context_release_pm(const struct device *dev, + struct spi_context *ctx, int status) { #ifdef CONFIG_SPI_SLAVE if (status >= 0 && (ctx->config->operation & SPI_LOCK_ON)) { @@ -119,16 +134,27 @@ static inline void spi_context_release(struct spi_context *ctx, int status) #ifdef CONFIG_SPI_ASYNC if (!ctx->asynchronous || (status < 0)) { ctx->owner = NULL; + if (dev) { + pm_device_runtime_put_async(dev); + } k_sem_give(&ctx->lock); } #else if (!(ctx->config->operation & SPI_LOCK_ON)) { ctx->owner = NULL; + if (dev) { + pm_device_runtime_put_async(dev); + } k_sem_give(&ctx->lock); } #endif /* CONFIG_SPI_ASYNC */ } +static inline void spi_context_release(struct spi_context *ctx, int status) +{ + spi_context_release_pm(NULL, ctx, status); +} + static inline size_t spi_context_total_tx_len(struct spi_context *ctx); static inline size_t spi_context_total_rx_len(struct spi_context *ctx); @@ -180,7 +206,7 @@ static inline int spi_context_wait_for_completion(struct spi_context *ctx) return status; } -static inline void spi_context_complete(struct spi_context *ctx, +static inline void spi_context_complete_pm(int do_pm, struct spi_context *ctx, const struct device *dev, int status) { @@ -203,6 +229,9 @@ static inline void spi_context_complete(struct spi_context *ctx, if (!(ctx->config->operation & SPI_LOCK_ON)) { ctx->owner = NULL; + if (do_pm) { + pm_device_runtime_put_async(dev); + } k_sem_give(&ctx->lock); } } @@ -212,6 +241,13 @@ static inline void spi_context_complete(struct spi_context *ctx, #endif /* CONFIG_SPI_ASYNC */ } +static inline void spi_context_complete(struct spi_context *ctx, + const struct device *dev, + int status) +{ + spi_context_complete_pm(0, ctx, dev, status); +} + static inline int spi_context_cs_configure_all(struct spi_context *ctx) { int ret; @@ -257,17 +293,27 @@ static inline void spi_context_cs_control(struct spi_context *ctx, bool on) _spi_context_cs_control(ctx, on, false); } -static inline void spi_context_unlock_unconditionally(struct spi_context *ctx) +static inline void spi_context_unlock_unconditionally_pm( + const struct device *dev, + struct spi_context *ctx) { /* Forcing CS to go to inactive status */ _spi_context_cs_control(ctx, false, true); if (!k_sem_count_get(&ctx->lock)) { ctx->owner = NULL; + if (dev) { + pm_device_runtime_put_async(dev); + } k_sem_give(&ctx->lock); } } +static inline void spi_context_unlock_unconditionally(struct spi_context *ctx) +{ + spi_context_unlock_unconditionally_pm(NULL, ctx); +} + static inline void *spi_context_get_next_buf(const struct spi_buf **current, size_t *count, size_t *buf_len, diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 3de9f82709c5d..99b021f72cfe7 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -317,10 +318,10 @@ static void finish_transaction(const struct device *dev, int error) LOG_DBG("Transaction finished with status %d", error); - spi_context_complete(ctx, dev, error); + finalize_spi_transaction(dev, true); dev_data->busy = false; - finalize_spi_transaction(dev, true); + spi_context_complete_pm(1, ctx, dev, error); } static void transfer_next_chunk(const struct device *dev) @@ -457,7 +458,8 @@ static int transceive(const struct device *dev, void *reg = dev_config->spim.p_reg; int error; - spi_context_lock(&dev_data->ctx, asynchronous, cb, userdata, spi_cfg); + spi_context_lock_pm(dev, &dev_data->ctx, asynchronous, + cb, userdata, spi_cfg); error = configure(dev, spi_cfg); if (error == 0) { @@ -513,7 +515,7 @@ static int transceive(const struct device *dev, } } - spi_context_release(&dev_data->ctx, error); + spi_context_release_pm(dev, &dev_data->ctx, error); return error; } @@ -551,8 +553,8 @@ static int spi_nrfx_release(const struct device *dev, return -EBUSY; } - spi_context_unlock_unconditionally(&dev_data->ctx); finalize_spi_transaction(dev, false); + spi_context_unlock_unconditionally_pm(dev, &dev_data->ctx); return 0; } @@ -568,11 +570,10 @@ static const struct spi_driver_api spi_nrfx_driver_api = { .release = spi_nrfx_release, }; -#ifdef CONFIG_PM_DEVICE static int spim_nrfx_pm_action(const struct device *dev, enum pm_device_action action) { - int ret = 0; + int ret = -ENOTSUP; struct spi_nrfx_data *dev_data = dev->data; const struct spi_nrfx_config *dev_config = dev->config; @@ -580,35 +581,29 @@ static int spim_nrfx_pm_action(const struct device *dev, case PM_DEVICE_ACTION_RESUME: ret = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; - } /* nrfx_spim_init() will be called at configuration before * the next transfer. */ break; case PM_DEVICE_ACTION_SUSPEND: - if (dev_data->initialized) { - nrfx_spim_uninit(&dev_config->spim); - dev_data->initialized = false; - } + if (IS_ENABLED(CONFIG_PM_DEVICE)) { + if (dev_data->initialized) { + nrfx_spim_uninit(&dev_config->spim); + dev_data->initialized = false; + } - ret = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; - } + ret = pinctrl_apply_state(dev_config->pcfg, + PINCTRL_STATE_SLEEP); + } break; default: - ret = -ENOTSUP; + break; } return ret; } -#endif /* CONFIG_PM_DEVICE */ - static int spi_nrfx_init(const struct device *dev) { @@ -643,10 +638,16 @@ static int spi_nrfx_init(const struct device *dev) spi_context_unlock_unconditionally(&dev_data->ctx); #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 - return anomaly_58_workaround_init(dev); -#else - return 0; + err = anomaly_58_workaround_init(dev); + if (err < 0) { + return err; + } #endif + if (IS_ENABLED(CONFIG_PM_DEVICE)) { + /* start in suspended state */ + pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); + } + return pm_device_driver_init(dev, spim_nrfx_pm_action); } /* * We use NODELABEL here because the nrfx API requires us to call diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/nrf52840dk_nrf52840.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/nrf52840dk_nrf52840.overlay index 97802a7a6377f..91cd073041e69 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/nrf52840dk_nrf52840.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/nrf52840dk_nrf52840.overlay @@ -50,9 +50,11 @@ pinctrl-names = "default", "sleep"; overrun-character = <0x00>; cs-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_common.dtsi index 8661760a5e30a..d431933ab5a75 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -60,6 +60,7 @@ pinctrl-names = "default", "sleep"; overrun-character = <0x00>; cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; diff --git a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay index 9422ff33fd6d7..798d28b8ab9cb 100644 --- a/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay +++ b/tests/drivers/spi/spi_controller_peripheral/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay @@ -59,6 +59,7 @@ overrun-character = <0x00>; memory-regions = <&dma_fast_region>; cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; 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 73a50a7c6fc10..0188a2c4e24dc 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 @@ -54,9 +54,11 @@ pinctrl-names = "default", "sleep"; overrun-character = <0x00>; cs-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; dut_spi_dt: test-spi-dev@0 { compatible = "vnd,spi-device"; reg = <0>; + spi-max-frequency = ; }; }; diff --git a/tests/drivers/spi/spi_controller_peripheral/testcase.yaml b/tests/drivers/spi/spi_controller_peripheral/testcase.yaml index 675259a4dd0ca..51a503e92318f 100644 --- a/tests/drivers/spi/spi_controller_peripheral/testcase.yaml +++ b/tests/drivers/spi/spi_controller_peripheral/testcase.yaml @@ -57,3 +57,9 @@ tests: - nrf52840dk/nrf52840 - nrf54l15dk/nrf54l15/cpuapp - nrf54h20dk/nrf54h20/cpurad + + drivers.spi.pm_runtime: + extra_configs: + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_RUNTIME=y + filter: CONFIG_SOC_FAMILY_NORDIC_NRF diff --git a/tests/drivers/spi/spi_loopback/boards/nrf51dk_nrf51822.overlay b/tests/drivers/spi/spi_loopback/boards/nrf51dk_nrf51822.overlay index 812f643f3e8e0..06a0d63816a56 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf51dk_nrf51822.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nrf51dk_nrf51822.overlay @@ -7,6 +7,7 @@ &spi1 { overrun-character = <0x00>; cs-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/boards/nrf52840dk_nrf52840.overlay b/tests/drivers/spi/spi_loopback/boards/nrf52840dk_nrf52840.overlay index 7f511d0753dae..7de4d8d6322cb 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf52840dk_nrf52840.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nrf52840dk_nrf52840.overlay @@ -8,6 +8,7 @@ overrun-character = <0x00>; rx-delay = <1>; cs-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/boards/nrf52dk_nrf52832.overlay b/tests/drivers/spi/spi_loopback/boards/nrf52dk_nrf52832.overlay index 812f643f3e8e0..06a0d63816a56 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf52dk_nrf52832.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nrf52dk_nrf52832.overlay @@ -7,6 +7,7 @@ &spi1 { overrun-character = <0x00>; cs-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 89e5fbad08a94..6743e1d093384 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -30,6 +30,7 @@ pinctrl-names = "default", "sleep"; overrun-character = <0x00>; memory-regions = <&cpuapp_dma_region>; + zephyr,pm-device-runtime-auto; slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay index b140cd34ff480..de624ab3c6611 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_cpuapp_fast.overlay @@ -34,6 +34,7 @@ pinctrl-names = "default", "sleep"; overrun-character = <0x00>; memory-regions = <&dma_fast_region>; + zephyr,pm-device-runtime-auto; slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/tests/drivers/spi/spi_loopback/boards/nrf54l15dk_nrf54l15_cpuapp.overlay index f2e84b72f9b35..8dcf6fd190d8f 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf54l15dk_nrf54l15_cpuapp.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -29,6 +29,7 @@ pinctrl-1 = <&spi00_sleep>; pinctrl-names = "default", "sleep"; overrun-character = <0x00>; + zephyr,pm-device-runtime-auto; slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/boards/nrf9160dk_nrf9160.overlay b/tests/drivers/spi/spi_loopback/boards/nrf9160dk_nrf9160.overlay index a07ed5fbf5d6b..bcd2472166a6d 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf9160dk_nrf9160.overlay +++ b/tests/drivers/spi/spi_loopback/boards/nrf9160dk_nrf9160.overlay @@ -7,6 +7,7 @@ &spi3 { overrun-character = <0x00>; cs-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>; + zephyr,pm-device-runtime-auto; slow@0 { compatible = "test-spi-loopback-slow"; reg = <0>; diff --git a/tests/drivers/spi/spi_loopback/testcase.yaml b/tests/drivers/spi/spi_loopback/testcase.yaml index 3087e65c640d2..d6a60ea6550e2 100644 --- a/tests/drivers/spi/spi_loopback/testcase.yaml +++ b/tests/drivers/spi/spi_loopback/testcase.yaml @@ -210,3 +210,8 @@ tests: platform_allow: - s32z2xxdc2/s32z270/rtu0 - s32z2xxdc2/s32z270/rtu1 + drivers.spi.nrf_pm_runtime: + extra_configs: + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_RUNTIME=y + filter: CONFIG_SOC_FAMILY_NORDIC_NRF