Skip to content

Commit f443363

Browse files
JordanYatesaescolar
authored andcommitted
i2c: nrfx_twim: native RTIO support
Add native support for RTIO to the TWIM hardware IP. Signed-off-by: Jordan Yates <[email protected]>
1 parent 627be7d commit f443363

File tree

2 files changed

+301
-4
lines changed

2 files changed

+301
-4
lines changed

drivers/i2c/CMakeLists.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,17 @@ else()
4646
)
4747
endif()
4848

49-
zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM
50-
i2c_nrfx_twim.c
51-
i2c_nrfx_twim_common.c
52-
)
49+
if(CONFIG_I2C_RTIO)
50+
zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM
51+
i2c_nrfx_twim_rtio.c
52+
i2c_nrfx_twim_common.c
53+
)
54+
else()
55+
zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM
56+
i2c_nrfx_twim.c
57+
i2c_nrfx_twim_common.c
58+
)
59+
endif()
5360
zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWI i2c_sam_twi.c)
5461

5562
if(CONFIG_I2C_RTIO)

drivers/i2c/i2c_nrfx_twim_rtio.c

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
* Copyright (c) 2018, Nordic Semiconductor ASA
3+
* Copyright (c) 2024, Croxel Inc
4+
* Copyright (c) 2024, Embeint Inc
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#include <zephyr/drivers/i2c.h>
10+
#include <zephyr/drivers/i2c/rtio.h>
11+
#include <zephyr/dt-bindings/i2c/i2c.h>
12+
#include <zephyr/logging/log.h>
13+
#include <zephyr/pm/device.h>
14+
#include <zephyr/pm/device_runtime.h>
15+
#include <zephyr/drivers/pinctrl.h>
16+
#include <soc.h>
17+
#include <nrfx_twim.h>
18+
19+
#include "i2c_nrfx_twim_common.h"
20+
21+
LOG_MODULE_REGISTER(i2c_nrfx_twim, CONFIG_I2C_LOG_LEVEL);
22+
23+
struct i2c_nrfx_twim_rtio_config {
24+
struct i2c_nrfx_twim_common_config common;
25+
struct i2c_rtio *ctx;
26+
};
27+
28+
static bool i2c_nrfx_twim_rtio_msg_start(const struct device *dev, uint8_t flags, uint8_t *buf,
29+
size_t buf_len, uint16_t i2c_addr)
30+
{
31+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
32+
struct i2c_rtio *ctx = config->ctx;
33+
int ret = 0;
34+
35+
ret = i2c_nrfx_twim_msg_transfer(dev, flags, buf, buf_len, i2c_addr);
36+
if (ret != 0) {
37+
return i2c_rtio_complete(ctx, ret);
38+
}
39+
40+
return false;
41+
}
42+
43+
static bool i2c_nrfx_twim_rtio_start(const struct device *dev)
44+
{
45+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
46+
struct i2c_rtio *ctx = config->ctx;
47+
struct rtio_sqe *sqe = &ctx->txn_curr->sqe;
48+
struct i2c_dt_spec *dt_spec = sqe->iodev->data;
49+
50+
switch (sqe->op) {
51+
case RTIO_OP_RX:
52+
return i2c_nrfx_twim_rtio_msg_start(dev, I2C_MSG_READ | sqe->iodev_flags,
53+
sqe->rx.buf, sqe->rx.buf_len, dt_spec->addr);
54+
case RTIO_OP_TINY_TX:
55+
return i2c_nrfx_twim_rtio_msg_start(dev, I2C_MSG_WRITE | sqe->iodev_flags,
56+
sqe->tiny_tx.buf, sqe->tiny_tx.buf_len,
57+
dt_spec->addr);
58+
case RTIO_OP_TX:
59+
/* If buffer is not accessible by DMA, copy it into the internal driver buffer */
60+
if (!nrf_dma_accessible_check(&config->common.twim, sqe->tx.buf)) {
61+
/* Validate buffer will fit */
62+
if (sqe->tx.buf_len > config->common.msg_buf_size) {
63+
LOG_ERR("Need to use the internal driver "
64+
"buffer but its size is insufficient "
65+
"(%u > %u). "
66+
"Adjust the zephyr,concat-buf-size or "
67+
"zephyr,flash-buf-max-size property "
68+
"(the one with greater value) in the "
69+
"\"%s\"' node.",
70+
sqe->tx.buf_len, config->common.msg_buf_size, dev->name);
71+
return i2c_rtio_complete(ctx, -ENOSPC);
72+
}
73+
memcpy(config->common.msg_buf, sqe->tx.buf, sqe->tx.buf_len);
74+
sqe->tx.buf = config->common.msg_buf;
75+
}
76+
return i2c_nrfx_twim_rtio_msg_start(dev, I2C_MSG_WRITE | sqe->iodev_flags,
77+
sqe->tx.buf, sqe->tx.buf_len, dt_spec->addr);
78+
case RTIO_OP_I2C_CONFIGURE:
79+
(void)i2c_nrfx_twim_configure(dev, sqe->i2c_config);
80+
return false;
81+
case RTIO_OP_I2C_RECOVER:
82+
(void)i2c_nrfx_twim_recover_bus(dev);
83+
return false;
84+
default:
85+
LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe);
86+
return i2c_rtio_complete(ctx, -EINVAL);
87+
}
88+
}
89+
90+
static void i2c_nrfx_twim_rtio_complete(const struct device *dev, int status)
91+
{
92+
/** Finalize if there are no more pending xfers */
93+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
94+
struct i2c_rtio *ctx = config->ctx;
95+
96+
if (i2c_rtio_complete(ctx, status)) {
97+
(void)i2c_nrfx_twim_rtio_start(dev);
98+
} else {
99+
/* Release bus on completion */
100+
pm_device_runtime_put(dev);
101+
}
102+
}
103+
104+
static int i2c_nrfx_twim_rtio_configure(const struct device *dev, uint32_t i2c_config)
105+
{
106+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
107+
struct i2c_rtio *ctx = config->ctx;
108+
109+
return i2c_rtio_configure(ctx, i2c_config);
110+
}
111+
112+
static int i2c_nrfx_twim_rtio_transfer(const struct device *dev, struct i2c_msg *msgs,
113+
uint8_t num_msgs, uint16_t addr)
114+
{
115+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
116+
struct i2c_rtio *ctx = config->ctx;
117+
118+
return i2c_rtio_transfer(ctx, msgs, num_msgs, addr);
119+
}
120+
121+
static int i2c_nrfx_twim_rtio_recover_bus(const struct device *dev)
122+
{
123+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
124+
struct i2c_rtio *ctx = config->ctx;
125+
126+
return i2c_rtio_recover(ctx);
127+
}
128+
129+
static void i2c_nrfx_twim_rtio_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_seq)
130+
{
131+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
132+
struct i2c_rtio *ctx = config->ctx;
133+
134+
if (i2c_rtio_submit(ctx, iodev_seq)) {
135+
if (pm_device_runtime_get(dev) < 0) {
136+
(void)i2c_rtio_complete(ctx, -EINVAL);
137+
} else {
138+
(void)i2c_nrfx_twim_rtio_start(dev);
139+
}
140+
}
141+
}
142+
143+
static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context)
144+
{
145+
const struct device *dev = p_context;
146+
int status = p_event->type == NRFX_TWIM_EVT_DONE ? 0 : -EIO;
147+
148+
i2c_nrfx_twim_rtio_complete(dev, status);
149+
}
150+
151+
static const struct i2c_driver_api i2c_nrfx_twim_driver_api = {
152+
.configure = i2c_nrfx_twim_rtio_configure,
153+
.transfer = i2c_nrfx_twim_rtio_transfer,
154+
.recover_bus = i2c_nrfx_twim_rtio_recover_bus,
155+
.iodev_submit = i2c_nrfx_twim_rtio_submit,
156+
};
157+
158+
int i2c_nrfx_twim_rtio_init(const struct device *dev)
159+
{
160+
const struct i2c_nrfx_twim_rtio_config *config = dev->config;
161+
162+
i2c_rtio_init(config->ctx, dev);
163+
return i2c_nrfx_twim_common_init(dev);
164+
}
165+
166+
#define CONCAT_BUF_SIZE(idx) \
167+
COND_CODE_1(DT_NODE_HAS_PROP(I2C(idx), zephyr_concat_buf_size), \
168+
(DT_PROP(I2C(idx), zephyr_concat_buf_size)), (0))
169+
#define FLASH_BUF_MAX_SIZE(idx) \
170+
COND_CODE_1(DT_NODE_HAS_PROP(I2C(idx), zephyr_flash_buf_max_size), \
171+
(DT_PROP(I2C(idx), zephyr_flash_buf_max_size)), (0))
172+
173+
#define USES_MSG_BUF(idx) \
174+
COND_CODE_0(CONCAT_BUF_SIZE(idx), (COND_CODE_0(FLASH_BUF_MAX_SIZE(idx), (0), (1))), (1))
175+
#define MSG_BUF_SIZE(idx) MAX(CONCAT_BUF_SIZE(idx), FLASH_BUF_MAX_SIZE(idx))
176+
177+
#define I2C_NRFX_TWIM_RTIO_DEVICE(idx) \
178+
NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(I2C(idx)); \
179+
BUILD_ASSERT(I2C_FREQUENCY(idx) != I2C_NRFX_TWIM_INVALID_FREQUENCY, \
180+
"Wrong I2C " #idx " frequency setting in dts"); \
181+
static void irq_connect##idx(void) \
182+
{ \
183+
IRQ_CONNECT(DT_IRQN(I2C(idx)), DT_IRQ(I2C(idx), priority), nrfx_isr, \
184+
nrfx_twim_##idx##_irq_handler, 0); \
185+
} \
186+
IF_ENABLED( \
187+
USES_MSG_BUF(idx), \
188+
(static uint8_t twim_##idx##_msg_buf[MSG_BUF_SIZE(idx)] I2C_MEMORY_SECTION(idx);)) \
189+
I2C_RTIO_DEFINE(_i2c##idx##_twim_rtio, \
190+
DT_INST_PROP_OR(n, sq_size, CONFIG_I2C_RTIO_SQ_SIZE), \
191+
DT_INST_PROP_OR(n, cq_size, CONFIG_I2C_RTIO_CQ_SIZE)); \
192+
PINCTRL_DT_DEFINE(I2C(idx)); \
193+
static const struct i2c_nrfx_twim_rtio_config twim_##idx##z_config = { \
194+
.common = \
195+
{ \
196+
.twim = NRFX_TWIM_INSTANCE(idx), \
197+
.twim_config = \
198+
{ \
199+
.skip_gpio_cfg = true, \
200+
.skip_psel_cfg = true, \
201+
.frequency = I2C_FREQUENCY(idx), \
202+
}, \
203+
.event_handler = event_handler, \
204+
.msg_buf_size = MSG_BUF_SIZE(idx), \
205+
.irq_connect = irq_connect##idx, \
206+
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2C(idx)), \
207+
IF_ENABLED(USES_MSG_BUF(idx), (.msg_buf = twim_##idx##_msg_buf,)) \
208+
.max_transfer_size = \
209+
BIT_MASK(DT_PROP(I2C(idx), easydma_maxcnt_bits)), \
210+
}, \
211+
.ctx = &_i2c##idx##_twim_rtio, \
212+
}; \
213+
PM_DEVICE_DT_DEFINE(I2C(idx), twim_nrfx_pm_action); \
214+
I2C_DEVICE_DT_DEFINE(I2C(idx), i2c_nrfx_twim_rtio_init, PM_DEVICE_DT_GET(I2C(idx)), NULL, \
215+
&twim_##idx##z_config, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \
216+
&i2c_nrfx_twim_driver_api)
217+
218+
#define I2C_MEMORY_SECTION(idx) \
219+
COND_CODE_1(I2C_HAS_PROP(idx, memory_regions), \
220+
(__attribute__((__section__( \
221+
LINKER_DT_NODE_REGION_NAME(DT_PHANDLE(I2C(idx), memory_regions)))))), \
222+
())
223+
224+
#ifdef CONFIG_HAS_HW_NRF_TWIM0
225+
I2C_NRFX_TWIM_RTIO_DEVICE(0);
226+
#endif
227+
228+
#ifdef CONFIG_HAS_HW_NRF_TWIM1
229+
I2C_NRFX_TWIM_RTIO_DEVICE(1);
230+
#endif
231+
232+
#ifdef CONFIG_HAS_HW_NRF_TWIM2
233+
I2C_NRFX_TWIM_RTIO_DEVICE(2);
234+
#endif
235+
236+
#ifdef CONFIG_HAS_HW_NRF_TWIM3
237+
I2C_NRFX_TWIM_RTIO_DEVICE(3);
238+
#endif
239+
240+
#ifdef CONFIG_HAS_HW_NRF_TWIM20
241+
I2C_NRFX_TWIM_RTIO_DEVICE(20);
242+
#endif
243+
244+
#ifdef CONFIG_HAS_HW_NRF_TWIM21
245+
I2C_NRFX_TWIM_RTIO_DEVICE(21);
246+
#endif
247+
248+
#ifdef CONFIG_HAS_HW_NRF_TWIM22
249+
I2C_NRFX_TWIM_RTIO_DEVICE(22);
250+
#endif
251+
252+
#ifdef CONFIG_HAS_HW_NRF_TWIM30
253+
I2C_NRFX_TWIM_RTIO_DEVICE(30);
254+
#endif
255+
256+
#ifdef CONFIG_HAS_HW_NRF_TWIM120
257+
I2C_NRFX_TWIM_RTIO_DEVICE(120);
258+
#endif
259+
260+
#ifdef CONFIG_HAS_HW_NRF_TWIM130
261+
I2C_NRFX_TWIM_RTIO_DEVICE(130);
262+
#endif
263+
264+
#ifdef CONFIG_HAS_HW_NRF_TWIM131
265+
I2C_NRFX_TWIM_RTIO_DEVICE(131);
266+
#endif
267+
268+
#ifdef CONFIG_HAS_HW_NRF_TWIM132
269+
I2C_NRFX_TWIM_RTIO_DEVICE(132);
270+
#endif
271+
272+
#ifdef CONFIG_HAS_HW_NRF_TWIM133
273+
I2C_NRFX_TWIM_RTIO_DEVICE(133);
274+
#endif
275+
276+
#ifdef CONFIG_HAS_HW_NRF_TWIM134
277+
I2C_NRFX_TWIM_RTIO_DEVICE(134);
278+
#endif
279+
280+
#ifdef CONFIG_HAS_HW_NRF_TWIM135
281+
I2C_NRFX_TWIM_RTIO_DEVICE(135);
282+
#endif
283+
284+
#ifdef CONFIG_HAS_HW_NRF_TWIM136
285+
I2C_NRFX_TWIM_RTIO_DEVICE(136);
286+
#endif
287+
288+
#ifdef CONFIG_HAS_HW_NRF_TWIM137
289+
I2C_NRFX_TWIM_RTIO_DEVICE(137);
290+
#endif

0 commit comments

Comments
 (0)