From 56903cab63ec7bb0846dff6eb811b68367336bf5 Mon Sep 17 00:00:00 2001 From: Derek Snell Date: Fri, 25 Feb 2022 11:21:52 -0500 Subject: [PATCH] drivers: i2s: mcux_sai: add control for purging buffers stream_disable()'s should not always purge buffers. And i2s_rx_stream_disable() needs separate control for purging in_queue and out_queue since app owns buffers after placed in out_queue for i2s_read() Signed-off-by: Derek Snell --- drivers/i2s/i2s_mcux_sai.c | 56 ++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/drivers/i2s/i2s_mcux_sai.c b/drivers/i2s/i2s_mcux_sai.c index 684321c8574..265b2339345 100644 --- a/drivers/i2s/i2s_mcux_sai.c +++ b/drivers/i2s/i2s_mcux_sai.c @@ -98,23 +98,30 @@ struct i2s_dev_data { static void i2s_dma_tx_callback(const struct device *, void *, uint32_t, int); -static void i2s_tx_stream_disable(const struct device *); -static void i2s_rx_stream_disable(const struct device *); +static void i2s_tx_stream_disable(const struct device *, bool drop); +static void i2s_rx_stream_disable(const struct device *, + bool in_drop, bool out_drop); static inline void i2s_purge_stream_buffers(struct stream *strm, - struct k_mem_slab *mem_slab) + struct k_mem_slab *mem_slab, + bool in_drop, bool out_drop) { void *buffer; - while (k_msgq_get(&strm->in_queue, &buffer, K_NO_WAIT) == 0) { - k_mem_slab_free(mem_slab, &buffer); + if (in_drop) { + while (k_msgq_get(&strm->in_queue, &buffer, K_NO_WAIT) == 0) { + k_mem_slab_free(mem_slab, &buffer); + } } - while (k_msgq_get(&strm->out_queue, &buffer, K_NO_WAIT) == 0) { - k_mem_slab_free(mem_slab, &buffer); + + if (out_drop) { + while (k_msgq_get(&strm->out_queue, &buffer, K_NO_WAIT) == 0) { + k_mem_slab_free(mem_slab, &buffer); + } } } -static void i2s_tx_stream_disable(const struct device *dev) +static void i2s_tx_stream_disable(const struct device *dev, bool drop) { struct i2s_dev_data *dev_data = dev->data; struct stream *strm = &dev_data->tx; @@ -128,7 +135,10 @@ static void i2s_tx_stream_disable(const struct device *dev) dev_cfg->base->TCR3 &= ~I2S_TCR3_TCE_MASK; /* purge buffers queued in the stream */ - i2s_purge_stream_buffers(strm, dev_data->tx.cfg.mem_slab); + if (drop) { + i2s_purge_stream_buffers(strm, dev_data->tx.cfg.mem_slab, + true, true); + } /* Disable DMA enable bit */ SAI_TxEnableDMA(dev_cfg->base, kSAI_FIFORequestDMAEnable, @@ -147,7 +157,8 @@ static void i2s_tx_stream_disable(const struct device *dev) } } -static void i2s_rx_stream_disable(const struct device *dev) +static void i2s_rx_stream_disable(const struct device *dev, + bool in_drop, bool out_drop) { struct i2s_dev_data *dev_data = dev->data; struct stream *strm = &dev_data->rx; @@ -168,7 +179,10 @@ static void i2s_rx_stream_disable(const struct device *dev) SAI_RxEnable(dev_cfg->base, false); /* purge buffers queued in the stream */ - i2s_purge_stream_buffers(strm, dev_data->rx.cfg.mem_slab); + if (in_drop || out_drop) { + i2s_purge_stream_buffers(strm, dev_data->rx.cfg.mem_slab, + in_drop, out_drop); + } strm->stream_starving = false; @@ -209,7 +223,7 @@ static void i2s_dma_tx_callback(const struct device *dma_dev, /* get the next buffer from queue */ if (strm->in_queue.used_msgs == 0) { LOG_DBG("tx no more in queue data"); - i2s_tx_stream_disable(dev); + i2s_tx_stream_disable(dev, false); /* stream is starving */ strm->stream_starving = true; return; @@ -242,13 +256,13 @@ static void i2s_dma_tx_callback(const struct device *dma_dev, LOG_ERR("DMA status %08x chan %u get ret %d", status, channel, ret); strm->state = I2S_STATE_READY; - i2s_tx_stream_disable(dev); + i2s_tx_stream_disable(dev, false); } break; case I2S_STATE_STOPPING: - i2s_tx_stream_disable(dev); + i2s_tx_stream_disable(dev, true); strm->state = I2S_STATE_READY; break; } @@ -289,7 +303,7 @@ static void i2s_dma_rx_callback(const struct device *dma_dev, if (ret != 0) { LOG_ERR("buffer alloc from slab %p err %d", strm->cfg.mem_slab, ret); - i2s_rx_stream_disable(dev); + i2s_rx_stream_disable(dev, false, false); strm->state = I2S_STATE_ERROR; } else { uint32_t data_path = strm->start_channel; @@ -323,7 +337,7 @@ static void i2s_dma_rx_callback(const struct device *dma_dev, } break; case I2S_STATE_ERROR: - i2s_rx_stream_disable(dev); + i2s_rx_stream_disable(dev, true, true); break; } } @@ -783,9 +797,9 @@ static int i2s_mcux_trigger(const struct device *dev, enum i2s_dir dir, break; } if (dir == I2S_DIR_TX) { - i2s_tx_stream_disable(dev); + i2s_tx_stream_disable(dev, true); } else { - i2s_rx_stream_disable(dev); + i2s_rx_stream_disable(dev, true, true); } strm->state = I2S_STATE_READY; break; @@ -814,9 +828,9 @@ static int i2s_mcux_trigger(const struct device *dev, enum i2s_dir dir, } strm->state = I2S_STATE_READY; if (dir == I2S_DIR_TX) { - i2s_tx_stream_disable(dev); + i2s_tx_stream_disable(dev, true); } else { - i2s_rx_stream_disable(dev); + i2s_rx_stream_disable(dev, true, true); } break; @@ -853,7 +867,7 @@ static int i2s_mcux_read(const struct device *dev, void **mem_block, switch (strm->state) { case I2S_STATE_STOPPING: - i2s_rx_stream_disable(dev); + i2s_rx_stream_disable(dev, true, false); strm->state = I2S_STATE_READY; break; case I2S_STATE_RUNNING: