diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 39377d7b777..d5480c9149b 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -64,20 +64,15 @@ static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags) return NRF_GPIO_PIN_NOPULL; } -static void gpio_nrfx_gpd_retain_set(const struct device *port, uint32_t mask, gpio_flags_t flags) +static void gpio_nrfx_gpd_retain_set(const struct device *port, uint32_t mask) { #ifdef CONFIG_SOC_NRF54H20_GPD const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); - if (cfg->pad_pd != NRF_GPD_FAST_ACTIVE1 || !(flags & GPIO_OUTPUT)) { - return; - } - nrf_gpio_port_retain_enable(cfg->port, mask); #else ARG_UNUSED(port); ARG_UNUSED(mask); - ARG_UNUSED(flags); #endif } @@ -86,10 +81,6 @@ static void gpio_nrfx_gpd_retain_clear(const struct device *port, uint32_t mask) #ifdef CONFIG_SOC_NRF54H20_GPD const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); - if (cfg->pad_pd != NRF_GPD_FAST_ACTIVE1) { - return; - } - nrf_gpio_port_retain_disable(cfg->port, mask); #else ARG_UNUSED(port); @@ -225,7 +216,7 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, } end: - gpio_nrfx_gpd_retain_set(port, BIT(pin), flags); + gpio_nrfx_gpd_retain_set(port, BIT(pin)); return pm_device_runtime_put(port); } @@ -329,7 +320,7 @@ static int gpio_nrfx_port_set_masked_raw(const struct device *port, gpio_nrfx_gpd_retain_clear(port, mask); nrf_gpio_port_out_set(reg, set_mask); nrf_gpio_port_out_clear(reg, clear_mask); - gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT); + gpio_nrfx_gpd_retain_set(port, mask); return pm_device_runtime_put(port); } @@ -346,7 +337,7 @@ static int gpio_nrfx_port_set_bits_raw(const struct device *port, gpio_nrfx_gpd_retain_clear(port, mask); nrf_gpio_port_out_set(reg, mask); - gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT); + gpio_nrfx_gpd_retain_set(port, mask); return pm_device_runtime_put(port); } @@ -363,7 +354,7 @@ static int gpio_nrfx_port_clear_bits_raw(const struct device *port, gpio_nrfx_gpd_retain_clear(port, mask); nrf_gpio_port_out_clear(reg, mask); - gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT); + gpio_nrfx_gpd_retain_set(port, mask); return pm_device_runtime_put(port); } @@ -384,7 +375,7 @@ static int gpio_nrfx_port_toggle_bits(const struct device *port, gpio_nrfx_gpd_retain_clear(port, mask); nrf_gpio_port_out_set(reg, set_mask); nrf_gpio_port_out_clear(reg, clear_mask); - gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT); + gpio_nrfx_gpd_retain_set(port, mask); return pm_device_runtime_put(port); } diff --git a/drivers/i2c/i2c_nrfx_twim.c b/drivers/i2c/i2c_nrfx_twim.c index d5b619bfc5a..b6c37f455dc 100644 --- a/drivers/i2c/i2c_nrfx_twim.c +++ b/drivers/i2c/i2c_nrfx_twim.c @@ -224,6 +224,11 @@ static int i2c_nrfx_twim_init(const struct device *dev) return i2c_nrfx_twim_common_init(dev); } +static int i2c_nrfx_twim_deinit(const struct device *dev) +{ + return i2c_nrfx_twim_common_deinit(dev); +} + static DEVICE_API(i2c, i2c_nrfx_twim_driver_api) = { .configure = i2c_nrfx_twim_configure, .transfer = i2c_nrfx_twim_transfer, @@ -280,8 +285,9 @@ static DEVICE_API(i2c, i2c_nrfx_twim_driver_api) = { }; \ PM_DEVICE_DT_DEFINE(I2C(idx), twim_nrfx_pm_action, \ PM_DEVICE_ISR_SAFE); \ - I2C_DEVICE_DT_DEFINE(I2C(idx), \ + I2C_DEVICE_DT_DEINIT_DEFINE(I2C(idx), \ i2c_nrfx_twim_init, \ + i2c_nrfx_twim_deinit, \ PM_DEVICE_DT_GET(I2C(idx)), \ &twim_##idx##_data, \ &twim_##idx##z_config, \ diff --git a/drivers/i2c/i2c_nrfx_twim_common.c b/drivers/i2c/i2c_nrfx_twim_common.c index 1539d7c90dd..f7fd0d097b0 100644 --- a/drivers/i2c/i2c_nrfx_twim_common.c +++ b/drivers/i2c/i2c_nrfx_twim_common.c @@ -102,18 +102,30 @@ int i2c_nrfx_twim_msg_transfer(const struct device *dev, uint8_t flags, uint8_t return ret; } -int twim_nrfx_pm_action(const struct device *dev, enum pm_device_action action) +void twim_nrfx_pm_resume(const struct device *dev) { const struct i2c_nrfx_twim_common_config *config = dev->config; + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + nrfx_twim_enable(&config->twim); +} + +void twim_nrfx_pm_suspend(const struct device *dev) +{ + const struct i2c_nrfx_twim_common_config *config = dev->config; + + nrfx_twim_disable(&config->twim); + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); +} + +int twim_nrfx_pm_action(const struct device *dev, enum pm_device_action action) +{ switch (action) { case PM_DEVICE_ACTION_RESUME: - (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - nrfx_twim_enable(&config->twim); + twim_nrfx_pm_resume(dev); break; case PM_DEVICE_ACTION_SUSPEND: - nrfx_twim_disable(&config->twim); - (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + twim_nrfx_pm_suspend(dev); break; default: return -ENOTSUP; @@ -138,3 +150,31 @@ int i2c_nrfx_twim_common_init(const struct device *dev) return pm_device_driver_init(dev, twim_nrfx_pm_action); } + +int i2c_nrfx_twim_common_deinit(const struct device *dev) +{ + const struct i2c_nrfx_twim_common_config *config = dev->config; +#if CONFIG_PM_DEVICE + enum pm_device_state state; +#endif + +#if CONFIG_PM_DEVICE + /* + * PM must have suspended the device before driver can + * be deinitialized + */ + (void)pm_device_state_get(dev, &state); + if (state != PM_DEVICE_STATE_SUSPENDED && + state != PM_DEVICE_STATE_OFF) { + LOG_ERR("device active"); + return -EBUSY; + } +#else + /* Suspend device */ + twim_nrfx_pm_suspend(dev); +#endif + + /* Uninit device hardware */ + nrfx_twim_uninit(&config->twim); + return 0; +} diff --git a/drivers/i2c/i2c_nrfx_twim_common.h b/drivers/i2c/i2c_nrfx_twim_common.h index ba7fa72f019..3c5c82311ba 100644 --- a/drivers/i2c/i2c_nrfx_twim_common.h +++ b/drivers/i2c/i2c_nrfx_twim_common.h @@ -43,6 +43,7 @@ struct i2c_nrfx_twim_common_config { }; int i2c_nrfx_twim_common_init(const struct device *dev); +int i2c_nrfx_twim_common_deinit(const struct device *dev); int i2c_nrfx_twim_configure(const struct device *dev, uint32_t i2c_config); int i2c_nrfx_twim_recover_bus(const struct device *dev); int i2c_nrfx_twim_msg_transfer(const struct device *dev, uint8_t flags, uint8_t *buf, diff --git a/drivers/i2c/i2c_nrfx_twim_rtio.c b/drivers/i2c/i2c_nrfx_twim_rtio.c index 6a7504dbd62..5eef549ba2e 100644 --- a/drivers/i2c/i2c_nrfx_twim_rtio.c +++ b/drivers/i2c/i2c_nrfx_twim_rtio.c @@ -203,7 +203,7 @@ static DEVICE_API(i2c, i2c_nrfx_twim_driver_api) = { .iodev_submit = i2c_nrfx_twim_rtio_submit, }; -int i2c_nrfx_twim_rtio_init(const struct device *dev) +static int i2c_nrfx_twim_rtio_init(const struct device *dev) { const struct i2c_nrfx_twim_rtio_config *config = dev->config; @@ -211,6 +211,11 @@ int i2c_nrfx_twim_rtio_init(const struct device *dev) return i2c_nrfx_twim_common_init(dev); } +static int i2c_nrfx_twim_rtio_deinit(const struct device *dev) +{ + return i2c_nrfx_twim_common_deinit(dev); +} + #define CONCAT_BUF_SIZE(idx) \ COND_CODE_1(DT_NODE_HAS_PROP(I2C(idx), zephyr_concat_buf_size), \ (DT_PROP(I2C(idx), zephyr_concat_buf_size)), (0)) @@ -282,9 +287,10 @@ int i2c_nrfx_twim_rtio_init(const struct device *dev) .ctx = &_i2c##idx##_twim_rtio, \ }; \ PM_DEVICE_DT_DEFINE(I2C(idx), twim_nrfx_pm_action, PM_DEVICE_ISR_SAFE); \ - I2C_DEVICE_DT_DEFINE(I2C(idx), i2c_nrfx_twim_rtio_init, PM_DEVICE_DT_GET(I2C(idx)), \ - &twim_##idx##z_data, &twim_##idx##z_config, POST_KERNEL, \ - CONFIG_I2C_INIT_PRIORITY, &i2c_nrfx_twim_driver_api); + I2C_DEVICE_DT_DEINIT_DEFINE(I2C(idx), i2c_nrfx_twim_rtio_init, i2c_nrfx_twim_rtio_deinit, \ + PM_DEVICE_DT_GET(I2C(idx)), &twim_##idx##z_data, \ + &twim_##idx##z_config, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ + &i2c_nrfx_twim_driver_api); #ifdef CONFIG_HAS_HW_NRF_TWIM0 I2C_NRFX_TWIM_RTIO_DEVICE(0); diff --git a/drivers/i2c/i2c_nrfx_twis.c b/drivers/i2c/i2c_nrfx_twis.c index c37c51ddd74..dca3a457cf2 100644 --- a/drivers/i2c/i2c_nrfx_twis.c +++ b/drivers/i2c/i2c_nrfx_twis.c @@ -73,6 +73,15 @@ static bool shim_nrf_twis_is_resumed(const struct device *dev) (void)pm_device_state_get(dev, &state); return state == PM_DEVICE_STATE_ACTIVE; } + +static bool shim_nrf_twis_is_suspended(const struct device *dev) +{ + enum pm_device_state state; + + (void)pm_device_state_get(dev, &state); + return state == PM_DEVICE_STATE_SUSPENDED || + state == PM_DEVICE_STATE_OFF; +} #else static bool shim_nrf_twis_is_resumed(const struct device *dev) { @@ -199,7 +208,7 @@ static int shim_nrf_twis_pm_action_cb(const struct device *dev, #if CONFIG_PM_DEVICE case PM_DEVICE_ACTION_SUSPEND: - shim_nrf_twis_disable(); + shim_nrf_twis_disable(dev); break; #endif @@ -283,6 +292,35 @@ static int shim_nrf_twis_init(const struct device *dev) return pm_device_driver_init(dev, shim_nrf_twis_pm_action_cb); } +static int shim_nrf_twis_deinit(const struct device *dev) +{ + const struct shim_nrf_twis_config *dev_config = dev->config; + struct shim_nrf_twis_data *dev_data = dev->data; + + if (dev_data->target_config != NULL) { + LOG_ERR("target registered"); + return -EPERM; + } + +#if CONFIG_PM_DEVICE + /* + * PM must have suspended the device before driver can + * be deinitialized + */ + if (!shim_nrf_twis_is_suspended(dev)) { + LOG_ERR("device active"); + return -EBUSY; + } +#else + /* Suspend device */ + shim_nrf_twis_disable(dev); +#endif + + /* Uninit device hardware */ + nrfx_twis_uninit(&dev_config->twis); + return 0; +} + #define SHIM_NRF_TWIS_NAME(id, name) \ _CONCAT_4(shim_nrf_twis_, name, _, id) @@ -323,9 +361,10 @@ static int shim_nrf_twis_init(const struct device *dev) shim_nrf_twis_pm_action_cb, \ ); \ \ - DEVICE_DT_DEFINE( \ + DEVICE_DT_DEINIT_DEFINE( \ SHIM_NRF_TWIS_NODE(id), \ shim_nrf_twis_init, \ + shim_nrf_twis_deinit, \ PM_DEVICE_DT_GET(SHIM_NRF_TWIS_NODE(id)), \ &SHIM_NRF_TWIS_NAME(id, data), \ &SHIM_NRF_TWIS_NAME(id, config), \ diff --git a/drivers/pinctrl/pinctrl_nrf.c b/drivers/pinctrl/pinctrl_nrf.c index 05c0ed9ac0b..34c0107b591 100644 --- a/drivers/pinctrl/pinctrl_nrf.c +++ b/drivers/pinctrl/pinctrl_nrf.c @@ -516,9 +516,13 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, } gpd_requested = true; } - - nrf_gpio_pin_retain_disable(pin); } + + /* + * Pad power domain now on, retain no longer needed + * as pad config will be persists as pad is powered. + */ + nrf_gpio_pin_retain_disable(pin); #endif /* CONFIG_SOC_NRF54H20_GPD */ if (write != NO_WRITE) { @@ -537,7 +541,13 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, nrf_gpio_pin_clock_set(pin, NRF_GET_CLOCKPIN_ENABLE(pins[i])); #endif #ifdef CONFIG_SOC_NRF54H20_GPD - if (NRF_GET_GPD_FAST_ACTIVE1(pins[i]) == 1U) { + if (NRF_GET_LP(pins[i]) == NRF_LP_ENABLE) { + /* + * Pad power domain may be turned off, and pad is not + * actively used as pincnf is low-power. Enable retain + * to ensure pad output and config persists if pad + * power domain is suspended. + */ nrf_gpio_pin_retain_enable(pin); } #endif /* CONFIG_SOC_NRF54H20_GPD */ diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index dcfee1c5ede..4faf29934c5 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -765,6 +765,28 @@ static int spi_nrfx_init(const struct device *dev) #endif return pm_device_driver_init(dev, spim_nrfx_pm_action); } + +static int spi_nrfx_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; +} + /* * We use NODELABEL here because the nrfx API requires us to call * functions which are named according to SoC peripheral instance @@ -870,8 +892,9 @@ static int spi_nrfx_init(const struct device *dev) !(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\ "WAKE line must be configured as active high"); \ PM_DEVICE_DT_DEFINE(SPIM(idx), spim_nrfx_pm_action); \ - SPI_DEVICE_DT_DEFINE(SPIM(idx), \ + SPI_DEVICE_DT_DEINIT_DEFINE(SPIM(idx), \ spi_nrfx_init, \ + spi_nrfx_deinit, \ PM_DEVICE_DT_GET(SPIM(idx)), \ &spi_##idx##_data, \ &spi_##idx##z_config, \ diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index 09640e3275d..c1972782660 100644 --- a/include/zephyr/drivers/i2c.h +++ b/include/zephyr/drivers/i2c.h @@ -635,7 +635,7 @@ static inline void i2c_xfer_stats(const struct device *dev, struct i2c_msg *msgs /** @endcond */ /** - * @brief Like DEVICE_DT_DEFINE() with I2C specifics. + * @brief Like DEVICE_DT_DEINIT_DEFINE() with I2C specifics. * * @details Defines a device which implements the I2C API. May * generate a custom device_state container struct and init_fn @@ -645,6 +645,8 @@ static inline void i2c_xfer_stats(const struct device *dev, struct i2c_msg *msgs * * @param init_fn Name of the init function of the driver. Can be `NULL`. * + * @param deinit_fn Name of the deinit function of the driver. Can be `NULL`. + * * @param pm PM device resources reference (NULL if device does not use PM). * * @param data Pointer to the device's private data. @@ -661,14 +663,14 @@ static inline void i2c_xfer_stats(const struct device *dev, struct i2c_msg *msgs * @param api Provides an initial pointer to the API function struct * used by the driver. Can be NULL. */ -#define I2C_DEVICE_DT_DEFINE(node_id, init_fn, pm, data, config, level, \ - prio, api, ...) \ +#define I2C_DEVICE_DT_DEINIT_DEFINE(node_id, init_fn, deinit_fn, pm, \ + data, config, level, prio, api, ...)\ Z_I2C_DEVICE_STATE_DEFINE(Z_DEVICE_DT_DEV_ID(node_id)); \ Z_I2C_INIT_FN(Z_DEVICE_DT_DEV_ID(node_id), init_fn) \ Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \ DEVICE_DT_NAME(node_id), \ &UTIL_CAT(Z_DEVICE_DT_DEV_ID(node_id), _init), \ - NULL, Z_DEVICE_DT_FLAGS(node_id), pm, data, \ + deinit_fn, Z_DEVICE_DT_FLAGS(node_id), pm, data,\ config, level, prio, api, \ &(Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)).devstate), \ __VA_ARGS__) @@ -683,12 +685,32 @@ static inline void i2c_xfer_stats(const struct device *dev, struct i2c_msg *msgs ARG_UNUSED(num_msgs); } +#define I2C_DEVICE_DT_DEINIT_DEFINE(node_id, init_fn, deinit_fn, pm, \ + data, config, level, prio, api, ...)\ + DEVICE_DT_DEINIT_DEFINE(node_id, init_fn, deinit_fn, pm, data, \ + config, level, prio, api, __VA_ARGS__) + +#endif /* CONFIG_I2C_STATS */ + +/** + * @brief Like I2C_DEVICE_DT_DEINIT_DEFINE() but without deinit_fn + */ #define I2C_DEVICE_DT_DEFINE(node_id, init_fn, pm, data, config, level, \ prio, api, ...) \ - DEVICE_DT_DEFINE(node_id, init_fn, pm, data, config, level, \ - prio, api, __VA_ARGS__) + I2C_DEVICE_DT_DEINIT_DEFINE(node_id, init_fn, NULL, pm, data, \ + config, level, prio, api, \ + __VA_ARGS__) -#endif /* CONFIG_I2C_STATS */ +/** + * @brief Like I2C_DEVICE_DT_DEINIT_DEFINE() for an instance of a DT_DRV_COMPAT compatible + * + * @param inst instance number. This is replaced by + * DT_DRV_COMPAT(inst) in the call to I2C_DEVICE_DT_DEINIT_DEFINE(). + * + * @param ... other parameters as expected by I2C_DEVICE_DT_DEINIT_DEFINE(). + */ +#define I2C_DEVICE_DT_INST_DEINIT_DEFINE(inst, ...) \ + I2C_DEVICE_DT_DEINIT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) /** * @brief Like I2C_DEVICE_DT_DEFINE() for an instance of a DT_DRV_COMPAT compatible @@ -701,7 +723,6 @@ static inline void i2c_xfer_stats(const struct device *dev, struct i2c_msg *msgs #define I2C_DEVICE_DT_INST_DEFINE(inst, ...) \ I2C_DEVICE_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) - /** * @brief Configure operation of a host controller. * diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index 8e8cdb5a994..08a3f03137b 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -657,16 +657,16 @@ struct spi_device_state { } /** @endcond */ -#define SPI_DEVICE_DT_DEFINE(node_id, init_fn, pm_device, \ - data_ptr, cfg_ptr, level, prio, \ - api_ptr, ...) \ +#define SPI_DEVICE_DT_DEINIT_DEFINE(node_id, init_fn, deinit_fn, \ + pm_device, data_ptr, cfg_ptr, \ + level, prio, api_ptr, ...) \ Z_SPI_DEVICE_STATE_DEFINE(Z_DEVICE_DT_DEV_ID(node_id)); \ Z_SPI_INIT_FN(Z_DEVICE_DT_DEV_ID(node_id), init_fn) \ Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \ DEVICE_DT_NAME(node_id), \ &UTIL_CAT(Z_DEVICE_DT_DEV_ID(node_id), _init), \ - NULL, Z_DEVICE_DT_FLAGS(node_id), pm_device, \ - data_ptr, cfg_ptr, level, prio, \ + deinit_fn, Z_DEVICE_DT_FLAGS(node_id), \ + pm_device, data_ptr, cfg_ptr, level, prio, \ api_ptr, \ &(Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)).devstate), \ __VA_ARGS__) @@ -700,8 +700,9 @@ static inline void spi_transceive_stats(const struct device *dev, int error, * @name SPI DT Device Macros * @{ */ + /** - * @brief Like DEVICE_DT_DEFINE() with SPI specifics. + * @brief Like DEVICE_DT_DEINIT_DEFINE() with SPI specifics. * * @details Defines a device which implements the SPI API. May * generate a custom device_state container struct and init_fn @@ -709,6 +710,7 @@ static inline void spi_transceive_stats(const struct device *dev, int error, * * @param node_id The devicetree node identifier. * @param init_fn Name of the init function of the driver. + * @param deinit_fn Name of the deinit function of the driver. * @param pm PM device resources reference (NULL if device does not use PM). * @param data Pointer to the device's private data. * @param config The address to the structure containing the configuration @@ -719,16 +721,16 @@ static inline void spi_transceive_stats(const struct device *dev, int error, * @param api Provides an initial pointer to the API function struct used by * the driver. Can be NULL. */ -#define SPI_DEVICE_DT_DEFINE(node_id, init_fn, pm, \ - data, config, level, prio, \ - api, ...) \ +#define SPI_DEVICE_DT_DEINIT_DEFINE(node_id, init_fn, deinit_fn, pm, data, \ + config, level, prio, api, ...) \ Z_DEVICE_STATE_DEFINE(Z_DEVICE_DT_DEV_ID(node_id)); \ Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \ - DEVICE_DT_NAME(node_id), init_fn, NULL, \ + DEVICE_DT_NAME(node_id), init_fn, deinit_fn, \ Z_DEVICE_DT_FLAGS(node_id), pm, data, config, \ level, prio, api, \ &Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_ID(node_id)), \ __VA_ARGS__) + /** @} */ #define SPI_STATS_RX_BYTES_INC(dev_) @@ -739,6 +741,40 @@ static inline void spi_transceive_stats(const struct device *dev, int error, #endif /*CONFIG_SPI_STATS*/ +/** + * @brief Like DEVICE_DT_DEINIT_DEFINE() without deinit function. + * + * @details Defines a device which implements the SPI API. May + * generate a custom device_state container struct and init_fn + * wrapper when needed depending on SPI @kconfig{CONFIG_SPI_STATS}. + * + * @param node_id The devicetree node identifier. + * @param init_fn Name of the init function of the driver. + * @param pm PM device resources reference (NULL if device does not use PM). + * @param data Pointer to the device's private data. + * @param config The address to the structure containing the configuration + * information for this instance of the driver. + * @param level The initialization level. See SYS_INIT() for details. + * @param prio Priority within the selected initialization level. See SYS_INIT() + * for details. + * @param api Provides an initial pointer to the API function struct used by + * the driver. Can be NULL. + */ +#define SPI_DEVICE_DT_DEFINE(node_id, init_fn, pm, data, config, level, prio, \ + api, ...) \ + SPI_DEVICE_DT_DEINIT_DEFINE(node_id, init_fn, NULL, pm, data, config, \ + level, prio, api, __VA_ARGS__) + +/** + * @brief Like SPI_DEVICE_DT_DEINIT_DEFINE(), but uses an instance of a `DT_DRV_COMPAT` + * compatible instead of a node identifier. + * + * @param inst Instance number. The `node_id` argument to SPI_DEVICE_DT_DEINIT_DEFINE() is + * set to `DT_DRV_INST(inst)`. + * @param ... Other parameters as expected by SPI_DEVICE_DT_DEFINE(). + */ +#define SPI_DEVICE_DT_INST_DEINIT_DEFINE(inst, ...) \ + SPI_DEVICE_DT_DEINIT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) /** * @brief Like SPI_DEVICE_DT_DEFINE(), but uses an instance of a `DT_DRV_COMPAT` diff --git a/tests/drivers/i2c/i2c_target_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/drivers/i2c/i2c_target_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 2fc033d534a..9390af2b5cd 100644 --- a/tests/drivers/i2c/i2c_target_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/drivers/i2c/i2c_target_api/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -9,6 +9,23 @@ * SCL = P1.2 and P1.3 */ +/ { + zephyr,user { + sda0-gpios = <&gpio2 8 0>; + scl0-gpios = <&gpio1 2 0>; + sda1-gpios = <&gpio2 9 0>; + scl1-gpios = <&gpio1 3 0>; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + &pinctrl { i2c130_default: i2c130_default { group1 { diff --git a/tests/drivers/i2c/i2c_target_api/src/main.c b/tests/drivers/i2c/i2c_target_api/src/main.c index 5c1540e3e79..b249daae90b 100644 --- a/tests/drivers/i2c/i2c_target_api/src/main.c +++ b/tests/drivers/i2c/i2c_target_api/src/main.c @@ -16,6 +16,7 @@ #include #include +#include #include @@ -166,6 +167,62 @@ static int run_program_read(const struct device *i2c, uint8_t addr, return 0; } +ZTEST(i2c_eeprom_target, test_deinit) +{ + const struct device *const i2c_0 = DEVICE_DT_GET(DT_BUS(NODE_EP0)); + const struct device *const i2c_1 = DEVICE_DT_GET(DT_BUS(NODE_EP1)); + const struct gpio_dt_spec sda_pin_0 = + GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), sda0_gpios, {}); + const struct gpio_dt_spec scl_pin_0 = + GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), scl0_gpios, {}); + const struct gpio_dt_spec sda_pin_1 = + GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), sda1_gpios, {}); + const struct gpio_dt_spec scl_pin_1 = + GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), scl1_gpios, {}); + int ret; + + if (i2c_0 == i2c_1) { + TC_PRINT(" gpio loopback required for test\n"); + ztest_test_skip(); + } + + if (scl_pin_0.port == NULL || sda_pin_0.port == NULL || + scl_pin_1.port == NULL || sda_pin_1.port == NULL) { + TC_PRINT(" bus gpios not specified in zephyr,path\n"); + ztest_test_skip(); + } + + ret = device_deinit(i2c_0); + if (ret == -ENOTSUP) { + TC_PRINT(" device deinit not supported\n"); + ztest_test_skip(); + } + + zassert_ok(ret); + + ret = device_deinit(i2c_1); + if (ret == -ENOTSUP) { + TC_PRINT(" device deinit not supported\n"); + zassert_ok(device_init(i2c_0)); + ztest_test_skip(); + } + + zassert_ok(gpio_pin_configure_dt(&sda_pin_0, GPIO_INPUT)); + zassert_ok(gpio_pin_configure_dt(&sda_pin_1, GPIO_OUTPUT_INACTIVE)); + zassert_ok(gpio_pin_configure_dt(&scl_pin_0, GPIO_INPUT)); + zassert_ok(gpio_pin_configure_dt(&scl_pin_1, GPIO_OUTPUT_INACTIVE)); + zassert_equal(gpio_pin_get_dt(&sda_pin_0), 0); + zassert_equal(gpio_pin_get_dt(&scl_pin_0), 0); + zassert_ok(gpio_pin_set_dt(&sda_pin_1, 1)); + zassert_ok(gpio_pin_set_dt(&scl_pin_1, 1)); + zassert_equal(gpio_pin_get_dt(&sda_pin_0), 1); + zassert_equal(gpio_pin_get_dt(&scl_pin_0), 1); + zassert_ok(gpio_pin_configure_dt(&sda_pin_1, GPIO_INPUT)); + zassert_ok(gpio_pin_configure_dt(&scl_pin_1, GPIO_INPUT)); + zassert_ok(device_init(i2c_0)); + zassert_ok(device_init(i2c_1)); +} + ZTEST(i2c_eeprom_target, test_eeprom_target) { const struct device *const eeprom_0 = DEVICE_DT_GET(NODE_EP0); diff --git a/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_common.dtsi b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_common.dtsi index 33170beda44..5111257a557 100644 --- a/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_common.dtsi +++ b/tests/drivers/spi/spi_loopback/boards/nrf54h20dk_nrf54h20_common.dtsi @@ -4,6 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + +/ { + zephyr,user { + miso-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + }; +}; + &pinctrl { spi130_default: spi130_default { group1 { diff --git a/tests/drivers/spi/spi_loopback/src/spi.c b/tests/drivers/spi/spi_loopback/src/spi.c index 64649ce7566..b6728db9dae 100644 --- a/tests/drivers/spi/spi_loopback/src/spi.c +++ b/tests/drivers/spi/spi_loopback/src/spi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,8 @@ static int spec_idx; */ struct spi_dt_spec spec_copies[5]; - +const struct gpio_dt_spec miso_pin = GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), miso_gpios, {}); +const struct gpio_dt_spec mosi_pin = GPIO_DT_SPEC_GET_OR(DT_PATH(zephyr_user), mosi_gpios, {}); /* ******************** @@ -806,6 +808,35 @@ ZTEST(spi_loopback, test_spi_concurrent_transfer_different_spec) test_spi_concurrent_transfer_helper(specs); } +ZTEST(spi_loopback, test_spi_deinit) +{ + struct spi_dt_spec *spec = loopback_specs[0]; + const struct device *dev = spec->bus; + int ret; + + if (miso_pin.port == NULL || mosi_pin.port == NULL) { + TC_PRINT(" zephyr,user miso-gpios or mosi-gpios are not defined\n"); + ztest_test_skip(); + } + + ret = device_deinit(dev); + if (ret == -ENOTSUP) { + TC_PRINT(" device deinit not supported\n"); + ztest_test_skip(); + } + + zassert_ok(ret); + zassert_ok(gpio_pin_configure_dt(&miso_pin, GPIO_INPUT)); + zassert_ok(gpio_pin_configure_dt(&mosi_pin, GPIO_OUTPUT_INACTIVE)); + zassert_equal(gpio_pin_get_dt(&miso_pin), 0); + zassert_ok(gpio_pin_set_dt(&mosi_pin, 1)); + zassert_equal(gpio_pin_get_dt(&miso_pin), 1); + zassert_ok(gpio_pin_set_dt(&mosi_pin, 0)); + zassert_equal(gpio_pin_get_dt(&miso_pin), 0); + zassert_ok(gpio_pin_configure_dt(&mosi_pin, GPIO_INPUT)); + zassert_ok(device_init(dev)); +} + #if (CONFIG_SPI_ASYNC) static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig); static struct k_poll_event async_evt =