Repository: zephyrproject-rtos/zephyr
Pull request #87731: STM32: Add I2C RTIO support
Author: login: gautierg-st
Labels: name: area: I2C
name: platform: STM32
description: ST Micro STM32
Created: 2025-03-27T08:11:52Z | Merged: 2025-05-22T18:56:29Z

This PR is the continuation of #71961 started by @teburd.
It introduces RTIO support for STM32 I2C v1 and v2.
It works fine with the `sensor_read` and `sensor_get_decoder` functions but there is currently a limitation with the `sensor_stream` function (used for example in `sensor/accel_polling` and `sensor/stream_fifo` samples).


Diff:
diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt
index 7a4dbfc538989..aee426e0848b8 100644
--- a/drivers/i2c/CMakeLists.txt
+++ b/drivers/i2c/CMakeLists.txt
@@ -65,14 +65,6 @@ zephyr_library_sources_ifdef(CONFIG_I2C_SC18IM704	i2c_sc18im704.c)
 zephyr_library_sources_ifdef(CONFIG_I2C_SEDI		i2c_sedi.c)
 zephyr_library_sources_ifdef(CONFIG_I2C_SIFIVE		i2c_sifive.c)
 zephyr_library_sources_ifdef(CONFIG_I2C_SMARTBOND	i2c_smartbond.c)
-zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1
-	i2c_ll_stm32_v1.c
-	i2c_ll_stm32.c
- )
-zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2
-	i2c_ll_stm32_v2.c
-	i2c_ll_stm32.c
- )
 zephyr_library_sources_ifdef(CONFIG_I2C_SY1XX		i2c_sy1xx.c)
 zephyr_library_sources_ifdef(CONFIG_I2C_TCA954X		i2c_tca954x.c)
 zephyr_library_sources_ifdef(CONFIG_I2C_TELINK_B91	i2c_b91.c)
@@ -91,6 +83,12 @@ if(CONFIG_I2C_RTIO)
 	zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM	i2c_nrfx_twim_common.c)
 	zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM	i2c_nrfx_twim_rtio.c)
 	zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS	i2c_sam_twihs_rtio.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1	i2c_ll_stm32_common.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1	i2c_ll_stm32_rtio.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1	i2c_ll_stm32_v1_rtio.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2	i2c_ll_stm32_common.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2	i2c_ll_stm32_rtio.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2	i2c_ll_stm32_v2_rtio.c)
 	# zephyr-keep-sorted-stop
 else()
 	# zephyr-keep-sorted-start
@@ -101,5 +99,11 @@ else()
 	zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM	i2c_nrfx_twim.c)
 	zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM	i2c_nrfx_twim_common.c)
 	zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS	i2c_sam_twihs.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1	i2c_ll_stm32.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1	i2c_ll_stm32_common.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1	i2c_ll_stm32_v1.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2	i2c_ll_stm32.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2	i2c_ll_stm32_common.c)
+	zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2	i2c_ll_stm32_v2.c)
 	# zephyr-keep-sorted-stop
 endif()
diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c
index 15809dabc9f00..63e21236ddb32 100644
--- a/drivers/i2c/i2c_ll_stm32.c
+++ b/drivers/i2c/i2c_ll_stm32.c
@@ -20,7 +20,7 @@
 #include <errno.h>
 #include <zephyr/drivers/i2c.h>
 #include <zephyr/drivers/pinctrl.h>
-#include "i2c_ll_stm32.h"
+#include <zephyr/irq.h>
 
 #ifdef CONFIG_I2C_STM32_BUS_RECOVERY
 #include "i2c_bitbang.h"
@@ -28,9 +28,9 @@
 
 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
 #include <zephyr/logging/log.h>
-#include <zephyr/irq.h>
 LOG_MODULE_REGISTER(i2c_ll_stm32);
 
+#include "i2c_ll_stm32.h"
 #include "i2c-priv.h"
 
 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2)
@@ -42,9 +42,9 @@ LOG_MODULE_REGISTER(i2c_ll_stm32);
 /* This symbol takes the value 1 if one of the device instances */
 /* is configured in dts with a domain clock */
 #if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
-#define STM32_I2C_DOMAIN_CLOCK_SUPPORT 1
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 1
 #else
-#define STM32_I2C_DOMAIN_CLOCK_SUPPORT 0
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 0
 #endif
 
 int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
@@ -90,7 +90,7 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config)
 	uint32_t i2c_clock = 0U;
 	int ret;
 
-	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+	if (IS_ENABLED(I2C_STM32_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
 		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
 					   &i2c_clock) < 0) {
 			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
@@ -120,7 +120,7 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config)
 #if defined(I2C_CR1_SMBUS) || defined(I2C_CR1_SMBDEN) || defined(I2C_CR1_SMBHEN)
 	i2c_stm32_set_smbus_mode(dev, data->mode);
 #endif
-	ret = stm32_i2c_configure_timing(dev, i2c_clock);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
 
 	if (data->smbalert_active) {
 		LL_I2C_Enable(i2c);
@@ -210,7 +210,7 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg,
 			next = current + 1;
 			next_msg_flags = &(next->flags);
 		}
-		ret = stm32_i2c_transaction(dev, *current, next_msg_flags, slave);
+		ret = i2c_stm32_transaction(dev, *current, next_msg_flags, slave);
 		if (ret < 0) {
 			break;
 		}
@@ -329,59 +329,6 @@ static DEVICE_API(i2c, api_funcs) = {
 #endif
 };
 
-#ifdef CONFIG_PM_DEVICE
-
-static int i2c_stm32_suspend(const struct device *dev)
-{
-	int ret;
-	const struct i2c_stm32_config *cfg = dev->config;
-	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
-
-	/* Disable device clock. */
-	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
-	if (ret < 0) {
-		LOG_ERR("failure disabling I2C clock");
-		return ret;
-	}
-
-	/* Move pins to sleep state */
-	ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP);
-	if (ret == -ENOENT) {
-		/* Warn but don't block suspend */
-		LOG_WRN("I2C pinctrl sleep state not available ");
-	} else if (ret < 0) {
-		return ret;
-	}
-
-	return 0;
-}
-
-#endif
-
-static int i2c_stm32_activate(const struct device *dev)
-{
-	int ret;
-	const struct i2c_stm32_config *cfg = dev->config;
-	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
-
-	/* Move pins to active/default state */
-	ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
-	if (ret < 0) {
-		LOG_ERR("I2C pinctrl setup failed (%d)", ret);
-		return ret;
-	}
-
-	/* Enable device clock. */
-	if (clock_control_on(clk,
-			     (clock_control_subsys_t) &cfg->pclken[0]) != 0) {
-		LOG_ERR("i2c: failure enabling clock");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-
 static int i2c_stm32_init(const struct device *dev)
 {
 	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
@@ -411,7 +358,7 @@ static int i2c_stm32_init(const struct device *dev)
 
 	i2c_stm32_activate(dev);
 
-	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+	if (IS_ENABLED(I2C_STM32_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
 		/* Enable I2C clock source */
 		ret = clock_control_configure(clk,
 					(clock_control_subsys_t) &cfg->pclken[1],
@@ -450,28 +397,6 @@ static int i2c_stm32_init(const struct device *dev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_DEVICE
-
-static int i2c_stm32_pm_action(const struct device *dev, enum pm_device_action action)
-{
-	int err;
-
-	switch (action) {
-	case PM_DEVICE_ACTION_RESUME:
-		err = i2c_stm32_activate(dev);
-		break;
-	case PM_DEVICE_ACTION_SUSPEND:
-		err = i2c_stm32_suspend(dev);
-		break;
-	default:
-		return -ENOTSUP;
-	}
-
-	return err;
-}
-
-#endif
-
 #ifdef CONFIG_SMBUS_STM32_SMBALERT
 void i2c_stm32_smbalert_set_callback(const struct device *dev, i2c_stm32_smbalert_cb_func_t func,
 				     const struct device *cb_dev)
@@ -540,63 +465,18 @@ void i2c_stm32_smbalert_disable(const struct device *dev)
 
 /* Macros for I2C instance declaration */
 
-#ifdef CONFIG_I2C_STM32_INTERRUPT
-
-#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT
-#define STM32_I2C_IRQ_CONNECT_AND_ENABLE(index)				\
-	do {								\
-		IRQ_CONNECT(DT_INST_IRQN(index),			\
-			    DT_INST_IRQ(index, priority),		\
-			    stm32_i2c_combined_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQN(index));			\
-	} while (false)
-#else
-#define STM32_I2C_IRQ_CONNECT_AND_ENABLE(index)				\
-	do {								\
-		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, event, irq),	\
-			    DT_INST_IRQ_BY_NAME(index, event, priority),\
-			    stm32_i2c_event_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQ_BY_NAME(index, event, irq));	\
-									\
-		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, error, irq),	\
-			    DT_INST_IRQ_BY_NAME(index, error, priority),\
-			    stm32_i2c_error_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQ_BY_NAME(index, error, irq));	\
-	} while (false)
-#endif /* CONFIG_I2C_STM32_COMBINED_INTERRUPT */
-
-#define STM32_I2C_IRQ_HANDLER_DECL(index)				\
-static void i2c_stm32_irq_config_func_##index(const struct device *dev)
-#define STM32_I2C_IRQ_HANDLER_FUNCTION(index)				\
-	.irq_config_func = i2c_stm32_irq_config_func_##index,
-#define STM32_I2C_IRQ_HANDLER(index)					\
-static void i2c_stm32_irq_config_func_##index(const struct device *dev)	\
-{									\
-	STM32_I2C_IRQ_CONNECT_AND_ENABLE(index);			\
-}
-#else
-
-#define STM32_I2C_IRQ_HANDLER_DECL(index)
-#define STM32_I2C_IRQ_HANDLER_FUNCTION(index)
-#define STM32_I2C_IRQ_HANDLER(index)
-
-#endif /* CONFIG_I2C_STM32_INTERRUPT */
-
 #ifdef CONFIG_I2C_STM32_V2_DMA
 
-#define I2C_DMA_INIT(index, dir)					\
-	.dir##_dma = {							\
-		.dev_dma = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir),\
-				(DEVICE_DT_GET(STM32_DMA_CTLR(index, dir))), (NULL)),\
-		.dma_channel = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir),\
-				(DT_INST_DMAS_CELL_BY_NAME(index, dir, channel)), (-1)),\
+#define I2C_DMA_INIT(index, dir)								\
+	.dir##_dma = {										\
+		.dev_dma = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir),			\
+				(DEVICE_DT_GET(STM32_DMA_CTLR(index, dir))), (NULL)),		\
+		.dma_channel = COND_CODE_1(DT_INST_DMAS_HAS_NAME(index, dir),			\
+				(DT_INST_DMAS_CELL_BY_NAME(index, dir, channel)), (-1)),	\
 		},
 
 void i2c_stm32_dma_tx_cb(const struct device *dma_dev, void *user_data,
-			uint32_t channel, int status)
+			 uint32_t channel, int status)
 {
 	ARG_UNUSED(dma_dev);
 	ARG_UNUSED(user_data);
@@ -609,7 +489,7 @@ void i2c_stm32_dma_tx_cb(const struct device *dma_dev, void *user_data,
 }
 
 void i2c_stm32_dma_rx_cb(const struct device *dma_dev, void *user_data,
-			uint32_t channel, int status)
+			 uint32_t channel, int status)
 {
 	ARG_UNUSED(dma_dev);
 	ARG_UNUSED(user_data);
@@ -621,23 +501,23 @@ void i2c_stm32_dma_rx_cb(const struct device *dma_dev, void *user_data,
 	}
 }
 
-#define I2C_DMA_DATA_INIT(index, dir, src, dest)			\
-	.dma_##dir##_cfg = {						\
-		.dma_slot = STM32_DMA_SLOT(index, dir, slot),		\
-		.channel_direction = STM32_DMA_CONFIG_DIRECTION(	\
-					STM32_DMA_CHANNEL_CONFIG(index, dir)),\
-		.cyclic =  STM32_DMA_CONFIG_CYCLIC(			\
-				STM32_DMA_CHANNEL_CONFIG(index, dir)),	\
-		.channel_priority = STM32_DMA_CONFIG_PRIORITY(		\
-				STM32_DMA_CHANNEL_CONFIG(index, dir)),	\
-		.source_data_size = STM32_DMA_CONFIG_##src##_DATA_SIZE(	\
-					STM32_DMA_CHANNEL_CONFIG(index, dir)),\
-		.dest_data_size = STM32_DMA_CONFIG_##dest##_DATA_SIZE(	\
-				STM32_DMA_CHANNEL_CONFIG(index, dir)),	\
-		.source_burst_length = 1,				\
-		.dest_burst_length = 1,					\
-		.dma_callback = i2c_stm32_dma_##dir##_cb,		\
-	},								\
+#define I2C_DMA_DATA_INIT(index, dir, src, dest)						\
+	.dma_##dir##_cfg = {									\
+		.dma_slot = STM32_DMA_SLOT(index, dir, slot),					\
+		.channel_direction = STM32_DMA_CONFIG_DIRECTION(				\
+					STM32_DMA_CHANNEL_CONFIG(index, dir)),			\
+		.cyclic =  STM32_DMA_CONFIG_CYCLIC(						\
+				STM32_DMA_CHANNEL_CONFIG(index, dir)),				\
+		.channel_priority = STM32_DMA_CONFIG_PRIORITY(					\
+				STM32_DMA_CHANNEL_CONFIG(index, dir)),				\
+		.source_data_size = STM32_DMA_CONFIG_##src##_DATA_SIZE(				\
+					STM32_DMA_CHANNEL_CONFIG(index, dir)),			\
+		.dest_data_size = STM32_DMA_CONFIG_##dest##_DATA_SIZE(				\
+				STM32_DMA_CHANNEL_CONFIG(index, dir)),				\
+		.source_burst_length = 1,							\
+		.dest_burst_length = 1,								\
+		.dma_callback = i2c_stm32_dma_##dir##_cb,					\
+	},											\
 
 #else
 
@@ -646,49 +526,49 @@ void i2c_stm32_dma_rx_cb(const struct device *dma_dev, void *user_data,
 
 #endif /* CONFIG_I2C_STM32_V2_DMA */
 
-#define STM32_I2C_INIT(index)						\
-STM32_I2C_IRQ_HANDLER_DECL(index);					\
-									\
-IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),			\
-	(static const uint32_t i2c_timings_##index[] =			\
-		DT_INST_PROP_OR(index, timings, {});))			\
-									\
-PINCTRL_DT_INST_DEFINE(index);						\
-									\
-static const struct stm32_pclken pclken_##index[] =			\
-				 STM32_DT_INST_CLOCKS(index);		\
-									\
-static const struct i2c_stm32_config i2c_stm32_cfg_##index = {		\
-	.i2c = (I2C_TypeDef *)DT_INST_REG_ADDR(index),			\
-	.pclken = pclken_##index,					\
-	.pclk_len = DT_INST_NUM_CLOCKS(index),				\
-	STM32_I2C_IRQ_HANDLER_FUNCTION(index)				\
-	.bitrate = DT_INST_PROP(index, clock_frequency),		\
-	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),			\
-	IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY,			\
-		(.scl =	GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),\
-		 .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))\
-	IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),		\
-		(.timings = (const struct i2c_config_timing *) i2c_timings_##index,\
-		 .n_timings = ARRAY_SIZE(i2c_timings_##index),))	\
-	I2C_DMA_INIT(index, tx)						\
-	I2C_DMA_INIT(index, rx)						\
-};									\
-									\
-static struct i2c_stm32_data i2c_stm32_dev_data_##index = {		\
-	I2C_DMA_DATA_INIT(index, tx, MEMORY, PERIPHERAL)		\
-	I2C_DMA_DATA_INIT(index, rx, PERIPHERAL, MEMORY)		\
-};									\
-									\
-PM_DEVICE_DT_INST_DEFINE(index, i2c_stm32_pm_action);			\
-									\
-I2C_DEVICE_DT_INST_DEFINE(index, i2c_stm32_init,			\
-			 PM_DEVICE_DT_INST_GET(index),			\
-			 &i2c_stm32_dev_data_##index,			\
-			 &i2c_stm32_cfg_##index,			\
-			 POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,		\
-			 &api_funcs);					\
-									\
-STM32_I2C_IRQ_HANDLER(index)
-
-DT_INST_FOREACH_STATUS_OKAY(STM32_I2C_INIT)
+#define I2C_STM32_INIT(index)									\
+I2C_STM32_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
+	(static const uint32_t i2c_timings_##index[] =						\
+		DT_INST_PROP_OR(index, timings, {});))						\
+												\
+PINCTRL_DT_INST_DEFINE(index);									\
+												\
+static const struct stm32_pclken pclken_##index[] =						\
+				 STM32_DT_INST_CLOCKS(index);					\
+												\
+static const struct i2c_stm32_config i2c_stm32_cfg_##index = {					\
+	.i2c = (I2C_TypeDef *)DT_INST_REG_ADDR(index),						\
+	.pclken = pclken_##index,								\
+	.pclk_len = DT_INST_NUM_CLOCKS(index),							\
+	I2C_STM32_IRQ_HANDLER_FUNCTION(index)							\
+	.bitrate = DT_INST_PROP(index, clock_frequency),					\
+	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),						\
+	IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY,						\
+		(.scl =	GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),			\
+		 .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))			\
+	IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),					\
+		(.timings = (const struct i2c_config_timing *) i2c_timings_##index,		\
+		 .n_timings = ARRAY_SIZE(i2c_timings_##index),))				\
+	I2C_DMA_INIT(index, tx)									\
+	I2C_DMA_INIT(index, rx)									\
+};												\
+												\
+static struct i2c_stm32_data i2c_stm32_dev_data_##index = {					\
+	I2C_DMA_DATA_INIT(index, tx, MEMORY, PERIPHERAL)					\
+	I2C_DMA_DATA_INIT(index, rx, PERIPHERAL, MEMORY)					\
+};												\
+												\
+PM_DEVICE_DT_INST_DEFINE(index, i2c_stm32_pm_action);						\
+												\
+I2C_DEVICE_DT_INST_DEFINE(index, i2c_stm32_init,						\
+			 PM_DEVICE_DT_INST_GET(index),						\
+			 &i2c_stm32_dev_data_##index,						\
+			 &i2c_stm32_cfg_##index,						\
+			 POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,					\
+			 &api_funcs);								\
+												\
+I2C_STM32_IRQ_HANDLER(index)
+
+DT_INST_FOREACH_STATUS_OKAY(I2C_STM32_INIT)
diff --git a/drivers/i2c/i2c_ll_stm32.h b/drivers/i2c/i2c_ll_stm32.h
index 962492400e5c4..d687370eaf319 100644
--- a/drivers/i2c/i2c_ll_stm32.h
+++ b/drivers/i2c/i2c_ll_stm32.h
@@ -10,6 +10,11 @@
 #define ZEPHYR_DRIVERS_I2C_I2C_LL_STM32_H_
 
 #include <zephyr/drivers/i2c/stm32.h>
+#include <zephyr/kernel.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/logging/log.h>
 
 #ifdef CONFIG_I2C_STM32_BUS_RECOVERY
 #include <zephyr/drivers/gpio.h>
@@ -64,23 +69,35 @@ struct i2c_stm32_config {
 };
 
 struct i2c_stm32_data {
+#ifdef CONFIG_I2C_RTIO
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+#ifdef CONFIG_I2C_STM32_V1
+	uint8_t msg_len;
+	uint8_t is_restart;
+	uint16_t slave_address;
+#endif /* CONFIG_I2C_STM32_V1 */
+#else /* CONFIG_I2C_RTIO */
 #ifdef CONFIG_I2C_STM32_INTERRUPT
 	struct k_sem device_sync_sem;
-#endif
+#endif /* CONFIG_I2C_STM32_INTERRUPT */
 	struct k_sem bus_mutex;
 	uint32_t dev_config;
 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2)
 	/* Store the current timing structure set by runtime config */
 	struct i2c_config_timing current_timing;
-#endif
+#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2) */
 #ifdef CONFIG_I2C_STM32_V1
 	uint16_t slave_address;
-#endif
+#endif /* CONFIG_I2C_STM32_V1 */
 	struct {
 #ifdef CONFIG_I2C_STM32_V1
 		unsigned int is_restart;
 		unsigned int flags;
-#endif
+#endif /* CONFIG_I2C_STM32_V1 */
 		unsigned int is_write;
 		unsigned int is_arlo;
 		unsigned int is_nack;
@@ -94,39 +111,95 @@ struct i2c_stm32_data {
 	struct i2c_target_config *slave_cfg;
 #ifdef CONFIG_I2C_STM32_V2
 	struct i2c_target_config *slave2_cfg;
-#endif
+#endif /* CONFIG_I2C_STM32_V2 */
 	bool slave_attached;
-#endif
+#endif /* CONFIG_I2C_TARGET */
 	bool is_configured;
 	bool smbalert_active;
 	enum i2c_stm32_mode mode;
 #ifdef CONFIG_SMBUS_STM32_SMBALERT
 	i2c_stm32_smbalert_cb_func_t smbalert_cb_func;
 	const struct device *smbalert_cb_dev;
-#endif
+#endif /* CONFIG_SMBUS_STM32_SMBALERT */
 #ifdef CONFIG_I2C_STM32_V2_DMA
 	struct dma_config dma_tx_cfg;
 	struct dma_config dma_rx_cfg;
 	struct dma_block_config dma_blk_cfg;
 #endif /* CONFIG_I2C_STM32_V2_DMA */
+#endif /* CONFIG_I2C_RTIO */
 };
 
-int stm32_i2c_transaction(const struct device *dev,
-			    struct i2c_msg msg, uint8_t *next_msg_flags,
-			    uint16_t periph);
-int stm32_i2c_configure_timing(const struct device *dev, uint32_t clk);
+#ifdef CONFIG_I2C_RTIO
+bool i2c_stm32_start(const struct device *dev);
+int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+			uint8_t *buf, size_t buf_len, uint16_t i2c_addr);
+#else /* CONFIG_I2C_RTIO */
+int i2c_stm32_transaction(const struct device *dev,
+			  struct i2c_msg msg, uint8_t *next_msg_flags,
+			  uint16_t periph);
 int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config);
-int i2c_stm32_get_config(const struct device *dev, uint32_t *config);
-
-void stm32_i2c_event_isr(void *arg);
-void stm32_i2c_error_isr(void *arg);
-#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT
-void stm32_i2c_combined_isr(void *arg);
-#endif
 
 #ifdef CONFIG_I2C_TARGET
 int i2c_stm32_target_register(const struct device *dev, struct i2c_target_config *config);
 int i2c_stm32_target_unregister(const struct device *dev, struct i2c_target_config *config);
-#endif
+#endif /* CONFIG_I2C_TARGET */
+#endif /* CONFIG_I2C_RTIO */
+
+int i2c_stm32_activate(const struct device *dev);
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clk);
+
+#ifdef CONFIG_PM_DEVICE
+int i2c_stm32_pm_action(const struct device *dev, enum pm_device_action action);
+int i2c_stm32_suspend(const struct device *dev);
+#endif /* CONFIG_PM_DEVICE */
+
+int i2c_stm32_error(const struct device *dev);
+void i2c_stm32_event(const struct device *dev);
+
+#ifdef CONFIG_I2C_STM32_INTERRUPT
+#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT
+void i2c_stm32_combined_isr(void *arg);
+#define I2C_STM32_IRQ_CONNECT_AND_ENABLE(index)							\
+	do {											\
+		IRQ_CONNECT(DT_INST_IRQN(index),						\
+			    DT_INST_IRQ(index, priority),					\
+			    i2c_stm32_combined_isr,						\
+			    DEVICE_DT_INST_GET(index), 0);					\
+		irq_enable(DT_INST_IRQN(index));						\
+	} while (false)
+#else /* CONFIG_I2C_STM32_COMBINED_INTERRUPT */
+void i2c_stm32_event_isr(void *arg);
+void i2c_stm32_error_isr(void *arg);
+#define I2C_STM32_IRQ_CONNECT_AND_ENABLE(index)							\
+	do {											\
+		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, event, irq),				\
+			    DT_INST_IRQ_BY_NAME(index, event, priority),			\
+			    i2c_stm32_event_isr,						\
+			    DEVICE_DT_INST_GET(index), 0);					\
+		irq_enable(DT_INST_IRQ_BY_NAME(index, event, irq));				\
+												\
+		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, error, irq),				\
+			    DT_INST_IRQ_BY_NAME(index, error, priority),			\
+			    i2c_stm32_error_isr,						\
+			    DEVICE_DT_INST_GET(index), 0);					\
+		irq_enable(DT_INST_IRQ_BY_NAME(index, error, irq));				\
+	} while (false)
+#endif /* CONFIG_I2C_STM32_COMBINED_INTERRUPT */
+
+#define I2C_STM32_IRQ_HANDLER_DECL(index)							\
+static void i2c_stm32_irq_config_func_##index(const struct device *dev)
+#define I2C_STM32_IRQ_HANDLER_FUNCTION(index)							\
+	.irq_config_func = i2c_stm32_irq_config_func_##index,
+#define I2C_STM32_IRQ_HANDLER(index)								\
+static void i2c_stm32_irq_config_func_##index(const struct device *dev)				\
+{												\
+	I2C_STM32_IRQ_CONNECT_AND_ENABLE(index);						\
+}
+
+#else /* CONFIG_I2C_STM32_INTERRUPT */
+#define STM32_I2C_IRQ_HANDLER_DECL(index)
+#define STM32_I2C_IRQ_HANDLER_FUNCTION(index)
+#define STM32_I2C_IRQ_HANDLER(index)
+#endif /* CONFIG_I2C_STM32_INTERRUPT */
 
 #endif	/* ZEPHYR_DRIVERS_I2C_I2C_LL_STM32_H_ */
diff --git a/drivers/i2c/i2c_ll_stm32_common.c b/drivers/i2c/i2c_ll_stm32_common.c
new file mode 100644
index 0000000000000..e94ae5ec2525b
--- /dev/null
+++ b/drivers/i2c/i2c_ll_stm32_common.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/pinctrl.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_common);
+
+#include "i2c_ll_stm32.h"
+
+#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT
+void i2c_stm32_combined_isr(void *arg)
+{
+	const struct device *dev = (const struct device *) arg;
+
+	if (i2c_stm32_error(dev)) {
+		return;
+	}
+	i2c_stm32_event(dev);
+}
+#else
+void i2c_stm32_event_isr(void *arg)
+{
+	const struct device *dev = (const struct device *) arg;
+
+	i2c_stm32_event(dev);
+}
+
+void i2c_stm32_error_isr(void *arg)
+{
+	const struct device *dev = (const struct device *) arg;
+
+	(void)i2c_stm32_error(dev);
+}
+#endif
+
+int i2c_stm32_activate(const struct device *dev)
+{
+	int ret;
+	const struct i2c_stm32_config *cfg = dev->config;
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+
+	/* Move pins to active/default state */
+	ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
+	if (ret < 0) {
+		LOG_ERR("I2C pinctrl setup failed (%d)", ret);
+		return ret;
+	}
+
+	/* Enable device clock. */
+	if (clock_control_on(clk,
+			     (clock_control_subsys_t) &cfg->pclken[0]) != 0) {
+		LOG_ERR("i2c: failure enabling clock");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_DEVICE
+int i2c_stm32_suspend(const struct device *dev)
+{
+	int ret;
+	const struct i2c_stm32_config *cfg = dev->config;
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+
+	/* Disable device clock. */
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+
+	/* Move pins to sleep state */
+	ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP);
+	if (ret == -ENOENT) {
+		/* Warn but don't block suspend */
+		LOG_WRN("I2C pinctrl sleep state not available ");
+	} else if (ret < 0) {
+		return ret;
+	}
+
+	return 0;
+}
+
+int i2c_stm32_pm_action(const struct device *dev, enum pm_device_action action)
+{
+	int err;
+
+	switch (action) {
+	case PM_DEVICE_ACTION_RESUME:
+		err = i2c_stm32_activate(dev);
+		break;
+	case PM_DEVICE_ACTION_SUSPEND:
+		err = i2c_stm32_suspend(dev);
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	return err;
+}
+#endif
diff --git a/drivers/i2c/i2c_ll_stm32_rtio.c b/drivers/i2c/i2c_ll_stm32_rtio.c
new file mode 100644
index 0000000000000..7d048ed4abc23
--- /dev/null
+++ b/drivers/i2c/i2c_ll_stm32_rtio.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2)
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+#else
+#define DT_DRV_COMPAT st_stm32_i2c_v1
+#endif
+
+/* This symbol takes the value 1 if one of the device instances */
+/* is configured in dts with a domain clock */
+#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 1
+#else
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 0
+#endif
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(I2C_STM32_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("Failed enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+	if (ret < 0) {
+		LOG_ERR("Failed configuring I2C timing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("Failed disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(I2C_STM32_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
+
+	bitrate_cfg = i2c_map_dt_bitrate(cfg->bitrate);
+
+	ret = i2c_stm32_do_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
+	if (ret < 0) {
+		LOG_ERR("i2c: failure initializing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	(void)pm_device_runtime_enable(dev);
+#endif
+
+	return 0;
+}
+
+#define I2C_STM32_INIT(index)									\
+I2C_STM32_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
+	(static const uint32_t i2c_timings_##index[] =						\
+		DT_INST_PROP_OR(index, timings, {});))						\
+												\
+PINCTRL_DT_INST_DEFINE(index);									\
+												\
+static const struct stm32_pclken pclken_##index[] =						\
+				 STM32_DT_INST_CLOCKS(index);					\
+												\
+static const struct i2c_stm32_config i2c_stm32_cfg_##index = {					\
+	.i2c = (I2C_TypeDef *)DT_INST_REG_ADDR(index),						\
+	.pclken = pclken_##index,								\
+	.pclk_len = DT_INST_NUM_CLOCKS(index),							\
+	I2C_STM32_IRQ_HANDLER_FUNCTION(index)							\
+	.bitrate = DT_INST_PROP(index, clock_frequency),					\
+	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),						\
+	IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),					\
+		(.timings = (const struct i2c_config_timing *) i2c_timings_##index,		\
+		 .n_timings = ARRAY_SIZE(i2c_timings_##index),))				\
+};												\
+												\
+I2C_RTIO_DEFINE(CONCAT(_i2c, index, _stm32_rtio),						\
+	DT_INST_PROP_OR(index, sq_size, CONFIG_I2C_RTIO_SQ_SIZE),				\
+	DT_INST_PROP_OR(index, cq_size, CONFIG_I2C_RTIO_CQ_SIZE));				\
+												\
+static struct i2c_stm32_data i2c_stm32_dev_data_##index = {					\
+	.ctx = &CONCAT(_i2c, index, _stm32_rtio),						\
+};												\
+												\
+PM_DEVICE_DT_INST_DEFINE(index, i2c_stm32_pm_action);						\
+												\
+I2C_DEVICE_DT_INST_DEFINE(index, i2c_stm32_init,						\
+			 PM_DEVICE_DT_INST_GET(index),						\
+			 &i2c_stm32_dev_data_##index,						\
+			 &i2c_stm32_cfg_##index,						\
+			 POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,					\
+			 &api_funcs);								\
+												\
+I2C_STM32_IRQ_HANDLER(index)
+
+DT_INST_FOREACH_STATUS_OKAY(I2C_STM32_INIT)
diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c
index 84624c53aa892..59e93f7413335 100644
--- a/drivers/i2c/i2c_ll_stm32_v1.c
+++ b/drivers/i2c/i2c_ll_stm32_v1.c
@@ -16,22 +16,22 @@
 #include <stm32_ll_i2c.h>
 #include <errno.h>
 #include <zephyr/drivers/i2c.h>
-#include "i2c_ll_stm32.h"
 
 #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
 #include <zephyr/logging/log.h>
 LOG_MODULE_REGISTER(i2c_ll_stm32_v1);
 
+#include "i2c_ll_stm32.h"
 #include "i2c-priv.h"
 
-#define STM32_I2C_TRANSFER_TIMEOUT_MSEC  500
+#define I2C_STM32_TRANSFER_TIMEOUT_MSEC  500
 
-#define STM32_I2C_TIMEOUT_USEC  1000
+#define I2C_STM32_TIMEOUT_USEC  1000
 #define I2C_REQUEST_WRITE       0x00
 #define I2C_REQUEST_READ        0x01
 #define HEADER                  0xF0
 
-static void stm32_i2c_generate_start_condition(I2C_TypeDef *i2c)
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
 {
 	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
 
@@ -45,7 +45,7 @@ static void stm32_i2c_generate_start_condition(I2C_TypeDef *i2c)
 
 #ifdef CONFIG_I2C_STM32_INTERRUPT
 
-static void stm32_i2c_disable_transfer_interrupts(const struct device *dev)
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -61,7 +61,7 @@ static void stm32_i2c_disable_transfer_interrupts(const struct device *dev)
 	}
 }
 
-static void stm32_i2c_enable_transfer_interrupts(const struct device *dev)
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	I2C_TypeDef *i2c = cfg->i2c;
@@ -73,7 +73,7 @@ static void stm32_i2c_enable_transfer_interrupts(const struct device *dev)
 
 #endif /* CONFIG_I2C_STM32_INTERRUPT */
 
-static void stm32_i2c_reset(const struct device *dev)
+static void i2c_stm32_reset(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	I2C_TypeDef *i2c = cfg->i2c;
@@ -85,7 +85,7 @@ static void stm32_i2c_reset(const struct device *dev)
 	/* disable i2c and disable IRQ's */
 	LL_I2C_Disable(i2c);
 #ifdef CONFIG_I2C_STM32_INTERRUPT
-	stm32_i2c_disable_transfer_interrupts(dev);
+	i2c_stm32_disable_transfer_interrupts(dev);
 #endif
 
 	/* save all important registers before reset */
@@ -119,14 +119,14 @@ static void stm32_i2c_reset(const struct device *dev)
 }
 
 
-static void stm32_i2c_master_finish(const struct device *dev)
+static void i2c_stm32_master_finish(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
 	I2C_TypeDef *i2c = cfg->i2c;
 
 #ifdef CONFIG_I2C_STM32_INTERRUPT
-	stm32_i2c_disable_transfer_interrupts(dev);
+	i2c_stm32_disable_transfer_interrupts(dev);
 #endif
 
 #if defined(CONFIG_I2C_TARGET)
@@ -134,7 +134,7 @@ static void stm32_i2c_master_finish(const struct device *dev)
 	if (!data->slave_attached && !data->smbalert_active) {
 		LL_I2C_Disable(i2c);
 	} else {
-		stm32_i2c_enable_transfer_interrupts(dev);
+		i2c_stm32_enable_transfer_interrupts(dev);
 		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
 	}
 #else
@@ -177,7 +177,7 @@ static inline void msg_init(const struct device *dev, struct i2c_msg *msg,
 	LL_I2C_DisableBitPOS(i2c);
 	LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
 	if (msg->flags & I2C_MSG_RESTART) {
-		stm32_i2c_generate_start_condition(i2c);
+		i2c_stm32_generate_start_condition(i2c);
 	}
 }
 
@@ -192,7 +192,7 @@ static int32_t msg_end(const struct device *dev, uint8_t *next_msg_flags,
 	}
 
 	if (!next_msg_flags) {
-		stm32_i2c_master_finish(dev);
+		i2c_stm32_master_finish(dev);
 	}
 
 	return 0;
@@ -214,14 +214,14 @@ static int32_t msg_end(const struct device *dev, uint8_t *next_msg_flags,
 			data->current.is_err);
 		data->current.is_err = 0U;
 	}
-	stm32_i2c_master_finish(dev);
+	i2c_stm32_master_finish(dev);
 
 	return -EIO;
 }
 
 #ifdef CONFIG_I2C_STM32_INTERRUPT
 
-static void stm32_i2c_master_mode_end(const struct device *dev)
+static void i2c_stm32_master_mode_end(const struct device *dev)
 {
 	struct i2c_stm32_data *data = dev->data;
 
@@ -272,7 +272,7 @@ static inline void handle_addr(const struct device *dev)
 		if (!data->current.is_write && data->current.is_restart) {
 			data->current.is_restart = 0U;
 			LL_I2C_ClearFlag_ADDR(i2c);
-			stm32_i2c_generate_start_condition(i2c);
+			i2c_stm32_generate_start_condition(i2c);
 
 			return;
 		}
@@ -435,7 +435,7 @@ static inline void handle_btf(const struct device *dev)
 
 
 #if defined(CONFIG_I2C_TARGET)
-static void stm32_i2c_slave_event(const struct device *dev)
+static void i2c_stm32_slave_event(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -481,7 +481,7 @@ static void stm32_i2c_slave_event(const struct device *dev)
 			LL_I2C_EnableIT_TX(i2c);
 		}
 
-		stm32_i2c_enable_transfer_interrupts(dev);
+		i2c_stm32_enable_transfer_interrupts(dev);
 	}
 }
 
