Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions drivers/i2c/i2c_nrfx_twim.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/i2c/i2c_nrfx_twim.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
Expand All @@ -31,8 +32,64 @@ struct i2c_nrfx_twim_data {
struct k_sem transfer_sync;
struct k_sem completion_sync;
volatile nrfx_err_t res;
i2c_nrfx_twim_async_transfer_handler_t async_transfer_handler;
void *async_transfer_handler_ctx;
};

int i2c_nrfx_twim_exclusive_access_acquire(const struct device *dev, k_timeout_t timeout)
{
struct i2c_nrfx_twim_data *dev_data = dev->data;
int ret;

ret = k_sem_take(&dev_data->transfer_sync, timeout);

if (ret == 0) {
(void)pm_device_runtime_get(dev);
}

return ret;
}

void i2c_nrfx_twim_exclusive_access_release(const struct device *dev)
{
struct i2c_nrfx_twim_data *dev_data = dev->data;

(void)pm_device_runtime_put(dev);

k_sem_give(&dev_data->transfer_sync);
}

int i2c_nrfx_twim_async_transfer_begin(const struct device *dev, struct i2c_msg *msg, uint16_t addr,
i2c_nrfx_twim_async_transfer_handler_t handler, void *ctx)
{
struct i2c_nrfx_twim_data *dev_data = dev->data;
const struct i2c_nrfx_twim_common_config *dev_config = dev->config;
uint8_t *buf;

if (I2C_MSG_ADDR_10_BITS & msg->flags) {
return -ENOTSUP;
}

if (!nrf_dma_accessible_check(&dev_config->twim, msg->buf)) {
if (msg->len > dev_config->msg_buf_size) {
return -ENOSPC;
}
memcpy(dev_config->msg_buf, msg->buf, msg->len);
buf = dev_config->msg_buf;
} else {
buf = msg->buf;
}

if (handler == NULL) {
return -ENOTSUP;
}

dev_data->async_transfer_handler = handler;
dev_data->async_transfer_handler_ctx = ctx;

return i2c_nrfx_twim_msg_transfer(dev, msg->flags, buf, msg->len, addr);
}

static int i2c_nrfx_twim_transfer(const struct device *dev,
struct i2c_msg *msgs,
uint8_t num_msgs, uint16_t addr)
Expand All @@ -46,13 +103,11 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
uint8_t *buf;
uint16_t buf_len;

k_sem_take(&dev_data->transfer_sync, K_FOREVER);
(void)i2c_nrfx_twim_exclusive_access_acquire(dev, K_FOREVER);

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

(void)pm_device_runtime_get(dev);

for (size_t i = 0; i < num_msgs; i++) {
if (I2C_MSG_ADDR_10_BITS & msgs[i].flags) {
ret = -ENOTSUP;
Expand Down Expand Up @@ -164,9 +219,7 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
msg_buf_used = 0;
}

(void)pm_device_runtime_put(dev);

k_sem_give(&dev_data->transfer_sync);
i2c_nrfx_twim_exclusive_access_release(dev);

return ret;
}
Expand All @@ -191,6 +244,15 @@ static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context)
break;
}

if (dev_data->async_transfer_handler != NULL) {
i2c_nrfx_twim_async_transfer_handler_t handler = dev_data->async_transfer_handler;
void *ctx = dev_data->async_transfer_handler_ctx;

dev_data->async_transfer_handler = NULL;
handler(dev, dev_data->res == NRFX_SUCCESS ? 0 : -EIO, ctx);
return;
}

k_sem_give(&dev_data->completion_sync);
}

Expand Down
63 changes: 63 additions & 0 deletions include/zephyr/drivers/i2c/i2c_nrfx_twim.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_DRIVERS_I2C_NRFX_TWIM_H
#define ZEPHYR_INCLUDE_DRIVERS_I2C_NRFX_TWIM_H

#include <zephyr/kernel.h>
#include <zephyr/drivers/i2c.h>

/** @brief Acquires exclusive access to the i2c bus controller.
*
* @param dev Pointer to the device structure for an I2C controller
* driver configured in controller mode.
* @param timeout Timeout for waiting to acquire exclusive access.
*
* @retval 0 If successful.
* @retval -EBUSY Returned without waiting.
* @retval -EAGAIN Waiting period timed out,
* or the underlying semaphore was reset during the waiting period.
*/
int i2c_nrfx_twim_exclusive_access_acquire(const struct device *dev, k_timeout_t timeout);

/** @brief Releases exclusive access to the i2c bus controller.
*
* @param dev Pointer to the device structure for an I2C controller
* driver on which @ref i2c_nrfx_twim_exclusive_access_acquire
* has been successfully called.
*/
void i2c_nrfx_twim_exclusive_access_release(const struct device *dev);

/** @brief Type of callback that finishes an asynchronous transfer.
*
* @param dev Pointer to the device structure for an I2C controller driver.
* @param res Result of a transfer.
* @param ctx Opaque pointer for providing a context passed to
* @ref i2c_nrfx_twim_async_transfer_begin .
*/
typedef void (*i2c_nrfx_twim_async_transfer_handler_t)(const struct device *dev, int res,
void *ctx);

