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 <derek.snell@nxp.com>
This commit is contained in:
Derek Snell 2022-02-25 11:21:52 -05:00 committed by Carles Cufí
commit 56903cab63

View file

@ -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: