Skip to content

Commit 6f2ce2c

Browse files
committed
[nrf fromlist] drivers: i2c_nrfx_twim: add asynchronous write and exclusive access API
This commit provides an extension to the i2c_nrfx_twim driver. It introduces possibility to: - acquire/release exclusive access to the i2c bus - perform asynchronous i2c write transfers. The provided API is necessary for use cases when, i2c transfers must be started from interrupt context, while still allowing to share the i2c bus in multi-tasking environment. Upstream PR #: 86721 Signed-off-by: Andrzej Kuros <[email protected]>
1 parent 6dc8dcd commit 6f2ce2c

File tree

2 files changed

+124
-6
lines changed

2 files changed

+124
-6
lines changed

drivers/i2c/i2c_nrfx_twim.c

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include <zephyr/drivers/i2c.h>
8+
#include <zephyr/drivers/i2c/i2c_nrfx_twim.h>
89
#include <zephyr/dt-bindings/i2c/i2c.h>
910
#include <zephyr/pm/device.h>
1011
#include <zephyr/pm/device_runtime.h>
@@ -31,8 +32,57 @@ struct i2c_nrfx_twim_data {
3132
struct k_sem transfer_sync;
3233
struct k_sem completion_sync;
3334
volatile nrfx_err_t res;
35+
i2c_nrfx_twim_async_transfer_handler_t async_transfer_handler;
36+
void *async_transfer_handler_ctx;
3437
};
3538

39+
int i2c_nrfx_twim_exclusive_access_acquire(const struct device *dev, k_timeout_t timeout)
40+
{
41+
struct i2c_nrfx_twim_data *dev_data = dev->data;
42+
int ret;
43+
44+
ret = k_sem_take(&dev_data->transfer_sync, timeout);
45+
46+
if (ret == 0) {
47+
(void)pm_device_runtime_get(dev);
48+
}
49+
50+
return ret;
51+
}
52+
53+
void i2c_nrfx_twim_exclusive_access_release(const struct device *dev)
54+
{
55+
struct i2c_nrfx_twim_data *dev_data = dev->data;
56+
57+
(void)pm_device_runtime_put(dev);
58+
59+
k_sem_give(&dev_data->transfer_sync);
60+
}
61+
62+
int i2c_nrfx_twim_async_transfer_begin(const struct device *dev, struct i2c_msg *msg, uint16_t addr,
63+
i2c_nrfx_twim_async_transfer_handler_t handler, void *ctx)
64+
{
65+
struct i2c_nrfx_twim_data *dev_data = dev->data;
66+
const struct i2c_nrfx_twim_common_config *dev_config = dev->config;
67+
68+
if (I2C_MSG_ADDR_10_BITS & msg->flags) {
69+
return -ENOTSUP;
70+
}
71+
72+
if (!nrf_dma_accessible_check(&dev_config->twim, msg->buf)) {
73+
return -ENOTSUP;
74+
}
75+
76+
if (handler == NULL) {
77+
return -ENOTSUP;
78+
}
79+
80+
dev_data->async_transfer_handler = handler;
81+
dev_data->async_transfer_handler_ctx = ctx;
82+
83+
return i2c_nrfx_twim_msg_transfer(dev, msg->flags, msg->buf, msg->len, addr);
84+
}
85+
3686
static int i2c_nrfx_twim_transfer(const struct device *dev,
3787
struct i2c_msg *msgs,
3888
uint8_t num_msgs, uint16_t addr)
@@ -46,13 +96,11 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
4696
uint8_t *buf;
4797
uint16_t buf_len;
4898

49-
k_sem_take(&dev_data->transfer_sync, K_FOREVER);
99+
(void)i2c_nrfx_twim_exclusive_access_acquire(dev, K_FOREVER);
50100

51101
/* Dummy take on completion_sync sem to be sure that it is empty */
52102
k_sem_take(&dev_data->completion_sync, K_NO_WAIT);
53103

