From 6e84121760cc8669b417d31837f900abe1d84264 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 15 Jul 2025 01:56:05 -0300 Subject: [PATCH 01/11] drivers: i2s: esp32: fix last block loss Avoids erroneous memory block freeing when stopping transfers Signed-off-by: Marcio Ribeiro --- drivers/i2s/i2s_esp32.c | 79 +++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 51 deletions(-) diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index d813b50a8415b..15d2a14d7fe83 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -55,7 +55,6 @@ struct i2s_esp32_stream_data { struct i2s_config i2s_cfg; void *mem_block; size_t mem_block_len; - bool last_block; bool stop_without_draining; struct k_msgq queue; struct intr_handle_data_t *irq_handle; @@ -175,6 +174,18 @@ static void i2s_esp32_rx_callback(void *arg, int status) const struct i2s_esp32_stream *stream = &dev_cfg->rx; int err; + if (!stream->data->dma_pending) { + return; + } + + stream->data->dma_pending = false; + + if (stream->data->mem_block == NULL) { + LOG_ERR("RX mem_block NULL"); + stream->data->state = I2S_STATE_ERROR; + goto rx_disable; + } + #if SOC_GDMA_SUPPORTED if (status < 0) { #else @@ -185,16 +196,6 @@ static void i2s_esp32_rx_callback(void *arg, int status) goto rx_disable; } - if (stream->data->mem_block == NULL) { - if (stream->data->state != I2S_STATE_READY) { - stream->data->state = I2S_STATE_ERROR; - LOG_ERR("RX mem_block NULL"); - goto rx_disable; - } else { - return; - } - } - #if SOC_GDMA_SUPPORTED const i2s_hal_context_t *hal = &(dev_cfg->hal); uint16_t chunk_len; @@ -339,11 +340,8 @@ static void i2s_esp32_rx_stop_transfer(const struct device *dev) i2s_hal_clear_intr_status(hal, I2S_INTR_MAX); #endif /* SOC_GDMA_SUPPORTED */ - if (stream->data->mem_block != NULL) { - k_mem_slab_free(stream->data->i2s_cfg.mem_slab, stream->data->mem_block); - stream->data->mem_block = NULL; - stream->data->mem_block_len = 0; - } + stream->data->mem_block = NULL; + stream->data->mem_block_len = 0; } #endif /* I2S_ESP32_IS_DIR_EN(rx) */ @@ -361,7 +359,6 @@ static void i2s_esp32_tx_callback(void *arg, int status) const struct i2s_esp32_cfg *const dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->tx; struct queue_item item; - void *mem_block_tmp; int err; if (!stream->data->dma_pending) { @@ -370,6 +367,14 @@ static void i2s_esp32_tx_callback(void *arg, int status) stream->data->dma_pending = false; + if (stream->data->mem_block == NULL) { + LOG_ERR("TX mem_block NULL"); + stream->data->state = I2S_STATE_ERROR; + goto tx_disable; + } + + k_mem_slab_free(stream->data->i2s_cfg.mem_slab, stream->data->mem_block); + #if SOC_GDMA_SUPPORTED if (status < 0) { #else @@ -380,32 +385,14 @@ static void i2s_esp32_tx_callback(void *arg, int status) goto tx_disable; } - if (stream->data->mem_block == NULL) { - if (stream->data->state != I2S_STATE_READY) { - stream->data->state = I2S_STATE_ERROR; - LOG_ERR("TX mem_block NULL"); - goto tx_disable; - } else { - return; - } - } - if (stream->data->state == I2S_STATE_STOPPING) { - if (k_msgq_num_used_get(&stream->data->queue) == 0) { - stream->data->state = I2S_STATE_READY; - goto tx_disable; - } else if (stream->data->stop_without_draining == true) { - stream->conf->queue_drop(stream); + if (k_msgq_num_used_get(&stream->data->queue) == 0 || + stream->data->stop_without_draining == true) { stream->data->state = I2S_STATE_READY; goto tx_disable; } } - if (stream->data->last_block) { - stream->data->state = I2S_STATE_READY; - goto tx_disable; - } - err = k_msgq_get(&stream->data->queue, &item, K_NO_WAIT); if (err < 0) { stream->data->state = I2S_STATE_ERROR; @@ -413,8 +400,6 @@ static void i2s_esp32_tx_callback(void *arg, int status) goto tx_disable; } - mem_block_tmp = stream->data->mem_block; - stream->data->mem_block = item.buffer; stream->data->mem_block_len = item.size; @@ -425,8 +410,6 @@ static void i2s_esp32_tx_callback(void *arg, int status) goto tx_disable; } - k_mem_slab_free(stream->data->i2s_cfg.mem_slab, mem_block_tmp); - return; tx_disable: @@ -502,11 +485,8 @@ static void i2s_esp32_tx_stop_transfer(const struct device *dev) i2s_hal_clear_intr_status(hal, I2S_INTR_MAX); #endif /* SOC_GDMA_SUPPORTED */ - if (stream->data->mem_block != NULL) { - k_mem_slab_free(stream->data->i2s_cfg.mem_slab, stream->data->mem_block); - stream->data->mem_block = NULL; - stream->data->mem_block_len = 0; - } + stream->data->mem_block = NULL; + stream->data->mem_block_len = 0; } #endif /* I2S_ESP32_IS_DIR_EN(tx) */ @@ -663,7 +643,6 @@ static int i2s_esp32_start_dma(const struct device *dev, enum i2s_dir dir) LOG_ERR("Failed to start DMA channel: %"PRIu32, stream->conf->dma_channel); goto unlock; } - stream->data->dma_pending = true; #else #if I2S_ESP32_IS_DIR_EN(rx) if (dir == I2S_DIR_RX) { @@ -682,6 +661,8 @@ static int i2s_esp32_start_dma(const struct device *dev, enum i2s_dir dir) #endif /* I2S_ESP32_IS_DIR_EN(tx) */ #endif /* SOC_GDMA_SUPPORTED */ + stream->data->dma_pending = true; + unlock: irq_unlock(key); return err; @@ -1227,7 +1208,6 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e irq_unlock(key); return -EIO; } - stream->data->last_block = false; stream->data->state = I2S_STATE_RUNNING; irq_unlock(key); break; @@ -1245,7 +1225,6 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e stream->data->state = I2S_STATE_STOPPING; } else { stream->conf->stop_transfer(dev); - stream->data->last_block = true; stream->data->state = I2S_STATE_READY; } @@ -1280,7 +1259,6 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e stream->data->state = I2S_STATE_STOPPING; } else { stream->conf->stop_transfer(dev); - stream->data->last_block = true; stream->data->state = I2S_STATE_READY; } } @@ -1494,7 +1472,6 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { .i2s_cfg = {0}, \ .mem_block = NULL, \ .mem_block_len = 0, \ - .last_block = false, \ .stop_without_draining = false, \ .queue = {}, \ .irq_handle = NULL, \ From e2492e03990b31fddf028bff91100f96f04b3ab2 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 22 Jul 2025 18:32:48 -0300 Subject: [PATCH 02/11] drivers: i2s: esp32: fix redundant pin configuration Moves the pinctrl_apply_state() call to avoid calling it twice Signed-off-by: Marcio Ribeiro --- drivers/i2s/i2s_esp32.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index 15d2a14d7fe83..7db965c219d8e 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -769,7 +769,6 @@ static int i2s_esp32_initialize(const struct device *dev) #if !SOC_GDMA_SUPPORTED const i2s_hal_context_t *hal = &(dev_cfg->hal); #endif /* !SOC_GDMA_SUPPORTED */ - if (!device_is_ready(clk_dev)) { LOG_ERR("clock control device not ready"); return -ENODEV; @@ -849,6 +848,12 @@ static int i2s_esp32_initialize(const struct device *dev) i2s_ll_clear_intr_status(hal->dev, I2S_INTR_MAX); #endif /* !SOC_GDMA_SUPPORTED */ + err = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + LOG_ERR("Pins setup failed: %d", err); + return -EIO; + } + LOG_DBG("%s initialized", dev->name); return 0; @@ -1044,11 +1049,6 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, #endif /* I2S_ESP32_IS_DIR_EN(rx) */ } - err = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); - if (err < 0) { - LOG_ERR("Pins setup failed: %d", err); - return -EIO; - } memcpy(&stream->data->i2s_cfg, i2s_cfg, sizeof(struct i2s_config)); From 97a536e6196bf6dc4e9f653c5f4d914748bf68e3 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 15 Jul 2025 02:25:07 -0300 Subject: [PATCH 03/11] drivers: i2s: esp32: add missing checks Adds missing checks regarding mem_slab and data_format during each stream configuration Signed-off-by: Marcio Ribeiro --- drivers/i2s/i2s_esp32.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index 7db965c219d8e..acb929f1cf513 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -916,6 +916,11 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, return 0; } + if (i2s_cfg->mem_slab == NULL) { + LOG_ERR("Memory slab is NULL"); + return -EINVAL; + } + data_format = i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK; if (data_format != I2S_FMT_DATA_FORMAT_I2S && @@ -925,6 +930,11 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, return -EINVAL; } + if (data_format == I2S_FMT_DATA_FORMAT_I2S && i2s_cfg->format & I2S_FMT_DATA_ORDER_LSB) { + LOG_ERR("Invalid format: %u", (unsigned int)i2s_cfg->format); + return -EINVAL; + } + if (i2s_cfg->word_size != 8 && i2s_cfg->word_size != 16 && i2s_cfg->word_size != 24 && i2s_cfg->word_size != 32) { LOG_ERR("Word size not supported: %d", (int)i2s_cfg->word_size); @@ -980,8 +990,10 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, #endif /* SOC_I2S_HW_VERSION_2 */ } else { LOG_ERR("Unsupported data format: %u", (unsigned int)data_format); + return -EINVAL; } } + slot_cfg.std.ws_width = slot_cfg.slot_bit_width; slot_cfg.std.slot_mask = I2S_STD_SLOT_BOTH; #if SOC_I2S_HW_VERSION_1 @@ -1517,8 +1529,7 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { I2S_ESP32_STREAM_DECL_DMA_DESC(index, tx); \ I2S_ESP32_STREAM_DECL(index, tx); \ \ - static struct i2s_esp32_data i2s_esp32_data_##index = { \ - .clk_info = {0}}; \ + static struct i2s_esp32_data i2s_esp32_data_##index = {.clk_info = {0}}; \ \ static const struct i2s_esp32_cfg i2s_esp32_config_##index = { \ .unit = DT_PROP(DT_DRV_INST(index), unit), \ @@ -1526,7 +1537,8 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(index)), \ .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(index, offset), \ - I2S_ESP32_STREAM_INIT(index, rx), I2S_ESP32_STREAM_INIT(index, tx)}; \ + I2S_ESP32_STREAM_INIT(index, rx), \ + I2S_ESP32_STREAM_INIT(index, tx)}; \ \ DEVICE_DT_INST_DEFINE(index, &i2s_esp32_initialize, NULL, &i2s_esp32_data_##index, \ &i2s_esp32_config_##index, POST_KERNEL, CONFIG_I2S_INIT_PRIORITY, \ From bae96876bb8284e3a63eacc19ddaa1bdb798c34f Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 15 Jul 2025 02:04:18 -0300 Subject: [PATCH 04/11] drivers: i2s: consistent use of stream state Reworks i2s_esp32_read() and i2s_esp32_write() to allow consistent use of stream->data->state Signed-off-by: Marcio Ribeiro --- drivers/i2s/i2s_esp32.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index acb929f1cf513..76bb8902b3bb6 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -1383,6 +1383,7 @@ static int i2s_esp32_read(const struct device *dev, void **mem_block, size_t *si #if I2S_ESP32_IS_DIR_EN(rx) const struct i2s_esp32_cfg *dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->rx; + enum i2s_state state = stream->data->state; struct queue_item item; int err; @@ -1394,26 +1395,26 @@ static int i2s_esp32_read(const struct device *dev, void **mem_block, size_t *si return -EINVAL; } - if (stream->data->state == I2S_STATE_NOT_READY) { + if (state == I2S_STATE_NOT_READY) { LOG_ERR("RX invalid state: %d", (int)stream->data->state); return -EIO; - } else if (stream->data->state == I2S_STATE_ERROR && - k_msgq_num_used_get(&stream->data->queue) == 0) { - LOG_ERR("RX queue empty"); - return -EIO; } err = k_msgq_get(&stream->data->queue, &item, - K_MSEC(stream->data->i2s_cfg.timeout)); - if (err < 0) { + (state == I2S_STATE_ERROR) ? K_NO_WAIT + : K_MSEC(stream->data->i2s_cfg.timeout)); + if (err == 0) { + *mem_block = item.buffer; + *size = item.size; + } else { LOG_ERR("RX queue empty"); - return err; - } - *mem_block = item.buffer; - *size = item.size; + if (err == -ENOMSG) { + err = -EIO; + } + } - return 0; + return err; #else *mem_block = NULL; *size = 0; @@ -1428,6 +1429,7 @@ static int i2s_esp32_write(const struct device *dev, void *mem_block, size_t siz #if I2S_ESP32_IS_DIR_EN(tx) const struct i2s_esp32_cfg *dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->tx; + enum i2s_state state = stream->data->state; int err; if (!stream) { @@ -1435,27 +1437,25 @@ static int i2s_esp32_write(const struct device *dev, void *mem_block, size_t siz return -EINVAL; } - if (stream->data->state != I2S_STATE_RUNNING && - stream->data->state != I2S_STATE_READY) { - LOG_ERR("TX Invalid state: %d", (int)stream->data->state); - return -EIO; - } - if (size > stream->data->i2s_cfg.block_size) { LOG_ERR("Max write size is: %zu", stream->data->i2s_cfg.block_size); return -EINVAL; } + if (state != I2S_STATE_RUNNING && state != I2S_STATE_READY) { + LOG_ERR("TX Invalid state: %d", (int)state); + return -EIO; + } + struct queue_item item = {.buffer = mem_block, .size = size}; err = k_msgq_put(&stream->data->queue, &item, K_MSEC(stream->data->i2s_cfg.timeout)); if (err < 0) { LOG_ERR("TX queue full"); - return err; } - return 0; + return err; #else LOG_ERR("I2S_DIR_TX not enabled"); return -EINVAL; From 8b738645c3f70b11eb6237a356481fb23b5ac6f1 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Fri, 1 Aug 2025 16:14:19 -0300 Subject: [PATCH 05/11] drivers: i2s: esp32: allow deferred processing of an empty tx queue Allows to defer processing of an empty tx queue when tx_callback is executed. This prevents error conditions if the tx dma interrupt is generated too early, as occurs with esp32 and esp32s2. Signed-off-by: Marcio Ribeiro --- drivers/i2s/Kconfig.esp32 | 8 +++- drivers/i2s/i2s_esp32.c | 89 ++++++++++++++++++++++++++++----------- 2 files changed, 71 insertions(+), 26 deletions(-) diff --git a/drivers/i2s/Kconfig.esp32 b/drivers/i2s/Kconfig.esp32 index 8cc13d01dc92e..63f3a8528a6cf 100644 --- a/drivers/i2s/Kconfig.esp32 +++ b/drivers/i2s/Kconfig.esp32 @@ -8,7 +8,7 @@ config I2S_ESP32 depends on DT_HAS_ESPRESSIF_ESP32_I2S_ENABLED select DMA if DT_HAS_ESPRESSIF_ESP32_GDMA_ENABLED help - Enables the ESP32 I2S driver (GDMA SoCs only). + Enables the ESP32 I2S driver. if I2S_ESP32 @@ -31,4 +31,10 @@ config I2S_ESP32_DMA_DESC_NUM_MAX help Max number of link descriptor available for DMA transfers on each I2S channel +config I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS + int "ESP32 I2S empty TX queue processing deferral time" + default 0 + help + Allowed deferral time for processing an empty tx queue in milliseconds + endif diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index 76bb8902b3bb6..01ba2273cbd57 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -96,6 +96,10 @@ struct i2s_esp32_cfg { struct i2s_esp32_data { i2s_hal_clock_info_t clk_info; +#if I2S_ESP32_IS_DIR_EN(tx) + struct k_timer tx_deferred_transfer_timer; + const struct device *dev; +#endif }; uint32_t i2s_esp32_get_source_clk_freq(i2s_clock_src_t clk_src) @@ -348,6 +352,47 @@ static void i2s_esp32_rx_stop_transfer(const struct device *dev) #if I2S_ESP32_IS_DIR_EN(tx) +void i2s_esp32_tx_compl_transfer(struct k_timer *timer) +{ + struct i2s_esp32_data *dev_data = + CONTAINER_OF(timer, struct i2s_esp32_data, tx_deferred_transfer_timer); + const struct device *dev = dev_data->dev; + const struct i2s_esp32_cfg *const dev_cfg = dev->config; + const struct i2s_esp32_stream *stream = &dev_cfg->tx; + struct queue_item item; + int err; + + if (stream->data->state == I2S_STATE_STOPPING) { + if (k_msgq_num_used_get(&stream->data->queue) == 0 || + stream->data->stop_without_draining == true) { + stream->data->state = I2S_STATE_READY; + goto tx_disable; + } + } + + err = k_msgq_get(&stream->data->queue, &item, K_NO_WAIT); + if (err < 0) { + stream->data->state = I2S_STATE_ERROR; + LOG_ERR("TX queue empty: %d", err); + goto tx_disable; + } + + stream->data->mem_block = item.buffer; + stream->data->mem_block_len = item.size; + + err = i2s_esp32_restart_dma(dev, I2S_DIR_TX); + if (err < 0) { + stream->data->state = I2S_STATE_ERROR; + LOG_ERR("Failed to restart TX transfer: %d", err); + goto tx_disable; + } + + return; + +tx_disable: + stream->conf->stop_transfer(dev); +} + #if SOC_GDMA_SUPPORTED static void i2s_esp32_tx_callback(const struct device *dma_dev, void *arg, uint32_t channel, int status) @@ -356,10 +401,9 @@ static void i2s_esp32_tx_callback(void *arg, int status) #endif /* SOC_GDMA_SUPPORTED */ { const struct device *dev = (const struct device *)arg; + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *const dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->tx; - struct queue_item item; - int err; if (!stream->data->dma_pending) { return; @@ -385,29 +429,16 @@ static void i2s_esp32_tx_callback(void *arg, int status) goto tx_disable; } - if (stream->data->state == I2S_STATE_STOPPING) { - if (k_msgq_num_used_get(&stream->data->queue) == 0 || - stream->data->stop_without_draining == true) { - stream->data->state = I2S_STATE_READY; - goto tx_disable; - } - } - - err = k_msgq_get(&stream->data->queue, &item, K_NO_WAIT); - if (err < 0) { - stream->data->state = I2S_STATE_ERROR; - LOG_ERR("TX queue empty: %d", err); - goto tx_disable; - } - - stream->data->mem_block = item.buffer; - stream->data->mem_block_len = item.size; - - err = i2s_esp32_restart_dma(dev, I2S_DIR_TX); - if (err < 0) { - stream->data->state = I2S_STATE_ERROR; - LOG_ERR("Failed to restart TX transfer: %d", err); - goto tx_disable; +#if CONFIG_I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS + if (k_msgq_num_used_get(&stream->data->queue) == 0) { + k_timer_start(&dev_data->tx_deferred_transfer_timer, + K_MSEC(CONFIG_I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS), + K_NO_WAIT); + } else { +#else + { +#endif + i2s_esp32_tx_compl_transfer(&dev_data->tx_deferred_transfer_timer); } return; @@ -769,6 +800,14 @@ static int i2s_esp32_initialize(const struct device *dev) #if !SOC_GDMA_SUPPORTED const i2s_hal_context_t *hal = &(dev_cfg->hal); #endif /* !SOC_GDMA_SUPPORTED */ + +#if I2S_ESP32_IS_DIR_EN(tx) + struct i2s_esp32_data *dev_data = dev->data; + + dev_data->dev = dev; + k_timer_init(&dev_data->tx_deferred_transfer_timer, i2s_esp32_tx_compl_transfer, NULL); +#endif /* I2S_ESP32_IS_DIR_EN(tx) */ + if (!device_is_ready(clk_dev)) { LOG_ERR("clock control device not ready"); return -ENODEV; From 8b03d4a3c4ca9e5892bfc2c05f7f363822196c6d Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Tue, 15 Jul 2025 02:26:08 -0300 Subject: [PATCH 06/11] drivers: i2s: esp32: log messages rework Reworks log messages to avoid timing issues Signed-off-by: Marcio Ribeiro --- drivers/i2s/i2s_esp32.c | 175 ++++++++++++++++++++-------------------- 1 file changed, 87 insertions(+), 88 deletions(-) diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index 01ba2273cbd57..7f0b8117d15cb 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -116,12 +116,10 @@ static esp_err_t i2s_esp32_calculate_clock(const struct i2s_config *i2s_cfg, uin uint16_t mclk_multiple = 256; if (i2s_cfg == NULL) { - LOG_ERR("Input i2s_cfg is NULL"); return ESP_ERR_INVALID_ARG; } if (i2s_hal_clock_info == NULL) { - LOG_ERR("Input hal_clock_info is NULL"); return ESP_ERR_INVALID_ARG; } @@ -145,7 +143,7 @@ static esp_err_t i2s_esp32_calculate_clock(const struct i2s_config *i2s_cfg, uin i2s_hal_clock_info->sclk = i2s_esp32_get_source_clk_freq(I2S_ESP32_CLK_SRC); i2s_hal_clock_info->mclk_div = i2s_hal_clock_info->sclk / i2s_hal_clock_info->mclk; if (i2s_hal_clock_info->mclk_div == 0) { - LOG_ERR("Sample rate is too large for the current clock source"); + LOG_DBG("Sample rate is too large for the current clock source"); return ESP_ERR_INVALID_ARG; } @@ -185,7 +183,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) stream->data->dma_pending = false; if (stream->data->mem_block == NULL) { - LOG_ERR("RX mem_block NULL"); + LOG_DBG("RX mem_block NULL"); stream->data->state = I2S_STATE_ERROR; goto rx_disable; } @@ -196,7 +194,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) if (status & I2S_LL_EVENT_RX_DSCR_ERR) { #endif /* SOC_GDMA_SUPPORTED */ stream->data->state = I2S_STATE_ERROR; - LOG_ERR("RX status bad: %d", status); + LOG_DBG("RX status bad: %d", status); goto rx_disable; } @@ -223,7 +221,8 @@ static void i2s_esp32_rx_callback(void *arg, int status) err = dma_reload(stream->conf->dma_dev, stream->conf->dma_channel, (uint32_t)NULL, (uint32_t)dst, chunk_len); if (err < 0) { - LOG_ERR("Failed to reload DMA channel: %"PRIu32, stream->conf->dma_channel); + LOG_DBG("Failed to reload DMA channel: %" PRIu32, + stream->conf->dma_channel); goto rx_disable; } @@ -231,7 +230,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) err = dma_start(stream->conf->dma_dev, stream->conf->dma_channel); if (err < 0) { - LOG_ERR("Failed to start DMA channel: %"PRIu32, stream->conf->dma_channel); + LOG_DBG("Failed to start DMA channel: %" PRIu32, stream->conf->dma_channel); goto rx_disable; } @@ -249,6 +248,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) err = k_msgq_put(&stream->data->queue, &item, K_NO_WAIT); if (err < 0) { stream->data->state = I2S_STATE_ERROR; + LOG_DBG("RX queue full"); goto rx_disable; } @@ -259,7 +259,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) err = k_mem_slab_alloc(stream->data->i2s_cfg.mem_slab, &stream->data->mem_block, K_NO_WAIT); if (err < 0) { - LOG_ERR("RX failed to allocate memory from slab: %i:", err); + LOG_DBG("RX failed to allocate memory from slab: %i:", err); stream->data->state = I2S_STATE_ERROR; goto rx_disable; } @@ -268,7 +268,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) err = i2s_esp32_restart_dma(dev, I2S_DIR_RX); if (err < 0) { stream->data->state = I2S_STATE_ERROR; - LOG_ERR("Failed to restart RX transfer: %d", err); + LOG_DBG("Failed to restart RX transfer: %d", err); goto rx_disable; } @@ -314,7 +314,7 @@ static int i2s_esp32_rx_start_transfer(const struct device *dev) err = i2s_esp32_start_dma(dev, I2S_DIR_RX); if (err < 0) { - LOG_ERR("Failed to start RX DMA transfer: %d", err); + LOG_DBG("Failed to start RX DMA transfer: %d", err); return -EIO; } @@ -373,7 +373,7 @@ void i2s_esp32_tx_compl_transfer(struct k_timer *timer) err = k_msgq_get(&stream->data->queue, &item, K_NO_WAIT); if (err < 0) { stream->data->state = I2S_STATE_ERROR; - LOG_ERR("TX queue empty: %d", err); + LOG_DBG("TX queue empty: %d", err); goto tx_disable; } @@ -383,7 +383,7 @@ void i2s_esp32_tx_compl_transfer(struct k_timer *timer) err = i2s_esp32_restart_dma(dev, I2S_DIR_TX); if (err < 0) { stream->data->state = I2S_STATE_ERROR; - LOG_ERR("Failed to restart TX transfer: %d", err); + LOG_DBG("Failed to restart TX transfer: %d", err); goto tx_disable; } @@ -412,7 +412,7 @@ static void i2s_esp32_tx_callback(void *arg, int status) stream->data->dma_pending = false; if (stream->data->mem_block == NULL) { - LOG_ERR("TX mem_block NULL"); + LOG_DBG("TX mem_block NULL"); stream->data->state = I2S_STATE_ERROR; goto tx_disable; } @@ -425,7 +425,7 @@ static void i2s_esp32_tx_callback(void *arg, int status) if (status & I2S_LL_EVENT_TX_DSCR_ERR) { #endif /* SOC_GDMA_SUPPORTED */ stream->data->state = I2S_STATE_ERROR; - LOG_ERR("TX bad status: %d", status); + LOG_DBG("TX bad status: %d", status); goto tx_disable; } @@ -486,7 +486,7 @@ static int i2s_esp32_tx_start_transfer(const struct device *dev) err = i2s_esp32_start_dma(dev, I2S_DIR_TX); if (err < 0) { - LOG_ERR("Failed to start TX DMA transfer: %d", err); + LOG_DBG("Failed to start TX DMA transfer: %d", err); return -EIO; } @@ -556,20 +556,19 @@ int i2s_esp32_config_dma(const struct device *dev, enum i2s_dir dir, err = dma_config(stream->conf->dma_dev, stream->conf->dma_channel, &dma_cfg); if (err < 0) { - LOG_ERR("Failed to configure DMA channel: %"PRIu32, stream->conf->dma_channel); + LOG_DBG("Failed to configure DMA channel: %" PRIu32, stream->conf->dma_channel); return -EINVAL; } #else lldesc_t *desc_iter = stream->conf->dma_desc; if (!mem_block) { - LOG_ERR("At least one dma block is required"); + LOG_DBG("At least one dma block is required"); return -EINVAL; } if (!esp_ptr_dma_capable((void *)mem_block)) { - LOG_ERR("Buffer is not in DMA capable memory: %p", - (uint32_t *)mem_block); + LOG_DBG("Buffer is not in DMA capable memory: %p", (uint32_t *)mem_block); return -EINVAL; } @@ -610,7 +609,7 @@ int i2s_esp32_config_dma(const struct device *dev, enum i2s_dir dir, if (desc_iter->empty) { stream->data->dma_pending = false; - LOG_ERR("Run out of descriptors. Increase CONFIG_I2S_ESP32_DMA_DESC_NUM_MAX"); + LOG_DBG("Run out of descriptors. Increase CONFIG_I2S_ESP32_DMA_DESC_NUM_MAX"); return -EINVAL; } #endif /* SOC_GDMA_SUPPORTED */ @@ -634,7 +633,7 @@ static int i2s_esp32_start_dma(const struct device *dev, enum i2s_dir dir) } else if (dir == I2S_DIR_TX) { stream = &dev_cfg->tx; } else { - LOG_ERR("Invalid DMA direction"); + LOG_DBG("Invalid DMA direction"); return -EINVAL; } @@ -642,7 +641,7 @@ static int i2s_esp32_start_dma(const struct device *dev, enum i2s_dir dir) err = i2s_esp32_config_dma(dev, dir, stream); if (err < 0) { - LOG_ERR("Dma configuration failed: %i", err); + LOG_DBG("Dma configuration failed: %i", err); goto unlock; } @@ -671,7 +670,7 @@ static int i2s_esp32_start_dma(const struct device *dev, enum i2s_dir dir) #if SOC_GDMA_SUPPORTED err = dma_start(stream->conf->dma_dev, stream->conf->dma_channel); if (err < 0) { - LOG_ERR("Failed to start DMA channel: %"PRIu32, stream->conf->dma_channel); + LOG_DBG("Failed to start DMA channel: %" PRIu32, stream->conf->dma_channel); goto unlock; } #else @@ -714,7 +713,7 @@ static int i2s_esp32_restart_dma(const struct device *dev, enum i2s_dir dir) } else if (dir == I2S_DIR_TX) { stream = &dev_cfg->tx; } else { - LOG_ERR("Invalid DMA direction"); + LOG_DBG("Invalid DMA direction"); return -EINVAL; } @@ -749,7 +748,7 @@ static int i2s_esp32_restart_dma(const struct device *dev, enum i2s_dir dir) err = dma_reload(stream->conf->dma_dev, stream->conf->dma_channel, (uint32_t)src, (uint32_t)dst, chunk_len); if (err < 0) { - LOG_ERR("Failed to reload DMA channel: %"PRIu32, stream->conf->dma_channel); + LOG_DBG("Failed to reload DMA channel: %" PRIu32, stream->conf->dma_channel); return -EIO; } @@ -761,13 +760,13 @@ static int i2s_esp32_restart_dma(const struct device *dev, enum i2s_dir dir) err = dma_start(stream->conf->dma_dev, stream->conf->dma_channel); if (err < 0) { - LOG_ERR("Failed to start DMA channel: %"PRIu32, stream->conf->dma_channel); + LOG_DBG("Failed to start DMA channel: %" PRIu32, stream->conf->dma_channel); return -EIO; } #else err = i2s_esp32_config_dma(dev, dir, stream); if (err < 0) { - LOG_ERR("Failed to configure DMA"); + LOG_DBG("Failed to configure DMA"); return -EIO; } @@ -809,13 +808,13 @@ static int i2s_esp32_initialize(const struct device *dev) #endif /* I2S_ESP32_IS_DIR_EN(tx) */ if (!device_is_ready(clk_dev)) { - LOG_ERR("clock control device not ready"); + LOG_DBG("clock control device not ready"); return -ENODEV; } err = clock_control_on(clk_dev, dev_cfg->clock_subsys); if (err != 0) { - LOG_ERR("Clock control enabling failed: %d", err); + LOG_DBG("Clock control enabling failed: %d", err); return -EIO; } @@ -824,7 +823,7 @@ static int i2s_esp32_initialize(const struct device *dev) stream = &dev_cfg->rx; #if SOC_GDMA_SUPPORTED if (stream->conf->dma_dev && !device_is_ready(stream->conf->dma_dev)) { - LOG_ERR("%s device not ready", stream->conf->dma_dev->name); + LOG_DBG("%s device not ready", stream->conf->dma_dev->name); return -ENODEV; } #else @@ -838,7 +837,7 @@ static int i2s_esp32_initialize(const struct device *dev) I2S_LL_RX_EVENT_MASK, i2s_esp32_rx_handler, (void *)dev, &(stream->data->irq_handle)); if (err != 0) { - LOG_ERR("Could not allocate rx interrupt (err %d)", err); + LOG_DBG("Could not allocate rx interrupt (err %d)", err); return err; } #endif /* SOC_GDMA_SUPPORTED */ @@ -856,7 +855,7 @@ static int i2s_esp32_initialize(const struct device *dev) stream = &dev_cfg->tx; #if SOC_GDMA_SUPPORTED if (stream->conf->dma_dev && !device_is_ready(stream->conf->dma_dev)) { - LOG_ERR("%s device not ready", stream->conf->dma_dev->name); + LOG_DBG("%s device not ready", stream->conf->dma_dev->name); return -ENODEV; } #else @@ -870,7 +869,7 @@ static int i2s_esp32_initialize(const struct device *dev) I2S_LL_TX_EVENT_MASK, i2s_esp32_tx_handler, (void *)dev, &(stream->data->irq_handle)); if (err != 0) { - LOG_ERR("Could not allocate tx interrupt (err %d)", err); + LOG_DBG("Could not allocate tx interrupt (err %d)", err); return err; } #endif /* SOC_GDMA_SUPPORTED */ @@ -889,7 +888,7 @@ static int i2s_esp32_initialize(const struct device *dev) err = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); if (err < 0) { - LOG_ERR("Pins setup failed: %d", err); + LOG_DBG("Pins setup failed: %d", err); return -EIO; } @@ -912,10 +911,10 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, if (stream->conf) { #if SOC_GDMA_SUPPORTED if (stream->conf->dma_dev == NULL) { - LOG_ERR("RX DMA controller not available"); + LOG_DBG("RX DMA controller not available"); #else if (stream->conf->irq_source == -1) { - LOG_ERR("RX IRQ source not available"); + LOG_DBG("RX IRQ source not available"); #endif /* SOC_GDMA_SUPPORTED */ return -EINVAL; } @@ -927,10 +926,10 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, if (stream->conf) { #if SOC_GDMA_SUPPORTED if (stream->conf->dma_dev == NULL) { - LOG_ERR("TX DMA controller not available"); + LOG_DBG("TX DMA controller not available"); #else if (stream->conf->irq_source == -1) { - LOG_ERR("TX IRQ source not available"); + LOG_DBG("TX IRQ source not available"); #endif /* SOC_GDMA_SUPPORTED */ return -EINVAL; } @@ -938,12 +937,12 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, break; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ default: - LOG_ERR("Invalid direction"); + LOG_DBG("Invalid direction"); return -EINVAL; } if (stream->data->state != I2S_STATE_NOT_READY && stream->data->state != I2S_STATE_READY) { - LOG_ERR("Invalid state: %d", (int)stream->data->state); + LOG_DBG("Invalid state: %d", (int)stream->data->state); return -EINVAL; } @@ -956,7 +955,7 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, } if (i2s_cfg->mem_slab == NULL) { - LOG_ERR("Memory slab is NULL"); + LOG_DBG("Memory slab is NULL"); return -EINVAL; } @@ -965,33 +964,33 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, if (data_format != I2S_FMT_DATA_FORMAT_I2S && data_format != I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED && data_format != I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED) { - LOG_ERR("Invalid data format: %u", (unsigned int)data_format); + LOG_DBG("Invalid data format: %u", (unsigned int)data_format); return -EINVAL; } if (data_format == I2S_FMT_DATA_FORMAT_I2S && i2s_cfg->format & I2S_FMT_DATA_ORDER_LSB) { - LOG_ERR("Invalid format: %u", (unsigned int)i2s_cfg->format); + LOG_DBG("Invalid format: %u", (unsigned int)i2s_cfg->format); return -EINVAL; } if (i2s_cfg->word_size != 8 && i2s_cfg->word_size != 16 && i2s_cfg->word_size != 24 && i2s_cfg->word_size != 32) { - LOG_ERR("Word size not supported: %d", (int)i2s_cfg->word_size); + LOG_DBG("Word size not supported: %d", (int)i2s_cfg->word_size); return -EINVAL; } if (i2s_cfg->channels != 2) { - LOG_ERR("Currently only 2 channels are supported"); + LOG_DBG("Currently only 2 channels are supported"); return -EINVAL; } if (i2s_cfg->options & I2S_OPT_LOOPBACK) { - LOG_ERR("For internal loopback: I2S#_O_SD_GPIO = I2S#_I_SD_GPIO"); + LOG_DBG("For internal loopback: I2S#_O_SD_GPIO = I2S#_I_SD_GPIO"); return -EINVAL; } if (i2s_cfg->options & I2S_OPT_PINGPONG) { - LOG_ERR("Unsupported option: I2S_OPT_PINGPONG"); + LOG_DBG("Unsupported option: I2S_OPT_PINGPONG"); return -EINVAL; } @@ -1002,7 +1001,7 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, (i2s_cfg->options & I2S_OPT_BIT_CLK_SLAVE) == 0) { stream->data->is_slave = false; } else { - LOG_ERR("I2S_OPT_FRAME_CLK and I2S_OPT_BIT_CLK options must both be" + LOG_DBG("I2S_OPT_FRAME_CLK and I2S_OPT_BIT_CLK options must both be" " MASTER or SLAVE"); return -EINVAL; } @@ -1028,7 +1027,7 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, slot_cfg.std.left_align = false; #endif /* SOC_I2S_HW_VERSION_2 */ } else { - LOG_ERR("Unsupported data format: %u", (unsigned int)data_format); + LOG_DBG("Unsupported data format: %u", (unsigned int)data_format); return -EINVAL; } } @@ -1122,11 +1121,11 @@ static int i2s_esp32_configure(const struct device *dev, enum i2s_dir dir, if (stream) { err = i2s_esp32_configure_dir(dev, I2S_DIR_RX, stream, i2s_cfg); } else { - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ break; @@ -1136,11 +1135,11 @@ static int i2s_esp32_configure(const struct device *dev, enum i2s_dir dir, if (stream) { err = i2s_esp32_configure_dir(dev, I2S_DIR_TX, stream, i2s_cfg); } else { - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ break; @@ -1150,11 +1149,11 @@ static int i2s_esp32_configure(const struct device *dev, enum i2s_dir dir, if (stream) { err = i2s_esp32_configure_dir(dev, I2S_DIR_TX, stream, i2s_cfg); } else { - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ if (err < 0) { @@ -1165,16 +1164,16 @@ static int i2s_esp32_configure(const struct device *dev, enum i2s_dir dir, if (stream) { err = i2s_esp32_configure_dir(dev, I2S_DIR_RX, stream, i2s_cfg); } else { - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ break; default: - LOG_ERR("Invalid direction: %d", (int)dir); + LOG_DBG("Invalid direction: %d", (int)dir); return -EINVAL; } @@ -1190,26 +1189,26 @@ static const struct i2s_config *i2s_esp32_config_get(const struct device *dev, e #if I2S_ESP32_IS_DIR_EN(rx) stream = &dev_cfg->rx; if (!stream) { - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); return NULL; } #else - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); return NULL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ } else if (dir == I2S_DIR_TX) { #if I2S_ESP32_IS_DIR_EN(tx) stream = &dev_cfg->tx; if (!stream) { - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); return NULL; } #else - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); return NULL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ } else { - LOG_ERR("Invalid direction: %d", (int)dir); + LOG_DBG("Invalid direction: %d", (int)dir); return NULL; } @@ -1231,7 +1230,7 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e switch (cmd) { case I2S_TRIGGER_START: if (stream->data->state != I2S_STATE_READY) { - LOG_ERR("START - Invalid state: %d", (int)stream->data->state); + LOG_DBG("START - Invalid state: %d", (int)stream->data->state); return -EIO; } @@ -1255,8 +1254,8 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e err = stream->conf->start_transfer(dev); if (err < 0) { - LOG_ERR("START - Transfer start failed: %d", err); irq_unlock(key); + LOG_DBG("START - Transfer start failed: %d", err); return -EIO; } stream->data->state = I2S_STATE_RUNNING; @@ -1267,7 +1266,7 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e key = irq_lock(); if (stream->data->state != I2S_STATE_RUNNING) { irq_unlock(key); - LOG_ERR("STOP - Invalid state: %d", (int)stream->data->state); + LOG_DBG("STOP - Invalid state: %d", (int)stream->data->state); return -EIO; } @@ -1286,7 +1285,7 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e key = irq_lock(); if (stream->data->state != I2S_STATE_RUNNING) { irq_unlock(key); - LOG_ERR("DRAIN - Invalid state: %d", (int)stream->data->state); + LOG_DBG("DRAIN - Invalid state: %d", (int)stream->data->state); return -EIO; } @@ -1320,7 +1319,7 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e case I2S_TRIGGER_DROP: if (stream->data->state == I2S_STATE_NOT_READY) { - LOG_ERR("DROP - invalid state: %d", (int)stream->data->state); + LOG_DBG("DROP - invalid state: %d", (int)stream->data->state); return -EIO; } stream->conf->stop_transfer(dev); @@ -1330,7 +1329,7 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e case I2S_TRIGGER_PREPARE: if (stream->data->state != I2S_STATE_ERROR) { - LOG_ERR("PREPARE - invalid state: %d", (int)stream->data->state); + LOG_DBG("PREPARE - invalid state: %d", (int)stream->data->state); return -EIO; } stream->conf->queue_drop(stream); @@ -1338,7 +1337,7 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e break; default: - LOG_ERR("Unsupported trigger command: %d", (int)cmd); + LOG_DBG("Unsupported trigger command: %d", (int)cmd); return -EINVAL; } @@ -1358,11 +1357,11 @@ static int i2s_esp32_trigger(const struct device *dev, enum i2s_dir dir, enum i2 if (stream) { err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_RX, cmd); } else { - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ break; @@ -1372,11 +1371,11 @@ static int i2s_esp32_trigger(const struct device *dev, enum i2s_dir dir, enum i2 if (stream) { err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_TX, cmd); } else { - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ break; @@ -1386,11 +1385,11 @@ static int i2s_esp32_trigger(const struct device *dev, enum i2s_dir dir, enum i2 if (stream) { err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_TX, cmd); } else { - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ if (err < 0) { @@ -1401,16 +1400,16 @@ static int i2s_esp32_trigger(const struct device *dev, enum i2s_dir dir, enum i2 if (stream) { err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_RX, cmd); } else { - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; } #else - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ break; default: - LOG_ERR("Invalid direction: %d", (int)dir); + LOG_DBG("Invalid direction: %d", (int)dir); err = -EINVAL; } @@ -1430,12 +1429,12 @@ static int i2s_esp32_read(const struct device *dev, void **mem_block, size_t *si *mem_block = NULL; *size = 0; - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); return -EINVAL; } if (state == I2S_STATE_NOT_READY) { - LOG_ERR("RX invalid state: %d", (int)stream->data->state); + LOG_DBG("RX invalid state: %d", (int)stream->data->state); return -EIO; } @@ -1446,7 +1445,7 @@ static int i2s_esp32_read(const struct device *dev, void **mem_block, size_t *si *mem_block = item.buffer; *size = item.size; } else { - LOG_ERR("RX queue empty"); + LOG_DBG("RX queue empty"); if (err == -ENOMSG) { err = -EIO; @@ -1458,7 +1457,7 @@ static int i2s_esp32_read(const struct device *dev, void **mem_block, size_t *si *mem_block = NULL; *size = 0; - LOG_ERR("I2S_DIR_RX not enabled"); + LOG_DBG("I2S_DIR_RX not enabled"); return -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ } @@ -1472,17 +1471,17 @@ static int i2s_esp32_write(const struct device *dev, void *mem_block, size_t siz int err; if (!stream) { - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); return -EINVAL; } if (size > stream->data->i2s_cfg.block_size) { - LOG_ERR("Max write size is: %zu", stream->data->i2s_cfg.block_size); + LOG_DBG("Max write size is: %u", stream->data->i2s_cfg.block_size); return -EINVAL; } if (state != I2S_STATE_RUNNING && state != I2S_STATE_READY) { - LOG_ERR("TX Invalid state: %d", (int)state); + LOG_DBG("TX Invalid state: %d", (int)state); return -EIO; } @@ -1491,12 +1490,12 @@ static int i2s_esp32_write(const struct device *dev, void *mem_block, size_t siz err = k_msgq_put(&stream->data->queue, &item, K_MSEC(stream->data->i2s_cfg.timeout)); if (err < 0) { - LOG_ERR("TX queue full"); + LOG_DBG("TX queue full"); } return err; #else - LOG_ERR("I2S_DIR_TX not enabled"); + LOG_DBG("I2S_DIR_TX not enabled"); return -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ } From 81e9f8b736842dbc64e71e1086035d4405e27984 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Thu, 21 Aug 2025 22:35:36 -0300 Subject: [PATCH 07/11] drivers: i2s: esp32: optimize stream structs and add sanity check Optimizes i2s_esp32_stream_data and i2s_esp32_stream_conf structs and adds property sanity check according to soc series based on SOC_GDMA_SUPPORTED feature Signed-off-by: Marcio Ribeiro --- drivers/i2s/i2s_esp32.c | 93 +++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index 7f0b8117d15cb..d97fe27da3a90 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -57,7 +57,9 @@ struct i2s_esp32_stream_data { size_t mem_block_len; bool stop_without_draining; struct k_msgq queue; +#if !SOC_GDMA_SUPPORTED struct intr_handle_data_t *irq_handle; +#endif bool dma_pending; uint8_t chunks_rem; uint8_t chunk_idx; @@ -67,16 +69,15 @@ struct i2s_esp32_stream_conf { void (*queue_drop)(const struct i2s_esp32_stream *stream); int (*start_transfer)(const struct device *dev); void (*stop_transfer)(const struct device *dev); +#if SOC_GDMA_SUPPORTED const struct device *dma_dev; uint32_t dma_channel; -#if SOC_GDMA_SUPPORTED - void *dma_desc; #else lldesc_t *dma_desc; -#endif int irq_source; int irq_priority; int irq_flags; +#endif }; struct i2s_esp32_stream { @@ -1508,12 +1509,46 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { .write = i2s_esp32_write }; -#define I2S_ESP32_STREAM_DECLARE_DMA_DESC(index, dir) \ +#if SOC_GDMA_SUPPORTED + +#define I2S_ESP32_DT_INST_SANITY_CHECK(index) \ + BUILD_ASSERT(DT_INST_NODE_HAS_PROP(index, dmas), "Missing property: dmas"); \ + BUILD_ASSERT(DT_INST_NODE_HAS_PROP(index, dma_names), "Missing property: dma-names"); + +#define I2S_ESP32_STREAM_DECL_DESC(index, rx) + +#define I2S_ESP32_STREAM_DECLARE_DATA(index, dir) + +#define I2S_ESP32_STREAM_DECLARE_CONF(index, dir) \ + .dma_dev = UTIL_AND(DT_INST_DMAS_HAS_NAME(index, dir), \ + DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(index, dir))), \ + .dma_channel = UTIL_AND(DT_INST_DMAS_HAS_NAME(index, dir), \ + DT_INST_DMAS_CELL_BY_NAME(index, dir, channel)) + +#else + +#define I2S_ESP32_DT_INST_SANITY_CHECK(index) \ + BUILD_ASSERT(!DT_INST_NODE_HAS_PROP(index, dmas), "Unexpected property: dmas"); \ + BUILD_ASSERT(!DT_INST_NODE_HAS_PROP(index, dma_names), "Unexpected property: dma-names"); \ + BUILD_ASSERT(DT_INST_NODE_HAS_PROP(index, interrupt_names), \ + "Missing property: interrupt-names") + +#define I2S_ESP32_STREAM_DECL_DESC(index, dir) \ lldesc_t i2s_esp32_stream_##index##_##dir##_dma_desc[CONFIG_I2S_ESP32_DMA_DESC_NUM_MAX] -#define I2S_ESP32_STREAM_DECL_DMA_DESC(index, dir) \ - COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), \ - (I2S_ESP32_STREAM_DECLARE_DMA_DESC(index, dir)), ()) +#define I2S_ESP32_STREAM_DECLARE_DATA(index, dir) .irq_handle = NULL + +#define I2S_ESP32_STREAM_DECLARE_CONF(index, dir) \ + .irq_source = COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), \ + (DT_INST_IRQ_BY_NAME(index, dir, irq)), (-1)), \ + .irq_priority = COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), \ + (DT_INST_IRQ_BY_NAME(index, dir, priority)), (-1)), \ + .irq_flags = COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), \ + (DT_INST_IRQ_BY_NAME(index, dir, flags)), (-1)), \ + .dma_desc = UTIL_AND(DT_INST_IRQ_HAS_NAME(index, dir), \ + i2s_esp32_stream_##index##_##dir##_dma_desc) + +#endif /* SOC_GDMA_SUPPORTED */ #define I2S_ESP32_STREAM_DECLARE(index, dir) \ struct i2s_esp32_stream_data i2s_esp32_stream_##index##_##dir##_data = { \ @@ -1524,48 +1559,34 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { .mem_block_len = 0, \ .stop_without_draining = false, \ .queue = {}, \ - .irq_handle = NULL, \ - .dma_pending = false \ - }; \ + .dma_pending = false, \ + I2S_ESP32_STREAM_DECLARE_DATA(index, dir)}; \ \ const struct i2s_esp32_stream_conf i2s_esp32_stream_##index##_##dir##_conf = { \ .queue_drop = i2s_esp32_queue_drop, \ .start_transfer = i2s_esp32_##dir##_start_transfer, \ .stop_transfer = i2s_esp32_##dir##_stop_transfer, \ - .dma_dev = UTIL_AND(DT_INST_DMAS_HAS_NAME(index, dir), \ - DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(index, dir))), \ - .dma_channel = UTIL_AND(DT_INST_DMAS_HAS_NAME(index, dir), \ - DT_INST_DMAS_CELL_BY_NAME(index, dir, channel)), \ - .dma_desc = UTIL_AND(DT_INST_IRQ_HAS_NAME(index, dir), \ - i2s_esp32_stream_##index##_##dir##_dma_desc), \ - .irq_source = COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), \ - (DT_INST_IRQ_BY_NAME(index, dir, irq)), (-1)), \ - .irq_priority = COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), \ - (DT_INST_IRQ_BY_NAME(index, dir, priority)), (-1)), \ - .irq_flags = COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), \ - (DT_INST_IRQ_BY_NAME(index, dir, flags)), (-1)) \ - } - -#define I2S_ESP32_STREAM_DECL(index, dir) \ + I2S_ESP32_STREAM_DECLARE_CONF(index, dir)}; + +#define I2S_ESP32_STREAM_COND_DECLARE(index, dir) \ + COND_CODE_1(DT_INST_IRQ_HAS_NAME(index, dir), (I2S_ESP32_STREAM_DECL_DESC(index, dir)), \ + ()); \ COND_CODE_1(UTIL_OR(DT_INST_DMAS_HAS_NAME(index, dir), DT_INST_IRQ_HAS_NAME(index, dir)), \ (I2S_ESP32_STREAM_DECLARE(index, dir)), ()) #define I2S_ESP32_STREAM_INIT(index, dir) \ - .dir = {.conf = UTIL_AND(UTIL_OR(DT_INST_DMAS_HAS_NAME(index, dir), \ - DT_INST_IRQ_HAS_NAME(index, dir)), \ - &i2s_esp32_stream_##index##_##dir##_conf), \ - .data = UTIL_AND(UTIL_OR(DT_INST_DMAS_HAS_NAME(index, dir), \ - DT_INST_IRQ_HAS_NAME(index, dir)), \ - &i2s_esp32_stream_##index##_##dir##_data)} + COND_CODE_1(UTIL_OR(DT_INST_DMAS_HAS_NAME(index, dir), DT_INST_IRQ_HAS_NAME(index, dir)), \ + (.dir = {.conf = &i2s_esp32_stream_##index##_##dir##_conf, \ + .data = &i2s_esp32_stream_##index##_##dir##_data}), \ + (.dir = {.conf = NULL, .data = NULL})) #define I2S_ESP32_INIT(index) \ - PINCTRL_DT_INST_DEFINE(index); \ + I2S_ESP32_DT_INST_SANITY_CHECK(index); \ \ - I2S_ESP32_STREAM_DECL_DMA_DESC(index, rx); \ - I2S_ESP32_STREAM_DECL(index, rx); \ + PINCTRL_DT_INST_DEFINE(index); \ \ - I2S_ESP32_STREAM_DECL_DMA_DESC(index, tx); \ - I2S_ESP32_STREAM_DECL(index, tx); \ + I2S_ESP32_STREAM_COND_DECLARE(index, rx); \ + I2S_ESP32_STREAM_COND_DECLARE(index, tx); \ \ static struct i2s_esp32_data i2s_esp32_data_##index = {.clk_info = {0}}; \ \ From 7f3fa223413f164daf6bd4a442823a04a699314a Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Mon, 29 Sep 2025 17:59:56 -0300 Subject: [PATCH 08/11] drivers: i2s: esp32: fix driver state management and I2S_DIR_BOTH behavior Rework to fix state management and I2S_DIR_BOTH behavior across the driver Signed-off-by: Marcio Ribeiro --- drivers/i2s/i2s_esp32.c | 884 ++++++++++++++++++++++------------------ 1 file changed, 483 insertions(+), 401 deletions(-) diff --git a/drivers/i2s/i2s_esp32.c b/drivers/i2s/i2s_esp32.c index d97fe27da3a90..3718ddc46406e 100644 --- a/drivers/i2s/i2s_esp32.c +++ b/drivers/i2s/i2s_esp32.c @@ -38,24 +38,22 @@ LOG_MODULE_REGISTER(i2s_esp32, CONFIG_I2S_LOG_LEVEL); #define I2S_ESP32_CLK_SRC I2S_CLK_SRC_DEFAULT #define I2S_ESP32_DMA_BUFFER_MAX_SIZE 4092 -#define I2S_ESP32_NUM_INST_OK DT_NUM_INST_STATUS_OKAY(espressif_esp32_i2s) +#define I2S_ESP32_NUM_INST_OK DT_NUM_INST_STATUS_OKAY(espressif_esp32_i2s) #define I2S_ESP32_IS_DIR_INST_EN(i, d) DT_INST_DMAS_HAS_NAME(i, d) || DT_INST_IRQ_HAS_NAME(i, d) -#define I2S_ESP32_IS_DIR_EN(d) LISTIFY(I2S_ESP32_NUM_INST_OK, I2S_ESP32_IS_DIR_INST_EN, (||), d) +#define I2S_ESP32_IS_DIR_EN(d) (LISTIFY(I2S_ESP32_NUM_INST_OK, I2S_ESP32_IS_DIR_INST_EN, \ + (||), d)) struct queue_item { void *buffer; size_t size; }; -struct i2s_esp32_stream; - struct i2s_esp32_stream_data { - int32_t state; - bool is_slave; + bool configured; + bool transferring; struct i2s_config i2s_cfg; void *mem_block; size_t mem_block_len; - bool stop_without_draining; struct k_msgq queue; #if !SOC_GDMA_SUPPORTED struct intr_handle_data_t *irq_handle; @@ -66,9 +64,6 @@ struct i2s_esp32_stream_data { }; struct i2s_esp32_stream_conf { - void (*queue_drop)(const struct i2s_esp32_stream *stream); - int (*start_transfer)(const struct device *dev); - void (*stop_transfer)(const struct device *dev); #if SOC_GDMA_SUPPORTED const struct device *dma_dev; uint32_t dma_channel; @@ -96,6 +91,9 @@ struct i2s_esp32_cfg { }; struct i2s_esp32_data { + int32_t state; + enum i2s_dir active_dir; + bool tx_stop_without_draining; i2s_hal_clock_info_t clk_info; #if I2S_ESP32_IS_DIR_EN(tx) struct k_timer tx_deferred_transfer_timer; @@ -151,13 +149,31 @@ static esp_err_t i2s_esp32_calculate_clock(const struct i2s_config *i2s_cfg, uin return ESP_OK; } -static void i2s_esp32_queue_drop(const struct i2s_esp32_stream *stream) +static void i2s_esp32_queue_drop(const struct device *dev, enum i2s_dir dir) { + const struct i2s_esp32_cfg *dev_cfg = dev->config; + const struct i2s_esp32_stream *stream; struct queue_item item; - while (k_msgq_get(&stream->data->queue, &item, K_NO_WAIT) == 0) { - k_mem_slab_free(stream->data->i2s_cfg.mem_slab, item.buffer); +#if I2S_ESP32_IS_DIR_EN(rx) + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { + stream = &dev_cfg->rx; + + while (k_msgq_get(&stream->data->queue, &item, K_NO_WAIT) == 0) { + k_mem_slab_free(stream->data->i2s_cfg.mem_slab, item.buffer); + } + } +#endif /* I2S_ESP32_IS_DIR_EN(rx) */ + +#if I2S_ESP32_IS_DIR_EN(tx) + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { + stream = &dev_cfg->tx; + + while (k_msgq_get(&stream->data->queue, &item, K_NO_WAIT) == 0) { + k_mem_slab_free(stream->data->i2s_cfg.mem_slab, item.buffer); + } } +#endif /* I2S_ESP32_IS_DIR_EN(tx) */ } static int i2s_esp32_restart_dma(const struct device *dev, enum i2s_dir dir); @@ -165,6 +181,8 @@ static int i2s_esp32_start_dma(const struct device *dev, enum i2s_dir dir); #if I2S_ESP32_IS_DIR_EN(rx) +static void i2s_esp32_rx_stop_transfer(const struct device *dev); + #if SOC_GDMA_SUPPORTED static void i2s_esp32_rx_callback(const struct device *dma_dev, void *arg, uint32_t channel, int status) @@ -173,6 +191,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) #endif /* SOC_GDMA_SUPPORTED */ { const struct device *dev = (const struct device *)arg; + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->rx; int err; @@ -185,7 +204,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) if (stream->data->mem_block == NULL) { LOG_DBG("RX mem_block NULL"); - stream->data->state = I2S_STATE_ERROR; + dev_data->state = I2S_STATE_ERROR; goto rx_disable; } @@ -194,7 +213,7 @@ static void i2s_esp32_rx_callback(void *arg, int status) #else if (status & I2S_LL_EVENT_RX_DSCR_ERR) { #endif /* SOC_GDMA_SUPPORTED */ - stream->data->state = I2S_STATE_ERROR; + dev_data->state = I2S_STATE_ERROR; LOG_DBG("RX status bad: %d", status); goto rx_disable; } @@ -248,35 +267,41 @@ static void i2s_esp32_rx_callback(void *arg, int status) err = k_msgq_put(&stream->data->queue, &item, K_NO_WAIT); if (err < 0) { - stream->data->state = I2S_STATE_ERROR; LOG_DBG("RX queue full"); + dev_data->state = I2S_STATE_ERROR; goto rx_disable; } - if (stream->data->state == I2S_STATE_STOPPING) { - stream->data->state = I2S_STATE_READY; - goto rx_disable; + if (dev_data->state == I2S_STATE_STOPPING) { + if (dev_data->active_dir == I2S_DIR_RX || + (dev_data->active_dir == I2S_DIR_BOTH && !dev_cfg->tx.data->transferring)) { + dev_data->state = I2S_STATE_READY; + goto rx_disable; + } } err = k_mem_slab_alloc(stream->data->i2s_cfg.mem_slab, &stream->data->mem_block, K_NO_WAIT); if (err < 0) { LOG_DBG("RX failed to allocate memory from slab: %i:", err); - stream->data->state = I2S_STATE_ERROR; + dev_data->state = I2S_STATE_ERROR; goto rx_disable; } stream->data->mem_block_len = stream->data->i2s_cfg.block_size; err = i2s_esp32_restart_dma(dev, I2S_DIR_RX); if (err < 0) { - stream->data->state = I2S_STATE_ERROR; LOG_DBG("Failed to restart RX transfer: %d", err); + k_mem_slab_free(stream->data->i2s_cfg.mem_slab, stream->data->mem_block); + stream->data->mem_block = NULL; + stream->data->mem_block_len = 0; + dev_data->state = I2S_STATE_ERROR; goto rx_disable; } return; rx_disable: - stream->conf->stop_transfer(dev); + i2s_esp32_rx_stop_transfer(dev); } #if !SOC_GDMA_SUPPORTED @@ -313,9 +338,19 @@ static int i2s_esp32_rx_start_transfer(const struct device *dev) } stream->data->mem_block_len = stream->data->i2s_cfg.block_size; + i2s_hal_rx_stop(hal); + i2s_hal_rx_reset(hal); +#if !SOC_GDMA_SUPPORTED + i2s_hal_rx_reset_dma(hal); +#endif /* !SOC_GDMA_SUPPORTED */ + i2s_hal_rx_reset_fifo(hal); + err = i2s_esp32_start_dma(dev, I2S_DIR_RX); if (err < 0) { LOG_DBG("Failed to start RX DMA transfer: %d", err); + k_mem_slab_free(stream->data->i2s_cfg.mem_slab, stream->data->mem_block); + stream->data->mem_block = NULL; + stream->data->mem_block_len = 0; return -EIO; } @@ -325,6 +360,8 @@ static int i2s_esp32_rx_start_transfer(const struct device *dev) esp_intr_enable(stream->data->irq_handle); #endif /* !SOC_GDMA_SUPPORTED */ + stream->data->transferring = true; + return 0; } @@ -347,12 +384,16 @@ static void i2s_esp32_rx_stop_transfer(const struct device *dev) stream->data->mem_block = NULL; stream->data->mem_block_len = 0; + + stream->data->transferring = false; } #endif /* I2S_ESP32_IS_DIR_EN(rx) */ #if I2S_ESP32_IS_DIR_EN(tx) +static void i2s_esp32_tx_stop_transfer(const struct device *dev); + void i2s_esp32_tx_compl_transfer(struct k_timer *timer) { struct i2s_esp32_data *dev_data = @@ -363,17 +404,25 @@ void i2s_esp32_tx_compl_transfer(struct k_timer *timer) struct queue_item item; int err; - if (stream->data->state == I2S_STATE_STOPPING) { + if (dev_data->state == I2S_STATE_ERROR) { + goto tx_disable; + } + + if (dev_data->state == I2S_STATE_STOPPING) { if (k_msgq_num_used_get(&stream->data->queue) == 0 || - stream->data->stop_without_draining == true) { - stream->data->state = I2S_STATE_READY; + dev_data->tx_stop_without_draining == true) { + if (dev_data->active_dir == I2S_DIR_TX || + (dev_data->active_dir == I2S_DIR_BOTH && + !dev_cfg->rx.data->transferring)) { + dev_data->state = I2S_STATE_READY; + } goto tx_disable; } } err = k_msgq_get(&stream->data->queue, &item, K_NO_WAIT); if (err < 0) { - stream->data->state = I2S_STATE_ERROR; + dev_data->state = I2S_STATE_ERROR; LOG_DBG("TX queue empty: %d", err); goto tx_disable; } @@ -383,7 +432,7 @@ void i2s_esp32_tx_compl_transfer(struct k_timer *timer) err = i2s_esp32_restart_dma(dev, I2S_DIR_TX); if (err < 0) { - stream->data->state = I2S_STATE_ERROR; + dev_data->state = I2S_STATE_ERROR; LOG_DBG("Failed to restart TX transfer: %d", err); goto tx_disable; } @@ -391,7 +440,7 @@ void i2s_esp32_tx_compl_transfer(struct k_timer *timer) return; tx_disable: - stream->conf->stop_transfer(dev); + i2s_esp32_tx_stop_transfer(dev); } #if SOC_GDMA_SUPPORTED @@ -406,6 +455,10 @@ static void i2s_esp32_tx_callback(void *arg, int status) const struct i2s_esp32_cfg *const dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->tx; + if (dev_data->state == I2S_STATE_ERROR) { + goto tx_disable; + } + if (!stream->data->dma_pending) { return; } @@ -414,7 +467,7 @@ static void i2s_esp32_tx_callback(void *arg, int status) if (stream->data->mem_block == NULL) { LOG_DBG("TX mem_block NULL"); - stream->data->state = I2S_STATE_ERROR; + dev_data->state = I2S_STATE_ERROR; goto tx_disable; } @@ -425,7 +478,7 @@ static void i2s_esp32_tx_callback(void *arg, int status) #else if (status & I2S_LL_EVENT_TX_DSCR_ERR) { #endif /* SOC_GDMA_SUPPORTED */ - stream->data->state = I2S_STATE_ERROR; + dev_data->state = I2S_STATE_ERROR; LOG_DBG("TX bad status: %d", status); goto tx_disable; } @@ -445,7 +498,7 @@ static void i2s_esp32_tx_callback(void *arg, int status) return; tx_disable: - stream->conf->stop_transfer(dev); + i2s_esp32_tx_stop_transfer(dev); } #if !SOC_GDMA_SUPPORTED @@ -485,6 +538,13 @@ static int i2s_esp32_tx_start_transfer(const struct device *dev) stream->data->mem_block = item.buffer; stream->data->mem_block_len = item.size; + i2s_hal_tx_stop(hal); + i2s_hal_tx_reset(hal); +#if !SOC_GDMA_SUPPORTED + i2s_hal_tx_reset_dma(hal); +#endif /* !SOC_GDMA_SUPPORTED */ + i2s_hal_tx_reset_fifo(hal); + err = i2s_esp32_start_dma(dev, I2S_DIR_TX); if (err < 0) { LOG_DBG("Failed to start TX DMA transfer: %d", err); @@ -497,6 +557,8 @@ static int i2s_esp32_tx_start_transfer(const struct device *dev) esp_intr_enable(stream->data->irq_handle); #endif /* !SOC_GDMA_SUPPORTED */ + stream->data->transferring = true; + return 0; } @@ -519,10 +581,102 @@ static void i2s_esp32_tx_stop_transfer(const struct device *dev) stream->data->mem_block = NULL; stream->data->mem_block_len = 0; + + stream->data->transferring = false; } #endif /* I2S_ESP32_IS_DIR_EN(tx) */ +static int i2s_esp32_start_transfer(const struct device *dev, enum i2s_dir dir) +{ + int err = 0; + +#if I2S_ESP32_IS_DIR_EN(rx) + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { + err = i2s_esp32_rx_start_transfer(dev); + if (err < 0) { + LOG_DBG("RX failed to start transfer"); + goto start_transfer_end; + } + } +#endif /* I2S_ESP32_IS_DIR_EN(rx) */ + +#if I2S_ESP32_IS_DIR_EN(tx) + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { + err = i2s_esp32_tx_start_transfer(dev); + if (err < 0) { + LOG_DBG("TX failed to start transfer"); + goto start_transfer_end; + } + } +#endif /* I2S_ESP32_IS_DIR_EN(tx) */ + +start_transfer_end: +#if I2S_ESP32_IS_DIR_EN(rx) && I2S_ESP32_IS_DIR_EN(tx) + if (dir == I2S_DIR_BOTH && err < 0) { + const struct i2s_esp32_cfg *dev_cfg = dev->config; + + if (dev_cfg->rx.data->transferring && !dev_cfg->tx.data->transferring) { + i2s_esp32_rx_stop_transfer(dev); + } + + if (!dev_cfg->rx.data->transferring && dev_cfg->tx.data->transferring) { + i2s_esp32_tx_stop_transfer(dev); + } + } +#endif /* I2S_ESP32_IS_DIR_EN(rx) && I2S_ESP32_IS_DIR_EN(tx) */ + + return err; +} + +static void i2s_esp32_stop_transfer(const struct device *dev, enum i2s_dir dir) +{ +#if I2S_ESP32_IS_DIR_EN(rx) + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { + i2s_esp32_rx_stop_transfer(dev); + } +#endif /* I2S_ESP32_IS_DIR_EN(rx) */ + +#if I2S_ESP32_IS_DIR_EN(tx) + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { + i2s_esp32_tx_stop_transfer(dev); + } +#endif /* I2S_ESP32_IS_DIR_EN(tx) */ +} + +static bool i2s_esp32_try_stop_transfer(const struct device *dev, enum i2s_dir dir, + enum i2s_trigger_cmd cmd) +{ + const struct i2s_esp32_cfg *dev_cfg = dev->config; + const struct i2s_esp32_stream *stream; + bool at_least_one_dir_with_pending_transfer = false; + +#if I2S_ESP32_IS_DIR_EN(rx) + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { + stream = &dev_cfg->rx; + if (stream->data->dma_pending) { + at_least_one_dir_with_pending_transfer = true; + } else { + i2s_esp32_rx_stop_transfer(dev); + } + } +#endif /* I2S_ESP32_IS_DIR_EN(rx) */ + +#if I2S_ESP32_IS_DIR_EN(tx) + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { + stream = &dev_cfg->tx; + if ((cmd == I2S_TRIGGER_DRAIN && k_msgq_num_used_get(&stream->data->queue) > 0) || + stream->data->dma_pending) { + at_least_one_dir_with_pending_transfer = true; + } else { + i2s_esp32_tx_stop_transfer(dev); + } + } +#endif /* I2S_ESP32_IS_DIR_EN(tx) */ + + return at_least_one_dir_with_pending_transfer; +} + int i2s_esp32_config_dma(const struct device *dev, enum i2s_dir dir, const struct i2s_esp32_stream *stream) { @@ -792,6 +946,7 @@ static int i2s_esp32_restart_dma(const struct device *dev, enum i2s_dir dir) static int i2s_esp32_initialize(const struct device *dev) { + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *dev_cfg = dev->config; const struct device *clk_dev = dev_cfg->clock_dev; const struct i2s_esp32_stream *stream; @@ -801,15 +956,8 @@ static int i2s_esp32_initialize(const struct device *dev) const i2s_hal_context_t *hal = &(dev_cfg->hal); #endif /* !SOC_GDMA_SUPPORTED */ -#if I2S_ESP32_IS_DIR_EN(tx) - struct i2s_esp32_data *dev_data = dev->data; - - dev_data->dev = dev; - k_timer_init(&dev_data->tx_deferred_transfer_timer, i2s_esp32_tx_compl_transfer, NULL); -#endif /* I2S_ESP32_IS_DIR_EN(tx) */ - if (!device_is_ready(clk_dev)) { - LOG_DBG("clock control device not ready"); + LOG_DBG("Clock control device not ready"); return -ENODEV; } @@ -819,6 +967,12 @@ static int i2s_esp32_initialize(const struct device *dev) return -EIO; } + err = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + LOG_DBG("Pins setup failed: %d", err); + return -EIO; + } + #if I2S_ESP32_IS_DIR_EN(rx) if (dev_cfg->rx.data && dev_cfg->rx.conf) { stream = &dev_cfg->rx; @@ -852,6 +1006,9 @@ static int i2s_esp32_initialize(const struct device *dev) #endif /* I2S_ESP32_IS_DIR_EN(rx) */ #if I2S_ESP32_IS_DIR_EN(tx) + dev_data->dev = dev; + k_timer_init(&dev_data->tx_deferred_transfer_timer, i2s_esp32_tx_compl_transfer, NULL); + if (dev_cfg->tx.data && dev_cfg->tx.conf) { stream = &dev_cfg->tx; #if SOC_GDMA_SUPPORTED @@ -887,71 +1044,78 @@ static int i2s_esp32_initialize(const struct device *dev) i2s_ll_clear_intr_status(hal->dev, I2S_INTR_MAX); #endif /* !SOC_GDMA_SUPPORTED */ - err = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); - if (err < 0) { - LOG_DBG("Pins setup failed: %d", err); - return -EIO; - } + dev_data->state = I2S_STATE_NOT_READY; LOG_DBG("%s initialized", dev->name); return 0; } -static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, - const struct i2s_esp32_stream *stream, - const struct i2s_config *i2s_cfg) +static int i2s_esp32_config_check(const struct device *dev, enum i2s_dir dir, + const struct i2s_config *i2s_cfg, uint8_t *data_format) { + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *dev_cfg = dev->config; - uint8_t data_format; - int err; + const struct i2s_esp32_stream *stream; + + if (dir == I2S_DIR_BOTH && + (!dev_cfg->rx.conf || !dev_cfg->rx.data || !dev_cfg->tx.conf || !dev_cfg->tx.data)) { + LOG_DBG("I2S_DIR_BOTH not supported"); + return -ENOSYS; + } + + if (dev_data->state != I2S_STATE_NOT_READY && dev_data->state != I2S_STATE_READY) { + LOG_DBG("Invalid state: %d", (int)dev_data->state); + return -EINVAL; + } - switch (dir) { + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { #if I2S_ESP32_IS_DIR_EN(rx) - case I2S_DIR_RX: - if (stream->conf) { + stream = &dev_cfg->rx; + if (!stream->data || !stream->conf) { + LOG_DBG("RX not enabled"); + return -EINVAL; + } + #if SOC_GDMA_SUPPORTED - if (stream->conf->dma_dev == NULL) { - LOG_DBG("RX DMA controller not available"); + if (stream->conf->dma_dev == NULL) { + LOG_DBG("RX DMA controller not available"); #else - if (stream->conf->irq_source == -1) { - LOG_DBG("RX IRQ source not available"); + if (stream->conf->irq_source == -1) { + LOG_DBG("RX IRQ source not available"); #endif /* SOC_GDMA_SUPPORTED */ - return -EINVAL; - } + return -EINVAL; } - break; +#else + LOG_DBG("RX not enabled"); + return -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ + } + + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { #if I2S_ESP32_IS_DIR_EN(tx) - case I2S_DIR_TX: - if (stream->conf) { + stream = &dev_cfg->tx; + if (!stream->data || !stream->conf) { + LOG_DBG("TX not enabled"); + return -EINVAL; + } + #if SOC_GDMA_SUPPORTED - if (stream->conf->dma_dev == NULL) { - LOG_DBG("TX DMA controller not available"); + if (stream->conf->dma_dev == NULL) { + LOG_DBG("TX DMA controller not available"); #else - if (stream->conf->irq_source == -1) { - LOG_DBG("TX IRQ source not available"); + if (stream->conf->irq_source == -1) { + LOG_DBG("TX IRQ source not available"); #endif /* SOC_GDMA_SUPPORTED */ - return -EINVAL; - } + return -EINVAL; } - break; -#endif /* I2S_ESP32_IS_DIR_EN(tx) */ - default: - LOG_DBG("Invalid direction"); - return -EINVAL; - } - - if (stream->data->state != I2S_STATE_NOT_READY && stream->data->state != I2S_STATE_READY) { - LOG_DBG("Invalid state: %d", (int)stream->data->state); +#else + LOG_DBG("TX not enabled"); return -EINVAL; +#endif /* I2S_ESP32_IS_DIR_EN(tx) */ } if (i2s_cfg->frame_clk_freq == 0U) { - stream->conf->queue_drop(stream); - memset(&stream->data->i2s_cfg, 0, sizeof(struct i2s_config)); - stream->data->is_slave = false; - stream->data->state = I2S_STATE_NOT_READY; return 0; } @@ -960,16 +1124,21 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, return -EINVAL; } - data_format = i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK; + if (i2s_cfg->block_size == 0) { + LOG_DBG("Block size is 0"); + return -EINVAL; + } + + *data_format = i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK; - if (data_format != I2S_FMT_DATA_FORMAT_I2S && - data_format != I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED && - data_format != I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED) { - LOG_DBG("Invalid data format: %u", (unsigned int)data_format); + if (*data_format != I2S_FMT_DATA_FORMAT_I2S && + *data_format != I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED && + *data_format != I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED) { + LOG_DBG("Invalid data format: %u", (unsigned int)*data_format); return -EINVAL; } - if (data_format == I2S_FMT_DATA_FORMAT_I2S && i2s_cfg->format & I2S_FMT_DATA_ORDER_LSB) { + if (*data_format == I2S_FMT_DATA_FORMAT_I2S && i2s_cfg->format & I2S_FMT_DATA_ORDER_LSB) { LOG_DBG("Invalid format: %u", (unsigned int)i2s_cfg->format); return -EINVAL; } @@ -986,7 +1155,8 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, } if (i2s_cfg->options & I2S_OPT_LOOPBACK) { - LOG_DBG("For internal loopback: I2S#_O_SD_GPIO = I2S#_I_SD_GPIO"); + LOG_DBG("Unsupported option: I2S_OPT_LOOPBACK"); + LOG_DBG("To enable loopback, use the same SD for TX and RX pinctrl"); return -EINVAL; } @@ -995,20 +1165,29 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, return -EINVAL; } + return 0; +} + +static int i2s_esp32_config_apply(const struct device *dev, enum i2s_dir dir, + const struct i2s_config *i2s_cfg, uint8_t data_format) +{ + const struct i2s_esp32_cfg *dev_cfg = dev->config; + const struct i2s_esp32_stream *stream; + i2s_hal_slot_config_t slot_cfg = {0}; + bool is_slave; + int err; + if ((i2s_cfg->options & I2S_OPT_FRAME_CLK_SLAVE) != 0 && (i2s_cfg->options & I2S_OPT_BIT_CLK_SLAVE) != 0) { - stream->data->is_slave = true; + is_slave = true; } else if ((i2s_cfg->options & I2S_OPT_FRAME_CLK_SLAVE) == 0 && (i2s_cfg->options & I2S_OPT_BIT_CLK_SLAVE) == 0) { - stream->data->is_slave = false; + is_slave = false; } else { - LOG_DBG("I2S_OPT_FRAME_CLK and I2S_OPT_BIT_CLK options must both be" - " MASTER or SLAVE"); + LOG_DBG("I2S_OPT_FRAME_CLK and I2S_OPT_BIT_CLK options are incompatible"); return -EINVAL; } - i2s_hal_slot_config_t slot_cfg = {0}; - slot_cfg.data_bit_width = i2s_cfg->word_size; slot_cfg.slot_mode = I2S_SLOT_MODE_STEREO; slot_cfg.slot_bit_width = i2s_cfg->word_size > 16 ? 32 : 16; @@ -1018,19 +1197,19 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, #if SOC_I2S_HW_VERSION_2 slot_cfg.std.left_align = true; #endif /* SOC_I2S_HW_VERSION_2 */ - } else { + } else if (data_format == I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED) { slot_cfg.std.ws_pol = i2s_cfg->format & I2S_FMT_FRAME_CLK_INV ? false : true; slot_cfg.std.bit_shift = false; - if (data_format == I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED) { #if SOC_I2S_HW_VERSION_2 - slot_cfg.std.left_align = true; - } else if (data_format == I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED) { - slot_cfg.std.left_align = false; + slot_cfg.std.left_align = true; + } else if (data_format == I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED) { + slot_cfg.std.ws_pol = i2s_cfg->format & I2S_FMT_FRAME_CLK_INV ? false : true; + slot_cfg.std.bit_shift = false; + slot_cfg.std.left_align = false; #endif /* SOC_I2S_HW_VERSION_2 */ - } else { - LOG_DBG("Unsupported data format: %u", (unsigned int)data_format); - return -EINVAL; - } + } else { + LOG_DBG("Unsupported data format: %u", (unsigned int)data_format); + return -EINVAL; } slot_cfg.std.ws_width = slot_cfg.slot_bit_width; @@ -1050,60 +1229,43 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, return -EINVAL; } - if (dir == I2S_DIR_TX) { -#if I2S_ESP32_IS_DIR_EN(tx) - i2s_hal_std_enable_tx_channel(hal); - if (dev_cfg->rx.data != NULL && dev_cfg->rx.data->state != I2S_STATE_NOT_READY) { - if (stream->data->is_slave && !dev_cfg->rx.data->is_slave) { /*full duplex*/ - i2s_ll_share_bck_ws(hal->dev, true); - } else { - i2s_ll_share_bck_ws(hal->dev, false); - } - } else { - i2s_ll_share_bck_ws(hal->dev, false); - } - - i2s_hal_std_set_tx_slot(hal, stream->data->is_slave, &slot_cfg); - i2s_hal_set_tx_clock(hal, &i2s_hal_clock_info, I2S_ESP32_CLK_SRC); - -#if SOC_I2S_HW_VERSION_2 - if (dev_cfg->rx.data != NULL && dev_cfg->rx.data->state != I2S_STATE_NOT_READY) { - if (stream->data->is_slave && !dev_cfg->rx.data->is_slave) { /*full duplex*/ - i2s_ll_mclk_bind_to_rx_clk(hal->dev); - } - } -#endif /* SOC_I2S_HW_VERSION_2 */ -#endif /* I2S_ESP32_IS_DIR_EN(tx) */ - } else if (dir == I2S_DIR_RX) { #if I2S_ESP32_IS_DIR_EN(rx) - i2s_hal_std_enable_rx_channel(hal); - if (dev_cfg->tx.data != NULL && dev_cfg->tx.data->state != I2S_STATE_NOT_READY) { - if (stream->data->is_slave && !dev_cfg->tx.data->is_slave) { /*full duplex*/ - i2s_ll_share_bck_ws(hal->dev, true); - } else { - i2s_ll_share_bck_ws(hal->dev, false); - } - } else { - i2s_ll_share_bck_ws(hal->dev, false); + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { + bool rx_is_slave; + + rx_is_slave = is_slave; + if (dir == I2S_DIR_BOTH || (dev_cfg->tx.data && dev_cfg->tx.data->configured)) { + rx_is_slave = true; } - i2s_hal_std_set_rx_slot(hal, stream->data->is_slave, &slot_cfg); + i2s_hal_std_set_rx_slot(hal, rx_is_slave, &slot_cfg); i2s_hal_set_rx_clock(hal, &i2s_hal_clock_info, I2S_ESP32_CLK_SRC); + i2s_ll_rx_enable_std(hal->dev); -#if SOC_I2S_HW_VERSION_2 - if (dev_cfg->tx.data != NULL && dev_cfg->tx.data->state != I2S_STATE_NOT_READY) { - if (stream->data->is_slave && !dev_cfg->tx.data->is_slave) { /*full duplex*/ - i2s_ll_mclk_bind_to_tx_clk(hal->dev); - } - } -#endif /* SOC_I2S_HW_VERSION_2 */ -#endif /* I2S_ESP32_IS_DIR_EN(rx) */ + stream = &dev_cfg->rx; + memcpy(&stream->data->i2s_cfg, i2s_cfg, sizeof(struct i2s_config)); + stream->data->configured = true; } +#endif /* I2S_ESP32_IS_DIR_EN(rx) */ +#if I2S_ESP32_IS_DIR_EN(tx) + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { + i2s_hal_std_set_tx_slot(hal, is_slave, &slot_cfg); + i2s_hal_set_tx_clock(hal, &i2s_hal_clock_info, I2S_ESP32_CLK_SRC); + i2s_ll_tx_enable_std(hal->dev); - memcpy(&stream->data->i2s_cfg, i2s_cfg, sizeof(struct i2s_config)); + stream = &dev_cfg->tx; + memcpy(&stream->data->i2s_cfg, i2s_cfg, sizeof(struct i2s_config)); + stream->data->configured = true; + } +#endif /* I2S_ESP32_IS_DIR_EN(tx) */ - stream->data->state = I2S_STATE_READY; + if (dev_cfg->rx.data && dev_cfg->rx.data->configured && dev_cfg->tx.data && + dev_cfg->tx.data->configured) { + i2s_ll_share_bck_ws(hal->dev, true); + } else { + i2s_ll_share_bck_ws(hal->dev, false); + } return 0; } @@ -1111,74 +1273,49 @@ static int i2s_esp32_configure_dir(const struct device *dev, enum i2s_dir dir, static int i2s_esp32_configure(const struct device *dev, enum i2s_dir dir, const struct i2s_config *i2s_cfg) { + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *dev_cfg = dev->config; const struct i2s_esp32_stream *stream; + uint8_t data_format; int err; - switch (dir) { - case I2S_DIR_RX: + err = i2s_esp32_config_check(dev, dir, i2s_cfg, &data_format); + if (err < 0) { + return err; + } + + if (i2s_cfg->frame_clk_freq == 0U) { + i2s_esp32_queue_drop(dev, dir); + #if I2S_ESP32_IS_DIR_EN(rx) - stream = &dev_cfg->rx; - if (stream) { - err = i2s_esp32_configure_dir(dev, I2S_DIR_RX, stream, i2s_cfg); - } else { - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { + stream = &dev_cfg->rx; + memset(&stream->data->i2s_cfg, 0, sizeof(struct i2s_config)); + stream->data->configured = false; } -#else - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ - break; - case I2S_DIR_TX: -#if I2S_ESP32_IS_DIR_EN(tx) - stream = &dev_cfg->tx; - if (stream) { - err = i2s_esp32_configure_dir(dev, I2S_DIR_TX, stream, i2s_cfg); - } else { - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; - } -#else - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; -#endif /* I2S_ESP32_IS_DIR_EN(tx) */ - break; - case I2S_DIR_BOTH: + #if I2S_ESP32_IS_DIR_EN(tx) - stream = &dev_cfg->tx; - if (stream) { - err = i2s_esp32_configure_dir(dev, I2S_DIR_TX, stream, i2s_cfg); - } else { - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { + stream = &dev_cfg->tx; + memset(&stream->data->i2s_cfg, 0, sizeof(struct i2s_config)); + stream->data->configured = false; } -#else - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ - if (err < 0) { - break; - } -#if I2S_ESP32_IS_DIR_EN(rx) - stream = &dev_cfg->rx; - if (stream) { - err = i2s_esp32_configure_dir(dev, I2S_DIR_RX, stream, i2s_cfg); - } else { - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; - } -#else - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; -#endif /* I2S_ESP32_IS_DIR_EN(rx) */ - break; - default: - LOG_DBG("Invalid direction: %d", (int)dir); - return -EINVAL; + + dev_data->state = I2S_STATE_NOT_READY; + + return 0; } - return err; + err = i2s_esp32_config_apply(dev, dir, i2s_cfg, data_format); + if (err < 0) { + return err; + } + + dev_data->state = I2S_STATE_READY; + + return 0; } static const struct i2s_config *i2s_esp32_config_get(const struct device *dev, enum i2s_dir dir) @@ -1189,23 +1326,23 @@ static const struct i2s_config *i2s_esp32_config_get(const struct device *dev, e if (dir == I2S_DIR_RX) { #if I2S_ESP32_IS_DIR_EN(rx) stream = &dev_cfg->rx; - if (!stream) { - LOG_DBG("I2S_DIR_RX not enabled"); + if (!stream->data) { + LOG_DBG("RX not enabled"); return NULL; } #else - LOG_DBG("I2S_DIR_RX not enabled"); + LOG_DBG("RX not enabled"); return NULL; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ } else if (dir == I2S_DIR_TX) { #if I2S_ESP32_IS_DIR_EN(tx) stream = &dev_cfg->tx; - if (!stream) { - LOG_DBG("I2S_DIR_TX not enabled"); + if (!stream->data) { + LOG_DBG("TX not enabled"); return NULL; } #else - LOG_DBG("I2S_DIR_TX not enabled"); + LOG_DBG("TX not enabled"); return NULL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ } else { @@ -1213,206 +1350,144 @@ static const struct i2s_config *i2s_esp32_config_get(const struct device *dev, e return NULL; } - if (stream->data->state == I2S_STATE_NOT_READY) { + if (!stream->data->configured) { return NULL; } return &stream->data->i2s_cfg; } -static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_esp32_stream *stream, - enum i2s_dir dir, enum i2s_trigger_cmd cmd) +static int i2s_esp32_trigger(const struct device *dev, enum i2s_dir dir, enum i2s_trigger_cmd cmd) { + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *dev_cfg = dev->config; - const i2s_hal_context_t *hal = &dev_cfg->hal; + bool configured, cmd_allowed, at_least_one_dir_with_pending_transfer; unsigned int key; int err; - switch (cmd) { - case I2S_TRIGGER_START: - if (stream->data->state != I2S_STATE_READY) { - LOG_DBG("START - Invalid state: %d", (int)stream->data->state); - return -EIO; + if (dir == I2S_DIR_BOTH) { + if (dev_cfg->rx.conf && dev_cfg->rx.data && dev_cfg->tx.conf && dev_cfg->tx.data) { + configured = dev_cfg->rx.data->configured && dev_cfg->tx.data->configured; + } else { + LOG_DBG("I2S_DIR_BOTH not supported"); + return -ENOSYS; } + } else if (dir == I2S_DIR_RX) { + configured = dev_cfg->rx.data->configured; + } else if (dir == I2S_DIR_TX) { + configured = dev_cfg->tx.data->configured; + } else { + LOG_DBG("Invalid dir: %d", dir); + return -EINVAL; + } - key = irq_lock(); - - if (dir == I2S_DIR_RX) { - i2s_hal_rx_stop(hal); - i2s_hal_rx_reset(hal); -#if !SOC_GDMA_SUPPORTED - i2s_hal_rx_reset_dma(hal); -#endif /* !SOC_GDMA_SUPPORTED */ - i2s_hal_rx_reset_fifo(hal); - } else if (dir == I2S_DIR_TX) { - i2s_hal_tx_stop(hal); - i2s_hal_tx_reset(hal); -#if !SOC_GDMA_SUPPORTED - i2s_hal_tx_reset_dma(hal); -#endif /* !SOC_GDMA_SUPPORTED */ - i2s_hal_tx_reset_fifo(hal); - } + if (!configured) { + LOG_DBG("Device is not configured"); + return -EIO; + } - err = stream->conf->start_transfer(dev); - if (err < 0) { - irq_unlock(key); - LOG_DBG("START - Transfer start failed: %d", err); - return -EIO; - } - stream->data->state = I2S_STATE_RUNNING; - irq_unlock(key); + switch (cmd) { + case I2S_TRIGGER_START: + cmd_allowed = (dev_data->state == I2S_STATE_READY); break; - case I2S_TRIGGER_STOP: - key = irq_lock(); - if (stream->data->state != I2S_STATE_RUNNING) { - irq_unlock(key); - LOG_DBG("STOP - Invalid state: %d", (int)stream->data->state); - return -EIO; - } - - if (stream->data->dma_pending) { - stream->data->stop_without_draining = true; - stream->data->state = I2S_STATE_STOPPING; - } else { - stream->conf->stop_transfer(dev); - stream->data->state = I2S_STATE_READY; - } - - irq_unlock(key); - break; - + __fallthrough; case I2S_TRIGGER_DRAIN: - key = irq_lock(); - if (stream->data->state != I2S_STATE_RUNNING) { - irq_unlock(key); - LOG_DBG("DRAIN - Invalid state: %d", (int)stream->data->state); - return -EIO; - } - -#if I2S_ESP32_IS_DIR_EN(tx) - if (dir == I2S_DIR_TX) { - if (k_msgq_num_used_get(&stream->data->queue) > 0 || - stream->data->dma_pending) { - stream->data->stop_without_draining = false; - stream->data->state = I2S_STATE_STOPPING; - } else { - stream->conf->stop_transfer(dev); - stream->data->state = I2S_STATE_READY; - } - } -#endif /* I2S_ESP32_IS_DIR_EN(tx) */ - -#if I2S_ESP32_IS_DIR_EN(rx) - if (dir == I2S_DIR_RX) { - if (stream->data->dma_pending) { - stream->data->stop_without_draining = true; - stream->data->state = I2S_STATE_STOPPING; - } else { - stream->conf->stop_transfer(dev); - stream->data->state = I2S_STATE_READY; - } - } -#endif /* I2S_ESP32_IS_DIR_EN(rx) */ - - irq_unlock(key); + cmd_allowed = (dev_data->state == I2S_STATE_RUNNING); break; - case I2S_TRIGGER_DROP: - if (stream->data->state == I2S_STATE_NOT_READY) { - LOG_DBG("DROP - invalid state: %d", (int)stream->data->state); - return -EIO; - } - stream->conf->stop_transfer(dev); - stream->conf->queue_drop(stream); - stream->data->state = I2S_STATE_READY; + cmd_allowed = configured; break; - case I2S_TRIGGER_PREPARE: - if (stream->data->state != I2S_STATE_ERROR) { - LOG_DBG("PREPARE - invalid state: %d", (int)stream->data->state); - return -EIO; - } - stream->conf->queue_drop(stream); - stream->data->state = I2S_STATE_READY; + cmd_allowed = (dev_data->state == I2S_STATE_ERROR); break; - default: - LOG_DBG("Unsupported trigger command: %d", (int)cmd); + LOG_DBG("Invalid trigger: %d", cmd); return -EINVAL; } - return 0; -} + if (!cmd_allowed) { + switch (cmd) { + case I2S_TRIGGER_START: + LOG_DBG("START - Invalid state: %d", (int)dev_data->state); + break; + case I2S_TRIGGER_STOP: + LOG_DBG("STOP - Invalid state: %d", (int)dev_data->state); + break; + case I2S_TRIGGER_DRAIN: + LOG_DBG("DRAIN - Invalid state: %d", (int)dev_data->state); + break; + case I2S_TRIGGER_DROP: + LOG_DBG("DROP - invalid state: %d", (int)dev_data->state); + break; + case I2S_TRIGGER_PREPARE: + LOG_DBG("PREPARE - invalid state: %d", (int)dev_data->state); + break; + default: + LOG_DBG("Invalid trigger: %d", cmd); + } -static int i2s_esp32_trigger(const struct device *dev, enum i2s_dir dir, enum i2s_trigger_cmd cmd) -{ - const struct i2s_esp32_cfg *dev_cfg = dev->config; - const struct i2s_esp32_stream *stream; - int err; + return -EIO; + } - switch (dir) { - case I2S_DIR_RX: -#if I2S_ESP32_IS_DIR_EN(rx) - stream = &dev_cfg->rx; - if (stream) { - err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_RX, cmd); - } else { - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; + if (dev_data->state == I2S_STATE_RUNNING && dev_data->active_dir != dir) { + LOG_DBG("Trigger dir (%d) different from active dir (%d)", dir, + dev_data->active_dir); + return -EINVAL; + } + + err = 0; + key = irq_lock(); + switch (cmd) { + case I2S_TRIGGER_START: + dev_data->active_dir = dir; + dev_data->tx_stop_without_draining = true; + err = i2s_esp32_start_transfer(dev, dir); + if (err < 0) { + LOG_DBG("START - Transfer start failed: %d", err); + err = -EIO; + break; } -#else - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; -#endif /* I2S_ESP32_IS_DIR_EN(rx) */ + dev_data->state = I2S_STATE_RUNNING; break; - case I2S_DIR_TX: -#if I2S_ESP32_IS_DIR_EN(tx) - stream = &dev_cfg->tx; - if (stream) { - err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_TX, cmd); + case I2S_TRIGGER_STOP: + __fallthrough; + case I2S_TRIGGER_DRAIN: + at_least_one_dir_with_pending_transfer = i2s_esp32_try_stop_transfer(dev, dir, cmd); + if (at_least_one_dir_with_pending_transfer) { + dev_data->state = I2S_STATE_STOPPING; } else { - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; + dev_data->state = I2S_STATE_READY; } -#else - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; -#endif /* I2S_ESP32_IS_DIR_EN(tx) */ - break; - case I2S_DIR_BOTH: + #if I2S_ESP32_IS_DIR_EN(tx) - stream = &dev_cfg->tx; - if (stream) { - err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_TX, cmd); - } else { - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; + if ((dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) && + dev_data->state == I2S_STATE_STOPPING) { + switch (cmd) { + case I2S_TRIGGER_STOP: + dev_data->tx_stop_without_draining = true; + break; + case I2S_TRIGGER_DRAIN: + dev_data->tx_stop_without_draining = false; + default: + } } -#else - LOG_DBG("I2S_DIR_TX not enabled"); - err = -EINVAL; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ - if (err < 0) { - break; - } -#if I2S_ESP32_IS_DIR_EN(rx) - stream = &dev_cfg->rx; - if (stream) { - err = i2s_esp32_trigger_stream(dev, stream, I2S_DIR_RX, cmd); - } else { - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; - } -#else - LOG_DBG("I2S_DIR_RX not enabled"); - err = -EINVAL; -#endif /* I2S_ESP32_IS_DIR_EN(rx) */ + break; + case I2S_TRIGGER_DROP: + i2s_esp32_stop_transfer(dev, dir); + i2s_esp32_queue_drop(dev, dir); + dev_data->state = I2S_STATE_READY; + break; + case I2S_TRIGGER_PREPARE: + i2s_esp32_queue_drop(dev, dir); + dev_data->state = I2S_STATE_READY; break; default: - LOG_DBG("Invalid direction: %d", (int)dir); - err = -EINVAL; + LOG_DBG("Unsupported trigger command: %d", (int)cmd); + err = -EIO; } + irq_unlock(key); return err; } @@ -1420,22 +1495,25 @@ static int i2s_esp32_trigger(const struct device *dev, enum i2s_dir dir, enum i2 static int i2s_esp32_read(const struct device *dev, void **mem_block, size_t *size) { #if I2S_ESP32_IS_DIR_EN(rx) + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->rx; - enum i2s_state state = stream->data->state; + enum i2s_state state = dev_data->state; struct queue_item item; int err; - if (!stream) { - *mem_block = NULL; - *size = 0; + if (!stream->data || !stream->conf) { + LOG_DBG("RX not enabled"); + return -EIO; + } - LOG_DBG("I2S_DIR_RX not enabled"); - return -EINVAL; + if (!stream->data->configured) { + LOG_DBG("RX not configured"); + return -EIO; } if (state == I2S_STATE_NOT_READY) { - LOG_DBG("RX invalid state: %d", (int)stream->data->state); + LOG_DBG("Invalid state: %d", (int)state); return -EIO; } @@ -1455,34 +1533,37 @@ static int i2s_esp32_read(const struct device *dev, void **mem_block, size_t *si return err; #else - *mem_block = NULL; - *size = 0; - - LOG_DBG("I2S_DIR_RX not enabled"); - return -EINVAL; + LOG_DBG("RX not enabled"); + return -EIO; #endif /* I2S_ESP32_IS_DIR_EN(rx) */ } static int i2s_esp32_write(const struct device *dev, void *mem_block, size_t size) { #if I2S_ESP32_IS_DIR_EN(tx) + struct i2s_esp32_data *dev_data = dev->data; const struct i2s_esp32_cfg *dev_cfg = dev->config; const struct i2s_esp32_stream *stream = &dev_cfg->tx; - enum i2s_state state = stream->data->state; + enum i2s_state state = dev_data->state; int err; - if (!stream) { - LOG_DBG("I2S_DIR_TX not enabled"); - return -EINVAL; + if (!stream->data || !stream->conf) { + LOG_DBG("TX not enabled"); + return -EIO; } - if (size > stream->data->i2s_cfg.block_size) { - LOG_DBG("Max write size is: %u", stream->data->i2s_cfg.block_size); - return -EINVAL; + if (!stream->data->configured) { + LOG_DBG("TX not configured"); + return -EIO; } if (state != I2S_STATE_RUNNING && state != I2S_STATE_READY) { - LOG_DBG("TX Invalid state: %d", (int)state); + LOG_DBG("Invalid state: %d", (int)state); + return -EIO; + } + + if (size > stream->data->i2s_cfg.block_size) { + LOG_DBG("Max write size is: %u", stream->data->i2s_cfg.block_size); return -EIO; } @@ -1496,8 +1577,8 @@ static int i2s_esp32_write(const struct device *dev, void *mem_block, size_t siz return err; #else - LOG_DBG("I2S_DIR_TX not enabled"); - return -EINVAL; + LOG_DBG("TX not enabled"); + return -EIO; #endif /* I2S_ESP32_IS_DIR_EN(tx) */ } @@ -1552,20 +1633,16 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { #define I2S_ESP32_STREAM_DECLARE(index, dir) \ struct i2s_esp32_stream_data i2s_esp32_stream_##index##_##dir##_data = { \ - .state = I2S_STATE_NOT_READY, \ - .is_slave = false, \ + .configured = false, \ + .transferring = false, \ .i2s_cfg = {0}, \ .mem_block = NULL, \ .mem_block_len = 0, \ - .stop_without_draining = false, \ .queue = {}, \ .dma_pending = false, \ I2S_ESP32_STREAM_DECLARE_DATA(index, dir)}; \ \ const struct i2s_esp32_stream_conf i2s_esp32_stream_##index##_##dir##_conf = { \ - .queue_drop = i2s_esp32_queue_drop, \ - .start_transfer = i2s_esp32_##dir##_start_transfer, \ - .stop_transfer = i2s_esp32_##dir##_stop_transfer, \ I2S_ESP32_STREAM_DECLARE_CONF(index, dir)}; #define I2S_ESP32_STREAM_COND_DECLARE(index, dir) \ @@ -1588,7 +1665,11 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { I2S_ESP32_STREAM_COND_DECLARE(index, rx); \ I2S_ESP32_STREAM_COND_DECLARE(index, tx); \ \ - static struct i2s_esp32_data i2s_esp32_data_##index = {.clk_info = {0}}; \ + static struct i2s_esp32_data i2s_esp32_data_##index = { \ + .state = I2S_STATE_NOT_READY, \ + .tx_stop_without_draining = true, \ + .clk_info = {0}, \ + }; \ \ static const struct i2s_esp32_cfg i2s_esp32_config_##index = { \ .unit = DT_PROP(DT_DRV_INST(index), unit), \ @@ -1597,7 +1678,8 @@ static DEVICE_API(i2s, i2s_esp32_driver_api) = { .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(index)), \ .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(index, offset), \ I2S_ESP32_STREAM_INIT(index, rx), \ - I2S_ESP32_STREAM_INIT(index, tx)}; \ + I2S_ESP32_STREAM_INIT(index, tx), \ + }; \ \ DEVICE_DT_INST_DEFINE(index, &i2s_esp32_initialize, NULL, &i2s_esp32_data_##index, \ &i2s_esp32_config_##index, POST_KERNEL, CONFIG_I2S_INIT_PRIORITY, \ From 91209395b6b0d99920c16d56e53c4bfd1aa3d999 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Mon, 8 Sep 2025 20:59:28 -0300 Subject: [PATCH 09/11] boards: esp32: rework i2s pin config on dtsi, dts, and overlay files Reworks i2s entries on esp32 pinctrl.dtsi and .dts board files and adequates overlay files regarding to i2s samples Signed-off-by: Marcio Ribeiro --- .../esp32_devkitc/esp32_devkitc-pinctrl.dtsi | 30 ++++---------- .../esp32_devkitc/esp32_devkitc_procpu.dts | 2 - .../esp32_ethernet_kit-pinctrl.dtsi | 30 ++++---------- .../esp32_ethernet_kit_procpu.dts | 2 - .../esp32c3_devkitc-pinctrl.dtsi | 10 +++++ .../esp32c3_devkitc/esp32c3_devkitc.dts | 5 +++ .../esp32c3_devkitc/esp32c3_devkitc.yaml | 1 + .../esp32c3_devkitm-pinctrl.dtsi | 15 +++---- .../esp32c3_devkitm/esp32c3_devkitm.dts | 1 - .../esp32c6_devkitc_hpcore-pinctrl.dtsi | 10 +++++ .../esp32c6_devkitc_hpcore.dts | 5 +++ .../esp32s2_devkitc-pinctrl.dtsi | 11 +---- .../esp32s2_devkitc/esp32s2_devkitc.dts | 1 - .../esp32s2_saola/esp32s2_saola-pinctrl.dtsi | 11 +---- .../espressif/esp32s2_saola/esp32s2_saola.dts | 1 - .../esp32s3_devkitc-pinctrl.dtsi | 34 +++++---------- .../esp32s3_devkitc_procpu.dts | 2 - .../esp32s3_devkitm-pinctrl.dtsi | 34 +++++---------- .../esp32s3_devkitm_procpu.dts | 2 - .../espressif/esp32c6/esp32c6_common.dtsi | 2 + .../espressif/esp32h2/esp32h2_common.dtsi | 2 + ...u.overlay => esp32_devkitc_procpu.overlay} | 12 ++---- .../i2s/echo/boards/esp32s2_devkitc.overlay | 16 +++----- .../boards/esp32s3_devkitc_procpu.overlay | 13 ++---- ...u.overlay => esp32_devkitc_procpu.overlay} | 9 +--- .../boards/esp32c6_devkitc_hpcore.overlay | 18 +++----- .../i2s/output/boards/esp32h2_devkitm.overlay | 30 ++++++++++++++ .../boards/esp32c6_devkitc_hpcore.overlay | 16 ++------ .../led_strip/boards/esp32h2_devkitm.overlay | 41 +++++++++++++++++++ .../led/led_strip/boards/esp32s2_devkitc.conf | 1 - .../led_strip/boards/esp32s2_devkitc.overlay | 1 - .../boards/esp32s3_devkitc_procpu.conf | 1 - .../boards/esp32s3_devkitc_procpu.overlay | 1 - 33 files changed, 173 insertions(+), 197 deletions(-) rename samples/drivers/i2s/echo/boards/{esp32_devkitc_wrover_procpu.overlay => esp32_devkitc_procpu.overlay} (65%) rename samples/drivers/i2s/output/boards/{esp32_devkitc_wrover_procpu.overlay => esp32_devkitc_procpu.overlay} (72%) create mode 100644 samples/drivers/i2s/output/boards/esp32h2_devkitm.overlay create mode 100644 samples/drivers/led/led_strip/boards/esp32h2_devkitm.overlay delete mode 100644 samples/drivers/led/led_strip/boards/esp32s2_devkitc.conf delete mode 100644 samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.conf diff --git a/boards/espressif/esp32_devkitc/esp32_devkitc-pinctrl.dtsi b/boards/espressif/esp32_devkitc/esp32_devkitc-pinctrl.dtsi index fef35fba08880..f0281a4beef3a 100644 --- a/boards/espressif/esp32_devkitc/esp32_devkitc-pinctrl.dtsi +++ b/boards/espressif/esp32_devkitc/esp32_devkitc-pinctrl.dtsi @@ -81,33 +81,19 @@ i2s0_default: i2s0_default { group1 { - pinmux = , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + ; }; }; i2s1_default: i2s1_default { group1 { - pinmux = , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + ; }; }; }; diff --git a/boards/espressif/esp32_devkitc/esp32_devkitc_procpu.dts b/boards/espressif/esp32_devkitc/esp32_devkitc_procpu.dts index 7432a24d48ab1..5cde12b1c6763 100644 --- a/boards/espressif/esp32_devkitc/esp32_devkitc_procpu.dts +++ b/boards/espressif/esp32_devkitc/esp32_devkitc_procpu.dts @@ -93,13 +93,11 @@ &i2s0 { pinctrl-0 = <&i2s0_default>; pinctrl-names = "default"; - status = "disabled"; }; &i2s1 { pinctrl-0 = <&i2s1_default>; pinctrl-names = "default"; - status = "disabled"; }; &spi2 { diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit-pinctrl.dtsi b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit-pinctrl.dtsi index 86bcaa54d5bc2..adcc55d43d158 100644 --- a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit-pinctrl.dtsi +++ b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit-pinctrl.dtsi @@ -43,33 +43,19 @@ i2s0_default: i2s0_default { group1 { - pinmux = , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + ; }; }; i2s1_default: i2s1_default { group1 { - pinmux = , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + ; }; }; }; diff --git a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.dts b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.dts index bf2fbbd6d3a7e..f186a895c7e01 100644 --- a/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.dts +++ b/boards/espressif/esp32_ethernet_kit/esp32_ethernet_kit_procpu.dts @@ -46,13 +46,11 @@ &i2s0 { pinctrl-0 = <&i2s0_default>; pinctrl-names = "default"; - status = "disabled"; }; &i2s1 { pinctrl-0 = <&i2s1_default>; pinctrl-names = "default"; - status = "disabled"; }; &spi2 { diff --git a/boards/espressif/esp32c3_devkitc/esp32c3_devkitc-pinctrl.dtsi b/boards/espressif/esp32c3_devkitc/esp32c3_devkitc-pinctrl.dtsi index 808df2df0355f..ea23aed2f2054 100644 --- a/boards/espressif/esp32c3_devkitc/esp32c3_devkitc-pinctrl.dtsi +++ b/boards/espressif/esp32c3_devkitc/esp32c3_devkitc-pinctrl.dtsi @@ -44,6 +44,16 @@ }; }; + i2s_default: i2s_default { + group1 { + pinmux = , + , + , + , + ; + }; + }; + twai_default: twai_default { group1 { pinmux = , diff --git a/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.dts b/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.dts index 627ee822aa669..6208c003f648d 100644 --- a/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.dts +++ b/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.dts @@ -60,6 +60,11 @@ pinctrl-names = "default"; }; +&i2s { + pinctrl-0 = <&i2s_default>; + pinctrl-names = "default"; +}; + &trng0 { status = "okay"; }; diff --git a/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.yaml b/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.yaml index f2b98e3e4ed67..20cef2fc49289 100644 --- a/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.yaml +++ b/boards/espressif/esp32c3_devkitc/esp32c3_devkitc.yaml @@ -8,6 +8,7 @@ supported: - adc - gpio - i2c + - i2s - watchdog - uart - dma diff --git a/boards/espressif/esp32c3_devkitm/esp32c3_devkitm-pinctrl.dtsi b/boards/espressif/esp32c3_devkitm/esp32c3_devkitm-pinctrl.dtsi index a3c53becbf441..f85c9f762a8b5 100644 --- a/boards/espressif/esp32c3_devkitm/esp32c3_devkitm-pinctrl.dtsi +++ b/boards/espressif/esp32c3_devkitm/esp32c3_devkitm-pinctrl.dtsi @@ -46,16 +46,11 @@ i2s_default: i2s_default { group1 { - pinmux = , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + , + ; }; }; diff --git a/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts index 824a214878dbd..0e30c972d636c 100644 --- a/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts +++ b/boards/espressif/esp32c3_devkitm/esp32c3_devkitm.dts @@ -63,7 +63,6 @@ &i2s { pinctrl-0 = <&i2s_default>; pinctrl-names = "default"; - status = "disabled"; }; &trng0 { diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore-pinctrl.dtsi b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore-pinctrl.dtsi index 8371bbc96d82d..4dab8a27f8d29 100644 --- a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore-pinctrl.dtsi +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore-pinctrl.dtsi @@ -43,4 +43,14 @@ output-high; }; }; + + i2s_default: i2s_default { + group1 { + pinmux = , + , + , + , + ; + }; + }; }; diff --git a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.dts b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.dts index 59a271cc8e9ad..c0efdf8ec231a 100644 --- a/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.dts +++ b/boards/espressif/esp32c6_devkitc/esp32c6_devkitc_hpcore.dts @@ -58,6 +58,11 @@ pinctrl-names = "default"; }; +&i2s { + pinctrl-0 = <&i2s_default>; + pinctrl-names = "default"; +}; + &spi2 { #address-cells = <1>; #size-cells = <0>; diff --git a/boards/espressif/esp32s2_devkitc/esp32s2_devkitc-pinctrl.dtsi b/boards/espressif/esp32s2_devkitc/esp32s2_devkitc-pinctrl.dtsi index 679be933a4621..9163d336faa3c 100644 --- a/boards/espressif/esp32s2_devkitc/esp32s2_devkitc-pinctrl.dtsi +++ b/boards/espressif/esp32s2_devkitc/esp32s2_devkitc-pinctrl.dtsi @@ -72,15 +72,8 @@ pinmux = , , , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + , + ; }; }; }; diff --git a/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts b/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts index c4a151f12f19b..804bd793541b3 100644 --- a/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts +++ b/boards/espressif/esp32s2_devkitc/esp32s2_devkitc.dts @@ -100,7 +100,6 @@ &i2s0 { pinctrl-0 = <&i2s0_default>; pinctrl-names = "default"; - status = "disabled"; }; &trng0 { diff --git a/boards/espressif/esp32s2_saola/esp32s2_saola-pinctrl.dtsi b/boards/espressif/esp32s2_saola/esp32s2_saola-pinctrl.dtsi index 499e756e4b193..27ea89cf89c64 100644 --- a/boards/espressif/esp32s2_saola/esp32s2_saola-pinctrl.dtsi +++ b/boards/espressif/esp32s2_saola/esp32s2_saola-pinctrl.dtsi @@ -72,15 +72,8 @@ pinmux = , , , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + , + ; }; }; }; diff --git a/boards/espressif/esp32s2_saola/esp32s2_saola.dts b/boards/espressif/esp32s2_saola/esp32s2_saola.dts index 005a76a0b7c6e..ddd6e4dc54bf0 100644 --- a/boards/espressif/esp32s2_saola/esp32s2_saola.dts +++ b/boards/espressif/esp32s2_saola/esp32s2_saola.dts @@ -100,7 +100,6 @@ &i2s0 { pinctrl-0 = <&i2s0_default>; pinctrl-names = "default"; - status = "disabled"; }; &trng0 { diff --git a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc-pinctrl.dtsi b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc-pinctrl.dtsi index dee1ce787ecc6..86d02c69e7421 100644 --- a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc-pinctrl.dtsi +++ b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc-pinctrl.dtsi @@ -55,35 +55,21 @@ i2s0_default: i2s0_default { group1 { - pinmux = , - , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + , + ; }; }; i2s1_default: i2s1_default { group1 { - pinmux = , - , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + , + ; }; }; diff --git a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts index 33572bbf70746..8c1b137d26d60 100644 --- a/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts +++ b/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_procpu.dts @@ -91,13 +91,11 @@ &i2s0 { pinctrl-0 = <&i2s0_default>; pinctrl-names = "default"; - status = "disabled"; }; &i2s1 { pinctrl-0 = <&i2s1_default>; pinctrl-names = "default"; - status = "disabled"; }; &spi2 { diff --git a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi index a41bbf59a96d8..f18676e095ca1 100644 --- a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi +++ b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm-pinctrl.dtsi @@ -55,35 +55,21 @@ i2s0_default: i2s0_default { group1 { - pinmux = , - , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + , + ; }; }; i2s1_default: i2s1_default { group1 { - pinmux = , - , - , - , - , - ; - output-enable; - }; - - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + , + ; }; }; diff --git a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.dts b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.dts index f3bdfd37d89eb..28a8f6456eec8 100644 --- a/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.dts +++ b/boards/espressif/esp32s3_devkitm/esp32s3_devkitm_procpu.dts @@ -87,13 +87,11 @@ &i2s0 { pinctrl-0 = <&i2s0_default>; pinctrl-names = "default"; - status = "disabled"; }; &i2s1 { pinctrl-0 = <&i2s1_default>; pinctrl-names = "default"; - status = "disabled"; }; &spi2 { diff --git a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi index 34d70c43121ee..482a81aca9a9f 100644 --- a/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi +++ b/dts/riscv/espressif/esp32c6/esp32c6_common.dtsi @@ -312,6 +312,8 @@ interrupts = ; interrupt-parent = <&intc>; clocks = <&clock ESP32_I2S1_MODULE>; + dmas = <&dma 2>, <&dma 3>; + dma-names = "rx", "tx"; unit = <0>; status = "disabled"; }; diff --git a/dts/riscv/espressif/esp32h2/esp32h2_common.dtsi b/dts/riscv/espressif/esp32h2/esp32h2_common.dtsi index 86d6a8a963db3..bef5cc99177a4 100644 --- a/dts/riscv/espressif/esp32h2/esp32h2_common.dtsi +++ b/dts/riscv/espressif/esp32h2/esp32h2_common.dtsi @@ -304,6 +304,8 @@ interrupts = ; interrupt-parent = <&intc>; clocks = <&clock ESP32_I2S1_MODULE>; + dmas = <&dma 2>, <&dma 3>; + dma-names = "rx", "tx"; unit = <0>; status = "disabled"; }; diff --git a/samples/drivers/i2s/echo/boards/esp32_devkitc_wrover_procpu.overlay b/samples/drivers/i2s/echo/boards/esp32_devkitc_procpu.overlay similarity index 65% rename from samples/drivers/i2s/echo/boards/esp32_devkitc_wrover_procpu.overlay rename to samples/drivers/i2s/echo/boards/esp32_devkitc_procpu.overlay index c336dbe8f97f5..7de7be6819a69 100644 --- a/samples/drivers/i2s/echo/boards/esp32_devkitc_wrover_procpu.overlay +++ b/samples/drivers/i2s/echo/boards/esp32_devkitc_procpu.overlay @@ -8,14 +8,8 @@ group1 { pinmux = , , - , - , - ; - output-enable; - }; - group2 { - pinmux = ; - input-enable; + , + ; }; }; @@ -24,5 +18,5 @@ i2s_rxtx: &i2s0 { interrupts = , ; - interrupt-names = "tx", "rx"; + interrupt-names = "rx", "tx"; }; diff --git a/samples/drivers/i2s/echo/boards/esp32s2_devkitc.overlay b/samples/drivers/i2s/echo/boards/esp32s2_devkitc.overlay index 7e81372d2046d..6735e73895e4c 100644 --- a/samples/drivers/i2s/echo/boards/esp32s2_devkitc.overlay +++ b/samples/drivers/i2s/echo/boards/esp32s2_devkitc.overlay @@ -6,16 +6,10 @@ &i2s0_default { group1 { - pinmux = , - , - , - , - ; - output-enable; - }; - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + ; }; }; @@ -24,5 +18,5 @@ i2s_rxtx: &i2s0 { interrupts = , ; - interrupt-names = "tx", "rx"; + interrupt-names = "rx", "tx"; }; diff --git a/samples/drivers/i2s/echo/boards/esp32s3_devkitc_procpu.overlay b/samples/drivers/i2s/echo/boards/esp32s3_devkitc_procpu.overlay index 5c51f7abc42ff..7ef35bfaa5c70 100644 --- a/samples/drivers/i2s/echo/boards/esp32s3_devkitc_procpu.overlay +++ b/samples/drivers/i2s/echo/boards/esp32s3_devkitc_procpu.overlay @@ -6,15 +6,10 @@ &i2s0_default { group1 { - pinmux = , - , - , - ; - output-enable; - }; - group2 { - pinmux = ; - input-enable; + pinmux = , + , + , + ; }; }; diff --git a/samples/drivers/i2s/output/boards/esp32_devkitc_wrover_procpu.overlay b/samples/drivers/i2s/output/boards/esp32_devkitc_procpu.overlay similarity index 72% rename from samples/drivers/i2s/output/boards/esp32_devkitc_wrover_procpu.overlay rename to samples/drivers/i2s/output/boards/esp32_devkitc_procpu.overlay index fd9aa4c1959f2..79dc911ed1ce0 100644 --- a/samples/drivers/i2s/output/boards/esp32_devkitc_wrover_procpu.overlay +++ b/samples/drivers/i2s/output/boards/esp32_devkitc_procpu.overlay @@ -13,13 +13,8 @@ &i2s0_default { group1 { pinmux = , - , - ; - output-enable; - }; - group2 { - pinmux = ; - input-enable; + , + ; }; }; diff --git a/samples/drivers/i2s/output/boards/esp32c6_devkitc_hpcore.overlay b/samples/drivers/i2s/output/boards/esp32c6_devkitc_hpcore.overlay index dec2b95ec30f4..7ca1eadfe048d 100644 --- a/samples/drivers/i2s/output/boards/esp32c6_devkitc_hpcore.overlay +++ b/samples/drivers/i2s/output/boards/esp32c6_devkitc_hpcore.overlay @@ -10,24 +10,16 @@ }; }; -&pinctrl { - i2s_default: i2s_default { - group1 { - pinmux = , - , - , - ; - }; - group2 { - pinmux = ; - }; +&i2s_default { + group1 { + pinmux = , + , + ; }; }; &i2s { status = "okay"; - pinctrl-0 = <&i2s_default>; - pinctrl-names = "default"; dmas = <&dma 3>; dma-names = "tx"; diff --git a/samples/drivers/i2s/output/boards/esp32h2_devkitm.overlay b/samples/drivers/i2s/output/boards/esp32h2_devkitm.overlay new file mode 100644 index 0000000000000..754938f50a612 --- /dev/null +++ b/samples/drivers/i2s/output/boards/esp32h2_devkitm.overlay @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2s-tx = &i2s; + }; +}; + +&i2s_default { + group1 { + pinmux = , + , + ; + }; +}; + +&i2s { + status = "okay"; + + dmas = <&dma 3>; + dma-names = "tx"; +}; + +&dma { + status = "okay"; +}; diff --git a/samples/drivers/led/led_strip/boards/esp32c6_devkitc_hpcore.overlay b/samples/drivers/led/led_strip/boards/esp32c6_devkitc_hpcore.overlay index 7ab7ebb2ff50f..6b223b68b6c7c 100644 --- a/samples/drivers/led/led_strip/boards/esp32c6_devkitc_hpcore.overlay +++ b/samples/drivers/led/led_strip/boards/esp32c6_devkitc_hpcore.overlay @@ -12,24 +12,14 @@ }; }; -&pinctrl { - i2s_default: i2s_default { - group1 { - pinmux = , - , - , - ; - }; - group2 { - pinmux = ; - }; +&i2s_default { + group1 { + pinmux = ; }; }; i2s_led: &i2s { status = "okay"; - pinctrl-0 = <&i2s_default>; - pinctrl-names = "default"; dmas = <&dma 3>; dma-names = "tx"; diff --git a/samples/drivers/led/led_strip/boards/esp32h2_devkitm.overlay b/samples/drivers/led/led_strip/boards/esp32h2_devkitm.overlay new file mode 100644 index 0000000000000..6b223b68b6c7c --- /dev/null +++ b/samples/drivers/led/led_strip/boards/esp32h2_devkitm.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + aliases { + led-strip = &led_strip; + }; +}; + +&i2s_default { + group1 { + pinmux = ; + }; +}; + +i2s_led: &i2s { + status = "okay"; + + dmas = <&dma 3>; + dma-names = "tx"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-i2s"; + + reg = <0>; + chain-length = <1>; + color-mapping = ; + reset-delay = <500>; + }; +}; + +&dma { + status = "okay"; +}; diff --git a/samples/drivers/led/led_strip/boards/esp32s2_devkitc.conf b/samples/drivers/led/led_strip/boards/esp32s2_devkitc.conf deleted file mode 100644 index c1378264b967c..0000000000000 --- a/samples/drivers/led/led_strip/boards/esp32s2_devkitc.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_I2S=y diff --git a/samples/drivers/led/led_strip/boards/esp32s2_devkitc.overlay b/samples/drivers/led/led_strip/boards/esp32s2_devkitc.overlay index 9b7c301a3fcd8..0d2a7699c7a76 100644 --- a/samples/drivers/led/led_strip/boards/esp32s2_devkitc.overlay +++ b/samples/drivers/led/led_strip/boards/esp32s2_devkitc.overlay @@ -15,7 +15,6 @@ &i2s0_default { group1 { pinmux = ; - output-enable; }; }; diff --git a/samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.conf b/samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.conf deleted file mode 100644 index c1378264b967c..0000000000000 --- a/samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_I2S=y diff --git a/samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.overlay b/samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.overlay index ab31f1d9b7739..518db69ff8794 100644 --- a/samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.overlay +++ b/samples/drivers/led/led_strip/boards/esp32s3_devkitc_procpu.overlay @@ -15,7 +15,6 @@ &i2s0_default { group1 { pinmux = ; - output-enable; }; }; From 5001b4051589f58a6e746641b3ae76f25fdf1ea2 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Mon, 14 Jul 2025 18:59:59 -0300 Subject: [PATCH 10/11] tests: drivers: i2s_api: add esp32 boards adds the following boards ot i2s_api test: - esp32c3_devkitm - esp32c6_devkitc/esp32c6/hpcore - esp32s3_devkitc/esp32s3/procpu - esp32h2_devkitm Signed-off-by: Marcio Ribeiro --- .../i2s/i2s_api/boards/esp32c3_devkitm.conf | 6 +++ .../i2s_api/boards/esp32c3_devkitm.overlay | 41 +++++++++++++++++++ .../boards/esp32c6_devkitc_hpcore.conf | 6 +++ .../boards/esp32c6_devkitc_hpcore.overlay | 41 +++++++++++++++++++ .../i2s/i2s_api/boards/esp32h2_devkitm.conf | 6 +++ .../i2s_api/boards/esp32h2_devkitm.overlay | 41 +++++++++++++++++++ .../boards/esp32s3_devkitm_procpu.conf | 6 +++ .../boards/esp32s3_devkitm_procpu.overlay | 41 +++++++++++++++++++ 8 files changed, 188 insertions(+) create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.conf create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.overlay create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.conf create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.overlay create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.conf create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.overlay create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.conf create mode 100644 tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.overlay diff --git a/tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.conf b/tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.conf new file mode 100644 index 0000000000000..f5a9ecb46a683 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2S_TEST_USE_I2S_DIR_BOTH=y +CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y +CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET=1 diff --git a/tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.overlay b/tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.overlay new file mode 100644 index 0000000000000..69b3174c14fa8 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32c3_devkitm.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s; + }; +}; + +&i2s_default { + group1 { + pinmux = , + ; + }; + + group2 { + pinmux = ; + input-enable; + }; + + group3 { + pinmux = ; + output-enable; + }; +}; + +&i2s { + status = "okay"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "rx", "tx"; +}; + +&dma { + status = "okay"; +}; diff --git a/tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.conf b/tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.conf new file mode 100644 index 0000000000000..f5a9ecb46a683 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2S_TEST_USE_I2S_DIR_BOTH=y +CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y +CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET=1 diff --git a/tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.overlay b/tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.overlay new file mode 100644 index 0000000000000..69b3174c14fa8 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32c6_devkitc_hpcore.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s; + }; +}; + +&i2s_default { + group1 { + pinmux = , + ; + }; + + group2 { + pinmux = ; + input-enable; + }; + + group3 { + pinmux = ; + output-enable; + }; +}; + +&i2s { + status = "okay"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "rx", "tx"; +}; + +&dma { + status = "okay"; +}; diff --git a/tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.conf b/tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.conf new file mode 100644 index 0000000000000..f5a9ecb46a683 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2S_TEST_USE_I2S_DIR_BOTH=y +CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y +CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET=1 diff --git a/tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.overlay b/tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.overlay new file mode 100644 index 0000000000000..49f7c8e862c69 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32h2_devkitm.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s; + }; +}; + +&i2s_default { + group1 { + pinmux = , + ; + }; + + group2 { + pinmux = ; + input-enable; + }; + + group3 { + pinmux = ; + output-enable; + }; +}; + +&i2s { + status = "okay"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "rx", "tx"; +}; + +&dma { + status = "okay"; +}; diff --git a/tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.conf b/tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.conf new file mode 100644 index 0000000000000..f5a9ecb46a683 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2S_TEST_USE_I2S_DIR_BOTH=y +CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y +CONFIG_I2S_TEST_ALLOWED_DATA_OFFSET=1 diff --git a/tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.overlay b/tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.overlay new file mode 100644 index 0000000000000..29264f14b6c21 --- /dev/null +++ b/tests/drivers/i2s/i2s_api/boards/esp32s3_devkitm_procpu.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s0; + }; +}; + +&i2s0_default { + group1 { + pinmux = , + ; + }; + + group2 { + pinmux = ; + input-enable; + }; + + group3 { + pinmux = ; + output-enable; + }; +}; + +&i2s0 { + status = "okay"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "rx", "tx"; +}; + +&dma { + status = "okay"; +}; From 92e02209f9b651aaa16e735cd614797cb2173ab2 Mon Sep 17 00:00:00 2001 From: Marcio Ribeiro Date: Wed, 13 Aug 2025 22:24:16 -0300 Subject: [PATCH 11/11] tests: boards: esp32: add simplified i2s test Adds simplified i2s test for: - esp32 - esp32s2 Signed-off-by: Marcio Ribeiro --- tests/boards/espressif/i2s/CMakeLists.txt | 9 + tests/boards/espressif/i2s/Kconfig | 25 ++ .../i2s/boards/esp32_devkitc_procpu.conf | 6 + .../i2s/boards/esp32_devkitc_procpu.overlay | 42 +++ .../espressif/i2s/boards/esp32s2_saola.conf | 6 + .../i2s/boards/esp32s2_saola.overlay | 38 +++ tests/boards/espressif/i2s/prj.conf | 3 + tests/boards/espressif/i2s/src/main.c | 242 ++++++++++++++++++ tests/boards/espressif/i2s/testcase.yaml | 12 + 9 files changed, 383 insertions(+) create mode 100644 tests/boards/espressif/i2s/CMakeLists.txt create mode 100644 tests/boards/espressif/i2s/Kconfig create mode 100644 tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.conf create mode 100644 tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.overlay create mode 100644 tests/boards/espressif/i2s/boards/esp32s2_saola.conf create mode 100644 tests/boards/espressif/i2s/boards/esp32s2_saola.overlay create mode 100644 tests/boards/espressif/i2s/prj.conf create mode 100644 tests/boards/espressif/i2s/src/main.c create mode 100644 tests/boards/espressif/i2s/testcase.yaml diff --git a/tests/boards/espressif/i2s/CMakeLists.txt b/tests/boards/espressif/i2s/CMakeLists.txt new file mode 100644 index 0000000000000..1122589916de8 --- /dev/null +++ b/tests/boards/espressif/i2s/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(i2s_test) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/boards/espressif/i2s/Kconfig b/tests/boards/espressif/i2s/Kconfig new file mode 100644 index 0000000000000..0aac5b532c3c6 --- /dev/null +++ b/tests/boards/espressif/i2s/Kconfig @@ -0,0 +1,25 @@ +# +# Copyright (c) 2025 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: Apache-2.0 +# + +mainmenu "ESP32 I2S Loopback Test" + +source "Kconfig.zephyr" + +config I2S_TEST_SEPARATE_DEVICES + bool "Use two separate I2S ports for loopback" + help + Use separate I2S ports for transmit and receive. + +config I2S_TEST_USE_GPIO_LOOPBACK + bool "Use GPIO loopback" + help + Use wiring between the data-out and data-in pins for looping back data. + +config I2S_TEST_ALLOWED_DATA_DISCARD + int "Allowed discard in received data" + default 0 + help + Maximum allowed discard between sent and received samples diff --git a/tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.conf b/tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.conf new file mode 100644 index 0000000000000..fd7b3f71d5059 --- /dev/null +++ b/tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y +CONFIG_I2S_TEST_ALLOWED_DATA_DISCARD=1 +CONFIG_I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS=1 diff --git a/tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.overlay b/tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.overlay new file mode 100644 index 0000000000000..58d97874eaba7 --- /dev/null +++ b/tests/boards/espressif/i2s/boards/esp32_devkitc_procpu.overlay @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s0; + }; +}; + +&pinctrl { + i2s0_default: i2s0_default { + group1 { + pinmux = , + ; + }; + + group2 { + pinmux = ; + input-enable; + }; + + group3 { + pinmux = ; + output-enable; + }; + }; +}; + +&i2s0 { + status = "okay"; + pinctrl-0 = <&i2s0_default>; + pinctrl-names = "default"; + + interrupts = , + ; + interrupt-names = "tx", "rx"; +}; diff --git a/tests/boards/espressif/i2s/boards/esp32s2_saola.conf b/tests/boards/espressif/i2s/boards/esp32s2_saola.conf new file mode 100644 index 0000000000000..fd7b3f71d5059 --- /dev/null +++ b/tests/boards/espressif/i2s/boards/esp32s2_saola.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2S_TEST_USE_GPIO_LOOPBACK=y +CONFIG_I2S_TEST_ALLOWED_DATA_DISCARD=1 +CONFIG_I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS=1 diff --git a/tests/boards/espressif/i2s/boards/esp32s2_saola.overlay b/tests/boards/espressif/i2s/boards/esp32s2_saola.overlay new file mode 100644 index 0000000000000..cf322a7406b08 --- /dev/null +++ b/tests/boards/espressif/i2s/boards/esp32s2_saola.overlay @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* i2s-node0 is the transmitter/receiver */ + +/ { + aliases { + i2s-node0 = &i2s0; + }; +}; + +&i2s0_default { + group1 { + pinmux = , + ; + }; + + group2 { + pinmux = ; + input-enable; + }; + + group3 { + pinmux = ; + output-enable; + }; +}; + +&i2s0 { + status = "okay"; + + interrupts = , + ; + interrupt-names = "rx", "tx"; +}; diff --git a/tests/boards/espressif/i2s/prj.conf b/tests/boards/espressif/i2s/prj.conf new file mode 100644 index 0000000000000..7c088b1ffe467 --- /dev/null +++ b/tests/boards/espressif/i2s/prj.conf @@ -0,0 +1,3 @@ +CONFIG_I2S=y +CONFIG_ZTEST=y +CONFIG_TEST_USERSPACE=y diff --git a/tests/boards/espressif/i2s/src/main.c b/tests/boards/espressif/i2s/src/main.c new file mode 100644 index 0000000000000..2f6e2744970f3 --- /dev/null +++ b/tests/boards/espressif/i2s/src/main.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define SAMPLE_NO 32 +#define TIMEOUT 2000 +#define FRAME_CLK_FREQ 8000 + +#define NUM_RX_BLOCKS 4 +#define NUM_TX_BLOCKS 4 + +#define VAL_L 11 +#define VAL_R 22 + +#define TRANSFER_REPEAT_COUNT 100 + +#define I2S_DEV_NODE_RX DT_ALIAS(i2s_node0) +#ifdef CONFIG_I2S_TEST_SEPARATE_DEVICES +#define I2S_DEV_NODE_TX DT_ALIAS(i2s_node1) +#else +#define I2S_DEV_NODE_TX DT_ALIAS(i2s_node0) +#endif + +ZTEST_DMEM const struct device *dev_i2s_rx = DEVICE_DT_GET_OR_NULL(I2S_DEV_NODE_RX); +ZTEST_DMEM const struct device *dev_i2s_tx = DEVICE_DT_GET_OR_NULL(I2S_DEV_NODE_TX); +ZTEST_DMEM const struct device *dev_i2s = DEVICE_DT_GET_OR_NULL(I2S_DEV_NODE_RX); + +#define BLOCK_SIZE (2 * SAMPLE_NO * sizeof(int16_t)) + +K_MEM_SLAB_DEFINE(rx_mem_slab, BLOCK_SIZE, NUM_RX_BLOCKS, 32); +K_MEM_SLAB_DEFINE(tx_mem_slab, BLOCK_SIZE, NUM_TX_BLOCKS, 32); + +void fill_buf(int16_t *tx_block, int16_t val_l, int16_t val_r) +{ + for (int16_t i = 0; i < SAMPLE_NO; i++) { + tx_block[2 * i] = val_l + i; + tx_block[2 * i + 1] = val_r + i; + } +} + +int verify_buf(int16_t *rx_block, int16_t val_l, int16_t val_r) +{ + int sample_no = SAMPLE_NO; + +#if (CONFIG_I2S_TEST_ALLOWED_DATA_DISCARD > 0) + static ZTEST_DMEM int offset = -1; + + if (offset < 0) { + do { + ++offset; + if (offset > CONFIG_I2S_TEST_ALLOWED_DATA_DISCARD) { + TC_PRINT("Allowed data discard exceeded\n"); + return -TC_FAIL; + } + } while ((rx_block[0] != val_l + offset) || (rx_block[1] != val_r + offset)); + } + + val_l += offset; + val_r += offset; + sample_no -= offset; +#endif + + for (int16_t i = 0; i < sample_no; i++) { + if (rx_block[2 * i] != (val_l + i)) { + TC_PRINT("Error: data_l mismatch at position " + "%d, expected %d, actual %d\n", + i, (int)(val_l + i), (int)rx_block[2 * i]); + return -TC_FAIL; + } + if (rx_block[2 * i + 1] != (val_r + i)) { + TC_PRINT("Error: data_r mismatch at position " + "%d, expected %d, actual %d\n", + i, (int)(val_r + i), (int)rx_block[2 * i + 1]); + return -TC_FAIL; + } + } + + return TC_PASS; +} + +static int tx_block_write_slab(const struct device *i2s_dev, int16_t val_l, int16_t val_r, int err, + struct k_mem_slab *slab) +{ + char tx_block[BLOCK_SIZE]; + int ret; + + fill_buf((uint16_t *)tx_block, val_l, val_r); + ret = i2s_buf_write(i2s_dev, tx_block, BLOCK_SIZE); + if (ret != err) { + TC_PRINT("Error: i2s_write failed expected %d, actual %d\n", err, ret); + return -TC_FAIL; + } + + return TC_PASS; +} + +int tx_block_write(const struct device *i2s_dev, int16_t val_l, int16_t val_r, int err) +{ + return tx_block_write_slab(i2s_dev, val_l, val_r, err, &tx_mem_slab); +} + +static int rx_block_read_slab(const struct device *i2s_dev, int16_t val_l, int16_t val_r, + struct k_mem_slab *slab) +{ + char rx_block[BLOCK_SIZE]; + size_t rx_size; + int ret; + + ret = i2s_buf_read(i2s_dev, rx_block, &rx_size); + if (ret < 0 || rx_size != BLOCK_SIZE) { + TC_PRINT("Error: Read failed\n"); + return -TC_FAIL; + } + ret = verify_buf((uint16_t *)rx_block, val_l, val_r); + if (ret < 0) { + TC_PRINT("Error: Verify failed\n"); + return -TC_FAIL; + } + + return TC_PASS; +} + +int rx_block_read(const struct device *i2s_dev, int16_t val_l, int16_t val_r) +{ + return rx_block_read_slab(i2s_dev, val_l, val_r, &rx_mem_slab); +} + +int configure_stream(const struct device *i2s_dev, enum i2s_dir dir) +{ + int ret; + struct i2s_config i2s_cfg = {0}; + + i2s_cfg.word_size = 16U; + i2s_cfg.channels = 2U; + i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S; + i2s_cfg.frame_clk_freq = FRAME_CLK_FREQ; + i2s_cfg.block_size = BLOCK_SIZE; + i2s_cfg.timeout = TIMEOUT; + + if (dir == I2S_DIR_TX) { + /* Configure the Transmit port as Master */ + i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER; + } else if (dir == I2S_DIR_RX) { + /* Configure the Receive port as Slave */ + i2s_cfg.options = I2S_OPT_FRAME_CLK_SLAVE | I2S_OPT_BIT_CLK_SLAVE; + } else { /* dir == I2S_DIR_BOTH */ + i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER | I2S_OPT_BIT_CLK_MASTER; + } + + if (!IS_ENABLED(CONFIG_I2S_TEST_USE_GPIO_LOOPBACK)) { + i2s_cfg.options |= I2S_OPT_LOOPBACK; + } + + if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { + i2s_cfg.mem_slab = &tx_mem_slab; + ret = i2s_configure(i2s_dev, I2S_DIR_TX, &i2s_cfg); + if (ret < 0) { + TC_PRINT("Failed to configure I2S TX stream (%d)\n", ret); + return -TC_FAIL; + } + } + + if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { + i2s_cfg.mem_slab = &rx_mem_slab; + ret = i2s_configure(i2s_dev, I2S_DIR_RX, &i2s_cfg); + if (ret < 0) { + TC_PRINT("Failed to configure I2S RX stream (%d)\n", ret); + return -TC_FAIL; + } + } + + return TC_PASS; +} + +static void *setup(void) +{ + k_thread_access_grant(k_current_get(), &rx_mem_slab, &tx_mem_slab); + k_object_access_grant(dev_i2s_rx, k_current_get()); + k_object_access_grant(dev_i2s_tx, k_current_get()); + + return NULL; +} + +static void before(void *fixture) +{ + ARG_UNUSED(fixture); + + int ret; + + zassert_not_null(dev_i2s_rx, "RX device not found"); + zassert_true(device_is_ready(dev_i2s_rx), "device %s is not ready", dev_i2s_rx->name); + + zassert_not_null(dev_i2s_tx, "TX device not found"); + zassert_true(device_is_ready(dev_i2s_tx), "device %s is not ready", dev_i2s_tx->name); + + ret = configure_stream(dev_i2s_rx, I2S_DIR_RX); + zassert_equal(ret, TC_PASS); + + ret = configure_stream(dev_i2s_tx, I2S_DIR_TX); + zassert_equal(ret, TC_PASS); +} + +/** @brief I2S transfer. + * + * - START trigger starts both the transmission and reception. + * - sending / receiving a sequence of data returns success. + * - DRAIN trigger empties the transmit queue and stops both streams. + */ +ZTEST_USER(i2s_loopback, test_i2s_transfer) +{ + int ret; + + /* Prefill TX queue */ + ret = tx_block_write(dev_i2s, VAL_L, VAL_R, 0); + zassert_equal(ret, TC_PASS); + + ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_START); + zassert_equal(ret, 0, "RX/TX START trigger failed\n"); + + for (int i = 0; i < TRANSFER_REPEAT_COUNT; i++) { + ret = tx_block_write(dev_i2s_tx, VAL_L, VAL_R, 0); + zassert_equal(ret, TC_PASS); + + ret = rx_block_read(dev_i2s_rx, VAL_L, VAL_R); + zassert_equal(ret, TC_PASS); + } + + /* All data written, all but one data block read, flush TX queue + * and stop both streams. + */ + ret = i2s_trigger(dev_i2s, I2S_DIR_BOTH, I2S_TRIGGER_DRAIN); + zassert_equal(ret, 0, "RX/TX DRAIN trigger failed"); +} + +ZTEST_SUITE(i2s_loopback, NULL, setup, before, NULL, NULL); diff --git a/tests/boards/espressif/i2s/testcase.yaml b/tests/boards/espressif/i2s/testcase.yaml new file mode 100644 index 0000000000000..4a3e979191e35 --- /dev/null +++ b/tests/boards/espressif/i2s/testcase.yaml @@ -0,0 +1,12 @@ +tests: + boards.esp32.i2s.gpio_loopback: + depends_on: + - i2s + - gpio + tags: + - drivers + - userspace + filter: CONFIG_I2S_TEST_USE_GPIO_LOOPBACK + harness: ztest + harness_config: + fixture: gpio_loopback