@@ -526,7 +526,7 @@ int i2c_stm32_target_register(const struct device *dev, struct i2c_target_config
 
 	LOG_DBG("i2c: target registered");
 
-	stm32_i2c_enable_transfer_interrupts(dev);
+	i2c_stm32_enable_transfer_interrupts(dev);
 	LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
 
 	return 0;
@@ -546,7 +546,7 @@ int i2c_stm32_target_unregister(const struct device *dev, struct i2c_target_conf
 		return -EBUSY;
 	}
 
-	stm32_i2c_disable_transfer_interrupts(dev);
+	i2c_stm32_disable_transfer_interrupts(dev);
 
 	LL_I2C_ClearFlag_AF(i2c);
 	LL_I2C_ClearFlag_STOP(i2c);
@@ -564,16 +564,15 @@ int i2c_stm32_target_unregister(const struct device *dev, struct i2c_target_conf
 }
 #endif /* defined(CONFIG_I2C_TARGET) */
 
-void stm32_i2c_event_isr(void *arg)
+void i2c_stm32_event(const struct device *dev)
 {
-	const struct device *dev = (const struct device *)arg;
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
 	I2C_TypeDef *i2c = cfg->i2c;
 
 #if defined(CONFIG_I2C_TARGET)
 	if (data->slave_attached && !data->master_active) {
-		stm32_i2c_slave_event(dev);
+		i2c_stm32_slave_event(dev);
 		return;
 	}
 #endif
@@ -593,9 +592,8 @@ void stm32_i2c_event_isr(void *arg)
 	}
 }
 
-void stm32_i2c_error_isr(void *arg)
+int i2c_stm32_error(const struct device *dev)
 {
-	const struct device *dev = (const struct device *)arg;
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
 	I2C_TypeDef *i2c = cfg->i2c;
@@ -603,7 +601,7 @@ void stm32_i2c_error_isr(void *arg)
 #if defined(CONFIG_I2C_TARGET)
 	if (data->slave_attached && !data->master_active) {
 		/* No need for a slave error function right now. */
-		return;
+		return 0;
 	}
 #endif
 
@@ -634,32 +632,33 @@ void stm32_i2c_error_isr(void *arg)
 		goto end;
 	}
 #endif
-	return;
+	return 0;
 end:
-	stm32_i2c_master_mode_end(dev);
+	i2c_stm32_master_mode_end(dev);
+	return -EIO;
 }
 
-static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
-			    uint8_t *next_msg_flags, uint16_t saddr)
+static int32_t i2c_stm32_msg_write(const struct device *dev, struct i2c_msg *msg,
+				   uint8_t *next_msg_flags, uint16_t saddr)
 {
 	struct i2c_stm32_data *data = dev->data;
 
 	msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_WRITE);
 
-	stm32_i2c_enable_transfer_interrupts(dev);
+	i2c_stm32_enable_transfer_interrupts(dev);
 
 	if (k_sem_take(&data->device_sync_sem,
-			K_MSEC(STM32_I2C_TRANSFER_TIMEOUT_MSEC)) != 0) {
+			K_MSEC(I2C_STM32_TRANSFER_TIMEOUT_MSEC)) != 0) {
 		LOG_DBG("%s: WRITE timeout", __func__);
-		stm32_i2c_reset(dev);
+		i2c_stm32_reset(dev);
 		return -EIO;
 	}
 
 	return msg_end(dev, next_msg_flags, __func__);
 }
 
-static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
-			   uint8_t *next_msg_flags, uint16_t saddr)
+static int32_t i2c_stm32_msg_read(const struct device *dev, struct i2c_msg *msg,
+				  uint8_t *next_msg_flags, uint16_t saddr)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -667,13 +666,13 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 
 	msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_READ);
 
-	stm32_i2c_enable_transfer_interrupts(dev);
+	i2c_stm32_enable_transfer_interrupts(dev);
 	LL_I2C_EnableIT_RX(i2c);
 
 	if (k_sem_take(&data->device_sync_sem,
-			K_MSEC(STM32_I2C_TRANSFER_TIMEOUT_MSEC)) != 0) {
+			K_MSEC(I2C_STM32_TRANSFER_TIMEOUT_MSEC)) != 0) {
 		LOG_DBG("%s: READ timeout", __func__);
-		stm32_i2c_reset(dev);
+		i2c_stm32_reset(dev);
 		return -EIO;
 	}
 
@@ -721,7 +720,7 @@ static inline int check_errors(const struct device *dev, const char *funcname)
 	return -EIO;
 }
 
-static int stm32_i2c_wait_timeout(uint16_t *timeout)
+static int i2c_stm32_wait_timeout(uint16_t *timeout)
 {
 	if (*timeout == 0) {
 		return 1;
@@ -732,8 +731,8 @@ static int stm32_i2c_wait_timeout(uint16_t *timeout)
 	}
 }
 
