diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index aced4db96934f88..852777f90cbbe29 100644 --- a/drivers/i2s/i2s_nrfx.c +++ b/drivers/i2s/i2s_nrfx.c @@ -20,6 +20,11 @@ struct stream_cfg { nrfx_i2s_config_t nrfx_cfg; }; +struct i2s_buf { + void *mem_block; + size_t size; +}; + struct i2s_nrfx_drv_data { struct onoff_manager *clk_mgr; struct onoff_client clk_cli; @@ -29,6 +34,7 @@ struct i2s_nrfx_drv_data { struct k_msgq rx_queue; const nrfx_i2s_t *p_i2s; const uint32_t *last_tx_buffer; + uint16_t last_buffer_size; enum i2s_state state; enum i2s_dir active_dir; bool stop; /* stop after the current (TX or RX) block */ @@ -189,9 +195,14 @@ static void find_suitable_clock(const struct i2s_nrfx_drv_cfg *drv_cfg, static bool get_next_tx_buffer(struct i2s_nrfx_drv_data *drv_data, nrfx_i2s_buffers_t *buffers) { + struct i2s_buf buf; int ret = k_msgq_get(&drv_data->tx_queue, - &buffers->p_tx_buffer, + &buf, K_NO_WAIT); + if (ret == 0) { + buffers->p_tx_buffer = buf.mem_block; + buffers->buffer_size = buf.size / sizeof(uint32_t); + } return (ret == 0); } @@ -226,21 +237,20 @@ static void free_rx_buffer(struct i2s_nrfx_drv_data *drv_data, void *buffer) static bool supply_next_buffers(struct i2s_nrfx_drv_data *drv_data, nrfx_i2s_buffers_t *next) { - uint32_t block_size = (drv_data->active_dir == I2S_DIR_TX) - ? drv_data->tx.cfg.block_size - : drv_data->rx.cfg.block_size; - - drv_data->last_tx_buffer = next->p_tx_buffer; - if (drv_data->active_dir != I2S_DIR_TX) { /* -> RX active */ if (!get_next_rx_buffer(drv_data, next)) { drv_data->state = I2S_STATE_ERROR; nrfx_i2s_stop(drv_data->p_i2s); return false; } + if (drv_data->active_dir == I2S_DIR_RX) { + next->buffer_size = + drv_data->rx.cfg.block_size / sizeof(uint32_t); + } } - next->buffer_size = block_size / sizeof(uint32_t); + drv_data->last_tx_buffer = next->p_tx_buffer; + drv_data->last_buffer_size = next->buffer_size; LOG_DBG("Next buffers: %p/%p", next->p_tx_buffer, next->p_rx_buffer); nrfx_i2s_next_buffers_set(drv_data->p_i2s, next); @@ -274,6 +284,7 @@ static void data_handler(const struct device *dev, drv_data->last_tx_buffer); } drv_data->last_tx_buffer = NULL; + drv_data->last_buffer_size = 0; } nrfx_i2s_uninit(drv_data->p_i2s); if (drv_data->request_clock) { @@ -300,8 +311,12 @@ static void data_handler(const struct device *dev, if (drv_data->discard_rx) { free_rx_buffer(drv_data, released->p_rx_buffer); } else { + struct i2s_buf buf = { + .mem_block = released->p_rx_buffer, + .size = released->buffer_size * sizeof(uint32_t) + }; int ret = k_msgq_put(&drv_data->rx_queue, - &released->p_rx_buffer, + &buf, K_NO_WAIT); if (ret < 0) { LOG_ERR("No room in RX queue"); @@ -351,6 +366,7 @@ static void data_handler(const struct device *dev, * before this buffer would be started again). */ next.p_tx_buffer = drv_data->last_tx_buffer; + next.buffer_size = drv_data->last_buffer_size; } else if (get_next_tx_buffer(drv_data, &next)) { /* Next TX buffer successfully retrieved from * the queue, nothing more to do here. @@ -367,6 +383,7 @@ static void data_handler(const struct device *dev, * will be stopped earlier. */ next.p_tx_buffer = drv_data->last_tx_buffer; + next.buffer_size = drv_data->last_buffer_size; } else { /* Next TX buffer cannot be supplied now. * Defer it to when the user writes more data. @@ -383,13 +400,13 @@ static void data_handler(const struct device *dev, static void purge_queue(const struct device *dev, enum i2s_dir dir) { struct i2s_nrfx_drv_data *drv_data = dev->data; - void *mem_block; + struct i2s_buf mem_block; if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { while (k_msgq_get(&drv_data->tx_queue, &mem_block, K_NO_WAIT) == 0) { - free_tx_buffer(drv_data, mem_block); + free_tx_buffer(drv_data, mem_block.mem_block); } } @@ -397,7 +414,7 @@ static void purge_queue(const struct device *dev, enum i2s_dir dir) while (k_msgq_get(&drv_data->rx_queue, &mem_block, K_NO_WAIT) == 0) { - free_rx_buffer(drv_data, mem_block); + free_rx_buffer(drv_data, mem_block.mem_block); } } } @@ -560,6 +577,7 @@ static int i2s_nrfx_read(const struct device *dev, void **mem_block, size_t *size) { struct i2s_nrfx_drv_data *drv_data = dev->data; + struct i2s_buf buf; int ret; if (!drv_data->rx_configured) { @@ -568,7 +586,7 @@ static int i2s_nrfx_read(const struct device *dev, } ret = k_msgq_get(&drv_data->rx_queue, - mem_block, + &buf, (drv_data->state == I2S_STATE_ERROR) ? K_NO_WAIT : SYS_TIMEOUT_MS(drv_data->rx.cfg.timeout)); @@ -576,10 +594,11 @@ static int i2s_nrfx_read(const struct device *dev, return -EIO; } - LOG_DBG("Released RX %p", *mem_block); + LOG_DBG("Released RX %p", buf.mem_block); if (ret == 0) { - *size = drv_data->rx.cfg.block_size; + *mem_block = buf.mem_block; + *size = buf.size; } return ret; @@ -589,6 +608,7 @@ static int i2s_nrfx_write(const struct device *dev, void *mem_block, size_t size) { struct i2s_nrfx_drv_data *drv_data = dev->data; + struct i2s_buf buf = { .mem_block = mem_block, .size = size }; int ret; if (!drv_data->tx_configured) { @@ -602,14 +622,8 @@ static int i2s_nrfx_write(const struct device *dev, return -EIO; } - if (size != drv_data->tx.cfg.block_size) { - LOG_ERR("This device can only write blocks of %u bytes", - drv_data->tx.cfg.block_size); - return -EIO; - } - ret = k_msgq_put(&drv_data->tx_queue, - &mem_block, + &buf, SYS_TIMEOUT_MS(drv_data->tx.cfg.timeout)); if (ret < 0) { return ret; @@ -662,13 +676,15 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data) /* Failed to allocate next RX buffer */ ret = -ENOMEM; } else { - uint32_t block_size = (drv_data->active_dir == I2S_DIR_TX) - ? drv_data->tx.cfg.block_size - : drv_data->rx.cfg.block_size; nrfx_err_t err; - initial_buffers.buffer_size = block_size / sizeof(uint32_t); + if (drv_data->active_dir == I2S_DIR_RX) { + initial_buffers.buffer_size = + drv_data->rx.cfg.block_size / sizeof(uint32_t); + } + drv_data->last_tx_buffer = initial_buffers.p_tx_buffer; + drv_data->last_buffer_size = initial_buffers.buffer_size; err = nrfx_i2s_start(drv_data->p_i2s, &initial_buffers, 0); if (err == NRFX_SUCCESS) { @@ -904,8 +920,8 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { #define I2S_CLK_SRC(idx) DT_STRING_TOKEN(I2S(idx), clock_source) #define I2S_NRFX_DEVICE(idx) \ - static void *tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \ - static void *rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \ + static struct i2s_buf tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \ + static struct i2s_buf rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \ static void data_handler##idx(nrfx_i2s_buffers_t const *p_released, \ uint32_t status) \ { \ @@ -941,10 +957,10 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { return err; \ } \ k_msgq_init(&i2s_nrfx_data##idx.tx_queue, \ - (char *)tx_msgs##idx, sizeof(void *), \ + (char *)tx_msgs##idx, sizeof(struct i2s_buf), \ ARRAY_SIZE(tx_msgs##idx)); \ k_msgq_init(&i2s_nrfx_data##idx.rx_queue, \ - (char *)rx_msgs##idx, sizeof(void *), \ + (char *)rx_msgs##idx, sizeof(struct i2s_buf), \ ARRAY_SIZE(rx_msgs##idx)); \ init_clock_manager(dev); \ return 0; \