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);