54-
(void)pm_device_runtime_get(dev);
55-
56104
for (size_t i = 0; i < num_msgs; i++) {
57105
if (I2C_MSG_ADDR_10_BITS & msgs[i].flags) {
58106
ret = -ENOTSUP;
@@ -164,9 +212,7 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
164212
msg_buf_used = 0;
165213
}
166214

167-
(void)pm_device_runtime_put(dev);
168-
169-
k_sem_give(&dev_data->transfer_sync);
215+
i2c_nrfx_twim_exclusive_access_release(dev);
170216

171217
return ret;
172218
}
@@ -191,6 +237,15 @@ static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context)
191237
break;
192238
}
193239

240+
if (dev_data->async_transfer_handler != NULL) {
241+
i2c_nrfx_twim_async_transfer_handler_t handler = dev_data->async_transfer_handler;
242+
void *ctx = dev_data->async_transfer_handler_ctx;
243+
244+
dev_data->async_transfer_handler = NULL;
245+
handler(dev, dev_data->res == NRFX_SUCCESS ? 0 : -EIO, ctx);
246+
return;
247+
}
248+
194249
k_sem_give(&dev_data->completion_sync);
195250
}
196251

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_DRIVERS_I2C_NRFX_TWIM_H
8+
#define ZEPHYR_INCLUDE_DRIVERS_I2C_NRFX_TWIM_H
9+
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/drivers/i2c.h>
12+
13+
/** @brief Acquires exclusive access to the i2c bus controller.
14+
*
15+
* @param dev Pointer to the device structure for an I2C controller
16+
* driver configured in controller mode.
17+
* @param timeout Timeout for waiting to acquire exclusive access.
18+
*
19+
* @retval 0 If successful.
20+
* @retval -EBUSY Returned without waiting.
21+
* @retval -EAGAIN Waiting period timed out,
22+
* or the underlying semaphore was reset during the waiting period.
23+
*/
24+
int i2c_nrfx_twim_exclusive_access_acquire(const struct device *dev, k_timeout_t timeout);
25+
26+
/** @brief Releases exclusive access to the i2c bus controller.
27+
*
28+
* @param dev Pointer to the device structure for an I2C controller
29+
* driver on which @ref i2c_nrfx_twim_exclusive_access_acquire
30+
* has been successfully called.
31+
*/
32+
void i2c_nrfx_twim_exclusive_access_release(const struct device *dev);
33+
34+
/** @brief Type of callback that finishes an asynchronous transfer.
35+
*
36+
* @param dev Pointer to the device structure for an I2C controller driver.
37+
* @param res Result of a transfer.
38+
* @param ctx Opaque pointer for providing a context passed to
39+
* @ref i2c_nrfx_twim_async_transfer_begin .
40+
*/
41+
typedef void (*i2c_nrfx_twim_async_transfer_handler_t)(const struct device *dev, int res,
42+
void *ctx);
43+
44+
/** @brief Begins an asynchronous write transfer on a I2C bus.
45+
*
46+
* @note This function may be called only when the exclusive access to the bus is granted.
47+
* See @ref i2c_nrfx_twim_exclusive_access_acquire .
48+
*
49+
* @param dev Pointer to the device structure for an I2C controller
50+
* driver configured in controller mode.
51+
* @param msg Message to transfer.
52+
* @param addr Address of the I2C target device.
53+
* @param handler Pointer to a callback function that will be called from an I2C
54+
* interrupt handler that notifies end of the transfer.
55+
* @param ctx Opaque pointer passed to the @p handler for passing context.
56+
*
57+
* @return @c 0 on success, the @p handler will be called in future.
58+
* Other values indicate an error, the @p handler will not be called.
59+
*/
60+
int i2c_nrfx_twim_async_transfer_begin(const struct device *dev, struct i2c_msg *msg, uint16_t addr,
61+
i2c_nrfx_twim_async_transfer_handler_t handler, void *ctx);
62+
63+
#endif /* ZEPHYR_INCLUDE_DRIVERS_I2C_NRFX_TWIM_H */

0 commit comments

Comments
 (0)