/** @brief Begins an asynchronous write transfer on a I2C bus.
*
* @note This function may be called only when the exclusive access to the bus is granted.
* See @ref i2c_nrfx_twim_exclusive_access_acquire .
*
* @param dev Pointer to the device structure for an I2C controller
* driver configured in controller mode.
* @param msg Message to transfer.
* @param addr Address of the I2C target device.
* @param handler Pointer to a callback function that will be called from an I2C
* interrupt handler that notifies end of the transfer.
* @param ctx Opaque pointer passed to the @p handler for passing context.
*
* @return @c 0 on success, the @p handler will be called in future.
* Other values indicate an error, the @p handler will not be called.
*/
int i2c_nrfx_twim_async_transfer_begin(const struct device *dev, struct i2c_msg *msg, uint16_t addr,
i2c_nrfx_twim_async_transfer_handler_t handler, void *ctx);

#endif /* ZEPHYR_INCLUDE_DRIVERS_I2C_NRFX_TWIM_H */
8 changes: 8 additions & 0 deletions tests/drivers/i2c/i2c_nrfx_twim/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(i2c_api)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

/*
* SDA = P0.26 and P1.2
* SCL = P0.25 and P1.3
*/

/ {
aliases {
i2c-controller = &i2c1;
i2c-controller-target = &i2c2;
};
};

&pinctrl {
i2c2_default: i2c2_default {
group1 {
psels = <NRF_PSEL(TWIS_SDA, 0, 26)>,
<NRF_PSEL(TWIS_SCL, 0, 25)>;
bias-pull-up;
};
};

i2c2_sleep: i2c2_sleep {
group1 {
psels = <NRF_PSEL(TWIS_SDA, 0, 26)>,
<NRF_PSEL(TWIS_SCL, 0, 25)>;
low-power-enable;
};
};
};

&i2c2 {
compatible = "nordic,nrf-twis";
pinctrl-0 = <&i2c2_default>;
pinctrl-1 = <&i2c2_sleep>;
pinctrl-names = "default", "sleep";
status = "okay";
};

&i2c1 {
compatible = "nordic,nrf-twim";
zephyr,concat-buf-size = <256>;
status = "okay";
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

/*
* SDA = P2.8 and P2.9
* SCL = P1.2 and P1.3
*/

/ {
aliases {
i2c-controller = &i2c130;
i2c-controller-target = &i2c131;
};
};

&pinctrl {
i2c130_default: i2c130_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 2, 8)>,
<NRF_PSEL(TWIM_SCL, 1, 2)>;
bias-pull-up;
};
};

i2c130_sleep: i2c130_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 2, 8)>,
<NRF_PSEL(TWIM_SCL, 1, 2)>;
low-power-enable;
};
};

i2c131_default: i2c131_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 2, 9)>,
<NRF_PSEL(TWIM_SCL, 1, 3)>;
bias-pull-up;
};
};

i2c131_sleep: i2c131_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 2, 9)>,
<NRF_PSEL(TWIM_SCL, 1, 3)>;
low-power-enable;
};
};
};

&i2c130 {
compatible = "nordic,nrf-twim";
clock-frequency = <I2C_BITRATE_STANDARD>;
pinctrl-0 = <&i2c130_default>;
pinctrl-1 = <&i2c130_sleep>;
pinctrl-names = "default", "sleep";
zephyr,concat-buf-size = <256>;
memory-regions = <&cpuapp_dma_region>;
status = "okay";
};

&i2c131 {
compatible = "nordic,nrf-twis";
clock-frequency = <I2C_BITRATE_STANDARD>;
pinctrl-0 = <&i2c131_default>;
pinctrl-1 = <&i2c131_sleep>;
pinctrl-names = "default", "sleep";
memory-regions = <&cpuapp_dma_region>;
status = "okay";
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

/*
* SDA = P1.8 and P1.9
* SCL = P1.10 and P1.11
*/

/ {
aliases {
i2c-controller = &i2c21;
i2c-controller-target = &i2c22;
};
};

&pinctrl {
i2c21_default: i2c21_default {
group1 {
psels = <NRF_PSEL(TWIS_SDA, 1, 8)>,
<NRF_PSEL(TWIS_SCL, 1, 10)>;
bias-pull-up;
};
};

i2c21_sleep: i2c21_sleep {
group1 {
psels = <NRF_PSEL(TWIS_SDA, 1, 8)>,
<NRF_PSEL(TWIS_SCL, 1, 10)>;
low-power-enable;
};
};

i2c22_default: i2c22_default {
group1 {
psels = <NRF_PSEL(TWIS_SDA, 1, 9)>,
<NRF_PSEL(TWIS_SCL, 1, 11)>;
bias-pull-up;
};
};

i2c22_sleep: i2c22_sleep {
group1 {
psels = <NRF_PSEL(TWIS_SDA, 1, 9)>,
<NRF_PSEL(TWIS_SCL, 1, 11)>;
low-power-enable;
};
};
};

&i2c21 {
compatible = "nordic,nrf-twim";
pinctrl-0 = <&i2c21_default>;
pinctrl-1 = <&i2c21_sleep>;
pinctrl-names = "default", "sleep";
zephyr,concat-buf-size = <256>;
status = "okay";
};

&i2c22 {
compatible = "nordic,nrf-twis";
pinctrl-0 = <&i2c22_default>;
pinctrl-1 = <&i2c22_sleep>;
pinctrl-names = "default", "sleep";
status = "okay";
};
11 changes: 11 additions & 0 deletions tests/drivers/i2c/i2c_nrfx_twim/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CONFIG_ZTEST=y
CONFIG_BOOT_BANNER=n

CONFIG_LOG=y
CONFIG_I2C_LOG_LEVEL_INF=y
CONFIG_I2C=y
CONFIG_I2C_TARGET=y
CONFIG_I2C_TARGET_BUFFER_MODE=y
CONFIG_I2C_NRFX_TWIS_BUF_SIZE=256

CONFIG_ZERO_LATENCY_IRQS=y
Loading