Skip to content
Open
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
3 changes: 1 addition & 2 deletions drivers/i2s/Kconfig.nrfx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ menuconfig I2S_NRFX
bool "nRF I2S nrfx driver"
default y
depends on DT_HAS_NORDIC_NRF_I2S_ENABLED
select NRFX_I2S0 if HAS_HW_NRF_I2S0
select NRFX_I2S20 if HAS_HW_NRF_I2S20
select NRFX_I2S
select PINCTRL
help
Enable support for nrfx I2S driver for nRF MCU series.
Expand Down
175 changes: 80 additions & 95 deletions drivers/i2s/i2s_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT nordic_nrf_i2s

#include <stdlib.h>
#include <zephyr/drivers/i2s.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
Expand Down Expand Up @@ -33,21 +35,20 @@ struct i2s_nrfx_drv_data {
struct k_msgq tx_queue;
struct stream_cfg rx;
struct k_msgq rx_queue;
const nrfx_i2s_t *p_i2s;
nrfx_i2s_t i2s;
const uint32_t *last_tx_buffer;
enum i2s_state state;
enum i2s_dir active_dir;
bool stop; /* stop after the current (TX or RX) block */
bool discard_rx; /* discard further RX blocks */
volatile bool next_tx_buffer_needed;
bool tx_configured : 1;
bool rx_configured : 1;
bool request_clock : 1;
bool tx_configured: 1;
bool rx_configured: 1;
bool request_clock: 1;
};

struct i2s_nrfx_drv_cfg {
nrfx_i2s_data_handler_t data_handler;
nrfx_i2s_t i2s;
nrfx_i2s_config_t nrfx_def_cfg;
const struct pinctrl_dev_config *pcfg;
enum clock_source {
Expand Down Expand Up @@ -81,7 +82,7 @@ static void find_suitable_clock(const struct i2s_nrfx_drv_cfg *drv_cfg,
.allow_bypass = IS_ENABLED(CONFIG_I2S_NRFX_ALLOW_MCK_BYPASS),
};

if (nrfx_i2s_prescalers_calc(&clk_params, &config->prescalers) != NRFX_SUCCESS) {
if (nrfx_i2s_prescalers_calc(&clk_params, &config->prescalers) != 0) {
LOG_ERR("Failed to find suitable I2S clock configuration.");
}
}
Expand Down Expand Up @@ -134,7 +135,7 @@ static bool supply_next_buffers(struct i2s_nrfx_drv_data *drv_data,
if (drv_data->active_dir != I2S_DIR_TX) { /* -> RX active */
if (!get_next_rx_buffer(drv_data, next)) {
drv_data->state = I2S_STATE_ERROR;
nrfx_i2s_stop(drv_data->p_i2s);
nrfx_i2s_stop(&drv_data->i2s);
return false;
}
/* Set buffer size if there is no TX buffer (which effectively
Expand All @@ -149,7 +150,7 @@ static bool supply_next_buffers(struct i2s_nrfx_drv_data *drv_data,
drv_data->last_tx_buffer = next->p_tx_buffer;

LOG_DBG("Next buffers: %p/%p", next->p_tx_buffer, next->p_rx_buffer);
nrfx_i2s_next_buffers_set(drv_data->p_i2s, next);
nrfx_i2s_next_buffers_set(&drv_data->i2s, next);
return true;
}

Expand Down Expand Up @@ -181,7 +182,7 @@ static void data_handler(const struct device *dev,
}
drv_data->last_tx_buffer = NULL;
}
nrfx_i2s_uninit(drv_data->p_i2s);
nrfx_i2s_uninit(&drv_data->i2s);
if (drv_data->request_clock) {
(void)onoff_release(drv_data->clk_mgr);
}
Expand All @@ -198,7 +199,7 @@ static void data_handler(const struct device *dev,
LOG_ERR("Next buffers not supplied on time");
drv_data->state = I2S_STATE_ERROR;
}
nrfx_i2s_stop(drv_data->p_i2s);
nrfx_i2s_stop(&drv_data->i2s);
return;
}

Expand Down Expand Up @@ -248,7 +249,7 @@ static void data_handler(const struct device *dev,
}

if (stop_transfer) {
nrfx_i2s_stop(drv_data->p_i2s);
nrfx_i2s_stop(&drv_data->i2s);
} else if (status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED) {
nrfx_i2s_buffers_t next = { 0 };

Expand Down Expand Up @@ -419,8 +420,8 @@ static int i2s_nrfx_configure(const struct device *dev, enum i2s_dir dir,
* the MCK output is used), find a suitable clock configuration for it.
*/
if (nrfx_cfg.mode == NRF_I2S_MODE_MASTER ||
(nrf_i2s_mck_pin_get(drv_cfg->i2s.p_reg) & I2S_PSEL_MCK_CONNECT_Msk)
== I2S_PSEL_MCK_CONNECT_Connected << I2S_PSEL_MCK_CONNECT_Pos) {
(nrf_i2s_mck_pin_get(drv_data->i2s.p_reg) & I2S_PSEL_MCK_CONNECT_Msk) ==
I2S_PSEL_MCK_CONNECT_Connected << I2S_PSEL_MCK_CONNECT_Pos) {
find_suitable_clock(drv_cfg, &nrfx_cfg, i2s_cfg);
/* Unless the PCLK32M source is used with the HFINT oscillator
* (which is always available without any additional actions),
Expand Down Expand Up @@ -578,7 +579,7 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data)
/* Failed to allocate next RX buffer */
ret = -ENOMEM;
} else {
nrfx_err_t err;
int err;

/* It is necessary to set buffer size here only for I2S_DIR_RX,
* because only then the get_next_tx_buffer() call in the if
Expand All @@ -591,16 +592,16 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data)

drv_data->last_tx_buffer = initial_buffers.p_tx_buffer;

err = nrfx_i2s_start(drv_data->p_i2s, &initial_buffers, 0);
if (err == NRFX_SUCCESS) {
err = nrfx_i2s_start(&drv_data->i2s, &initial_buffers, 0);
if (err == 0) {
return 0;
}

LOG_ERR("Failed to start I2S transfer: 0x%08x", err);
LOG_ERR("Failed to start I2S transfer: %d", err);
ret = -EIO;
}

nrfx_i2s_uninit(drv_data->p_i2s);
nrfx_i2s_uninit(&drv_data->i2s);
if (drv_data->request_clock) {
(void)onoff_release(drv_data->clk_mgr);
}
Expand Down Expand Up @@ -629,7 +630,7 @@ static void clock_started_callback(struct onoff_manager *mgr,
* the actual transfer in such case.
*/
if (drv_data->state == I2S_STATE_READY) {
nrfx_i2s_uninit(drv_data->p_i2s);
nrfx_i2s_uninit(&drv_data->i2s);
(void)onoff_release(drv_data->clk_mgr);
} else {
(void)start_transfer(drv_data);
Expand All @@ -640,22 +641,22 @@ static int trigger_start(const struct device *dev)
{
struct i2s_nrfx_drv_data *drv_data = dev->data;
const struct i2s_nrfx_drv_cfg *drv_cfg = dev->config;
nrfx_err_t err;
int err;
int ret;
const nrfx_i2s_config_t *nrfx_cfg = (drv_data->active_dir == I2S_DIR_TX)
? &drv_data->tx.nrfx_cfg
: &drv_data->rx.nrfx_cfg;

err = nrfx_i2s_init(drv_data->p_i2s, nrfx_cfg, drv_cfg->data_handler);
if (err != NRFX_SUCCESS) {
LOG_ERR("Failed to initialize I2S: 0x%08x", err);
err = nrfx_i2s_init(&drv_data->i2s, nrfx_cfg, drv_cfg->data_handler);
if (err != 0) {
LOG_ERR("Failed to initialize I2S: %d", err);
return -EIO;
}

drv_data->state = I2S_STATE_RUNNING;

#if NRF_I2S_HAS_CLKCONFIG
nrf_i2s_clk_configure(drv_cfg->i2s.p_reg,
nrf_i2s_clk_configure(drv_data->i2s.p_reg,
drv_cfg->clk_src == ACLK ? NRF_I2S_CLKSRC_ACLK
: NRF_I2S_CLKSRC_PCLK32M,
nrfx_cfg->prescalers.enable_bypass);
Expand All @@ -669,7 +670,7 @@ static int trigger_start(const struct device *dev)
clock_started_callback);
ret = onoff_request(drv_data->clk_mgr, &drv_data->clk_cli);
if (ret < 0) {
nrfx_i2s_uninit(drv_data->p_i2s);
nrfx_i2s_uninit(&drv_data->i2s);
drv_data->state = I2S_STATE_READY;

LOG_ERR("Failed to request clock: %d", ret);
Expand Down Expand Up @@ -776,7 +777,7 @@ static int i2s_nrfx_trigger(const struct device *dev,
case I2S_TRIGGER_DROP:
if (drv_data->state != I2S_STATE_READY) {
drv_data->discard_rx = true;
nrfx_i2s_stop(drv_data->p_i2s);
nrfx_i2s_stop(&drv_data->i2s);
}
purge_queue(dev, dir);
drv_data->state = I2S_STATE_READY;
Expand Down Expand Up @@ -821,72 +822,56 @@ static DEVICE_API(i2s, i2s_nrf_drv_api) = {
.trigger = i2s_nrfx_trigger,
};

#define I2S(idx) DT_NODELABEL(i2s##idx)
#define I2S_CLK_SRC(idx) DT_STRING_TOKEN(I2S(idx), clock_source)

#define I2S_NRFX_DEVICE(idx) \
static struct i2s_buf tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \
static struct i2s_buf rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \
static void data_handler##idx(nrfx_i2s_buffers_t const *p_released, \
uint32_t status) \
{ \
data_handler(DEVICE_DT_GET(I2S(idx)), p_released, status); \
} \
PINCTRL_DT_DEFINE(I2S(idx)); \
static const struct i2s_nrfx_drv_cfg i2s_nrfx_cfg##idx = { \
.data_handler = data_handler##idx, \
.i2s = NRFX_I2S_INSTANCE(idx), \
.nrfx_def_cfg = NRFX_I2S_DEFAULT_CONFIG( \
NRF_I2S_PIN_NOT_CONNECTED, \
NRF_I2S_PIN_NOT_CONNECTED, \
NRF_I2S_PIN_NOT_CONNECTED, \
NRF_I2S_PIN_NOT_CONNECTED, \
NRF_I2S_PIN_NOT_CONNECTED), \
.nrfx_def_cfg.skip_gpio_cfg = true, \
.nrfx_def_cfg.skip_psel_cfg = true, \
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(I2S(idx)), \
.clk_src = I2S_CLK_SRC(idx), \
}; \
static struct i2s_nrfx_drv_data i2s_nrfx_data##idx = { \
.state = I2S_STATE_READY, \
.p_i2s = &i2s_nrfx_cfg##idx.i2s \
}; \
static int i2s_nrfx_init##idx(const struct device *dev) \
{ \
IRQ_CONNECT(DT_IRQN(I2S(idx)), DT_IRQ(I2S(idx), priority), \
nrfx_isr, nrfx_i2s_##idx##_irq_handler, 0); \
const struct i2s_nrfx_drv_cfg *drv_cfg = dev->config; \
int err = pinctrl_apply_state(drv_cfg->pcfg, \
PINCTRL_STATE_DEFAULT); \
if (err < 0) { \
return err; \
} \
k_msgq_init(&i2s_nrfx_data##idx.tx_queue, \
(char *)tx_msgs##idx, sizeof(struct i2s_buf), \
ARRAY_SIZE(tx_msgs##idx)); \
k_msgq_init(&i2s_nrfx_data##idx.rx_queue, \
(char *)rx_msgs##idx, sizeof(struct i2s_buf), \
ARRAY_SIZE(rx_msgs##idx)); \
init_clock_manager(dev); \
return 0; \
} \
BUILD_ASSERT(I2S_CLK_SRC(idx) != ACLK || \
(NRF_I2S_HAS_CLKCONFIG && NRF_CLOCK_HAS_HFCLKAUDIO), \
"Clock source ACLK is not available."); \
BUILD_ASSERT(I2S_CLK_SRC(idx) != ACLK || \
DT_NODE_HAS_PROP(DT_NODELABEL(clock), \
hfclkaudio_frequency), \
"Clock source ACLK requires the hfclkaudio-frequency " \
"property to be defined in the nordic,nrf-clock node."); \
DEVICE_DT_DEFINE(I2S(idx), i2s_nrfx_init##idx, NULL, \
&i2s_nrfx_data##idx, &i2s_nrfx_cfg##idx, \
POST_KERNEL, CONFIG_I2S_INIT_PRIORITY, \
&i2s_nrf_drv_api);

#ifdef CONFIG_HAS_HW_NRF_I2S0
I2S_NRFX_DEVICE(0);
#endif

#ifdef CONFIG_HAS_HW_NRF_I2S20
I2S_NRFX_DEVICE(20);
#endif
#define I2S_CLK_SRC(inst) DT_STRING_TOKEN(DT_DRV_INST(inst), clock_source)

#define I2S_NRFX_DEVICE(inst) \
static struct i2s_buf tx_msgs##inst[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \
static struct i2s_buf rx_msgs##inst[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \
static void data_handler##inst(nrfx_i2s_buffers_t const *p_released, uint32_t status) \
{ \
data_handler(DEVICE_DT_GET(DT_DRV_INST(inst)), p_released, status); \
} \
PINCTRL_DT_DEFINE(DT_DRV_INST(inst)); \
static const struct i2s_nrfx_drv_cfg i2s_nrfx_cfg##inst = { \
.data_handler = data_handler##inst, \
.nrfx_def_cfg = NRFX_I2S_DEFAULT_CONFIG( \
NRF_I2S_PIN_NOT_CONNECTED, NRF_I2S_PIN_NOT_CONNECTED, \
NRF_I2S_PIN_NOT_CONNECTED, NRF_I2S_PIN_NOT_CONNECTED, \
NRF_I2S_PIN_NOT_CONNECTED), \
.nrfx_def_cfg.skip_gpio_cfg = true, \
.nrfx_def_cfg.skip_psel_cfg = true, \
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_DRV_INST(inst)), \
.clk_src = I2S_CLK_SRC(inst), \
}; \
static struct i2s_nrfx_drv_data i2s_nrfx_data##inst = { \
.state = I2S_STATE_READY, \
.i2s = NRFX_I2S_INSTANCE(DT_INST_REG_ADDR(inst)), \
}; \
static int i2s_nrfx_init##inst(const struct device *dev) \
{ \
IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), nrfx_i2s_irq_handler, \
&i2s_nrfx_data##inst.i2s, 0); \
const struct i2s_nrfx_drv_cfg *drv_cfg = dev->config; \
int err = pinctrl_apply_state(drv_cfg->pcfg, PINCTRL_STATE_DEFAULT); \
if (err < 0) { \
return err; \
} \
k_msgq_init(&i2s_nrfx_data##inst.tx_queue, (char *)tx_msgs##inst, \
sizeof(struct i2s_buf), ARRAY_SIZE(tx_msgs##inst)); \
k_msgq_init(&i2s_nrfx_data##inst.rx_queue, (char *)rx_msgs##inst, \
sizeof(struct i2s_buf), ARRAY_SIZE(rx_msgs##inst)); \
init_clock_manager(dev); \
return 0; \
} \
BUILD_ASSERT(I2S_CLK_SRC(inst) != ACLK || \
(NRF_I2S_HAS_CLKCONFIG && NRF_CLOCK_HAS_HFCLKAUDIO), \
"Clock source ACLK is not available."); \
BUILD_ASSERT(I2S_CLK_SRC(inst) != ACLK || \
DT_NODE_HAS_PROP(DT_NODELABEL(clock), hfclkaudio_frequency), \
"Clock source ACLK requires the hfclkaudio-frequency " \
"property to be defined in the nordic,nrf-clock node."); \
DEVICE_DT_INST_DEFINE(inst, i2s_nrfx_init##inst, NULL, &i2s_nrfx_data##inst, \
&i2s_nrfx_cfg##inst, POST_KERNEL, CONFIG_I2S_INIT_PRIORITY, \
&i2s_nrf_drv_api);

DT_INST_FOREACH_STATUS_OKAY(I2S_NRFX_DEVICE)
12 changes: 1 addition & 11 deletions modules/hal_nordic/nrfx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -252,17 +252,7 @@ config NRFX_GRTC
depends on $(dt_nodelabel_exists,grtc)

config NRFX_I2S
bool

config NRFX_I2S0
bool "I2S0 driver instance"
depends on $(dt_nodelabel_exists,i2s0)
select NRFX_I2S

config NRFX_I2S20
bool "I2S20 driver instance"
depends on $(dt_nodelabel_exists,i2s20)
select NRFX_I2S
bool "I2S driver"

config NRFX_IPC
bool "IPC driver"
Expand Down
24 changes: 24 additions & 0 deletions modules/hal_nordic/nrfx/nrfx_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,27 @@
default: return "unknown";
}
}

char const *nrfx_new_error_string_get(int code)
{
#define NRFX_NEW_ERROR_STRING_CASE(code) \

Check warning on line 51 in modules/hal_nordic/nrfx/nrfx_glue.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

MACRO_WITH_FLOW_CONTROL

modules/hal_nordic/nrfx/nrfx_glue.c:51 Macros with flow control statements should be avoided
case code: \
return #code
switch (-code) {
NRFX_NEW_ERROR_STRING_CASE(0);
NRFX_NEW_ERROR_STRING_CASE(ECANCELED);
NRFX_NEW_ERROR_STRING_CASE(ENOMEM);
NRFX_NEW_ERROR_STRING_CASE(ENOTSUP);
NRFX_NEW_ERROR_STRING_CASE(EINVAL);
NRFX_NEW_ERROR_STRING_CASE(EINPROGRESS);
NRFX_NEW_ERROR_STRING_CASE(E2BIG);
NRFX_NEW_ERROR_STRING_CASE(ETIMEDOUT);
NRFX_NEW_ERROR_STRING_CASE(EPERM);
NRFX_NEW_ERROR_STRING_CASE(EFAULT);
NRFX_NEW_ERROR_STRING_CASE(EACCES);
NRFX_NEW_ERROR_STRING_CASE(EBUSY);
NRFX_NEW_ERROR_STRING_CASE(EALREADY);
default:
return "unknown";
}
}
6 changes: 0 additions & 6 deletions modules/hal_nordic/nrfx/nrfx_kconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,6 @@
#ifdef CONFIG_NRFX_I2S_LOG
#define NRFX_I2S_CONFIG_LOG_ENABLED 1
#endif
#ifdef CONFIG_NRFX_I2S0
#define NRFX_I2S0_ENABLED 1
#endif
#ifdef CONFIG_NRFX_I2S20
#define NRFX_I2S20_ENABLED 1
#endif

#ifdef CONFIG_NRFX_IPC
#define NRFX_IPC_ENABLED 1
Expand Down
10 changes: 10 additions & 0 deletions modules/hal_nordic/nrfx/nrfx_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ LOG_MODULE_REGISTER(NRFX_MODULE_PREFIX, NRFX_MODULE_LOG_LEVEL);
#define NRFX_LOG_ERROR_STRING_GET(error_code) nrfx_error_string_get(error_code)
extern char const *nrfx_error_string_get(nrfx_err_t code);

/**
* @brief Macro for getting the textual representation of a given errno error code.
*
* @param[in] error_code Errno error code.
*
* @return String containing the textual representation of the errno error code.
*/
#define NRFX_NEW_LOG_ERROR_STRING_GET(error_code) nrfx_new_error_string_get(error_code)
extern char const *nrfx_new_error_string_get(int code);

/** @} */

#ifdef __cplusplus
Expand Down
Loading
Loading