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:
parent
6505cbc085
commit
56903cab63
1 changed files with 35 additions and 21 deletions
|
@ -98,23 +98,30 @@ struct i2s_dev_data {
|
||||||
|
|
||||||
static void i2s_dma_tx_callback(const struct device *, void *,
|
static void i2s_dma_tx_callback(const struct device *, void *,
|
||||||
uint32_t, int);
|
uint32_t, int);
|
||||||
static void i2s_tx_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 *);
|
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,
|
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;
|
void *buffer;
|
||||||
|
|
||||||
while (k_msgq_get(&strm->in_queue, &buffer, K_NO_WAIT) == 0) {
|
if (in_drop) {
|
||||||
k_mem_slab_free(mem_slab, &buffer);
|
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 i2s_dev_data *dev_data = dev->data;
|
||||||
struct stream *strm = &dev_data->tx;
|
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;
|
dev_cfg->base->TCR3 &= ~I2S_TCR3_TCE_MASK;
|
||||||
|
|
||||||
/* purge buffers queued in the stream */
|
/* 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 */
|
/* Disable DMA enable bit */
|
||||||
SAI_TxEnableDMA(dev_cfg->base, kSAI_FIFORequestDMAEnable,
|
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 i2s_dev_data *dev_data = dev->data;
|
||||||
struct stream *strm = &dev_data->rx;
|
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);
|
SAI_RxEnable(dev_cfg->base, false);
|
||||||
|
|
||||||
/* purge buffers queued in the stream */
|
/* 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;
|
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 */
|
/* get the next buffer from queue */
|
||||||
if (strm->in_queue.used_msgs == 0) {
|
if (strm->in_queue.used_msgs == 0) {
|
||||||
LOG_DBG("tx no more in queue data");
|
LOG_DBG("tx no more in queue data");
|
||||||
i2s_tx_stream_disable(dev);
|
i2s_tx_stream_disable(dev, false);
|
||||||
/* stream is starving */
|
/* stream is starving */
|
||||||
strm->stream_starving = true;
|
strm->stream_starving = true;
|
||||||
return;
|
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",
|
LOG_ERR("DMA status %08x chan %u get ret %d",
|
||||||
status, channel, ret);
|
status, channel, ret);
|
||||||
strm->state = I2S_STATE_READY;
|
strm->state = I2S_STATE_READY;
|
||||||
i2s_tx_stream_disable(dev);
|
i2s_tx_stream_disable(dev, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case I2S_STATE_STOPPING:
|
case I2S_STATE_STOPPING:
|
||||||
i2s_tx_stream_disable(dev);
|
i2s_tx_stream_disable(dev, true);
|
||||||
strm->state = I2S_STATE_READY;
|
strm->state = I2S_STATE_READY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +303,7 @@ static void i2s_dma_rx_callback(const struct device *dma_dev,
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
LOG_ERR("buffer alloc from slab %p err %d",
|
LOG_ERR("buffer alloc from slab %p err %d",
|
||||||
strm->cfg.mem_slab, ret);
|
strm->cfg.mem_slab, ret);
|
||||||
i2s_rx_stream_disable(dev);
|
i2s_rx_stream_disable(dev, false, false);
|
||||||
strm->state = I2S_STATE_ERROR;
|
strm->state = I2S_STATE_ERROR;
|
||||||
} else {
|
} else {
|
||||||
uint32_t data_path = strm->start_channel;
|
uint32_t data_path = strm->start_channel;
|
||||||
|
@ -323,7 +337,7 @@ static void i2s_dma_rx_callback(const struct device *dma_dev,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case I2S_STATE_ERROR:
|
case I2S_STATE_ERROR:
|
||||||
i2s_rx_stream_disable(dev);
|
i2s_rx_stream_disable(dev, true, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -783,9 +797,9 @@ static int i2s_mcux_trigger(const struct device *dev, enum i2s_dir dir,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (dir == I2S_DIR_TX) {
|
if (dir == I2S_DIR_TX) {
|
||||||
i2s_tx_stream_disable(dev);
|
i2s_tx_stream_disable(dev, true);
|
||||||
} else {
|
} else {
|
||||||
i2s_rx_stream_disable(dev);
|
i2s_rx_stream_disable(dev, true, true);
|
||||||
}
|
}
|
||||||
strm->state = I2S_STATE_READY;
|
strm->state = I2S_STATE_READY;
|
||||||
break;
|
break;
|
||||||
|
@ -814,9 +828,9 @@ static int i2s_mcux_trigger(const struct device *dev, enum i2s_dir dir,
|
||||||
}
|
}
|
||||||
strm->state = I2S_STATE_READY;
|
strm->state = I2S_STATE_READY;
|
||||||
if (dir == I2S_DIR_TX) {
|
if (dir == I2S_DIR_TX) {
|
||||||
i2s_tx_stream_disable(dev);
|
i2s_tx_stream_disable(dev, true);
|
||||||
} else {
|
} else {
|
||||||
i2s_rx_stream_disable(dev);
|
i2s_rx_stream_disable(dev, true, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -853,7 +867,7 @@ static int i2s_mcux_read(const struct device *dev, void **mem_block,
|
||||||
|
|
||||||
switch (strm->state) {
|
switch (strm->state) {
|
||||||
case I2S_STATE_STOPPING:
|
case I2S_STATE_STOPPING:
|
||||||
i2s_rx_stream_disable(dev);
|
i2s_rx_stream_disable(dev, true, false);
|
||||||
strm->state = I2S_STATE_READY;
|
strm->state = I2S_STATE_READY;
|
||||||
break;
|
break;
|
||||||
case I2S_STATE_RUNNING:
|
case I2S_STATE_RUNNING:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue