diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index cf7155ecdd8..25a68ea5f8f 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -46,7 +46,17 @@ else() ) endif() -zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM i2c_nrfx_twim.c) +if(CONFIG_I2C_RTIO) + zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM + i2c_nrfx_twim_rtio.c + i2c_nrfx_twim_common.c + ) +else() + zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM + i2c_nrfx_twim.c + i2c_nrfx_twim_common.c + ) +endif() zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWI i2c_sam_twi.c) if(CONFIG_I2C_RTIO) diff --git a/drivers/i2c/i2c_nrfx_twi_common.h b/drivers/i2c/i2c_nrfx_twi_common.h index a8925d3f75b..a3e9847bab5 100644 --- a/drivers/i2c/i2c_nrfx_twi_common.h +++ b/drivers/i2c/i2c_nrfx_twi_common.h @@ -22,7 +22,8 @@ extern "C" { : I2C_NRFX_TWI_INVALID_FREQUENCY) #define I2C(idx) DT_NODELABEL(i2c##idx) #define I2C_FREQUENCY(idx) \ - I2C_NRFX_TWI_FREQUENCY(DT_PROP(I2C(idx), clock_frequency)) + I2C_NRFX_TWI_FREQUENCY(DT_PROP_OR(I2C(idx), clock_frequency, \ + I2C_BITRATE_STANDARD)) struct i2c_nrfx_twi_common_data { uint32_t dev_config; diff --git a/drivers/i2c/i2c_nrfx_twim.c b/drivers/i2c/i2c_nrfx_twim.c index 4d1ff0f4640..9609709d8c3 100644 --- a/drivers/i2c/i2c_nrfx_twim.c +++ b/drivers/i2c/i2c_nrfx_twim.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ - #include #include #include @@ -17,6 +16,9 @@ #include #include + +#include "i2c_nrfx_twim_common.h" + LOG_MODULE_REGISTER(i2c_nrfx_twim, CONFIG_I2C_LOG_LEVEL); #if CONFIG_I2C_NRFX_TRANSFER_TIMEOUT @@ -31,31 +33,18 @@ struct i2c_nrfx_twim_data { volatile nrfx_err_t res; }; -struct i2c_nrfx_twim_config { - nrfx_twim_t twim; - nrfx_twim_config_t twim_config; - uint16_t msg_buf_size; - void (*irq_connect)(void); - const struct pinctrl_dev_config *pcfg; - uint8_t *msg_buf; - uint16_t max_transfer_size; -}; - -static int i2c_nrfx_twim_recover_bus(const struct device *dev); - static int i2c_nrfx_twim_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr) { struct i2c_nrfx_twim_data *dev_data = dev->data; - const struct i2c_nrfx_twim_config *dev_config = dev->config; + const struct i2c_nrfx_twim_common_config *dev_config = dev->config; int ret = 0; uint8_t *msg_buf = dev_config->msg_buf; uint16_t msg_buf_used = 0; uint16_t msg_buf_size = dev_config->msg_buf_size; - nrfx_twim_xfer_desc_t cur_xfer = { - .address = addr - }; + uint8_t *buf; + uint16_t buf_len; k_sem_take(&dev_data->transfer_sync, K_FOREVER); @@ -116,35 +105,15 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, } if (msg_buf_used == 0) { - cur_xfer.p_primary_buf = msgs[i].buf; - cur_xfer.primary_length = msgs[i].len; + buf = msgs[i].buf; + buf_len = msgs[i].len; } else { - cur_xfer.p_primary_buf = msg_buf; - cur_xfer.primary_length = msg_buf_used; - } - cur_xfer.type = (msgs[i].flags & I2C_MSG_READ) ? - NRFX_TWIM_XFER_RX : NRFX_TWIM_XFER_TX; - - if (cur_xfer.primary_length > dev_config->max_transfer_size) { - LOG_ERR("Trying to transfer more than the maximum size " - "for this device: %d > %d", - cur_xfer.primary_length, - dev_config->max_transfer_size); - return -ENOSPC; + buf = msg_buf; + buf_len = msg_buf_used; } - - nrfx_err_t res = nrfx_twim_xfer(&dev_config->twim, - &cur_xfer, - (msgs[i].flags & I2C_MSG_STOP) ? - 0 : NRFX_TWIM_FLAG_TX_NO_STOP); - if (res != NRFX_SUCCESS) { - if (res == NRFX_ERROR_BUSY) { - ret = -EBUSY; - break; - } else { - ret = -EIO; - break; - } + ret = i2c_nrfx_twim_msg_transfer(dev, msgs[i].flags, buf, buf_len, addr); + if (ret < 0) { + break; } ret = k_sem_take(&dev_data->completion_sync, @@ -171,9 +140,7 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, break; } - res = dev_data->res; - - if (res != NRFX_SUCCESS) { + if (dev_data->res != NRFX_SUCCESS) { ret = -EIO; break; } @@ -181,8 +148,7 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, /* If concatenated messages were I2C_MSG_READ type, then * content of concatenation buffer has to be copied back into * buffers provided by user. */ - if ((msgs[i].flags & I2C_MSG_READ) - && cur_xfer.p_primary_buf == msg_buf) { + if ((msgs[i].flags & I2C_MSG_READ) && (buf == msg_buf)) { int j = i; while (msg_buf_used >= msgs[j].len) { @@ -207,7 +173,8 @@ static int i2c_nrfx_twim_transfer(const struct device *dev, static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context) { - struct i2c_nrfx_twim_data *dev_data = p_context; + const struct device *dev = p_context; + struct i2c_nrfx_twim_data *dev_data = dev->data; switch (p_event->type) { case NRFX_TWIM_EVT_DONE: @@ -227,65 +194,14 @@ static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context) k_sem_give(&dev_data->completion_sync); } -static int i2c_nrfx_twim_configure(const struct device *dev, - uint32_t i2c_config) -{ - const struct i2c_nrfx_twim_config *dev_config = dev->config; - - if (I2C_ADDR_10_BITS & i2c_config) { - return -EINVAL; - } - - switch (I2C_SPEED_GET(i2c_config)) { - case I2C_SPEED_STANDARD: - nrf_twim_frequency_set(dev_config->twim.p_twim, - NRF_TWIM_FREQ_100K); - break; - case I2C_SPEED_FAST: - nrf_twim_frequency_set(dev_config->twim.p_twim, - NRF_TWIM_FREQ_400K); - break; -#if NRF_TWIM_HAS_1000_KHZ_FREQ - case I2C_SPEED_FAST_PLUS: - nrf_twim_frequency_set(dev_config->twim.p_twim, - NRF_TWIM_FREQ_1000K); - break; -#endif - default: - LOG_ERR("unsupported speed"); - return -EINVAL; - } - - return 0; -} - -static int i2c_nrfx_twim_recover_bus(const struct device *dev) +static int i2c_nrfx_twim_init(const struct device *dev) { - const struct i2c_nrfx_twim_config *dev_config = dev->config; - enum pm_device_state state; - uint32_t scl_pin; - uint32_t sda_pin; - nrfx_err_t err; - - scl_pin = nrf_twim_scl_pin_get(dev_config->twim.p_twim); - sda_pin = nrf_twim_sda_pin_get(dev_config->twim.p_twim); - - /* disable peripheral if active (required to release SCL/SDA lines) */ - (void)pm_device_state_get(dev, &state); - if (state == PM_DEVICE_STATE_ACTIVE) { - nrfx_twim_disable(&dev_config->twim); - } + struct i2c_nrfx_twim_data *data = dev->data; - err = nrfx_twim_bus_recover(scl_pin, sda_pin); + k_sem_init(&data->transfer_sync, 1, 1); + k_sem_init(&data->completion_sync, 0, 1); - /* restore peripheral if it was active before */ - if (state == PM_DEVICE_STATE_ACTIVE) { - (void)pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_DEFAULT); - nrfx_twim_enable(&dev_config->twim); - } - - return (err == NRFX_SUCCESS ? 0 : -EBUSY); + return i2c_nrfx_twim_common_init(dev); } static const struct i2c_driver_api i2c_nrfx_twim_driver_api = { @@ -297,89 +213,6 @@ static const struct i2c_driver_api i2c_nrfx_twim_driver_api = { .recover_bus = i2c_nrfx_twim_recover_bus, }; -#ifdef CONFIG_PM_DEVICE -static int twim_nrfx_pm_action(const struct device *dev, - enum pm_device_action action) -{ - const struct i2c_nrfx_twim_config *dev_config = dev->config; - int ret = 0; - - switch (action) { - case PM_DEVICE_ACTION_RESUME: - ret = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; - } - nrfx_twim_enable(&dev_config->twim); - break; - - case PM_DEVICE_ACTION_SUSPEND: - nrfx_twim_disable(&dev_config->twim); - - ret = pinctrl_apply_state(dev_config->pcfg, - PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; - } - break; - - default: - ret = -ENOTSUP; - } - - return ret; -} -#endif /* CONFIG_PM_DEVICE */ - -static int i2c_nrfx_twim_init(const struct device *dev) -{ - const struct i2c_nrfx_twim_config *dev_config = dev->config; - struct i2c_nrfx_twim_data *dev_data = dev->data; - - dev_config->irq_connect(); - - k_sem_init(&dev_data->transfer_sync, 1, 1); - k_sem_init(&dev_data->completion_sync, 0, 1); - - int err = pinctrl_apply_state(dev_config->pcfg, - COND_CODE_1(CONFIG_PM_DEVICE_RUNTIME, - (PINCTRL_STATE_SLEEP), - (PINCTRL_STATE_DEFAULT))); - if (err < 0) { - return err; - } - - if (nrfx_twim_init(&dev_config->twim, &dev_config->twim_config, - event_handler, dev_data) != NRFX_SUCCESS) { - LOG_ERR("Failed to initialize device: %s", dev->name); - return -EIO; - } - -#ifdef CONFIG_PM_DEVICE_RUNTIME - pm_device_init_suspended(dev); - pm_device_runtime_enable(dev); -#else - nrfx_twim_enable(&dev_config->twim); -#endif - - return 0; -} - -#define I2C_NRFX_TWIM_INVALID_FREQUENCY ((nrf_twim_frequency_t)-1) -#define I2C_NRFX_TWIM_FREQUENCY(bitrate) \ - (bitrate == I2C_BITRATE_STANDARD ? NRF_TWIM_FREQ_100K : \ - bitrate == 250000 ? NRF_TWIM_FREQ_250K : \ - bitrate == I2C_BITRATE_FAST ? NRF_TWIM_FREQ_400K : \ - IF_ENABLED(NRF_TWIM_HAS_1000_KHZ_FREQ, \ - (bitrate == I2C_BITRATE_FAST_PLUS ? NRF_TWIM_FREQ_1000K :)) \ - I2C_NRFX_TWIM_INVALID_FREQUENCY) - -#define I2C(idx) DT_NODELABEL(i2c##idx) -#define I2C_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(I2C(idx), prop) -#define I2C_FREQUENCY(idx) \ - I2C_NRFX_TWIM_FREQUENCY(DT_PROP(I2C(idx), clock_frequency)) - #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)) @@ -408,13 +241,15 @@ static int i2c_nrfx_twim_init(const struct device *dev) I2C_MEMORY_SECTION(idx);)) \ static struct i2c_nrfx_twim_data twim_##idx##_data; \ PINCTRL_DT_DEFINE(I2C(idx)); \ - static const struct i2c_nrfx_twim_config twim_##idx##z_config = { \ + static const \ + struct i2c_nrfx_twim_common_config twim_##idx##z_config = { \ .twim = NRFX_TWIM_INSTANCE(idx), \ .twim_config = { \ .skip_gpio_cfg = true, \ .skip_psel_cfg = true, \ .frequency = I2C_FREQUENCY(idx), \ }, \ + .event_handler = event_handler, \ .msg_buf_size = MSG_BUF_SIZE(idx), \ .irq_connect = irq_connect##idx, \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2C(idx)), \ diff --git a/drivers/i2c/i2c_nrfx_twim_common.c b/drivers/i2c/i2c_nrfx_twim_common.c new file mode 100644 index 00000000000..1539d7c90dd --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twim_common.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "i2c_nrfx_twim_common.h" + +LOG_MODULE_DECLARE(i2c_nrfx_twim); + +int i2c_nrfx_twim_recover_bus(const struct device *dev) +{ + const struct i2c_nrfx_twim_common_config *config = dev->config; + enum pm_device_state state; + uint32_t scl_pin; + uint32_t sda_pin; + nrfx_err_t err; + + scl_pin = nrf_twim_scl_pin_get(config->twim.p_twim); + sda_pin = nrf_twim_sda_pin_get(config->twim.p_twim); + + /* disable peripheral if active (required to release SCL/SDA lines) */ + (void)pm_device_state_get(dev, &state); + if (state == PM_DEVICE_STATE_ACTIVE) { + nrfx_twim_disable(&config->twim); + } + + err = nrfx_twim_bus_recover(scl_pin, sda_pin); + + /* restore peripheral if it was active before */ + if (state == PM_DEVICE_STATE_ACTIVE) { + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + nrfx_twim_enable(&config->twim); + } + + return (err == NRFX_SUCCESS ? 0 : -EBUSY); +} + +int i2c_nrfx_twim_configure(const struct device *dev, uint32_t i2c_config) +{ + const struct i2c_nrfx_twim_common_config *config = dev->config; + + if (I2C_ADDR_10_BITS & i2c_config) { + return -EINVAL; + } + + switch (I2C_SPEED_GET(i2c_config)) { + case I2C_SPEED_STANDARD: + nrf_twim_frequency_set(config->twim.p_twim, NRF_TWIM_FREQ_100K); + break; + case I2C_SPEED_FAST: + nrf_twim_frequency_set(config->twim.p_twim, NRF_TWIM_FREQ_400K); + break; +#if NRF_TWIM_HAS_1000_KHZ_FREQ + case I2C_SPEED_FAST_PLUS: + nrf_twim_frequency_set(config->twim.p_twim, NRF_TWIM_FREQ_1000K); + break; +#endif + default: + LOG_ERR("unsupported speed"); + return -EINVAL; + } + + return 0; +} + +int i2c_nrfx_twim_msg_transfer(const struct device *dev, uint8_t flags, uint8_t *buf, + size_t buf_len, uint16_t i2c_addr) +{ + const struct i2c_nrfx_twim_common_config *config = dev->config; + nrfx_twim_xfer_desc_t cur_xfer = { + .address = i2c_addr, + .type = (flags & I2C_MSG_READ) ? NRFX_TWIM_XFER_RX : NRFX_TWIM_XFER_TX, + .p_primary_buf = buf, + .primary_length = buf_len, + }; + nrfx_err_t res; + int ret = 0; + + if (buf_len > config->max_transfer_size) { + LOG_ERR("Trying to transfer more than the maximum size " + "for this device: %d > %d", + buf_len, config->max_transfer_size); + return -ENOSPC; + } + + res = nrfx_twim_xfer(&config->twim, &cur_xfer, + (flags & I2C_MSG_STOP) ? 0 : NRFX_TWIM_FLAG_TX_NO_STOP); + if (res != NRFX_SUCCESS) { + if (res == NRFX_ERROR_BUSY) { + ret = -EBUSY; + } else { + ret = -EIO; + } + } + return ret; +} + +int twim_nrfx_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct i2c_nrfx_twim_common_config *config = dev->config; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + nrfx_twim_enable(&config->twim); + break; + case PM_DEVICE_ACTION_SUSPEND: + nrfx_twim_disable(&config->twim); + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +int i2c_nrfx_twim_common_init(const struct device *dev) +{ + const struct i2c_nrfx_twim_common_config *config = dev->config; + + config->irq_connect(); + + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + + if (nrfx_twim_init(&config->twim, &config->twim_config, config->event_handler, + (void *)dev) != NRFX_SUCCESS) { + LOG_ERR("Failed to initialize device: %s", dev->name); + return -EIO; + } + + return pm_device_driver_init(dev, twim_nrfx_pm_action); +} diff --git a/drivers/i2c/i2c_nrfx_twim_common.h b/drivers/i2c/i2c_nrfx_twim_common.h new file mode 100644 index 00000000000..ba7fa72f019 --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twim_common.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, Croxel Inc + * Copyright (c) 2024, Embeint Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_I2C_I2C_NRFX_TWIM_COMMON_H_ +#define ZEPHYR_DRIVERS_I2C_I2C_NRFX_TWIM_COMMON_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2C_NRFX_TWIM_INVALID_FREQUENCY ((nrf_twim_frequency_t)-1) +#define I2C_NRFX_TWIM_FREQUENCY(bitrate) \ + (bitrate == I2C_BITRATE_STANDARD ? NRF_TWIM_FREQ_100K \ + : bitrate == 250000 ? NRF_TWIM_FREQ_250K \ + : bitrate == I2C_BITRATE_FAST \ + ? NRF_TWIM_FREQ_400K \ + : IF_ENABLED(NRF_TWIM_HAS_1000_KHZ_FREQ, \ + (bitrate == I2C_BITRATE_FAST_PLUS ? NRF_TWIM_FREQ_1000K :)) \ + I2C_NRFX_TWIM_INVALID_FREQUENCY) + +#define I2C(idx) DT_NODELABEL(i2c##idx) +#define I2C_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(I2C(idx), prop) +#define I2C_FREQUENCY(idx) I2C_NRFX_TWIM_FREQUENCY(DT_PROP_OR(I2C(idx), clock_frequency, \ + I2C_BITRATE_STANDARD)) + +struct i2c_nrfx_twim_common_config { + nrfx_twim_t twim; + nrfx_twim_config_t twim_config; + nrfx_twim_evt_handler_t event_handler; + uint16_t msg_buf_size; + void (*irq_connect)(void); + const struct pinctrl_dev_config *pcfg; + uint8_t *msg_buf; + uint16_t max_transfer_size; +}; + +int i2c_nrfx_twim_common_init(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, + size_t buf_len, uint16_t i2c_addr); + +#ifdef CONFIG_PM_DEVICE +int twim_nrfx_pm_action(const struct device *dev, enum pm_device_action action); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_I2C_I2C_NRFX_TWIM_COMMON_H_ */ diff --git a/drivers/i2c/i2c_nrfx_twim_rtio.c b/drivers/i2c/i2c_nrfx_twim_rtio.c new file mode 100644 index 00000000000..ad455433263 --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twim_rtio.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * Copyright (c) 2024, Croxel Inc + * Copyright (c) 2024, Embeint Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c_nrfx_twim_common.h" + +LOG_MODULE_REGISTER(i2c_nrfx_twim, CONFIG_I2C_LOG_LEVEL); + +struct i2c_nrfx_twim_rtio_config { + struct i2c_nrfx_twim_common_config common; + struct i2c_rtio *ctx; +}; + +static bool i2c_nrfx_twim_rtio_msg_start(const struct device *dev, uint8_t flags, uint8_t *buf, + size_t buf_len, uint16_t i2c_addr) +{ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + struct i2c_rtio *ctx = config->ctx; + int ret = 0; + + ret = i2c_nrfx_twim_msg_transfer(dev, flags, buf, buf_len, i2c_addr); + if (ret != 0) { + return i2c_rtio_complete(ctx, ret); + } + + return false; +} + +static bool i2c_nrfx_twim_rtio_start(const struct device *dev) +{ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + struct i2c_rtio *ctx = config->ctx; + struct rtio_sqe *sqe = &ctx->txn_curr->sqe; + struct i2c_dt_spec *dt_spec = sqe->iodev->data; + + switch (sqe->op) { + case RTIO_OP_RX: + return i2c_nrfx_twim_rtio_msg_start(dev, I2C_MSG_READ | sqe->iodev_flags, + sqe->rx.buf, sqe->rx.buf_len, dt_spec->addr); + case RTIO_OP_TINY_TX: + return i2c_nrfx_twim_rtio_msg_start(dev, I2C_MSG_WRITE | sqe->iodev_flags, + sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, + dt_spec->addr); + case RTIO_OP_TX: + /* If buffer is not accessible by DMA, copy it into the internal driver buffer */ + if (!nrf_dma_accessible_check(&config->common.twim, sqe->tx.buf)) { + /* Validate buffer will fit */ + if (sqe->tx.buf_len > config->common.msg_buf_size) { + LOG_ERR("Need to use the internal driver " + "buffer but its size is insufficient " + "(%u > %u). " + "Adjust the zephyr,concat-buf-size or " + "zephyr,flash-buf-max-size property " + "(the one with greater value) in the " + "\"%s\"' node.", + sqe->tx.buf_len, config->common.msg_buf_size, dev->name); + return i2c_rtio_complete(ctx, -ENOSPC); + } + memcpy(config->common.msg_buf, sqe->tx.buf, sqe->tx.buf_len); + sqe->tx.buf = config->common.msg_buf; + } + return i2c_nrfx_twim_rtio_msg_start(dev, I2C_MSG_WRITE | sqe->iodev_flags, + sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr); + case RTIO_OP_I2C_CONFIGURE: + (void)i2c_nrfx_twim_configure(dev, sqe->i2c_config); + return false; + case RTIO_OP_I2C_RECOVER: + (void)i2c_nrfx_twim_recover_bus(dev); + return false; + default: + LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe); + return i2c_rtio_complete(ctx, -EINVAL); + } +} + +static void i2c_nrfx_twim_rtio_complete(const struct device *dev, int status) +{ + /** Finalize if there are no more pending xfers */ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + struct i2c_rtio *ctx = config->ctx; + + if (i2c_rtio_complete(ctx, status)) { + (void)i2c_nrfx_twim_rtio_start(dev); + } else { + /* Release bus on completion */ + pm_device_runtime_put(dev); + } +} + +static int i2c_nrfx_twim_rtio_configure(const struct device *dev, uint32_t i2c_config) +{ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + struct i2c_rtio *ctx = config->ctx; + + return i2c_rtio_configure(ctx, i2c_config); +} + +static int i2c_nrfx_twim_rtio_transfer(const struct device *dev, struct i2c_msg *msgs, + uint8_t num_msgs, uint16_t addr) +{ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + struct i2c_rtio *ctx = config->ctx; + + return i2c_rtio_transfer(ctx, msgs, num_msgs, addr); +} + +static int i2c_nrfx_twim_rtio_recover_bus(const struct device *dev) +{ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + struct i2c_rtio *ctx = config->ctx; + + return i2c_rtio_recover(ctx); +} + +static void i2c_nrfx_twim_rtio_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_seq) +{ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + struct i2c_rtio *ctx = config->ctx; + + if (i2c_rtio_submit(ctx, iodev_seq)) { + if (pm_device_runtime_get(dev) < 0) { + (void)i2c_rtio_complete(ctx, -EINVAL); + } else { + (void)i2c_nrfx_twim_rtio_start(dev); + } + } +} + +static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context) +{ + const struct device *dev = p_context; + int status = p_event->type == NRFX_TWIM_EVT_DONE ? 0 : -EIO; + + i2c_nrfx_twim_rtio_complete(dev, status); +} + +static const struct i2c_driver_api i2c_nrfx_twim_driver_api = { + .configure = i2c_nrfx_twim_rtio_configure, + .transfer = i2c_nrfx_twim_rtio_transfer, + .recover_bus = i2c_nrfx_twim_rtio_recover_bus, + .iodev_submit = i2c_nrfx_twim_rtio_submit, +}; + +int i2c_nrfx_twim_rtio_init(const struct device *dev) +{ + const struct i2c_nrfx_twim_rtio_config *config = dev->config; + + i2c_rtio_init(config->ctx, dev); + return i2c_nrfx_twim_common_init(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)) +#define FLASH_BUF_MAX_SIZE(idx) \ + COND_CODE_1(DT_NODE_HAS_PROP(I2C(idx), zephyr_flash_buf_max_size), \ + (DT_PROP(I2C(idx), zephyr_flash_buf_max_size)), (0)) + +#define USES_MSG_BUF(idx) \ + COND_CODE_0(CONCAT_BUF_SIZE(idx), (COND_CODE_0(FLASH_BUF_MAX_SIZE(idx), (0), (1))), (1)) +#define MSG_BUF_SIZE(idx) MAX(CONCAT_BUF_SIZE(idx), FLASH_BUF_MAX_SIZE(idx)) + +#define I2C_NRFX_TWIM_RTIO_DEVICE(idx) \ + NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(I2C(idx)); \ + BUILD_ASSERT(I2C_FREQUENCY(idx) != I2C_NRFX_TWIM_INVALID_FREQUENCY, \ + "Wrong I2C " #idx " frequency setting in dts"); \ + static void irq_connect##idx(void) \ + { \ + IRQ_CONNECT(DT_IRQN(I2C(idx)), DT_IRQ(I2C(idx), priority), nrfx_isr, \ + nrfx_twim_##idx##_irq_handler, 0); \ + } \ + IF_ENABLED( \ + USES_MSG_BUF(idx), \ + (static uint8_t twim_##idx##_msg_buf[MSG_BUF_SIZE(idx)] I2C_MEMORY_SECTION(idx);)) \ + I2C_RTIO_DEFINE(_i2c##idx##_twim_rtio, \ + DT_INST_PROP_OR(n, sq_size, CONFIG_I2C_RTIO_SQ_SIZE), \ + DT_INST_PROP_OR(n, cq_size, CONFIG_I2C_RTIO_CQ_SIZE)); \ + PINCTRL_DT_DEFINE(I2C(idx)); \ + static const struct i2c_nrfx_twim_rtio_config twim_##idx##z_config = { \ + .common = \ + { \ + .twim = NRFX_TWIM_INSTANCE(idx), \ + .twim_config = \ + { \ + .skip_gpio_cfg = true, \ + .skip_psel_cfg = true, \ + .frequency = I2C_FREQUENCY(idx), \ + }, \ + .event_handler = event_handler, \ + .msg_buf_size = MSG_BUF_SIZE(idx), \ + .irq_connect = irq_connect##idx, \ + .pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2C(idx)), \ + IF_ENABLED(USES_MSG_BUF(idx), (.msg_buf = twim_##idx##_msg_buf,)) \ + .max_transfer_size = \ + BIT_MASK(DT_PROP(I2C(idx), easydma_maxcnt_bits)), \ + }, \ + .ctx = &_i2c##idx##_twim_rtio, \ + }; \ + PM_DEVICE_DT_DEFINE(I2C(idx), twim_nrfx_pm_action); \ + I2C_DEVICE_DT_DEFINE(I2C(idx), i2c_nrfx_twim_rtio_init, PM_DEVICE_DT_GET(I2C(idx)), NULL, \ + &twim_##idx##z_config, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ + &i2c_nrfx_twim_driver_api) + +#define I2C_MEMORY_SECTION(idx) \ + COND_CODE_1(I2C_HAS_PROP(idx, memory_regions), \ + (__attribute__((__section__( \ + LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(I2C(idx), memory_regions)))))), \ + ()) + +#ifdef CONFIG_HAS_HW_NRF_TWIM0 +I2C_NRFX_TWIM_RTIO_DEVICE(0); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM1 +I2C_NRFX_TWIM_RTIO_DEVICE(1); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM2 +I2C_NRFX_TWIM_RTIO_DEVICE(2); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM3 +I2C_NRFX_TWIM_RTIO_DEVICE(3); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM20 +I2C_NRFX_TWIM_RTIO_DEVICE(20); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM21 +I2C_NRFX_TWIM_RTIO_DEVICE(21); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM22 +I2C_NRFX_TWIM_RTIO_DEVICE(22); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM30 +I2C_NRFX_TWIM_RTIO_DEVICE(30); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM120 +I2C_NRFX_TWIM_RTIO_DEVICE(120); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM130 +I2C_NRFX_TWIM_RTIO_DEVICE(130); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM131 +I2C_NRFX_TWIM_RTIO_DEVICE(131); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM132 +I2C_NRFX_TWIM_RTIO_DEVICE(132); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM133 +I2C_NRFX_TWIM_RTIO_DEVICE(133); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM134 +I2C_NRFX_TWIM_RTIO_DEVICE(134); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM135 +I2C_NRFX_TWIM_RTIO_DEVICE(135); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM136 +I2C_NRFX_TWIM_RTIO_DEVICE(136); +#endif + +#ifdef CONFIG_HAS_HW_NRF_TWIM137 +I2C_NRFX_TWIM_RTIO_DEVICE(137); +#endif diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index 8966c4bf684..7d9c89ffe8d 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -132,6 +132,7 @@ interrupts = <3 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <14>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@40004000 { diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index a67d677e7a2..f03feb12bf1 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -136,6 +136,7 @@ interrupts = <3 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <10>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@40004000 { diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 41391b7eb3d..7b9094804a2 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -148,6 +148,7 @@ interrupts = <3 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <14>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi1: spi@40003000 { diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index 4d05bc741a0..61aeb9a28ec 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -150,6 +150,7 @@ interrupts = <3 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <15>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@40003000 { @@ -186,6 +187,7 @@ interrupts = <4 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <15>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi1: spi@40004000 { diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index 32245608a80..c82066bf5f9 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -136,6 +136,7 @@ interrupts = <3 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <8>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@40003000 { @@ -172,6 +173,7 @@ interrupts = <4 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <8>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi1: spi@40004000 { diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index b576401803a..72730dc18d3 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -150,6 +150,7 @@ interrupts = <3 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@40003000 { @@ -186,6 +187,7 @@ interrupts = <4 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi1: spi@40004000 { diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index 3965c4f3b11..1eddc5b1f12 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -138,6 +138,7 @@ interrupts = <3 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@40003000 { @@ -174,6 +175,7 @@ interrupts = <4 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi1: spi@40004000 { diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index 50842fb3801..f36dabc398a 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -108,6 +108,7 @@ i2c0: i2c@8000 { interrupts = <8 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@8000 { @@ -149,6 +150,7 @@ i2c1: i2c@9000 { interrupts = <9 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi1: spi@9000 { @@ -203,6 +205,7 @@ i2c2: i2c@b000 { interrupts = <11 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi2: spi@b000 { @@ -244,6 +247,7 @@ i2c3: i2c@c000 { interrupts = <12 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi3: spi@c000 { diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index 0da1e06866f..88d4d0d0924 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -206,6 +206,7 @@ interrupts = <19 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@41013000 { diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index 93abc17d48b..1be26d50af9 100644 --- a/dts/arm/nordic/nrf91_peripherals.dtsi +++ b/dts/arm/nordic/nrf91_peripherals.dtsi @@ -160,6 +160,7 @@ i2c0: i2c@8000 { interrupts = <8 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <13>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; i2c1: i2c@9000 { @@ -176,6 +177,7 @@ i2c1: i2c@9000 { interrupts = <9 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <13>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; i2c2: i2c@a000 { @@ -192,6 +194,7 @@ i2c2: i2c@a000 { interrupts = <10 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <13>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; i2c3: i2c@b000 { @@ -208,6 +211,7 @@ i2c3: i2c@b000 { interrupts = <11 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <13>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi0: spi@8000 { diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index b28ddb83fdb..a9523f15465 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -987,6 +987,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi130: spi@9a5000 { @@ -1032,6 +1033,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi131: spi@9a6000 { @@ -1118,6 +1120,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi132: spi@9b5000 { @@ -1163,6 +1166,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi133: spi@9b6000 { @@ -1249,6 +1253,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi134: spi@9c5000 { @@ -1294,6 +1299,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi135: spi@9c6000 { @@ -1380,6 +1386,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi136: spi@9d5000 { @@ -1425,6 +1432,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi137: spi@9d6000 { diff --git a/dts/common/nordic/nrf54l15.dtsi b/dts/common/nordic/nrf54l15.dtsi index d3c0c551823..af1a0d9a261 100644 --- a/dts/common/nordic/nrf54l15.dtsi +++ b/dts/common/nordic/nrf54l15.dtsi @@ -245,6 +245,7 @@ interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi20: spi@c6000 { @@ -284,6 +285,7 @@ interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi21: spi@c7000 { @@ -323,6 +325,7 @@ interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi22: spi@c8000 { @@ -533,6 +536,7 @@ interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi30: spi@104000 { diff --git a/dts/common/nordic/nrf54l20.dtsi b/dts/common/nordic/nrf54l20.dtsi index dfe8d7b4531..26fe41d6d7b 100644 --- a/dts/common/nordic/nrf54l20.dtsi +++ b/dts/common/nordic/nrf54l20.dtsi @@ -195,6 +195,7 @@ interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi20: spi@c6000 { @@ -234,6 +235,7 @@ interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi21: spi@c7000 { @@ -273,6 +275,7 @@ interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi22: spi@c8000 { @@ -474,6 +477,7 @@ interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; easydma-maxcnt-bits = <16>; status = "disabled"; + zephyr,pm-device-runtime-auto; }; spi30: spi@104000 { diff --git a/dts/common/nordic/nrf9280.dtsi b/dts/common/nordic/nrf9280.dtsi index 45b05f9262e..4fd64cd10be 100644 --- a/dts/common/nordic/nrf9280.dtsi +++ b/dts/common/nordic/nrf9280.dtsi @@ -815,6 +815,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi130: spi@9a5000 { @@ -854,6 +855,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi131: spi@9a6000 { @@ -927,6 +929,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi132: spi@9b5000 { @@ -966,6 +969,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi133: spi@9b6000 { @@ -1039,6 +1043,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi134: spi@9c5000 { @@ -1078,6 +1083,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi135: spi@9c6000 { @@ -1151,6 +1157,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi136: spi@9d5000 { @@ -1190,6 +1197,7 @@ #size-cells = <0>; nordic,clockpin-enable = , ; + zephyr,pm-device-runtime-auto; }; spi137: spi@9d6000 {