-static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
-			    uint8_t *next_msg_flags, uint16_t saddr)
+static int32_t i2c_stm32_msg_write(const struct device *dev, struct i2c_msg *msg,
+				   uint8_t *next_msg_flags, uint16_t saddr)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -746,9 +745,9 @@ static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg
 	msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_WRITE);
 
 	if (msg->flags & I2C_MSG_RESTART) {
-		timeout = STM32_I2C_TIMEOUT_USEC;
+		timeout = I2C_STM32_TIMEOUT_USEC;
 		while (!LL_I2C_IsActiveFlag_SB(i2c)) {
-			if (stm32_i2c_wait_timeout(&timeout)) {
+			if (i2c_stm32_wait_timeout(&timeout)) {
 				LL_I2C_GenerateStopCondition(i2c);
 				data->current.is_err = 1U;
 				goto end;
@@ -760,9 +759,9 @@ static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg
 			uint8_t header = slave | HEADER;
 
 			LL_I2C_TransmitData8(i2c, header);
-			timeout = STM32_I2C_TIMEOUT_USEC;
+			timeout = I2C_STM32_TIMEOUT_USEC;
 			while (!LL_I2C_IsActiveFlag_ADD10(i2c)) {
-				if (stm32_i2c_wait_timeout(&timeout)) {
+				if (i2c_stm32_wait_timeout(&timeout)) {
 					LL_I2C_GenerateStopCondition(i2c);
 					data->current.is_err = 1U;
 					goto end;
@@ -777,9 +776,9 @@ static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg
 			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
 		}
 
-		timeout = STM32_I2C_TIMEOUT_USEC;
+		timeout = I2C_STM32_TIMEOUT_USEC;
 		while (!LL_I2C_IsActiveFlag_ADDR(i2c)) {
-			if (LL_I2C_IsActiveFlag_AF(i2c) || stm32_i2c_wait_timeout(&timeout)) {
+			if (LL_I2C_IsActiveFlag_AF(i2c) || i2c_stm32_wait_timeout(&timeout)) {
 				LL_I2C_ClearFlag_AF(i2c);
 				LL_I2C_GenerateStopCondition(i2c);
 				data->current.is_nack = 1U;
@@ -790,12 +789,12 @@ static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg
 	}
 
 	while (len) {
-		timeout = STM32_I2C_TIMEOUT_USEC;
+		timeout = I2C_STM32_TIMEOUT_USEC;
 		while (1) {
 			if (LL_I2C_IsActiveFlag_TXE(i2c)) {
 				break;
 			}
-			if (LL_I2C_IsActiveFlag_AF(i2c) || stm32_i2c_wait_timeout(&timeout)) {
+			if (LL_I2C_IsActiveFlag_AF(i2c) || i2c_stm32_wait_timeout(&timeout)) {
 				LL_I2C_ClearFlag_AF(i2c);
 				LL_I2C_GenerateStopCondition(i2c);
 				data->current.is_nack = 1U;
@@ -807,9 +806,9 @@ static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg
 		len--;
 	}
 
-	timeout = STM32_I2C_TIMEOUT_USEC;
+	timeout = I2C_STM32_TIMEOUT_USEC;
 	while (!LL_I2C_IsActiveFlag_BTF(i2c)) {
-		if (stm32_i2c_wait_timeout(&timeout)) {
+		if (i2c_stm32_wait_timeout(&timeout)) {
 			LL_I2C_GenerateStopCondition(i2c);
 			data->current.is_err = 1U;
 			goto end;
@@ -824,14 +823,14 @@ static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg
 	check_errors(dev, __func__);
 	res = msg_end(dev, next_msg_flags, __func__);
 	if (res < 0) {
-		stm32_i2c_reset(dev);
+		i2c_stm32_reset(dev);
 	}
 
 	return res;
 }
 
-static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
-			   uint8_t *next_msg_flags, uint16_t saddr)
+static int32_t i2c_stm32_msg_read(const struct device *dev, struct i2c_msg *msg,
+				  uint8_t *next_msg_flags, uint16_t saddr)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -844,9 +843,9 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 	msg_init(dev, msg, next_msg_flags, saddr, I2C_REQUEST_READ);
 
 	if (msg->flags & I2C_MSG_RESTART) {
-		timeout = STM32_I2C_TIMEOUT_USEC;
+		timeout = I2C_STM32_TIMEOUT_USEC;
 		while (!LL_I2C_IsActiveFlag_SB(i2c)) {
-			if (stm32_i2c_wait_timeout(&timeout)) {
+			if (i2c_stm32_wait_timeout(&timeout)) {
 				LL_I2C_GenerateStopCondition(i2c);
 				data->current.is_err = 1U;
 				goto end;
@@ -858,9 +857,9 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 			uint8_t header = slave | HEADER;
 
 			LL_I2C_TransmitData8(i2c, header);
-			timeout = STM32_I2C_TIMEOUT_USEC;
+			timeout = I2C_STM32_TIMEOUT_USEC;
 			while (!LL_I2C_IsActiveFlag_ADD10(i2c)) {
-				if (stm32_i2c_wait_timeout(&timeout)) {
+				if (i2c_stm32_wait_timeout(&timeout)) {
 					LL_I2C_GenerateStopCondition(i2c);
 					data->current.is_err = 1U;
 					goto end;
@@ -869,9 +868,9 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 
 			slave = saddr & 0xFF;
 			LL_I2C_TransmitData8(i2c, slave);
-			timeout = STM32_I2C_TIMEOUT_USEC;
+			timeout = I2C_STM32_TIMEOUT_USEC;
 			while (!LL_I2C_IsActiveFlag_ADDR(i2c)) {
-				if (stm32_i2c_wait_timeout(&timeout)) {
+				if (i2c_stm32_wait_timeout(&timeout)) {
 					LL_I2C_GenerateStopCondition(i2c);
 					data->current.is_err = 1U;
 					goto end;
@@ -879,10 +878,10 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 			}
 
 			LL_I2C_ClearFlag_ADDR(i2c);
-			stm32_i2c_generate_start_condition(i2c);
-			timeout = STM32_I2C_TIMEOUT_USEC;
+			i2c_stm32_generate_start_condition(i2c);
+			timeout = I2C_STM32_TIMEOUT_USEC;
 			while (!LL_I2C_IsActiveFlag_SB(i2c)) {
-				if (stm32_i2c_wait_timeout(&timeout)) {
+				if (i2c_stm32_wait_timeout(&timeout)) {
 					LL_I2C_GenerateStopCondition(i2c);
 					data->current.is_err = 1U;
 					goto end;
@@ -897,9 +896,9 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
 		}
 
-		timeout = STM32_I2C_TIMEOUT_USEC;
+		timeout = I2C_STM32_TIMEOUT_USEC;
 		while (!LL_I2C_IsActiveFlag_ADDR(i2c)) {
-			if (LL_I2C_IsActiveFlag_AF(i2c) || stm32_i2c_wait_timeout(&timeout)) {
+			if (LL_I2C_IsActiveFlag_AF(i2c) || i2c_stm32_wait_timeout(&timeout)) {
 				LL_I2C_ClearFlag_AF(i2c);
 				LL_I2C_GenerateStopCondition(i2c);
 				data->current.is_nack = 1U;
@@ -921,16 +920,16 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 	}
 
 	while (len) {
-		timeout = STM32_I2C_TIMEOUT_USEC;
+		timeout = I2C_STM32_TIMEOUT_USEC;
 		while (!LL_I2C_IsActiveFlag_RXNE(i2c)) {
-			if (stm32_i2c_wait_timeout(&timeout)) {
+			if (i2c_stm32_wait_timeout(&timeout)) {
 				LL_I2C_GenerateStopCondition(i2c);
 				data->current.is_err = 1U;
 				goto end;
 			}
 		}
 
-		timeout = STM32_I2C_TIMEOUT_USEC;
+		timeout = I2C_STM32_TIMEOUT_USEC;
 		switch (len) {
 		case 1:
 			if (msg->flags & I2C_MSG_STOP) {
@@ -942,7 +941,7 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 			break;
 		case 2:
 			while (!LL_I2C_IsActiveFlag_BTF(i2c)) {
-				if (stm32_i2c_wait_timeout(&timeout)) {
+				if (i2c_stm32_wait_timeout(&timeout)) {
 					LL_I2C_GenerateStopCondition(i2c);
 					data->current.is_err = 1U;
 					goto end;
@@ -966,7 +965,7 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 			break;
 		case 3:
 			while (!LL_I2C_IsActiveFlag_BTF(i2c)) {
-				if (stm32_i2c_wait_timeout(&timeout)) {
+				if (i2c_stm32_wait_timeout(&timeout)) {
 					LL_I2C_GenerateStopCondition(i2c);
 					data->current.is_err = 1U;
 					goto end;
@@ -986,14 +985,14 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 	check_errors(dev, __func__);
 	res = msg_end(dev, next_msg_flags, __func__);
 	if (res < 0) {
-		stm32_i2c_reset(dev);
+		i2c_stm32_reset(dev);
 	}
 
 	return res;
 }
 #endif /* CONFIG_I2C_STM32_INTERRUPT */
 
-int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -1013,16 +1012,16 @@ int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
 	return 0;
 }
 
-int stm32_i2c_transaction(const struct device *dev,
-						  struct i2c_msg msg, uint8_t *next_msg_flags,
-						  uint16_t periph)
+int i2c_stm32_transaction(const struct device *dev,
+			  struct i2c_msg msg, uint8_t *next_msg_flags,
+			  uint16_t periph)
 {
 	int ret;
 
 	if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
-		ret = stm32_i2c_msg_write(dev, &msg, next_msg_flags, periph);
+		ret = i2c_stm32_msg_write(dev, &msg, next_msg_flags, periph);
 	} else {
-		ret = stm32_i2c_msg_read(dev, &msg, next_msg_flags, periph);
+		ret = i2c_stm32_msg_read(dev, &msg, next_msg_flags, periph);
 	}
 	return ret;
 }
diff --git a/drivers/i2c/i2c_ll_stm32_v1_rtio.c b/drivers/i2c/i2c_ll_stm32_v1_rtio.c
new file mode 100644
index 0000000000000..7e8ef89039a18
--- /dev/null
+++ b/drivers/i2c/i2c_ll_stm32_v1_rtio.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if ((cr1 & I2C_CR1_STOP) != 0) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if ((data->xfer_len == 0) && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if ((data->xfer_flags & I2C_MSG_ADDR_10_BITS) != 0) {
+		slave = ((saddr & 0x0300) >> 7) & 0xFF;
+		slave |= HEADER;
+
+		if (data->is_restart == 0U) {
+			data->is_restart = 1U;
+		} else {
+			slave |= I2C_REQUEST_READ;
+			data->is_restart = 0U;
+		}
+		LL_I2C_TransmitData8(i2c, slave);
+	} else {
+		slave = (saddr << 1) & 0xFF;
+		if ((data->xfer_flags & I2C_MSG_READ) != 0) {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
+			if (data->xfer_len == 2) {
+				LL_I2C_EnableBitPOS(i2c);
+			}
+		} else {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
+		}
+	}
+}
+
+static void handle_addr(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if ((data->xfer_flags & I2C_MSG_ADDR_10_BITS) != 0) {
+		if (((data->xfer_flags & I2C_MSG_READ) != 0) && (data->is_restart != 0)) {
+			data->is_restart = 0U;
+			LL_I2C_ClearFlag_ADDR(i2c);
+			i2c_stm32_generate_start_condition(i2c);
+			return;
+		}
+	}
+
+	if ((data->xfer_flags & I2C_MSG_READ) == 0) {
+		LL_I2C_ClearFlag_ADDR(i2c);
+		return;
+	}
+	/* According to STM32F1 errata we need to handle these corner cases in
+	 * a specific way.
+	 * Please ref to STM32F10xxC/D/E I2C peripheral Errata sheet 2.14.1
+	 */
+	if ((data->xfer_len == 0U) && IS_ENABLED(CONFIG_SOC_SERIES_STM32F1X)) {
+		LL_I2C_GenerateStopCondition(i2c);
+	} else if (data->xfer_len == 1U) {
+		/* Single byte reception: enable NACK and clear POS */
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+#ifdef CONFIG_SOC_SERIES_STM32F1X
+		LL_I2C_ClearFlag_ADDR(i2c);
+		LL_I2C_GenerateStopCondition(i2c);
+#endif
+	} else if (data->xfer_len == 2U) {
+#ifdef CONFIG_SOC_SERIES_STM32F1X
+		LL_I2C_ClearFlag_ADDR(i2c);
+#endif
+		/* 2-byte reception: enable NACK and set POS */
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+		LL_I2C_EnableBitPOS(i2c);
+	}
+	LL_I2C_ClearFlag_ADDR(i2c);
+}
+
+static void handle_txe(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if (data->xfer_len != 0) {
+		data->xfer_len--;
+		if (data->xfer_len == 0U) {
+			/*
+			 * This is the last byte to transmit disable Buffer
+			 * interrupt and wait for a BTF interrupt
+			 */
+			LL_I2C_DisableIT_BUF(i2c);
+		}
+		LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		data->xfer_buf++;
+	} else {
+		if ((data->xfer_flags & I2C_MSG_STOP) != 0) {
+			LL_I2C_GenerateStopCondition(i2c);
+		}
+		if (LL_I2C_IsActiveFlag_BTF(i2c)) {
+			/* Read DR to clear BTF flag */
+			LL_I2C_ReceiveData8(i2c);
+		}
+		i2c_stm32_master_mode_end(dev);
+	}
+}
+
+static void handle_rxne(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	switch (data->xfer_len) {
+	case 0:
+		if ((data->xfer_flags & I2C_MSG_STOP) != 0) {
+			LL_I2C_GenerateStopCondition(i2c);
+		}
+		i2c_stm32_master_mode_end(dev);
+		break;
+	case 1:
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+		LL_I2C_DisableBitPOS(i2c);
+		/* Single byte reception */
+		if ((data->xfer_flags & I2C_MSG_STOP) != 0) {
+			LL_I2C_GenerateStopCondition(i2c);
+		}
+		LL_I2C_DisableIT_BUF(i2c);
+		data->xfer_len--;
+		*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		data->xfer_buf++;
+		i2c_stm32_master_mode_end(dev);
+		break;
+	case 2:
+		/*
+		 * 2-byte reception for N > 3 has already set the NACK
+		 * bit, and must not set the POS bit. See pg. 854 in
+		 * the F4 reference manual (RM0090).
+		 */
+		if (data->msg_len > 2) {
+			break;
+		}
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+		LL_I2C_EnableBitPOS(i2c);
+		__fallthrough;
+	case 3:
+		/*
+		 * 2-byte, 3-byte reception and for N-2, N-1,
+		 * N when N > 3
+		 */
+		LL_I2C_DisableIT_BUF(i2c);
+		break;
+	default:
+		/* N byte reception when N > 3 */
+		data->xfer_len--;
+		*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		data->xfer_buf++;
+	}
+}
+
+static void handle_btf(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if ((data->xfer_flags & I2C_MSG_READ) == 0) {
+		handle_txe(dev);
+	} else {
+		uint32_t counter = 0U;
+
+		switch (data->xfer_len) {
+		case 2:
+			/*
+			 * Stop condition must be generated before reading the
+			 * last two bytes.
+			 */
+			if (data->xfer_flags & I2C_MSG_STOP) {
+				LL_I2C_GenerateStopCondition(i2c);
+			}
+
+			for (counter = 2U; counter > 0; counter--) {
+				data->xfer_len--;
+				*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+				data->xfer_buf++;
+			}
+			i2c_stm32_master_mode_end(dev);
+			break;
+		case 3:
+			/* Set NACK before reading N-2 byte*/
+			LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+			data->xfer_len--;
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+			data->xfer_buf++;
+			break;
+		default:
+			handle_rxne(dev);
+		}
+	}
+}
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if (LL_I2C_IsActiveFlag_SB(i2c)) {
+		handle_sb(dev);
+	} else if (LL_I2C_IsActiveFlag_ADD10(i2c)) {
+		LL_I2C_TransmitData8(i2c, data->slave_address);
+	} else if (LL_I2C_IsActiveFlag_ADDR(i2c)) {
+		handle_addr(dev);
+	} else if (LL_I2C_IsActiveFlag_BTF(i2c)) {
+		handle_btf(dev);
+	} else if (LL_I2C_IsActiveFlag_TXE(i2c) && ((data->xfer_flags & I2C_MSG_READ) == 0)) {
+		handle_txe(dev);
+	} else if (LL_I2C_IsActiveFlag_RXNE(i2c) && ((data->xfer_flags & I2C_MSG_READ) != 0)) {
+		handle_rxne(dev);
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if (LL_I2C_IsActiveFlag_AF(i2c)) {
+		LL_I2C_ClearFlag_AF(i2c);
+		LL_I2C_GenerateStopCondition(i2c);
+		return -EIO;
+	}
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		return -EIO;
+	}
+
+	if (LL_I2C_IsActiveFlag_BERR(i2c)) {
+		LL_I2C_ClearFlag_BERR(i2c);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+			uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+	data->msg_len = buf_len;
+	data->is_restart = 0;
+	data->slave_address = i2c_addr;
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_DisableBitPOS(i2c);
+	LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
+	i2c_stm32_generate_start_condition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		LL_I2C_ConfigSpeed(i2c, clock, 100000, LL_I2C_DUTYCYCLE_2);
+		break;
+	case I2C_SPEED_FAST:
+		LL_I2C_ConfigSpeed(i2c, clock, 400000, LL_I2C_DUTYCYCLE_2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c
index 367d15cef2ad6..ee820272215e7 100644
--- a/drivers/i2c/i2c_ll_stm32_v2.c
+++ b/drivers/i2c/i2c_ll_stm32_v2.c
@@ -19,7 +19,6 @@
 #include <zephyr/drivers/i2c.h>
 #include <zephyr/pm/device.h>
 #include <zephyr/pm/device_runtime.h>
-#include "i2c_ll_stm32.h"
 
 #include <zephyr/cache.h>
 #include <zephyr/linker/linker-defs.h>
@@ -30,30 +29,31 @@
 #include <zephyr/logging/log.h>
 LOG_MODULE_REGISTER(i2c_ll_stm32_v2);
 
+#include "i2c_ll_stm32.h"
 #include "i2c-priv.h"
 
-#define STM32_I2C_TRANSFER_TIMEOUT_MSEC  500
+#define I2C_STM32_TRANSFER_TIMEOUT_MSEC  500
 
 #ifdef CONFIG_I2C_STM32_V2_TIMING
 /* Use the algorithm to calcuate the I2C timing */
-#ifndef STM32_I2C_VALID_TIMING_NBR
-#define STM32_I2C_VALID_TIMING_NBR                 128U
+#ifndef I2C_STM32_VALID_TIMING_NBR
+#define I2C_STM32_VALID_TIMING_NBR                 128U
 #endif
-#define STM32_I2C_SPEED_FREQ_STANDARD                0U    /* 100 kHz */
-#define STM32_I2C_SPEED_FREQ_FAST                    1U    /* 400 kHz */
-#define STM32_I2C_SPEED_FREQ_FAST_PLUS               2U    /* 1 MHz */
-#define STM32_I2C_ANALOG_FILTER_DELAY_MIN            50U   /* ns */
-#define STM32_I2C_ANALOG_FILTER_DELAY_MAX            260U  /* ns */
-#define STM32_I2C_USE_ANALOG_FILTER                  1U
-#define STM32_I2C_DIGITAL_FILTER_COEF                0U
-#define STM32_I2C_PRESC_MAX                          16U
-#define STM32_I2C_SCLDEL_MAX                         16U
-#define STM32_I2C_SDADEL_MAX                         16U
-#define STM32_I2C_SCLH_MAX                           256U
-#define STM32_I2C_SCLL_MAX                           256U
+#define I2C_STM32_SPEED_FREQ_STANDARD                0U    /* 100 kHz */
+#define I2C_STM32_SPEED_FREQ_FAST                    1U    /* 400 kHz */
+#define I2C_STM32_SPEED_FREQ_FAST_PLUS               2U    /* 1 MHz */
+#define I2C_STM32_ANALOG_FILTER_DELAY_MIN            50U   /* ns */
+#define I2C_STM32_ANALOG_FILTER_DELAY_MAX            260U  /* ns */
+#define I2C_STM32_USE_ANALOG_FILTER                  1U
+#define I2C_STM32_DIGITAL_FILTER_COEF                0U
+#define I2C_STM32_PRESC_MAX                          16U
+#define I2C_STM32_SCLDEL_MAX                         16U
+#define I2C_STM32_SDADEL_MAX                         16U
+#define I2C_STM32_SCLH_MAX                           256U
+#define I2C_STM32_SCLL_MAX                           256U
 
 /* I2C_DEVICE_Private_Types */
-struct stm32_i2c_charac_t {
+struct i2c_stm32_charac_t {
 	uint32_t freq;       /* Frequency in Hz */
 	uint32_t freq_min;   /* Minimum frequency in Hz */
 	uint32_t freq_max;   /* Maximum frequency in Hz */
@@ -67,7 +67,7 @@ struct stm32_i2c_charac_t {
 	uint32_t dnf;        /* Digital noise filter coefficient */
 };
 
-struct stm32_i2c_timings_t {
+struct i2c_stm32_timings_t {
 	uint32_t presc;      /* Timing prescaler */
 	uint32_t tscldel;    /* SCL delay */
 	uint32_t tsdadel;    /* SDA delay */
@@ -76,8 +76,8 @@ struct stm32_i2c_timings_t {
 };
 
 /* I2C_DEVICE Private Constants */
-static const struct stm32_i2c_charac_t stm32_i2c_charac[] = {
-	[STM32_I2C_SPEED_FREQ_STANDARD] = {
+static const struct i2c_stm32_charac_t i2c_stm32_charac[] = {
+	[I2C_STM32_SPEED_FREQ_STANDARD] = {
 		.freq = 100000,
 		.freq_min = 80000,
 		.freq_max = 120000,
@@ -88,9 +88,9 @@ static const struct stm32_i2c_charac_t stm32_i2c_charac[] = {
 		.hscl_min = 4000,
 		.trise = 640,
 		.tfall = 20,
-		.dnf = STM32_I2C_DIGITAL_FILTER_COEF,
+		.dnf = I2C_STM32_DIGITAL_FILTER_COEF,
 	},
-	[STM32_I2C_SPEED_FREQ_FAST] = {
+	[I2C_STM32_SPEED_FREQ_FAST] = {
 		.freq = 400000,
 		.freq_min = 320000,
 		.freq_max = 480000,
@@ -101,9 +101,9 @@ static const struct stm32_i2c_charac_t stm32_i2c_charac[] = {
 		.hscl_min = 600,
 		.trise = 250,
 		.tfall = 100,
-		.dnf = STM32_I2C_DIGITAL_FILTER_COEF,
+		.dnf = I2C_STM32_DIGITAL_FILTER_COEF,
 	},
-	[STM32_I2C_SPEED_FREQ_FAST_PLUS] = {
+	[I2C_STM32_SPEED_FREQ_FAST_PLUS] = {
 		.freq = 1000000,
 		.freq_min = 800000,
 		.freq_max = 1200000,
@@ -114,11 +114,11 @@ static const struct stm32_i2c_charac_t stm32_i2c_charac[] = {
 		.hscl_min = 260,
 		.trise = 60,
 		.tfall = 100,
-		.dnf = STM32_I2C_DIGITAL_FILTER_COEF,
+		.dnf = I2C_STM32_DIGITAL_FILTER_COEF,
 	},
 };
 
-static struct stm32_i2c_timings_t i2c_valid_timing[STM32_I2C_VALID_TIMING_NBR];
+static struct i2c_stm32_timings_t i2c_valid_timing[I2C_STM32_VALID_TIMING_NBR];
 static uint32_t i2c_valid_timing_nbr;
 #endif /* CONFIG_I2C_STM32_V2_TIMING */
 
@@ -238,7 +238,7 @@ static inline void msg_init(const struct device *dev, struct i2c_msg *msg,
 
 #ifdef CONFIG_I2C_STM32_INTERRUPT
 
-static void stm32_i2c_disable_transfer_interrupts(const struct device *dev)
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -255,7 +255,7 @@ static void stm32_i2c_disable_transfer_interrupts(const struct device *dev)
 	}
 }
 
-static void stm32_i2c_enable_transfer_interrupts(const struct device *dev)
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	I2C_TypeDef *i2c = cfg->i2c;
@@ -266,13 +266,13 @@ static void stm32_i2c_enable_transfer_interrupts(const struct device *dev)
 	LL_I2C_EnableIT_ERR(i2c);
 }
 
-static void stm32_i2c_master_mode_end(const struct device *dev)
+static void i2c_stm32_master_mode_end(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
 	I2C_TypeDef *i2c = cfg->i2c;
 
-	stm32_i2c_disable_transfer_interrupts(dev);
+	i2c_stm32_disable_transfer_interrupts(dev);
 
 	if (LL_I2C_IsEnabledReloadMode(i2c)) {
 		LL_I2C_DisableReloadMode(i2c);
@@ -303,7 +303,7 @@ static void stm32_i2c_master_mode_end(const struct device *dev)
 }
 
 #if defined(CONFIG_I2C_TARGET)
-static void stm32_i2c_slave_event(const struct device *dev)
+static void i2c_stm32_slave_event(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -366,7 +366,7 @@ static void stm32_i2c_slave_event(const struct device *dev)
 	}
 
 	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
-		stm32_i2c_disable_transfer_interrupts(dev);
+		i2c_stm32_disable_transfer_interrupts(dev);
 
 		/* Flush remaining TX byte before clearing Stop Flag */
 		LL_I2C_ClearFlag_TXE(i2c);
@@ -402,13 +402,13 @@ static void stm32_i2c_slave_event(const struct device *dev)
 			}
 		}
 
-		stm32_i2c_enable_transfer_interrupts(dev);
+		i2c_stm32_enable_transfer_interrupts(dev);
 	}
 }
 
 /* Attach and start I2C as target */
 int i2c_stm32_target_register(const struct device *dev,
-			     struct i2c_target_config *config)
+			      struct i2c_target_config *config)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -481,7 +481,7 @@ int i2c_stm32_target_register(const struct device *dev,
 }
 
 int i2c_stm32_target_unregister(const struct device *dev,
-			       struct i2c_target_config *config)
+				struct i2c_target_config *config)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -517,7 +517,7 @@ int i2c_stm32_target_unregister(const struct device *dev,
 
 	/* Otherwise disable I2C */
 	LL_I2C_DisableIT_ADDR(i2c);
-	stm32_i2c_disable_transfer_interrupts(dev);
+	i2c_stm32_disable_transfer_interrupts(dev);
 
 	LL_I2C_ClearFlag_NACK(i2c);
 	LL_I2C_ClearFlag_STOP(i2c);
@@ -544,7 +544,7 @@ int i2c_stm32_target_unregister(const struct device *dev,
 
 #endif /* defined(CONFIG_I2C_TARGET) */
 
-static void stm32_i2c_event(const struct device *dev)
+void i2c_stm32_event(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -552,7 +552,7 @@ static void stm32_i2c_event(const struct device *dev)
 
 #if defined(CONFIG_I2C_TARGET)
 	if (data->slave_attached && !data->master_active) {
-		stm32_i2c_slave_event(dev);
+		i2c_stm32_slave_event(dev);
 		return;
 	}
 #endif
@@ -597,7 +597,7 @@ static void stm32_i2c_event(const struct device *dev)
 		if (data->current.msg->flags & I2C_MSG_STOP) {
 			LL_I2C_GenerateStopCondition(i2c);
 		} else {
-			stm32_i2c_disable_transfer_interrupts(dev);
+			i2c_stm32_disable_transfer_interrupts(dev);
 
 #ifdef CONFIG_I2C_STM32_V2_DMA
 			if (data->current.msg->flags & I2C_MSG_READ) {
@@ -615,10 +615,10 @@ static void stm32_i2c_event(const struct device *dev)
 
 	return;
 end:
-	stm32_i2c_master_mode_end(dev);
+	i2c_stm32_master_mode_end(dev);
 }
 
-static int stm32_i2c_error(const struct device *dev)
+int i2c_stm32_error(const struct device *dev)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -655,37 +655,10 @@ static int stm32_i2c_error(const struct device *dev)
 
 	return 0;
 end:
-	stm32_i2c_master_mode_end(dev);
+	i2c_stm32_master_mode_end(dev);
 	return -EIO;
 }
 
-#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT
-void stm32_i2c_combined_isr(void *arg)
-{
-	const struct device *dev = (const struct device *) arg;
-
-	if (stm32_i2c_error(dev)) {
-		return;
-	}
-	stm32_i2c_event(dev);
-}
-#else
-
-void stm32_i2c_event_isr(void *arg)
-{
-	const struct device *dev = (const struct device *) arg;
-
-	stm32_i2c_event(dev);
-}
-
-void stm32_i2c_error_isr(void *arg)
-{
-	const struct device *dev = (const struct device *) arg;
-
-	stm32_i2c_error(dev);
-}
-#endif
-
 #if defined(CONFIG_DCACHE) && defined(CONFIG_I2C_STM32_V2_DMA)
 static bool buf_in_nocache(uintptr_t buf, size_t len_bytes)
 {
@@ -717,8 +690,8 @@ static bool buf_in_nocache(uintptr_t buf, size_t len_bytes)
 }
 #endif /* CONFIG_DCACHE && CONFIG_I2C_STM32_V2_DMA */
 
-static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
-			uint8_t *next_msg_flags, uint16_t slave)
+static int i2c_stm32_msg_write(const struct device *dev, struct i2c_msg *msg,
+			       uint8_t *next_msg_flags, uint16_t slave)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -742,12 +715,12 @@ static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
 
 	msg_init(dev, msg, next_msg_flags, slave, LL_I2C_REQUEST_WRITE);
 
-	stm32_i2c_enable_transfer_interrupts(dev);
+	i2c_stm32_enable_transfer_interrupts(dev);
 	LL_I2C_EnableIT_TX(i2c);
 
 	if (k_sem_take(&data->device_sync_sem,
-		       K_MSEC(STM32_I2C_TRANSFER_TIMEOUT_MSEC)) != 0) {
-		stm32_i2c_master_mode_end(dev);
+		       K_MSEC(I2C_STM32_TRANSFER_TIMEOUT_MSEC)) != 0) {
+		i2c_stm32_master_mode_end(dev);
 		k_sem_take(&data->device_sync_sem, K_FOREVER);
 		is_timeout = true;
 	}
@@ -783,8 +756,8 @@ static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
 	return -EIO;
 }
 
-static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
-		       uint8_t *next_msg_flags, uint16_t slave)
+static int i2c_stm32_msg_read(const struct device *dev, struct i2c_msg *msg,
+			      uint8_t *next_msg_flags, uint16_t slave)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -801,12 +774,12 @@ static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 
 	msg_init(dev, msg, next_msg_flags, slave, LL_I2C_REQUEST_READ);
 
-	stm32_i2c_enable_transfer_interrupts(dev);
+	i2c_stm32_enable_transfer_interrupts(dev);
 	LL_I2C_EnableIT_RX(i2c);
 
 	if (k_sem_take(&data->device_sync_sem,
-		       K_MSEC(STM32_I2C_TRANSFER_TIMEOUT_MSEC)) != 0) {
-		stm32_i2c_master_mode_end(dev);
+		       K_MSEC(I2C_STM32_TRANSFER_TIMEOUT_MSEC)) != 0) {
+		i2c_stm32_master_mode_end(dev);
 		k_sem_take(&data->device_sync_sem, K_FOREVER);
 		is_timeout = true;
 	}
@@ -913,8 +886,8 @@ static inline int msg_done(const struct device *dev,
 	return 0;
 }
 
-static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
-			uint8_t *next_msg_flags, uint16_t slave)
+static int i2c_stm32_msg_write(const struct device *dev, struct i2c_msg *msg,
+			       uint8_t *next_msg_flags, uint16_t slave)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	I2C_TypeDef *i2c = cfg->i2c;
@@ -943,8 +916,8 @@ static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
 	return msg_done(dev, msg->flags);
 }
 
-static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
-		       uint8_t *next_msg_flags, uint16_t slave)
+static int i2c_stm32_msg_read(const struct device *dev, struct i2c_msg *msg,
+			      uint8_t *next_msg_flags, uint16_t slave)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	I2C_TypeDef *i2c = cfg->i2c;
@@ -979,7 +952,7 @@ static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
 #define I2C_LOOP_SCLH();						\
 	if ((tscl >= clk_min) &&					\
 		(tscl <= clk_max) &&					\
-		(tscl_h >= stm32_i2c_charac[i2c_speed].hscl_min) &&	\
+		(tscl_h >= i2c_stm32_charac[i2c_speed].hscl_min) &&	\
 		(ti2cclk < tscl_h)) {					\
 									\
 		int32_t error = (int32_t)tscl - (int32_t)ti2cspeed;	\
@@ -1014,26 +987,26 @@ uint32_t i2c_compute_scll_sclh(uint32_t clock_src_freq, uint32_t i2c_speed)
 	uint32_t tafdel_min;
 
 	ti2cclk = (NSEC_PER_SEC + (clock_src_freq / 2U)) / clock_src_freq;
-	ti2cspeed = (NSEC_PER_SEC + (stm32_i2c_charac[i2c_speed].freq / 2U)) /
-		stm32_i2c_charac[i2c_speed].freq;
+	ti2cspeed = (NSEC_PER_SEC + (i2c_stm32_charac[i2c_speed].freq / 2U)) /
+		i2c_stm32_charac[i2c_speed].freq;
 
-	tafdel_min = (STM32_I2C_USE_ANALOG_FILTER == 1U) ?
-		STM32_I2C_ANALOG_FILTER_DELAY_MIN :
+	tafdel_min = (I2C_STM32_USE_ANALOG_FILTER == 1U) ?
+		I2C_STM32_ANALOG_FILTER_DELAY_MIN :
 		0U;
 
 	/* tDNF = DNF x tI2CCLK */
-	dnf_delay = stm32_i2c_charac[i2c_speed].dnf * ti2cclk;
+	dnf_delay = i2c_stm32_charac[i2c_speed].dnf * ti2cclk;
 
-	clk_max = NSEC_PER_SEC / stm32_i2c_charac[i2c_speed].freq_min;
-	clk_min = NSEC_PER_SEC / stm32_i2c_charac[i2c_speed].freq_max;
+	clk_max = NSEC_PER_SEC / i2c_stm32_charac[i2c_speed].freq_min;
+	clk_min = NSEC_PER_SEC / i2c_stm32_charac[i2c_speed].freq_max;
 
 	prev_error = ti2cspeed;
 
-	for (uint32_t count = 0; count < STM32_I2C_VALID_TIMING_NBR; count++) {
+	for (uint32_t count = 0; count < I2C_STM32_VALID_TIMING_NBR; count++) {
 		/* tPRESC = (PRESC+1) x tI2CCLK*/
 		uint32_t tpresc = (i2c_valid_timing[count].presc + 1U) * ti2cclk;
 
-		for (scll = 0; scll < STM32_I2C_SCLL_MAX; scll++) {
+		for (scll = 0; scll < I2C_STM32_SCLL_MAX; scll++) {
 			/* tLOW(min) <= tAF(min) + tDNF + 2 x tI2CCLK + [(SCLL+1) x tPRESC ] */
 			uint32_t tscl_l = tafdel_min + dnf_delay +
 				(2U * ti2cclk) + ((scll + 1U) * tpresc);
@@ -1042,9 +1015,9 @@ uint32_t i2c_compute_scll_sclh(uint32_t clock_src_freq, uint32_t i2c_speed)
 			 * The I2CCLK period tI2CCLK must respect the following conditions:
 			 * tI2CCLK < (tLOW - tfilters) / 4 and tI2CCLK < tHIGH
 			 */
-			if ((tscl_l > stm32_i2c_charac[i2c_speed].lscl_min) &&
+			if ((tscl_l > i2c_stm32_charac[i2c_speed].lscl_min) &&
 				(ti2cclk < ((tscl_l - tafdel_min - dnf_delay) / 4U))) {
-				for (sclh = 0; sclh < STM32_I2C_SCLH_MAX; sclh++) {
+				for (sclh = 0; sclh < I2C_STM32_SCLH_MAX; sclh++) {
 					/*
 					 * tHIGH(min) <= tAF(min) + tDNF +
 					 * 2 x tI2CCLK + [(SCLH+1) x tPRESC]
@@ -1054,8 +1027,8 @@ uint32_t i2c_compute_scll_sclh(uint32_t clock_src_freq, uint32_t i2c_speed)
 
 					/* tSCL = tf + tLOW + tr + tHIGH */
 					uint32_t tscl = tscl_l +
-						tscl_h + stm32_i2c_charac[i2c_speed].trise +
-					stm32_i2c_charac[i2c_speed].tfall;
+						tscl_h + i2c_stm32_charac[i2c_speed].trise +
+					i2c_stm32_charac[i2c_speed].tfall;
 
 					/* get timings with the lowest clock error */
 					I2C_LOOP_SCLH();
@@ -1083,7 +1056,7 @@ uint32_t i2c_compute_scll_sclh(uint32_t clock_src_freq, uint32_t i2c_speed)
 			prev_presc = presc;						\
 			i2c_valid_timing_nbr++;						\
 											\
-			if (i2c_valid_timing_nbr >= STM32_I2C_VALID_TIMING_NBR) {	\
+			if (i2c_valid_timing_nbr >= I2C_STM32_VALID_TIMING_NBR) {	\
 				break;							\
 			}								\
 		}									\
@@ -1097,7 +1070,7 @@ uint32_t i2c_compute_scll_sclh(uint32_t clock_src_freq, uint32_t i2c_speed)
  */
 void i2c_compute_presc_scldel_sdadel(uint32_t clock_src_freq, uint32_t i2c_speed)
 {
-	uint32_t prev_presc = STM32_I2C_PRESC_MAX;
+	uint32_t prev_presc = I2C_STM32_PRESC_MAX;
 	uint32_t ti2cclk;
 	int32_t  tsdadel_min, tsdadel_max;
 	int32_t  tscldel_min;
@@ -1106,31 +1079,31 @@ void i2c_compute_presc_scldel_sdadel(uint32_t clock_src_freq, uint32_t i2c_speed
 
 	ti2cclk   = (NSEC_PER_SEC + (clock_src_freq / 2U)) / clock_src_freq;
 
-	tafdel_min = (STM32_I2C_USE_ANALOG_FILTER == 1U) ?
-		STM32_I2C_ANALOG_FILTER_DELAY_MIN : 0U;
-	tafdel_max = (STM32_I2C_USE_ANALOG_FILTER == 1U) ?
-		STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0U;
+	tafdel_min = (I2C_STM32_USE_ANALOG_FILTER == 1U) ?
+		I2C_STM32_ANALOG_FILTER_DELAY_MIN : 0U;
+	tafdel_max = (I2C_STM32_USE_ANALOG_FILTER == 1U) ?
+		I2C_STM32_ANALOG_FILTER_DELAY_MAX : 0U;
 	/*
 	 * tDNF = DNF x tI2CCLK
 	 * tPRESC = (PRESC+1) x tI2CCLK
 	 * SDADEL >= {tf +tHD;DAT(min) - tAF(min) - tDNF - [3 x tI2CCLK]} / {tPRESC}
 	 * SDADEL <= {tVD;DAT(max) - tr - tAF(max) - tDNF- [4 x tI2CCLK]} / {tPRESC}
 	 */
-	tsdadel_min = (int32_t)stm32_i2c_charac[i2c_speed].tfall +
-		(int32_t)stm32_i2c_charac[i2c_speed].hddat_min -
+	tsdadel_min = (int32_t)i2c_stm32_charac[i2c_speed].tfall +
+		(int32_t)i2c_stm32_charac[i2c_speed].hddat_min -
 		(int32_t)tafdel_min -
-		(int32_t)(((int32_t)stm32_i2c_charac[i2c_speed].dnf + 3) *
+		(int32_t)(((int32_t)i2c_stm32_charac[i2c_speed].dnf + 3) *
 		(int32_t)ti2cclk);
 
-	tsdadel_max = (int32_t)stm32_i2c_charac[i2c_speed].vddat_max -
-		(int32_t)stm32_i2c_charac[i2c_speed].trise -
+	tsdadel_max = (int32_t)i2c_stm32_charac[i2c_speed].vddat_max -
+		(int32_t)i2c_stm32_charac[i2c_speed].trise -
 		(int32_t)tafdel_max -
-		(int32_t)(((int32_t)stm32_i2c_charac[i2c_speed].dnf + 4) *
+		(int32_t)(((int32_t)i2c_stm32_charac[i2c_speed].dnf + 4) *
 		(int32_t)ti2cclk);
 
 	/* {[tr+ tSU;DAT(min)] / [tPRESC]} - 1 <= SCLDEL */
-	tscldel_min = (int32_t)stm32_i2c_charac[i2c_speed].trise +
-		(int32_t)stm32_i2c_charac[i2c_speed].sudat_min;
+	tscldel_min = (int32_t)i2c_stm32_charac[i2c_speed].trise +
+		(int32_t)i2c_stm32_charac[i2c_speed].sudat_min;
 
 	if (tsdadel_min <= 0) {
 		tsdadel_min = 0;
@@ -1140,20 +1113,20 @@ void i2c_compute_presc_scldel_sdadel(uint32_t clock_src_freq, uint32_t i2c_speed
 		tsdadel_max = 0;
 	}
 
-	for (presc = 0; presc < STM32_I2C_PRESC_MAX; presc++) {
-		for (scldel = 0; scldel < STM32_I2C_SCLDEL_MAX; scldel++) {
+	for (presc = 0; presc < I2C_STM32_PRESC_MAX; presc++) {
+		for (scldel = 0; scldel < I2C_STM32_SCLDEL_MAX; scldel++) {
 			/* TSCLDEL = (SCLDEL+1) * (PRESC+1) * TI2CCLK */
 			uint32_t tscldel = (scldel + 1U) * (presc + 1U) * ti2cclk;
 
 			if (tscldel >= (uint32_t)tscldel_min) {
-				for (sdadel = 0; sdadel < STM32_I2C_SDADEL_MAX; sdadel++) {
+				for (sdadel = 0; sdadel < I2C_STM32_SDADEL_MAX; sdadel++) {
 					/* TSDADEL = SDADEL * (PRESC+1) * TI2CCLK */
 					uint32_t tsdadel = (sdadel * (presc + 1U)) * ti2cclk;
 
 					I2C_LOOP_SDADEL();
 				}
 
-				if (i2c_valid_timing_nbr >= STM32_I2C_VALID_TIMING_NBR) {
+				if (i2c_valid_timing_nbr >= I2C_STM32_VALID_TIMING_NBR) {
 					return;
 				}
 			}
@@ -1161,7 +1134,7 @@ void i2c_compute_presc_scldel_sdadel(uint32_t clock_src_freq, uint32_t i2c_speed
 	}
 }
 
-int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -1175,12 +1148,12 @@ int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
 	i2c_valid_timing_nbr = 0;
 
 	if ((clock != 0U) && (i2c_freq != 0U)) {
-		for (speed = 0 ; speed <= (uint32_t)STM32_I2C_SPEED_FREQ_FAST_PLUS ; speed++) {
-			if ((i2c_freq >= stm32_i2c_charac[speed].freq_min) &&
-				(i2c_freq <= stm32_i2c_charac[speed].freq_max)) {
+		for (speed = 0 ; speed <= (uint32_t)I2C_STM32_SPEED_FREQ_FAST_PLUS ; speed++) {
+			if ((i2c_freq >= i2c_stm32_charac[speed].freq_min) &&
+				(i2c_freq <= i2c_stm32_charac[speed].freq_max)) {
 				i2c_compute_presc_scldel_sdadel(clock, speed);
 				idx = i2c_compute_scll_sclh(clock, speed);
-				if (idx < STM32_I2C_VALID_TIMING_NBR) {
+				if (idx < I2C_STM32_VALID_TIMING_NBR) {
 					timing = ((i2c_valid_timing[idx].presc  &
 						0x0FU) << 28) |
 					((i2c_valid_timing[idx].tscldel & 0x0FU) << 20) |
@@ -1204,7 +1177,7 @@ int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
 }
 #else/* CONFIG_I2C_STM32_V2_TIMING */
 
-int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
 {
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
@@ -1243,7 +1216,7 @@ int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
 		break;
 	default:
 		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
-				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+			"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
 		return -EINVAL;
 	}
 
@@ -1283,9 +1256,9 @@ int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
 }
 #endif /* CONFIG_I2C_STM32_V2_TIMING */
 
-int stm32_i2c_transaction(const struct device *dev,
-						  struct i2c_msg msg, uint8_t *next_msg_flags,
-						  uint16_t periph)
+int i2c_stm32_transaction(const struct device *dev,
+			  struct i2c_msg msg, uint8_t *next_msg_flags,
+			  uint16_t periph)
 {
 	/*
 	 * Perform a I2C transaction, while taking into account the STM32 I2C V2
@@ -1317,9 +1290,9 @@ int stm32_i2c_transaction(const struct device *dev,
 			flagsp = next_msg_flags;
 		}
 		if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
-			ret = stm32_i2c_msg_write(dev, &msg, flagsp, periph);
+			ret = i2c_stm32_msg_write(dev, &msg, flagsp, periph);
 		} else {
-			ret = stm32_i2c_msg_read(dev, &msg, flagsp, periph);
+			ret = i2c_stm32_msg_read(dev, &msg, flagsp, periph);
 		}
 		if (ret < 0) {
 			break;
diff --git a/drivers/i2c/i2c_ll_stm32_v2_rtio.c b/drivers/i2c/i2c_ll_stm32_v2_rtio.c
new file mode 100644
index 0000000000000..c0f5697f9c31c
--- /dev/null
+++ b/drivers/i2c/i2c_ll_stm32_v2_rtio.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v2_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len != 0) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if ((data->xfer_flags & I2C_MSG_STOP) != 0) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if ((data->xfer_len == 0) && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if ((flags & I2C_MSG_READ) != 0) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if ((I2C_MSG_ADDR_10_BITS & flags) != 0) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if ((flags & I2C_MSG_READ) != 0) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}


Reviews:
user: login: teburd
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T15:21:38Z
user: login: erwango
body: Mainly questions about code duplication.
Also, what's the plan versus DMA support, should it be kept excluded from RTIO right now ?
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-04T12:27:50Z
user: login: teburd
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T13:08:28Z
user: login: etienne-lms
body: some minor comments.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T13:17:09Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:19:46Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:19:57Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:22:44Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:22:53Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:23:13Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:23:33Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:23:56Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:26:02Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T07:29:19Z
user: login: etienne-lms
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T09:52:20Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:03:48Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:03:53Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:03:58Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:04:03Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:04:11Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:04:18Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:04:23Z
user: login: gautierg-st
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T13:04:54Z
user: login: teburd
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T15:00:14Z
user: login: ubieda
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-22T15:05:56Z

Review comments:
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
+
+	bitrate_cfg = i2c_map_dt_bitrate(cfg->bitrate);
+
+	ret = i2c_stm32_do_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
+	if (ret < 0) {
+		LOG_ERR("i2c: failure initializing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	(void)pm_device_runtime_enable(dev);
+#endif
+
+	return 0;
+}
+
+#define STM32_I2C_INIT(index)									\
+STM32_I2C_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: erwango
body: Not required
created_at: 2025-04-04T11:54:48Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
+
+	bitrate_cfg = i2c_map_dt_bitrate(cfg->bitrate);
+
+	ret = i2c_stm32_do_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
+	if (ret < 0) {
+		LOG_ERR("i2c: failure initializing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	(void)pm_device_runtime_enable(dev);
+#endif
+
+	return 0;
+}
+
+#define STM32_I2C_INIT(index)									\
+STM32_I2C_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
+	(static const uint32_t i2c_timings_##index[] =						\
+		DT_INST_PROP_OR(index, timings, {});))						\
+												\
+PINCTRL_DT_INST_DEFINE(index);									\
+												\
+static const struct stm32_pclken pclken_##index[] =						\
+				 STM32_DT_INST_CLOCKS(index);					\
+												\
+static const struct i2c_stm32_config i2c_stm32_cfg_##index = {					\
+	.i2c = (I2C_TypeDef *)DT_INST_REG_ADDR(index),						\
+	.pclken = pclken_##index,								\
+	.pclk_len = DT_INST_NUM_CLOCKS(index),							\
+	STM32_I2C_IRQ_HANDLER_FUNCTION(index)							\
+	.bitrate = DT_INST_PROP(index, clock_frequency),					\
+	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),						\
+	IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY,						\
+		(.scl =	GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),			\
+		 .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))			\
+	IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),					\
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: erwango
body: Not required if kept separate
created_at: 2025-04-04T11:54:56Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
+
+	bitrate_cfg = i2c_map_dt_bitrate(cfg->bitrate);
+
+	ret = i2c_stm32_do_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
+	if (ret < 0) {
+		LOG_ERR("i2c: failure initializing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	(void)pm_device_runtime_enable(dev);
+#endif
+
+	return 0;
+}
+
+#define STM32_I2C_INIT(index)									\
+STM32_I2C_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
+	(static const uint32_t i2c_timings_##index[] =						\
+		DT_INST_PROP_OR(index, timings, {});))						\
+												\
+PINCTRL_DT_INST_DEFINE(index);									\
+												\
+static const struct stm32_pclken pclken_##index[] =						\
+				 STM32_DT_INST_CLOCKS(index);					\
+												\
+static const struct i2c_stm32_config i2c_stm32_cfg_##index = {					\
+	.i2c = (I2C_TypeDef *)DT_INST_REG_ADDR(index),						\
+	.pclken = pclken_##index,								\
+	.pclk_len = DT_INST_NUM_CLOCKS(index),							\
+	STM32_I2C_IRQ_HANDLER_FUNCTION(index)							\
+	.bitrate = DT_INST_PROP(index, clock_frequency),					\
+	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),						\
+	IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY,						\
+		(.scl =	GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),			\
+		 .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))			\
+	IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),					\
+		(.timings = (const struct i2c_config_timing *) i2c_timings_##index,		\
+		 .n_timings = ARRAY_SIZE(i2c_timings_##index),))				\
+};												\
+												\
+I2C_RTIO_DEFINE(CONCAT(_i2c, index, _stm32_rtio),						\
+	DT_INST_PROP_OR(index, sq_size, CONFIG_I2C_RTIO_SQ_SIZE),				\
+	DT_INST_PROP_OR(index, cq_size, CONFIG_I2C_RTIO_CQ_SIZE));				\
+												\
+static struct i2c_stm32_data_rtio i2c_stm32_dev_data_##index = {				\
+	.ctx = &CONCAT(_i2c, index, _stm32_rtio),						\
+};												\
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: erwango
body: Question: IIUC we're duplicating the whole `STM32_I2C_INIT` because of this part.
Can't those RTIO specific bits be put with `IF_ENABLED(CONFIG_I2C_RTIO` primitive and kept factorized (in common.c file for instance)?

created_at: 2025-04-04T11:58:55Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: erwango
body: `CONFIG_SOC_SERIES_STM32F1X` is v1, could be purely removed from this file.
created_at: 2025-04-04T11:59:38Z
author_association: MEMBER
diff_hunk: @@ -593,9 +592,8 @@ void stm32_i2c_event_isr(void *arg)
 	}
 }
 
-void stm32_i2c_error_isr(void *arg)
+int i2c_stm32_error(const struct device *dev)
 {
-	const struct device *dev = (const struct device *)arg;
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
 	I2C_TypeDef *i2c = cfg->i2c;
path: drivers/i2c/i2c_ll_stm32_v1.c
user: login: etienne-lms
body: Add a return value (`0`?) at line 604.
created_at: 2025-04-09T11:56:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -540,50 +465,6 @@ void i2c_stm32_smbalert_disable(const struct device *dev)
 
 /* Macros for I2C instance declaration */
 
-#ifdef CONFIG_I2C_STM32_INTERRUPT
-
-#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT
-#define STM32_I2C_IRQ_CONNECT_AND_ENABLE(index)				\
-	do {								\
-		IRQ_CONNECT(DT_INST_IRQN(index),			\
-			    DT_INST_IRQ(index, priority),		\
-			    stm32_i2c_combined_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQN(index));			\
-	} while (false)
-#else
-#define STM32_I2C_IRQ_CONNECT_AND_ENABLE(index)				\
-	do {								\
-		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, event, irq),	\
-			    DT_INST_IRQ_BY_NAME(index, event, priority),\
-			    stm32_i2c_event_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQ_BY_NAME(index, event, irq));	\
-									\
-		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, error, irq),	\
-			    DT_INST_IRQ_BY_NAME(index, error, priority),\
-			    stm32_i2c_error_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQ_BY_NAME(index, error, irq));	\
-	} while (false)
-#endif /* CONFIG_I2C_STM32_COMBINED_INTERRUPT */
-
-#define STM32_I2C_IRQ_HANDLER_DECL(index)				\
-static void i2c_stm32_irq_config_func_##index(const struct device *dev)
-#define STM32_I2C_IRQ_HANDLER_FUNCTION(index)				\
-	.irq_config_func = i2c_stm32_irq_config_func_##index,
-#define STM32_I2C_IRQ_HANDLER(index)					\
-static void i2c_stm32_irq_config_func_##index(const struct device *dev)	\
-{									\
-	STM32_I2C_IRQ_CONNECT_AND_ENABLE(index);			\
-}
-#else
-
-#define STM32_I2C_IRQ_HANDLER_DECL(index)
-#define STM32_I2C_IRQ_HANDLER_FUNCTION(index)
-#define STM32_I2C_IRQ_HANDLER(index)
path: drivers/i2c/i2c_ll_stm32.c
user: login: etienne-lms
body: When `CONFIG_I2C_STM32_INTERRUPT` is disabled, **i2c_ll_stm32.c** requires stubbed `STM32_I2C_IRQ_HANDLE*()` macros. This is case sill to be considered (from **i2c_ll_stm32.h**)? I think it is still possible to disable `CONFIG_I2C_STM32_INTERRUPT` from menuconfig, even if quite unlikely used.
created_at: 2025-04-30T13:08:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: etienne-lms
body: Nitpicking: maybe group all the zephyr header files together.
created_at: 2025-04-30T13:11:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: etienne-lms
body: can remove one of the empty lines.
ditto at line 76, 365, 384, and 411.
created_at: 2025-04-30T13:11:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v1
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+	uint8_t msg_len;
+	uint8_t is_restart;
+	uint16_t slave_address;
+};
+
+static bool i2c_stm32_start(const struct device *dev);
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static inline void handle_sb(const struct device *dev)
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: etienne-lms
body: Is the `inline` directive really useful?
created_at: 2025-04-30T13:15:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
+
+	bitrate_cfg = i2c_map_dt_bitrate(cfg->bitrate);
+
+	ret = i2c_stm32_do_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
+	if (ret < 0) {
+		LOG_ERR("i2c: failure initializing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	(void)pm_device_runtime_enable(dev);
+#endif
+
+	return 0;
+}
+
+#define STM32_I2C_INIT(index)									\
+STM32_I2C_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: gautierg-st
body: Moved to common RTIO file
created_at: 2025-05-22T07:19:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
+
+	bitrate_cfg = i2c_map_dt_bitrate(cfg->bitrate);
+
+	ret = i2c_stm32_do_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
+	if (ret < 0) {
+		LOG_ERR("i2c: failure initializing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	(void)pm_device_runtime_enable(dev);
+#endif
+
+	return 0;
+}
+
+#define STM32_I2C_INIT(index)									\
+STM32_I2C_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
+	(static const uint32_t i2c_timings_##index[] =						\
+		DT_INST_PROP_OR(index, timings, {});))						\
+												\
+PINCTRL_DT_INST_DEFINE(index);									\
+												\
+static const struct stm32_pclken pclken_##index[] =						\
+				 STM32_DT_INST_CLOCKS(index);					\
+												\
+static const struct i2c_stm32_config i2c_stm32_cfg_##index = {					\
+	.i2c = (I2C_TypeDef *)DT_INST_REG_ADDR(index),						\
+	.pclken = pclken_##index,								\
+	.pclk_len = DT_INST_NUM_CLOCKS(index),							\
+	STM32_I2C_IRQ_HANDLER_FUNCTION(index)							\
+	.bitrate = DT_INST_PROP(index, clock_frequency),					\
+	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),						\
+	IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY,						\
+		(.scl =	GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),			\
+		 .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))			\
+	IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),					\
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: gautierg-st
body: Moved to common RTIO file
created_at: 2025-05-22T07:19:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
+
+	bitrate_cfg = i2c_map_dt_bitrate(cfg->bitrate);
+
+	ret = i2c_stm32_do_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
+	if (ret < 0) {
+		LOG_ERR("i2c: failure initializing");
+		return ret;
+	}
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	(void)pm_device_runtime_enable(dev);
+#endif
+
+	return 0;
+}
+
+#define STM32_I2C_INIT(index)									\
+STM32_I2C_IRQ_HANDLER_DECL(index);								\
+												\
+IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),						\
+	(static const uint32_t i2c_timings_##index[] =						\
+		DT_INST_PROP_OR(index, timings, {});))						\
+												\
+PINCTRL_DT_INST_DEFINE(index);									\
+												\
+static const struct stm32_pclken pclken_##index[] =						\
+				 STM32_DT_INST_CLOCKS(index);					\
+												\
+static const struct i2c_stm32_config i2c_stm32_cfg_##index = {					\
+	.i2c = (I2C_TypeDef *)DT_INST_REG_ADDR(index),						\
+	.pclken = pclken_##index,								\
+	.pclk_len = DT_INST_NUM_CLOCKS(index),							\
+	STM32_I2C_IRQ_HANDLER_FUNCTION(index)							\
+	.bitrate = DT_INST_PROP(index, clock_frequency),					\
+	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index),						\
+	IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY,						\
+		(.scl =	GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),			\
+		 .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))			\
+	IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2),					\
+		(.timings = (const struct i2c_config_timing *) i2c_timings_##index,		\
+		 .n_timings = ARRAY_SIZE(i2c_timings_##index),))				\
+};												\
+												\
+I2C_RTIO_DEFINE(CONCAT(_i2c, index, _stm32_rtio),						\
+	DT_INST_PROP_OR(index, sq_size, CONFIG_I2C_RTIO_SQ_SIZE),				\
+	DT_INST_PROP_OR(index, cq_size, CONFIG_I2C_RTIO_CQ_SIZE));				\
+												\
+static struct i2c_stm32_data_rtio i2c_stm32_dev_data_##index = {				\
+	.ctx = &CONCAT(_i2c, index, _stm32_rtio),						\
+};												\
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: gautierg-st
body: "Standard" I2C driver has target, DMA, bus recovery and SMBus support (which are not present in the RTIO driver), so I've kept things separate for the moment as a compromise between factorization and code readability.
created_at: 2025-05-22T07:22:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+};
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+
+static bool i2c_stm32_start(const struct device *dev);
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
+			*data->xfer_buf = LL_I2C_ReceiveData8(i2c);
+		}
+
+		data->xfer_buf++;
+		data->xfer_len--;
+	}
+
+	/* NACK received */
+	if (LL_I2C_IsActiveFlag_NACK(i2c)) {
+		LL_I2C_ClearFlag_NACK(i2c);
+		/*
+		 * AutoEndMode is always disabled in master mode,
+		 * so send a stop condition manually
+		 */
+		LL_I2C_GenerateStopCondition(i2c);
+		ret = -EIO;
+	}
+
+	/* STOP received */
+	if (LL_I2C_IsActiveFlag_STOP(i2c)) {
+		LL_I2C_ClearFlag_STOP(i2c);
+		LL_I2C_DisableReloadMode(i2c);
+		i2c_stm32_master_mode_end(dev);
+	}
+
+	/* TODO handle the reload separately from complete */
+	/* Transfer Complete or Transfer Complete Reload */
+	if (LL_I2C_IsActiveFlag_TC(i2c) ||
+	    LL_I2C_IsActiveFlag_TCR(i2c)) {
+		/* Issue stop condition if necessary */
+		/* TODO look at current sqe flags */
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		} else {
+			i2c_stm32_disable_transfer_interrupts(dev);
+		}
+
+		if (data->xfer_len == 0 && i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+}
+
+int i2c_stm32_error(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (LL_I2C_IsActiveFlag_ARLO(i2c)) {
+		LL_I2C_ClearFlag_ARLO(i2c);
+		ret = -EIO;
+	}
+
+	if (ret) {
+		i2c_stm32_master_mode_end(dev);
+		if (i2c_rtio_complete(ctx, ret)) {
+			i2c_stm32_start(dev);
+		}
+	}
+
+	return ret;
+}
+
+static int i2c_stm32_msg_start(const struct device *dev, uint8_t flags,
+	uint8_t *buf, size_t buf_len, uint16_t i2c_addr)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t transfer;
+
+	data->xfer_buf = buf;
+	data->xfer_len = buf_len;
+	data->xfer_flags = flags;
+
+	if (flags & I2C_MSG_READ) {
+		transfer = LL_I2C_REQUEST_READ;
+	} else {
+		transfer = LL_I2C_REQUEST_WRITE;
+	}
+
+	/* TODO deal with larger than 255 byte transfers correctly */
+	if (buf_len > UINT8_MAX) {
+		/* TODO LL_I2C_EnableReloadMode(i2c); */
+		return -EINVAL;
+	}
+
+	if (I2C_ADDR_10_BITS & data->dev_config) {
+		LL_I2C_SetMasterAddressingMode(i2c,
+				LL_I2C_ADDRESSING_MODE_10BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr);
+	} else {
+		LL_I2C_SetMasterAddressingMode(i2c,
+			LL_I2C_ADDRESSING_MODE_7BIT);
+		LL_I2C_SetSlaveAddr(i2c, (uint32_t) i2c_addr << 1);
+	}
+
+	LL_I2C_DisableAutoEndMode(i2c);
+	LL_I2C_SetTransferRequest(i2c, transfer);
+	LL_I2C_SetTransferSize(i2c, buf_len);
+
+	LL_I2C_Enable(i2c);
+
+	LL_I2C_GenerateStartCondition(i2c);
+
+	i2c_stm32_enable_transfer_interrupts(dev);
+	if (flags & I2C_MSG_READ) {
+		LL_I2C_EnableIT_RX(i2c);
+	} else {
+		LL_I2C_EnableIT_TX(i2c);
+	}
+
+	return 0;
+}
+
+int i2c_stm32_configure_timing(const struct device *dev, uint32_t clock)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_hold_time_min, i2c_setup_time_min;
+	uint32_t i2c_h_min_time, i2c_l_min_time;
+	uint32_t presc = 1U;
+	uint32_t timing = 0U;
+
+	/*  Look for an adequate preset timing value */
+	for (uint32_t i = 0; i < cfg->n_timings; i++) {
+		const struct i2c_config_timing *preset = &cfg->timings[i];
+		uint32_t speed = i2c_map_dt_bitrate(preset->i2c_speed);
+
+		if ((I2C_SPEED_GET(speed) == I2C_SPEED_GET(data->dev_config))
+		   && (preset->periph_clock == clock)) {
+			/*  Found a matching periph clock and i2c speed */
+			LL_I2C_SetTiming(i2c, preset->timing_setting);
+			return 0;
+		}
+	}
+
+	/* No preset timing was provided, let's dynamically configure */
+	switch (I2C_SPEED_GET(data->dev_config)) {
+	case I2C_SPEED_STANDARD:
+		i2c_h_min_time = 4000U;
+		i2c_l_min_time = 4700U;
+		i2c_hold_time_min = 500U;
+		i2c_setup_time_min = 1250U;
+		break;
+	case I2C_SPEED_FAST:
+		i2c_h_min_time = 600U;
+		i2c_l_min_time = 1300U;
+		i2c_hold_time_min = 375U;
+		i2c_setup_time_min = 500U;
+		break;
+	default:
+		LOG_ERR("i2c: speed above \"fast\" requires manual timing configuration, "
+				"see \"timings\" property of st,stm32-i2c-v2 devicetree binding");
+		return -EINVAL;
+	}
+
+	/* Calculate period until prescaler matches */
+	do {
+		uint32_t t_presc = clock / presc;
+		uint32_t ns_presc = NSEC_PER_SEC / t_presc;
+		uint32_t sclh = i2c_h_min_time / ns_presc;
+		uint32_t scll = i2c_l_min_time / ns_presc;
+		uint32_t sdadel = i2c_hold_time_min / ns_presc;
+		uint32_t scldel = i2c_setup_time_min / ns_presc;
+
+		if ((sclh - 1) > 255 ||  (scll - 1) > 255) {
+			++presc;
+			continue;
+		}
+
+		if (sdadel > 15 || (scldel - 1) > 15) {
+			++presc;
+			continue;
+		}
+
+		timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
+					scldel - 1, sdadel, sclh - 1, scll - 1);
+		break;
+	} while (presc < 16);
+
+	if (presc >= 16U) {
+		LOG_DBG("I2C:failed to find prescaler value");
+		return -EINVAL;
+	}
+
+	LL_I2C_SetTiming(i2c, timing);
+
+	return 0;
+}
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure disabling I2C clock");
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static bool i2c_stm32_start(const struct device *dev)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
+	struct i2c_dt_spec *dt_spec = sqe->iodev->data;
+
+	int res = 0;
+
+	switch (sqe->op) {
+	case RTIO_OP_RX:
+		return i2c_stm32_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_stm32_msg_start(dev,  sqe->iodev_flags,
+					   sqe->tiny_tx.buf, sqe->tiny_tx.buf_len, dt_spec->addr);
+	case RTIO_OP_TX:
+		return i2c_stm32_msg_start(dev, sqe->iodev_flags,
+					   (uint8_t *)sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
+	case RTIO_OP_I2C_CONFIGURE:
+		res = i2c_stm32_do_configure(dev, sqe->i2c_config);
+		return i2c_rtio_complete(data->ctx, res);
+	default:
+		LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
+		return i2c_rtio_complete(data->ctx, -EINVAL);
+	}
+}
+
+
+static int i2c_stm32_configure(const struct device *dev,
+				uint32_t dev_config_raw)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_configure(ctx, dev_config_raw);
+}
+
+static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msgs,
+				   uint8_t num_msgs, uint16_t addr)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
+}
+
+
+int i2c_stm32_get_config(const struct device *dev, uint32_t *config)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	*config = data->dev_config;
+
+	return 0;
+}
+
+static void i2c_stm32_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *const ctx = data->ctx;
+
+	if (i2c_rtio_submit(ctx, iodev_sqe)) {
+		i2c_stm32_start(dev);
+	}
+}
+
+static const struct i2c_driver_api api_funcs = {
+	.configure = i2c_stm32_configure,
+	.transfer = i2c_stm32_transfer,
+	.get_config = i2c_stm32_get_config,
+	.iodev_submit = i2c_stm32_submit,
+};
+
+
+static int i2c_stm32_init(const struct device *dev)
+{
+	const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	const struct i2c_stm32_config *cfg = dev->config;
+	uint32_t bitrate_cfg;
+	int ret;
+	struct i2c_stm32_data_rtio *data = dev->data;
+
+	cfg->irq_config_func(dev);
+
+	i2c_rtio_init(data->ctx, dev);
+
+	if (!device_is_ready(clk)) {
+		LOG_ERR("clock control device not ready");
+		return -ENODEV;
+	}
+
+	i2c_stm32_activate(dev);
+
+	if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		/* Enable I2C clock source */
+		ret = clock_control_configure(clk,
+					(clock_control_subsys_t) &cfg->pclken[1],
+					NULL);
+		if (ret < 0) {
+			return -EIO;
+		}
+	}
+
+#if defined(CONFIG_SOC_SERIES_STM32F1X)
+	/*
+	 * Force i2c reset for STM32F1 series.
+	 * So that they can enter master mode properly.
+	 * Issue described in ES096 2.14.7
+	 */
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableReset(i2c);
+	LL_I2C_DisableReset(i2c);
+#endif
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: gautierg-st
body: Moved to common RTIO file
created_at: 2025-05-22T07:22:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -593,9 +592,8 @@ void stm32_i2c_event_isr(void *arg)
 	}
 }
 
-void stm32_i2c_error_isr(void *arg)
+int i2c_stm32_error(const struct device *dev)
 {
-	const struct device *dev = (const struct device *)arg;
 	const struct i2c_stm32_config *cfg = dev->config;
 	struct i2c_stm32_data *data = dev->data;
 	I2C_TypeDef *i2c = cfg->i2c;
path: drivers/i2c/i2c_ll_stm32_v1.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T07:23:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -540,50 +465,6 @@ void i2c_stm32_smbalert_disable(const struct device *dev)
 
 /* Macros for I2C instance declaration */
 
-#ifdef CONFIG_I2C_STM32_INTERRUPT
-
-#ifdef CONFIG_I2C_STM32_COMBINED_INTERRUPT
-#define STM32_I2C_IRQ_CONNECT_AND_ENABLE(index)				\
-	do {								\
-		IRQ_CONNECT(DT_INST_IRQN(index),			\
-			    DT_INST_IRQ(index, priority),		\
-			    stm32_i2c_combined_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQN(index));			\
-	} while (false)
-#else
-#define STM32_I2C_IRQ_CONNECT_AND_ENABLE(index)				\
-	do {								\
-		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, event, irq),	\
-			    DT_INST_IRQ_BY_NAME(index, event, priority),\
-			    stm32_i2c_event_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQ_BY_NAME(index, event, irq));	\
-									\
-		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, error, irq),	\
-			    DT_INST_IRQ_BY_NAME(index, error, priority),\
-			    stm32_i2c_error_isr,			\
-			    DEVICE_DT_INST_GET(index), 0);		\
-		irq_enable(DT_INST_IRQ_BY_NAME(index, error, irq));	\
-	} while (false)
-#endif /* CONFIG_I2C_STM32_COMBINED_INTERRUPT */
-
-#define STM32_I2C_IRQ_HANDLER_DECL(index)				\
-static void i2c_stm32_irq_config_func_##index(const struct device *dev)
-#define STM32_I2C_IRQ_HANDLER_FUNCTION(index)				\
-	.irq_config_func = i2c_stm32_irq_config_func_##index,
-#define STM32_I2C_IRQ_HANDLER(index)					\
-static void i2c_stm32_irq_config_func_##index(const struct device *dev)	\
-{									\
-	STM32_I2C_IRQ_CONNECT_AND_ENABLE(index);			\
-}
-#else
-
-#define STM32_I2C_IRQ_HANDLER_DECL(index)
-#define STM32_I2C_IRQ_HANDLER_FUNCTION(index)
-#define STM32_I2C_IRQ_HANDLER(index)
path: drivers/i2c/i2c_ll_stm32.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T07:23:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T07:23:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/kernel.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <errno.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+
+
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T07:26:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define DT_DRV_COMPAT st_stm32_i2c_v1
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+
+struct i2c_stm32_data_rtio {
+	struct i2c_rtio *ctx;
+	uint32_t dev_config;
+	uint8_t *xfer_buf;
+	uint8_t xfer_len;
+	uint8_t xfer_flags;
+	uint8_t msg_len;
+	uint8_t is_restart;
+	uint16_t slave_address;
+};
+
+static bool i2c_stm32_start(const struct device *dev);
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data_rtio *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static inline void handle_sb(const struct device *dev)
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: gautierg-st
body: They were copied from "standard" I2C driver. Removed now. The compiler will decide itself if it should be inline or not
created_at: 2025-05-22T07:29:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2)
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+#else
+#define DT_DRV_COMPAT st_stm32_i2c_v1
+#endif
+
+/* This symbol takes the value 1 if one of the device instances */
+/* is configured in dts with a domain clock */
+#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 1
+#else
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 0
+#endif
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(I2C_STM32_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
path: drivers/i2c/i2c_ll_stm32_rtio.c
user: login: etienne-lms
body: Scratches previous `ret` values
created_at: 2025-05-22T09:33:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: etienne-lms
body: remove the extra empty line
created_at: 2025-05-22T09:36:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
+		slave |= HEADER;
+
+		if (data->is_restart == 0U) {
+			data->is_restart = 1U;
+		} else {
+			slave |= I2C_REQUEST_READ;
+			data->is_restart = 0U;
+		}
+		LL_I2C_TransmitData8(i2c, slave);
+	} else {
+		slave = (saddr << 1) & 0xFF;
+		if (data->xfer_flags & I2C_MSG_READ) {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
+			if (data->xfer_len == 2) {
+				LL_I2C_EnableBitPOS(i2c);
+			}
+		} else {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
+		}
+	}
+}
+
+static void handle_addr(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: etienne-lms
body: remove the extra empty line
created_at: 2025-05-22T09:36:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: etienne-lms
body: can remove outer parentheses
created_at: 2025-05-22T09:39:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
+		slave |= HEADER;
+
+		if (data->is_restart == 0U) {
+			data->is_restart = 1U;
+		} else {
+			slave |= I2C_REQUEST_READ;
+			data->is_restart = 0U;
+		}
+		LL_I2C_TransmitData8(i2c, slave);
+	} else {
+		slave = (saddr << 1) & 0xFF;
+		if (data->xfer_flags & I2C_MSG_READ) {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
+			if (data->xfer_len == 2) {
+				LL_I2C_EnableBitPOS(i2c);
+			}
+		} else {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
+		}
+	}
+}
+
+static void handle_addr(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		if ((data->xfer_flags & I2C_MSG_READ) && data->is_restart) {
+			data->is_restart = 0U;
+			LL_I2C_ClearFlag_ADDR(i2c);
+			i2c_stm32_generate_start_condition(i2c);
+			return;
+		}
+	}
+
+	if (!(data->xfer_flags & I2C_MSG_READ)) {
+		LL_I2C_ClearFlag_ADDR(i2c);
+		return;
+	}
+	/* according to STM32F1 errata we need to handle these corner cases in
+	 * specific way.
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: etienne-lms
body: ```suggestion
	/* According to STM32F1 errata we need to handle these corner cases in
	 * a specific way.
	 *
```

created_at: 2025-05-22T09:42:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: etienne-lms
body: `if (data->xfer_flags & I2C_MSG_ADDR_10_BITS != 0U)`

Equivalent comments on a few other tests implementation (line 102, 120, 129, 163, 175, ...)

Ditto in **drivers/i2c/i2c_ll_stm32_v2_rtio.c**.
created_at: 2025-05-22T09:42:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
+		slave |= HEADER;
+
+		if (data->is_restart == 0U) {
+			data->is_restart = 1U;
+		} else {
+			slave |= I2C_REQUEST_READ;
+			data->is_restart = 0U;
+		}
+		LL_I2C_TransmitData8(i2c, slave);
+	} else {
+		slave = (saddr << 1) & 0xFF;
+		if (data->xfer_flags & I2C_MSG_READ) {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
+			if (data->xfer_len == 2) {
+				LL_I2C_EnableBitPOS(i2c);
+			}
+		} else {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
+		}
+	}
+}
+
+static void handle_addr(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		if ((data->xfer_flags & I2C_MSG_READ) && data->is_restart) {
+			data->is_restart = 0U;
+			LL_I2C_ClearFlag_ADDR(i2c);
+			i2c_stm32_generate_start_condition(i2c);
+			return;
+		}
+	}
+
+	if (!(data->xfer_flags & I2C_MSG_READ)) {
+		LL_I2C_ClearFlag_ADDR(i2c);
+		return;
+	}
+	/* according to STM32F1 errata we need to handle these corner cases in
+	 * specific way.
+	 * Please ref to STM32F10xxC/D/E I2C peripheral Errata sheet 2.14.1
+	 */
+	if (data->xfer_len == 0U && IS_ENABLED(CONFIG_SOC_SERIES_STM32F1X)) {
+		LL_I2C_GenerateStopCondition(i2c);
+	} else if (data->xfer_len == 1U) {
+		/* Single byte reception: enable NACK and clear POS */
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+#ifdef CONFIG_SOC_SERIES_STM32F1X
+		LL_I2C_ClearFlag_ADDR(i2c);
+		LL_I2C_GenerateStopCondition(i2c);
+#endif
+	} else if (data->xfer_len == 2U) {
+#ifdef CONFIG_SOC_SERIES_STM32F1X
+		LL_I2C_ClearFlag_ADDR(i2c);
+#endif
+		/* 2-byte reception: enable NACK and set POS */
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+		LL_I2C_EnableBitPOS(i2c);
+	}
+	LL_I2C_ClearFlag_ADDR(i2c);
+}
+
+static void handle_txe(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if (data->xfer_len) {
+		data->xfer_len--;
+		if (data->xfer_len == 0U) {
+			/*
+			 * This is the last byte to transmit disable Buffer
+			 * interrupt and wait for a BTF interrupt
+			 */
+			LL_I2C_DisableIT_BUF(i2c);
+		}
+		LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		data->xfer_buf++;
+	} else {
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		}
+		if (LL_I2C_IsActiveFlag_BTF(i2c)) {
+			/* Read DR to clear BTF flag */
+			LL_I2C_ReceiveData8(i2c);
+		}
+		i2c_stm32_master_mode_end(dev);
+	}
+}
+
+static void handle_rxne(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if (data->xfer_len > 0) {
+		switch (data->xfer_len) {
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: etienne-lms
body: Could add case 0 in the switch/case:
```c
	switch (data->xfer_len) {
	case 0:
		if (data->xfer_flags & I2C_MSG_STOP) {
			LL_I2C_GenerateStopCondition(i2c);
		}
		i2c_stm32_master_mode_end(dev);
		break;
	case 1:
		...
created_at: 2025-05-22T09:45:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v2_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: etienne-lms
body: Deserves an `else` instructions?
created_at: 2025-05-22T09:50:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2)
+#define DT_DRV_COMPAT st_stm32_i2c_v2
+#else
+#define DT_DRV_COMPAT st_stm32_i2c_v1
+#endif
+
+/* This symbol takes the value 1 if one of the device instances */
+/* is configured in dts with a domain clock */
+#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 1
+#else
+#define I2C_STM32_DOMAIN_CLOCK_SUPPORT 0
+#endif
+
+static int i2c_stm32_do_configure(const struct device *dev, uint32_t config)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
+	I2C_TypeDef *i2c = cfg->i2c;
+	uint32_t i2c_clock = 0U;
+	int ret;
+
+	if (IS_ENABLED(I2C_STM32_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[1])");
+			return -EIO;
+		}
+	} else {
+		if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0],
+					   &i2c_clock) < 0) {
+			LOG_ERR("Failed call clock_control_get_rate(pclken[0])");
+			return -EIO;
+		}
+	}
+
+	data->dev_config = config;
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_on(clk, (clock_control_subsys_t)&cfg->pclken[0]);
+	if (ret < 0) {
+		LOG_ERR("failure Enabling I2C clock");
+		return ret;
+	}
+#endif
+
+	LL_I2C_Disable(i2c);
+	ret = i2c_stm32_configure_timing(dev, i2c_clock);
+
+#ifdef CONFIG_PM_DEVICE_RUNTIME
+	ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]);
path: drivers/i2c/i2c_ll_stm32_rtio.c
user: login: gautierg-st
body: Fixed
created_at: 2025-05-22T13:03:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T13:03:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
+		slave |= HEADER;
+
+		if (data->is_restart == 0U) {
+			data->is_restart = 1U;
+		} else {
+			slave |= I2C_REQUEST_READ;
+			data->is_restart = 0U;
+		}
+		LL_I2C_TransmitData8(i2c, slave);
+	} else {
+		slave = (saddr << 1) & 0xFF;
+		if (data->xfer_flags & I2C_MSG_READ) {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
+			if (data->xfer_len == 2) {
+				LL_I2C_EnableBitPOS(i2c);
+			}
+		} else {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
+		}
+	}
+}
+
+static void handle_addr(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T13:03:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T13:04:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
+		slave |= HEADER;
+
+		if (data->is_restart == 0U) {
+			data->is_restart = 1U;
+		} else {
+			slave |= I2C_REQUEST_READ;
+			data->is_restart = 0U;
+		}
+		LL_I2C_TransmitData8(i2c, slave);
+	} else {
+		slave = (saddr << 1) & 0xFF;
+		if (data->xfer_flags & I2C_MSG_READ) {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
+			if (data->xfer_len == 2) {
+				LL_I2C_EnableBitPOS(i2c);
+			}
+		} else {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
+		}
+	}
+}
+
+static void handle_addr(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		if ((data->xfer_flags & I2C_MSG_READ) && data->is_restart) {
+			data->is_restart = 0U;
+			LL_I2C_ClearFlag_ADDR(i2c);
+			i2c_stm32_generate_start_condition(i2c);
+			return;
+		}
+	}
+
+	if (!(data->xfer_flags & I2C_MSG_READ)) {
+		LL_I2C_ClearFlag_ADDR(i2c);
+		return;
+	}
+	/* according to STM32F1 errata we need to handle these corner cases in
+	 * specific way.
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T13:04:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: gautierg-st
body: Fixed
created_at: 2025-05-22T13:04:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2025 STMicroelectronics
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v1_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+#define I2C_REQUEST_WRITE       0x00
+#define I2C_REQUEST_READ        0x01
+#define HEADER                  0xF0
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_EVT(i2c);
+	LL_I2C_DisableIT_BUF(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_ERR(i2c);
+	LL_I2C_EnableIT_EVT(i2c);
+	LL_I2C_EnableIT_BUF(i2c);
+}
+
+static void i2c_stm32_generate_start_condition(I2C_TypeDef *i2c)
+{
+	uint16_t cr1 = LL_I2C_ReadReg(i2c, CR1);
+
+	if (cr1 & I2C_CR1_STOP) {
+		LOG_DBG("%s: START while STOP active!", __func__);
+		LL_I2C_WriteReg(i2c, CR1, cr1 & ~I2C_CR1_STOP);
+	}
+
+	LL_I2C_GenerateStartCondition(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+	LL_I2C_Disable(i2c);
+	if (data->xfer_len == 0 && i2c_rtio_complete(ctx, 0)) {
+		i2c_stm32_start(dev);
+	}
+
+}
+
+static void handle_sb(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	uint16_t saddr = data->slave_address;
+	uint8_t slave;
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		slave = (((saddr & 0x0300) >> 7) & 0xFF);
+		slave |= HEADER;
+
+		if (data->is_restart == 0U) {
+			data->is_restart = 1U;
+		} else {
+			slave |= I2C_REQUEST_READ;
+			data->is_restart = 0U;
+		}
+		LL_I2C_TransmitData8(i2c, slave);
+	} else {
+		slave = (saddr << 1) & 0xFF;
+		if (data->xfer_flags & I2C_MSG_READ) {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
+			if (data->xfer_len == 2) {
+				LL_I2C_EnableBitPOS(i2c);
+			}
+		} else {
+			LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
+		}
+	}
+}
+
+static void handle_addr(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+
+	if (data->xfer_flags & I2C_MSG_ADDR_10_BITS) {
+		if ((data->xfer_flags & I2C_MSG_READ) && data->is_restart) {
+			data->is_restart = 0U;
+			LL_I2C_ClearFlag_ADDR(i2c);
+			i2c_stm32_generate_start_condition(i2c);
+			return;
+		}
+	}
+
+	if (!(data->xfer_flags & I2C_MSG_READ)) {
+		LL_I2C_ClearFlag_ADDR(i2c);
+		return;
+	}
+	/* according to STM32F1 errata we need to handle these corner cases in
+	 * specific way.
+	 * Please ref to STM32F10xxC/D/E I2C peripheral Errata sheet 2.14.1
+	 */
+	if (data->xfer_len == 0U && IS_ENABLED(CONFIG_SOC_SERIES_STM32F1X)) {
+		LL_I2C_GenerateStopCondition(i2c);
+	} else if (data->xfer_len == 1U) {
+		/* Single byte reception: enable NACK and clear POS */
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+#ifdef CONFIG_SOC_SERIES_STM32F1X
+		LL_I2C_ClearFlag_ADDR(i2c);
+		LL_I2C_GenerateStopCondition(i2c);
+#endif
+	} else if (data->xfer_len == 2U) {
+#ifdef CONFIG_SOC_SERIES_STM32F1X
+		LL_I2C_ClearFlag_ADDR(i2c);
+#endif
+		/* 2-byte reception: enable NACK and set POS */
+		LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
+		LL_I2C_EnableBitPOS(i2c);
+	}
+	LL_I2C_ClearFlag_ADDR(i2c);
+}
+
+static void handle_txe(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if (data->xfer_len) {
+		data->xfer_len--;
+		if (data->xfer_len == 0U) {
+			/*
+			 * This is the last byte to transmit disable Buffer
+			 * interrupt and wait for a BTF interrupt
+			 */
+			LL_I2C_DisableIT_BUF(i2c);
+		}
+		LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		data->xfer_buf++;
+	} else {
+		if (data->xfer_flags & I2C_MSG_STOP) {
+			LL_I2C_GenerateStopCondition(i2c);
+		}
+		if (LL_I2C_IsActiveFlag_BTF(i2c)) {
+			/* Read DR to clear BTF flag */
+			LL_I2C_ReceiveData8(i2c);
+		}
+		i2c_stm32_master_mode_end(dev);
+	}
+}
+
+static void handle_rxne(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	if (data->xfer_len > 0) {
+		switch (data->xfer_len) {
path: drivers/i2c/i2c_ll_stm32_v1_rtio.c
user: login: gautierg-st
body: Done
created_at: 2025-05-22T13:04:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Copyright (c) 2017 Linaro Ltd
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <soc.h>
+#include <stm32_ll_i2c.h>
+#include <stm32_ll_rcc.h>
+#include <zephyr/drivers/clock_control.h>
+#include <zephyr/drivers/clock_control/stm32_clock_control.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/i2c/rtio.h>
+#include <zephyr/drivers/pinctrl.h>
+#include <zephyr/kernel.h>
+#include <zephyr/pm/device.h>
+#include <zephyr/pm/device_runtime.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(i2c_ll_stm32_v2_rtio);
+
+#include "i2c_ll_stm32.h"
+#include "i2c-priv.h"
+
+static void i2c_stm32_disable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_DisableIT_TX(i2c);
+	LL_I2C_DisableIT_RX(i2c);
+	LL_I2C_DisableIT_STOP(i2c);
+	LL_I2C_DisableIT_NACK(i2c);
+	LL_I2C_DisableIT_TC(i2c);
+}
+
+static void i2c_stm32_enable_transfer_interrupts(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	LL_I2C_EnableIT_STOP(i2c);
+	LL_I2C_EnableIT_NACK(i2c);
+	LL_I2C_EnableIT_TC(i2c);
+	LL_I2C_EnableIT_ERR(i2c);
+}
+
+static void i2c_stm32_master_mode_end(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	I2C_TypeDef *i2c = cfg->i2c;
+
+	i2c_stm32_disable_transfer_interrupts(dev);
+
+	if (LL_I2C_IsEnabledReloadMode(i2c)) {
+		LL_I2C_DisableReloadMode(i2c);
+	}
+}
+
+void i2c_stm32_event(const struct device *dev)
+{
+	const struct i2c_stm32_config *cfg = dev->config;
+	struct i2c_stm32_data *data = dev->data;
+	struct i2c_rtio *ctx = data->ctx;
+	I2C_TypeDef *i2c = cfg->i2c;
+	int ret = 0;
+
+	if (data->xfer_len) {
+		/* Send next byte */
+		if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
+			LL_I2C_TransmitData8(i2c, *data->xfer_buf);
+		}
+
+		/* Receive next byte */
+		if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
path: drivers/i2c/i2c_ll_stm32_v2_rtio.c
user: login: gautierg-st
body: Not present in the standard driver, so I don't think it is necessary
created_at: 2025-05-22T13:04:53Z
author_association: CONTRIBUTOR

PR comments:
user: login: teburd
created_at: 2025-03-27T12:53:21Z
body: There's a test against an fram/sram i2c chip that uses rtio and I would recommend testing against that rather than a sensor as its better isolated.

e.g. this fram board https://learn.adafruit.com/adafruit-i2c-fram-breakout

and this test

https://github.com/zephyrproject-rtos/zephyr/tree/main/tests/drivers/i2c/i2c_ram

author_association: CONTRIBUTOR
user: login: teburd
created_at: 2025-04-03T15:22:04Z
body: Need to pass CI, but I *know* this worked when I wrote it. And it doesn't look too different.
author_association: CONTRIBUTOR
user: login: gautierg-st
created_at: 2025-04-04T07:20:01Z
body: > Need to pass CI, but I _know_ this worked when I wrote it. And it doesn't look too different.

It is indeed very similar, I merely rebased to integrate latest modifications and did some cosmetic changes.
I am working on adding I2Cv1 support, but that will come as another PR later.
author_association: CONTRIBUTOR
user: login: gautierg-st
created_at: 2025-04-04T07:41:30Z
body: Split into two commits: first one to move the common functions into a common file, second one to add the RTIO driver.
author_association: CONTRIBUTOR
user: login: teburd
created_at: 2025-04-17T13:16:34Z
body: > Mainly questions about code duplication. Also, what's the plan versus DMA support, should it be kept excluded from RTIO right now ?

DMA is optional, the way I did it with the SAM driver is by applying a heuristic to the size of the transfer. I don't recall the details of ST's DMA and I2C peripherals, but there's often a cutoff when it makes sense to pay the cost of programming the DMA or not. E.g. single word size or smaller transfers might fit entirely the in the device FIFO, no need to go program a DMA.

Mostly for Zephyr and RTIO we want to reduce the number of interrupts. Or at the very least avoid the costly indirect interrupts with scheduler overhead if we don't need them.

E.g. what many drivers do today would be maybe be better done if the interrupt handler were the "DIRECT" kind without the scheduling wrapper, only doing scheduling/pm work once a transfer is complete rather than some FIFO wm/refill signaling happening.

author_association: CONTRIBUTOR
user: login: gautierg-st
created_at: 2025-04-30T12:53:10Z
body: Last commit introduces the support of I2Cv1 also. But this needs further work to factorize some parts of the code, as is, too much is needlessly duplicated.
I'll be OoO for the next two weeks, so I'll do that when I'll be back.
author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-05-22T15:15:37Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=zephyrproject-rtos_zephyr&pullRequest=87731) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [16 New issues](https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&pullRequest=87731&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&pullRequest=87731&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=zephyrproject-rtos_zephyr&pullRequest=87731&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=zephyrproject-rtos_zephyr&pullRequest=87731&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [12.2% Duplication on New Code](https://sonarcloud.io/component_measures?id=zephyrproject-rtos_zephyr&pullRequest=87731&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=zephyrproject-rtos_zephyr&pullRequest=87731)


author_association: NONE