[Sound-open-firmware] [PATCH] comp: states: align states between DAIs, DMACs and components.

Liam Girdwood liam.r.girdwood at linux.intel.com
Wed Sep 20 15:58:01 CEST 2017


Align all components, DAIs and DMACs to use the same state levels and
transitions. This simplifies DAI and DMAC components integration.

The DRAIN state has also been removed to further reduce DMAC and DAI
complexity.

Signed-off-by: Liam Girdwood <liam.r.girdwood at linux.intel.com>
---
 src/audio/component.c              |  10 +--
 src/audio/dai.c                    |  73 +++++-----------
 src/audio/eq_iir.c                 |  11 ++-
 src/audio/host.c                   |   7 +-
 src/audio/mixer.c                  |   6 +-
 src/audio/pipeline.c               |  16 ++--
 src/drivers/dw-dma.c               | 173 +++++--------------------------------
 src/drivers/ssp.c                  | 135 +++++++----------------------
 src/include/reef/audio/component.h |  33 ++++---
 src/include/reef/dma.h             |  16 +---
 src/include/reef/ssp.h             |   9 --
 11 files changed, 125 insertions(+), 364 deletions(-)

diff --git a/src/audio/component.c b/src/audio/component.c
index 2a397d7..fd0d65e 100644
--- a/src/audio/component.c
+++ b/src/audio/component.c
@@ -93,7 +93,6 @@ struct comp_dev *comp_new(struct sof_ipc_comp *comp)
 	/* init component */
 	memcpy(&cdev->comp, comp, sizeof(*comp));
 	cdev->drv = drv;
-	cdev->state = COMP_STATE_INIT;
 	spinlock_init(&cdev->lock);
 	list_init(&cdev->bsource_list);
 	list_init(&cdev->bsink_list);
@@ -124,14 +123,13 @@ int comp_set_state(struct comp_dev *dev, int cmd)
 	switch (cmd) {
 	case COMP_CMD_START:
 	case COMP_CMD_RELEASE:
-		dev->state = COMP_STATE_RUNNING;
+		dev->state = COMP_STATE_ACTIVE;
 		break;
 	case COMP_CMD_STOP:
-		if (dev->state == COMP_STATE_RUNNING ||
-		dev->state == COMP_STATE_DRAINING ||
+		if (dev->state == COMP_STATE_ACTIVE ||
 		dev->state == COMP_STATE_PAUSED) {
 			comp_buffer_reset(dev);
-			dev->state = COMP_STATE_SETUP;
+			dev->state = COMP_STATE_READY;
 		} else {
 			trace_comp_error("CEs");
 			ret = -EINVAL;
@@ -139,7 +137,7 @@ int comp_set_state(struct comp_dev *dev, int cmd)
 		break;
 	case COMP_CMD_PAUSE:
 		/* only support pausing for running */
-		if (dev->state == COMP_STATE_RUNNING)
+		if (dev->state == COMP_STATE_ACTIVE)
 			dev->state = COMP_STATE_PAUSED;
 		else {
 			trace_comp_error("CEp");
diff --git a/src/audio/dai.c b/src/audio/dai.c
index 358ad2d..7f4cde6 100644
--- a/src/audio/dai.c
+++ b/src/audio/dai.c
@@ -82,6 +82,17 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
 
 	tracev_dai("irq");
 
+	/* is stream stopped or paused ? */
+	if (dev->state == COMP_STATE_PAUSED) {
+
+		/* stop the DAI */
+		dai_trigger(dd->dai, COMP_CMD_STOP, dev->params.direction);
+
+		/* tell DMA not to reload */
+		next->size = DMA_RELOAD_END;
+		return;
+	}
+
 	if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
 		dma_buffer = list_first_item(&dev->bsource_list,
 			struct comp_buffer, sink_list);
@@ -178,7 +189,7 @@ static struct comp_dev *dai_new_ssp(struct sof_ipc_comp *comp)
 
 	/* set up callback */
 	dma_set_cb(dd->dma, dd->chan, DMA_IRQ_TYPE_LLIST, dai_dma_cb, dev);
-
+	dev->state = COMP_STATE_READY;
 	return dev;
 
 error:
@@ -340,7 +351,7 @@ static int dai_params(struct comp_dev *dev)
 	trace_dai("par");
 
 	/* can set params on only init state */
-	if (dev->state != COMP_STATE_INIT) {
+	if (dev->state != COMP_STATE_READY) {
 		trace_dai_error("wdp");
 		return -EINVAL;
 	}
@@ -417,13 +428,13 @@ static int dai_reset(struct comp_dev *dev)
 		rfree(elem);
 	}
 
-	dev->state = COMP_STATE_INIT;
 	dd->dai_pos_blks = 0;
 	if (dd->dai_pos)
 		*dd->dai_pos = 0;
 	dd->dai_pos = NULL;
 	dd->last_bytes = 0;
 	dev->position = 0;
+	dev->state = COMP_STATE_READY;
 
 	return 0;
 }
@@ -439,61 +450,25 @@ static int dai_cmd(struct comp_dev *dev, int cmd, void *data)
 	tracev_value(cmd);
 
 	switch (cmd) {
-
 	case COMP_CMD_PAUSE:
-		if (dev->state == COMP_STATE_RUNNING) {
-			dma_pause(dd->dma, dd->chan);
-			dai_trigger(dd->dai, cmd, dev->params.direction);
-			dev->state = COMP_STATE_PAUSED;
-		}
-		break;
 	case COMP_CMD_STOP:
-		switch (dev->state) {
-		case COMP_STATE_RUNNING:
-		case COMP_STATE_PAUSED:
-			dma_stop(dd->dma, dd->chan,
-				dev->state == COMP_STATE_RUNNING ? 1 : 0);
-			/* need stop ssp */
-			dai_trigger(dd->dai, cmd, dev->params.direction);
-			/* go through */
-		case COMP_STATE_PREPARE:
-			dd->last_bytes = 0;
-			dev->state = COMP_STATE_SETUP;
-			break;
-		}
+		dev->state = COMP_STATE_PAUSED;
 		break;
 	case COMP_CMD_RELEASE:
-		/* only release from paused*/
-		if (dev->state == COMP_STATE_PAUSED) {
-			dai_trigger(dd->dai, cmd, dev->params.direction);
-			dma_release(dd->dma, dd->chan);
-
-			/* update starting wallclock */
-			platform_dai_wallclock(dev, &dd->wallclock);
-			dev->state = COMP_STATE_RUNNING;
-		}
-		break;
 	case COMP_CMD_START:
-		/* only start from prepared*/
-		if (dev->state == COMP_STATE_PREPARE) {
-			ret = dma_start(dd->dma, dd->chan);
-			if (ret < 0)
-				return ret;
-			dai_trigger(dd->dai, cmd, dev->params.direction);
-
-			/* update starting wallclock */
-			platform_dai_wallclock(dev, &dd->wallclock);
-			dev->state = COMP_STATE_RUNNING;
-		}
+
+		ret = dma_start(dd->dma, dd->chan);
+		if (ret < 0)
+			return ret;
+		dai_trigger(dd->dai, cmd, dev->params.direction);
+
+		/* update starting wallclock */
+		platform_dai_wallclock(dev, &dd->wallclock);
+		dev->state = COMP_STATE_ACTIVE;
 		break;
 	case COMP_CMD_SUSPEND:
 	case COMP_CMD_RESUME:
 		break;
-	case COMP_CMD_IPC_MMAP_PPOS:
-		dd->dai_pos = data;
-		if (dd->dai_pos)
-			*dd->dai_pos = 0;
-		break;
 	default:
 		break;
 	}
diff --git a/src/audio/eq_iir.c b/src/audio/eq_iir.c
index 66a613c..4a4cff1 100644
--- a/src/audio/eq_iir.c
+++ b/src/audio/eq_iir.c
@@ -398,27 +398,26 @@ static int eq_iir_cmd(struct comp_dev *dev, int cmd, void *data)
 		break;
 	case COMP_CMD_START:
 		trace_eq_iir("EFs");
-		dev->state = COMP_STATE_RUNNING;
+		dev->state = COMP_STATE_ACTIVE;
 		break;
 	case COMP_CMD_STOP:
 		trace_eq_iir("ESp");
-		if (dev->state == COMP_STATE_RUNNING ||
-			dev->state == COMP_STATE_DRAINING ||
+		if (dev->state == COMP_STATE_ACTIVE ||
 			dev->state == COMP_STATE_PAUSED) {
 			comp_buffer_reset(dev);
-			dev->state = COMP_STATE_SETUP;
+			dev->state = COMP_STATE_READY;
 		}
 		break;
 	case COMP_CMD_PAUSE:
 		trace_eq_iir("EPe");
 		/* only support pausing for running */
-		if (dev->state == COMP_STATE_RUNNING)
+		if (dev->state == COMP_STATE_ACTIVE)
 			dev->state = COMP_STATE_PAUSED;
 
 		break;
 	case COMP_CMD_RELEASE:
 		trace_eq_iir("ERl");
-		dev->state = COMP_STATE_RUNNING;
+		dev->state = COMP_STATE_ACTIVE;
 		break;
 	default:
 		trace_eq_iir("EDf");
diff --git a/src/audio/host.c b/src/audio/host.c
index e61e2d9..36e4c29 100644
--- a/src/audio/host.c
+++ b/src/audio/host.c
@@ -527,7 +527,7 @@ static int host_stop(struct comp_dev *dev)
 	/* now reset downstream buffer */
 	comp_buffer_reset(dev);
 
-	dev->state = COMP_STATE_SETUP;
+	dev->state = COMP_STATE_READY;
 	return 0;
 }
 
@@ -552,8 +552,7 @@ static int host_cmd(struct comp_dev *dev, int cmd, void *data)
 	// TODO: align cmd macros.
 	switch (cmd) {
 	case COMP_CMD_STOP:
-		if (dev->state == COMP_STATE_RUNNING ||
-			dev->state == COMP_STATE_DRAINING ||
+		if (dev->state == COMP_STATE_ACTIVE ||
 			dev->state == COMP_STATE_PAUSED)
 			ret = host_stop(dev);
 		break;
@@ -631,7 +630,7 @@ static int host_copy(struct comp_dev *dev)
 
 	tracev_host("cpy");
 
-	if (dev->state != COMP_STATE_RUNNING)
+	if (dev->state != COMP_STATE_ACTIVE)
 		return 0;
 
 	local_elem = list_first_item(&hd->config.elem_list,
diff --git a/src/audio/mixer.c b/src/audio/mixer.c
index a4dea4d..30ac8cc 100644
--- a/src/audio/mixer.c
+++ b/src/audio/mixer.c
@@ -270,7 +270,7 @@ static int mixer_reset(struct comp_dev *dev)
 	list_for_item(blist, &dev->bsource_list) {
 		source = container_of(blist, struct comp_buffer, sink_list);
 		/* only mix the sources with the same state with mixer*/
-		if (source->source->state > COMP_STATE_SETUP)
+		if (source->source->state > COMP_STATE_READY)
 			return 1; /* should not reset the downstream components */
 	}
 
@@ -295,7 +295,7 @@ static int mixer_prepare(struct comp_dev *dev)
 
 	trace_mixer("pre");
 
-	if (dev->state != COMP_STATE_RUNNING) {
+	if (dev->state != COMP_STATE_ACTIVE) {
 		md->mix_func = mix_n;
 		dev->state = COMP_STATE_PREPARE;
 		//dev->preload = PLAT_INT_PERIODS;
@@ -307,7 +307,7 @@ static int mixer_prepare(struct comp_dev *dev)
 
 		/* only prepare downstream if we have no active sources */
 		if (source->source->state == COMP_STATE_PAUSED ||
-				source->source->state == COMP_STATE_RUNNING) {
+				source->source->state == COMP_STATE_ACTIVE) {
 			downstream = 1;
 		}
 	}
diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c
index 2800d64..c7b95f9 100644
--- a/src/audio/pipeline.c
+++ b/src/audio/pipeline.c
@@ -237,7 +237,7 @@ int pipeline_free(struct pipeline *p)
 	trace_pipe("fre");
 
 	/* make sure we are not in use */
-	if (p->sched_comp->state > COMP_STATE_SETUP) {
+	if (p->sched_comp->state > COMP_STATE_READY) {
 		trace_pipe_error("epb");
 		return -EBUSY;
 	}
@@ -325,7 +325,7 @@ static int component_op_downstream(struct op_data *op_data,
 	case COMP_OPS_PARAMS:
 
 		/* dont do any params downstream if current is running */
-		if (current->state == COMP_STATE_RUNNING)
+		if (current->state == COMP_STATE_ACTIVE)
 			return 0;
 
 		/* send params to the component */
@@ -401,7 +401,7 @@ static int component_op_upstream(struct op_data *op_data,
 	case COMP_OPS_PARAMS:
 
 		/* dont do any params upstream if current is running */
-		if (current->state == COMP_STATE_RUNNING)
+		if (current->state == COMP_STATE_ACTIVE)
 			return 0;
 
 		/* send params to the component */
@@ -688,7 +688,7 @@ static int pipeline_copy_from_upstream(struct comp_dev *start,
 		buffer = container_of(clist, struct comp_buffer, sink_list);
 
 		/* dont go upstream if this component is not connected */
-		if (!buffer->connected || buffer->source->state != COMP_STATE_RUNNING)
+		if (!buffer->connected || buffer->source->state != COMP_STATE_ACTIVE)
 			continue;
 
 		/* dont go upstream if this source is from another pipeline */
@@ -746,7 +746,7 @@ static int pipeline_copy_to_downstream(struct comp_dev *start,
 		buffer = container_of(clist, struct comp_buffer, source_list);
 
 		/* dont go downstream if this component is not connected */
-		if (!buffer->connected || buffer->sink->state != COMP_STATE_RUNNING)
+		if (!buffer->connected || buffer->sink->state != COMP_STATE_ACTIVE)
 			continue;
 
 		/* dont go downstream if this sink is from another pipeline */
@@ -794,7 +794,7 @@ downstream:
 		buffer = container_of(clist, struct comp_buffer, source_list);
 
 		/* dont go downstream if this component is not connected */
-		if (!buffer->connected || buffer->sink->state != COMP_STATE_RUNNING)
+		if (!buffer->connected || buffer->sink->state != COMP_STATE_ACTIVE)
 			continue;
 
 		/* continue downstream */
@@ -837,7 +837,7 @@ upstream:
 		buffer = container_of(clist, struct comp_buffer, sink_list);
 
 		/* dont go downstream if this component is not connected */
-		if (!buffer->connected || buffer->source->state != COMP_STATE_RUNNING)
+		if (!buffer->connected || buffer->source->state != COMP_STATE_ACTIVE)
 			continue;
 
 		/* continue downstream */
@@ -942,7 +942,7 @@ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev,
 		return;
 
 	/* only send when we are running */
-	if (dev->state != COMP_STATE_RUNNING)
+	if (dev->state != COMP_STATE_ACTIVE)
 		return;
 
 	memset(&posn, 0, sizeof(posn));
diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c
index e851e54..1395ecc 100644
--- a/src/drivers/dw-dma.c
+++ b/src/drivers/dw-dma.c
@@ -56,6 +56,7 @@
 #include <reef/lock.h>
 #include <reef/trace.h>
 #include <reef/wait.h>
+#include <reef/audio/component.h>
 #include <platform/dma.h>
 #include <platform/platform.h>
 #include <platform/interrupt.h>
@@ -160,8 +161,6 @@
 struct dma_chan_data {
 	uint32_t status;
 	uint32_t direction;
-	completion_t complete;
-	int32_t drain_count;
 	struct dw_lli2 *lli;
 	struct dw_lli2 *lli_current;
 	uint32_t desc_count;
@@ -170,8 +169,6 @@ struct dma_chan_data {
 	struct dma *dma;
 	int32_t channel;
 
-	struct work work;
-
 	void (*cb)(void *data, uint32_t type, struct dma_sg_elem *next);	/* client callback function */
 	void *cb_data;		/* client callback data */
 	int cb_type;		/* callback type */
@@ -218,10 +215,10 @@ static int dw_dma_channel_get(struct dma *dma)
 	for (i = 0; i < DW_MAX_CHAN; i++) {
 
 		/* use channel if it's free */
-		if (p->chan[i].status != DMA_STATUS_FREE)
+		if (p->chan[i].status != COMP_STATE_READY)
 			continue;
 
-		p->chan[i].status = DMA_STATUS_IDLE;
+		p->chan[i].status = COMP_STATE_PREPARE;
 
 		/* unmask block, transfer and error interrupts for channel */
 		dw_write(dma, DW_MASK_TFR, INT_UNMASK(i));
@@ -244,27 +241,7 @@ static void dw_dma_channel_put_unlocked(struct dma *dma, int channel)
 {
 	struct dma_pdata *p = dma_get_drvdata(dma);
 
-	trace_dma("Dpt");
-
-	/* channel can only be freed if it's not still draining */
-	if (p->chan[channel].status == DMA_STATUS_DRAINING) {
-		p->chan[channel].status = DMA_STATUS_CLOSING;
-		return;
-	}
-
-#ifdef DW_CFG_CH_DRAIN /* have drain feature */
-	if (p->chan[channel].status == DMA_STATUS_PAUSED) {
-
-		dw_update_bits(dma, DW_CFG_LOW(channel),
-			DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN,
-			DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN);
-
-		/* free channel later */
-		p->chan[channel].status = DMA_STATUS_CLOSING;
-		work_schedule_default(&p->chan[channel].work, 100);
-		return;
-	}
-#endif
+	tracev_dma("Dpt");
 
 	/* mask block, transfer and error interrupts for channel */
 	dw_write(dma, DW_MASK_TFR, INT_MASK(channel));
@@ -278,7 +255,7 @@ static void dw_dma_channel_put_unlocked(struct dma *dma, int channel)
 	}
 
 	/* set new state */
-	p->chan[channel].status = DMA_STATUS_FREE;
+	p->chan[channel].status = COMP_STATE_READY;
 	p->chan[channel].cb = NULL;
 	p->chan[channel].desc_count = 0;
 }
@@ -304,7 +281,7 @@ static int dw_dma_start(struct dma *dma, int channel)
 	tracev_dma("DEn");
 
 	/* is channel idle, disabled and ready ? */
-	if (p->chan[channel].status != DMA_STATUS_IDLE ||
+	if (p->chan[channel].status != COMP_STATE_PREPARE ||
 		(dw_read(dma, DW_DMA_CHAN_EN) & (0x1 << channel))) {
 		ret = -EBUSY;
 		trace_dma_error("eDi");
@@ -364,7 +341,7 @@ static int dw_dma_start(struct dma *dma, int channel)
 	dw_write(dma, DW_CFG_HIGH(channel), p->chan[channel].cfg_hi);
 
 	/* enable the channel */
-	p->chan[channel].status = DMA_STATUS_RUNNING;
+	p->chan[channel].status = COMP_STATE_ACTIVE;
 	p->chan[channel].lli_current = p->chan[channel].lli;
 	dw_write(dma, DW_DMA_CHAN_EN, CHAN_ENABLE(channel));
 
@@ -382,12 +359,12 @@ static int dw_dma_release(struct dma *dma, int channel)
 
 	trace_dma("Dpr");
 
-	if (p->chan[channel].status == DMA_STATUS_PAUSED) {
+	if (p->chan[channel].status == COMP_STATE_PAUSED) {
 		dw_dma_chan_reload_lli(dma, channel);
 	}
 
 	/* resume and reload DMA */
-	p->chan[channel].status = DMA_STATUS_RUNNING;
+	p->chan[channel].status = COMP_STATE_ACTIVE;
 
 	spin_unlock_irq(&dma->lock, flags);
 	return 0;
@@ -402,136 +379,37 @@ static int dw_dma_pause(struct dma *dma, int channel)
 
 	trace_dma("Dpa");
 
-	if (p->chan[channel].status != DMA_STATUS_RUNNING)
+	if (p->chan[channel].status != COMP_STATE_ACTIVE)
 		goto out;
 
 	/* pause the channel */
-	p->chan[channel].status = DMA_STATUS_PAUSING;
+	p->chan[channel].status = COMP_STATE_PAUSED;
 
 out:
 	spin_unlock_irq(&dma->lock, flags);
 	return 0;
 }
 
-/*
- * Wait for DMA drain completion using delayed work. This allows the stream
- * IPC to return immediately without blocking the host. This work is called
- * by the general system timer.
- */
-static uint32_t dw_dma_fifo_work(void *data, uint32_t udelay)
-{
-	struct dma_chan_data *cd = (struct dma_chan_data *)data;
-	struct dma *dma = cd->dma;
-	int schedule = 0;
-	uint32_t flags;
-
-	spin_lock_irq(&dma->lock, flags);
-
-	trace_dma("DFw");
-
-	/* only check channels that are still draining */
-	if (cd->status != DMA_STATUS_DRAINING &&
-		cd->status != DMA_STATUS_CLOSING &&
-		cd->status != DMA_STATUS_STOPPING)
-		goto out;
-
-	/* is channel finished */
-	if (cd->drain_count-- <= 0) {
-		trace_dma("wDw");
-
-		/* do we need to free it ? */
-		if (cd->status == DMA_STATUS_CLOSING)
-			dw_dma_channel_put_unlocked(dma, cd->channel);
-
-		/* clear suspend */
-		dw_update_bits(dma, DW_CFG_LOW(cd->channel),
-#ifdef DW_CFG_CH_DRAIN /* have drain feature */
-				DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN, 0);
-#else
-				DW_CFG_CH_SUSPEND, 0);
-#endif
-		cd->status = DMA_STATUS_IDLE;
-		goto out;
-	}
-
-	/* is draining complete ? */
-	if (dw_read(dma, DW_CFG_LOW(cd->channel)) & DW_CFG_CH_FIFO_EMPTY)  {
-
-		/* fifo is empty so now check if channel is disabled */
-		if (!(dw_read(dma, DW_DMA_CHAN_EN) & (0x1 << cd->channel))) {
-
-			/* clear suspend */
-			dw_update_bits(dma, DW_CFG_LOW(cd->channel),
-#ifdef DW_CFG_CH_DRAIN /* have drain feature */
-				DW_CFG_CH_SUSPEND | DW_CFG_CH_DRAIN, 0);
-#else
-				DW_CFG_CH_SUSPEND, 0);
-#endif
-			/* do we need to free it ? */
-			if (cd->status == DMA_STATUS_CLOSING)
-				dw_dma_channel_put_unlocked(dma, cd->channel);
-
-			cd->status = DMA_STATUS_IDLE;
-			wait_completed(&cd->complete);
-			goto out;
-		}
-
-		/* disable the channel */
-		dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(cd->channel));
-	}
-
-	/* need to reschedule and check again */
-	schedule = 100;
-
-out:
-	spin_unlock_irq(&dma->lock, flags);
-
-	/* still waiting on more FIFOs to drain ? */
-	return schedule;
-}
-
-static int dw_dma_stop(struct dma *dma, int channel, int drain)
+static int dw_dma_stop(struct dma *dma, int channel)
 {
 	struct dma_pdata *p = dma_get_drvdata(dma);
-	int schedule = 0, ret = 0;
-	uint32_t flags, bits;
+	int  ret = 0;
+	uint32_t flags;
 
 	spin_lock_irq(&dma->lock, flags);
 
-	trace_dma("DDi");
+	tracev_dma("DDi");
 
 	/* has channel already disabled ? */
 	if (!(dw_read(dma, DW_DMA_CHAN_EN) & (0x1 << channel))) {
-		p->chan[channel].status = DMA_STATUS_IDLE;
+		p->chan[channel].status = COMP_STATE_PREPARE;
 		goto out;
 	}
 
-	/* suspend and drain */
-	bits = DW_CFG_CH_SUSPEND;
-	p->chan[channel].drain_count = 3;
-	p->chan[channel].status = DMA_STATUS_STOPPING;
-
-#ifdef DW_CFG_CH_DRAIN /* have drain feature, then may drain */
-	if (drain) {
-		bits |= DW_CFG_CH_DRAIN;
-		p->chan[channel].drain_count = 14;
-		p->chan[channel].status = DMA_STATUS_DRAINING;
-	}
-#endif
-
-	dw_update_bits(dma, DW_CFG_LOW(channel), bits, bits);
-	schedule = 1;
+	p->chan[channel].status = COMP_STATE_PAUSED;
 
 out:
 	spin_unlock_irq(&dma->lock, flags);
-
-	/* buffer and FIFO drain done by general purpose timer */
-	if (schedule) {
-		wait_clear(&p->chan[channel].complete);
-		work_schedule_default(&p->chan[channel].work, 100);
-		ret = wait_for_completion_timeout(&p->chan[channel].complete);
-	}
-
 	return ret;
 }
 
@@ -739,7 +617,7 @@ static inline void dw_dma_chan_reload_lli(struct dma *dma, int channel)
 
 	/* only need to reload if this is a block transfer */
 	if (lli == 0 || (lli && lli->llp == 0)) {
-		p->chan[channel].status = DMA_STATUS_IDLE;
+		p->chan[channel].status = COMP_STATE_PREPARE;
 		return;
 	}
 
@@ -833,9 +711,8 @@ static void dw_dma_irq_handler(void *data)
 
 	for (i = 0; i < DW_MAX_CHAN; i++) {
 
-		/* skip if channel is not running or pausing*/
-		if (p->chan[i].status != DMA_STATUS_RUNNING &&
-			p->chan[i].status != DMA_STATUS_PAUSING)
+		/* skip if channel is not running */
+		if (p->chan[i].status != COMP_STATE_ACTIVE)
 			continue;
 
 		mask = 0x1 << i;
@@ -857,14 +734,13 @@ static void dw_dma_irq_handler(void *data)
 			 * otherwise, reload lli
 			 */
 			if (next.size == DMA_RELOAD_END) {
-				p->chan[i].status = DMA_STATUS_IDLE;
+				p->chan[i].status = COMP_STATE_PREPARE;
 				continue;
 			}
 			else if (next.size != DMA_RELOAD_LLI)
 				dw_dma_chan_reload_next(dma, i, &next);
 			/* reload lli, but let's check if we are pausing first */
-			else if (p->chan[i].status == DMA_STATUS_PAUSING) {
-				p->chan[i].status = DMA_STATUS_PAUSED;
+			else if (p->chan[i].status == COMP_STATE_PAUSED) {
 				continue;
 			} else
 				dw_dma_chan_reload_lli(dma, i);
@@ -952,12 +828,9 @@ static int dw_dma_probe(struct dma *dma)
 
 	/* init work */
 	for (i = 0; i < DW_MAX_CHAN; i++) {
-		work_init(&dw_pdata->chan[i].work, dw_dma_fifo_work,
-			&dw_pdata->chan[i], WORK_ASYNC);
 		dw_pdata->chan[i].dma = dma;
 		dw_pdata->chan[i].channel = i;
-		dw_pdata->chan[i].complete.timeout = PLATFORM_DMA_TIMEOUT;
-		wait_init(&dw_pdata->chan[i].complete);
+		dw_pdata->chan[i].status = COMP_STATE_READY;
 	}
 
 	/* register our IRQ handler */
diff --git a/src/drivers/ssp.c b/src/drivers/ssp.c
index 0b7589a..6d2c004 100644
--- a/src/drivers/ssp.c
+++ b/src/drivers/ssp.c
@@ -76,9 +76,10 @@ static inline int ssp_set_config(struct dai *dai,
 	spin_lock(&ssp->lock);
 
 	/* is playback/capture already running */
-	if (ssp->state[DAI_DIR_PLAYBACK] > SSP_STATE_IDLE ||
-		ssp->state[DAI_DIR_CAPTURE] > SSP_STATE_IDLE) {
+	if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE ||
+		ssp->state[DAI_DIR_CAPTURE] == COMP_STATE_ACTIVE) {
 		trace_ssp_error("ec1");
+		ret = -EINVAL;
 		goto out;
 	}
 
@@ -258,8 +259,8 @@ static inline int ssp_set_config(struct dai *dai,
 	ssp_write(dai, SSPSP, sspsp);
 	ssp_write(dai, SFIFOTT, sfifott);
 
-	ssp->state[DAI_DIR_PLAYBACK] = SSP_STATE_IDLE;
-	ssp->state[DAI_DIR_CAPTURE] = SSP_STATE_IDLE;
+	ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_PREPARE;
+	ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
 
 out:
 	spin_unlock(&ssp->lock);
@@ -291,7 +292,7 @@ static void ssp_start(struct dai *dai, int direction)
 
 	/* enable port */
 	ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
-	ssp->state[direction] = SSP_STATE_RUNNING;
+	ssp->state[direction] = COMP_STATE_ACTIVE;
 
 	trace_ssp("sta");
 
@@ -304,70 +305,37 @@ static void ssp_start(struct dai *dai, int direction)
 	spin_unlock(&ssp->lock);
 }
 
-/* stop the SSP port stream DMA and disable SSP port if no users */
+/* stop the SSP for either playback or capture */
 static void ssp_stop(struct dai *dai, int direction)
 {
 	struct ssp_pdata *ssp = dai_get_drvdata(dai);
-	uint32_t sscr1;
 
 	spin_lock(&ssp->lock);
 
-	trace_ssp("sto");
-
-	/* disable DMA */
-	if (direction == DAI_DIR_PLAYBACK) {
-		if (ssp->state[DAI_DIR_PLAYBACK] == SSP_STATE_DRAINING)
-			ssp_update_bits(dai, SSCR1, SSCR1_TSRE, 0);
-	} else
+	/* stop Rx if we are not capturing */
+	if (ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE) {
 		ssp_update_bits(dai, SSCR1, SSCR1_RSRE, 0);
-
-	/* disable port if no users */
-	sscr1 = ssp_read(dai, SSCR1);
-	if (!(sscr1 & (SSCR1_TSRE | SSCR1_RSRE))) {
-		ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
-		trace_ssp("SDp");
+		trace_ssp("Ss0");
 	}
 
-	ssp->state[direction] = SSP_STATE_IDLE;
-
-	spin_unlock(&ssp->lock);
-}
-
-static void ssp_pause(struct dai *dai, int direction)
-{
-	struct ssp_pdata *ssp = dai_get_drvdata(dai);
-
-	spin_lock(&ssp->lock);
-
-	trace_ssp("pau");
-
-	/* disable DMA */
-	if (direction == DAI_DIR_PLAYBACK) {
-		if (ssp->state[DAI_DIR_PLAYBACK] == SSP_STATE_PAUSING)
-			ssp_update_bits(dai, SSCR1, SSCR1_TSRE, 0);
-	} else
-		ssp_update_bits(dai, SSCR1, SSCR1_RSRE, 0);
+	/* stop Tx if we are not playing */
+	if (ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE) {
+		ssp_update_bits(dai, SSCR1, SSCR1_TSRE, 0);
+		trace_ssp("Ss1");
+	}
 
-	ssp->state[direction] = SSP_STATE_PAUSED;
+	/* disable SSP port if no users */
+	if (ssp->state[SOF_IPC_STREAM_CAPTURE] != COMP_STATE_ACTIVE &&
+		ssp->state[SOF_IPC_STREAM_PLAYBACK] != COMP_STATE_ACTIVE) {
+		ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
+		ssp->state[SOF_IPC_STREAM_CAPTURE] = COMP_STATE_PREPARE;
+		ssp->state[SOF_IPC_STREAM_PLAYBACK] = COMP_STATE_PREPARE;
+		trace_ssp("Ss2");
+	}
 
 	spin_unlock(&ssp->lock);
 }
 
-static uint32_t ssp_drain_work(void *data, uint32_t udelay)
-{
-	struct dai *dai = (struct dai *)data;
-	struct ssp_pdata *ssp = dai_get_drvdata(dai);
-
-	trace_ssp("dra");
-
-	if (ssp->state[SOF_IPC_STREAM_CAPTURE] == SSP_STATE_DRAINING)
-		ssp_stop(dai, SOF_IPC_STREAM_CAPTURE);
-	else
-		ssp_pause(dai, SOF_IPC_STREAM_CAPTURE);
-	wait_completed(&ssp->drain_complete);
-	return 0;
-}
-
 static int ssp_trigger(struct dai *dai, int cmd, int direction)
 {
 	struct ssp_pdata *ssp = dai_get_drvdata(dai);
@@ -376,63 +344,23 @@ static int ssp_trigger(struct dai *dai, int cmd, int direction)
 
 	switch (cmd) {
 	case COMP_CMD_START:
-/* let's only wait until draining finished(timout) before another start */
-#if 0
-		/* cancel any scheduled work */
-		if (ssp->state[direction] == SSP_STATE_DRAINING)
-			work_cancel_default(&ssp->work);
-#endif
-		if (ssp->state[direction] == SSP_STATE_IDLE)
+		if (ssp->state[direction] == COMP_STATE_PREPARE ||
+			ssp->state[direction] == COMP_STATE_PAUSED)
 			ssp_start(dai, direction);
 		break;
 	case COMP_CMD_RELEASE:
-/* let's only wait until pausing finished(timout) before next release */
-#if 0
-		if (ssp->state[direction] == SSP_STATE_PAUSING)
-			work_cancel_default(&ssp->work);
-#endif
-		if (ssp->state[direction] == SSP_STATE_PAUSED)
+		if (ssp->state[direction] == COMP_STATE_PAUSED)
 			ssp_start(dai, direction);
 		break;
-	case COMP_CMD_PAUSE:
-		if (ssp->state[direction] != SSP_STATE_RUNNING) {
-			trace_ssp_error("wsP");
-			return 0;
-		}
-		if (direction == SOF_IPC_STREAM_CAPTURE) {
-			ssp->state[SOF_IPC_STREAM_CAPTURE] =
-				SSP_STATE_PAUSING;
-			/* make sure the maximum 256 bytes are drained */
-			work_schedule_default(&ssp->work, 1333);
-			wait_init(&ssp->drain_complete);
-			ssp->drain_complete.timeout = 1500;
-			wait_for_completion_timeout(&ssp->drain_complete);
-		} else
-			ssp_pause(dai, direction);
-		break;
 	case COMP_CMD_STOP:
-		if (ssp->state[direction] != SSP_STATE_RUNNING &&
-			ssp->state[direction] != SSP_STATE_PAUSED) {
-			trace_ssp_error("wsO");
-			return 0;
-		}
-		if (direction == SOF_IPC_STREAM_PLAYBACK &&
-			ssp->state[direction] == SSP_STATE_RUNNING) {
-			ssp->state[SOF_IPC_STREAM_PLAYBACK] =
-				SSP_STATE_DRAINING;
-			work_schedule_default(&ssp->work, 2000);
-			wait_init(&ssp->drain_complete);
-			ssp->drain_complete.timeout = 3000;
-			wait_for_completion_timeout(&ssp->drain_complete);
-		} else
-			ssp_stop(dai, direction);
+	case COMP_CMD_PAUSE:
+		ssp->state[direction] = COMP_STATE_PAUSED;
+		ssp_stop(dai, direction);
 		break;
 	case COMP_CMD_RESUME:
 		ssp_context_restore(dai);
-		ssp_start(dai, direction);
 		break;
 	case COMP_CMD_SUSPEND:
-		ssp_stop(dai, direction);
 		ssp_context_store(dai);
 		break;
 	default:
@@ -450,11 +378,10 @@ static int ssp_probe(struct dai *dai)
 	ssp = rzalloc(RZONE_SYS, RFLAGS_NONE, sizeof(*ssp));
 	dai_set_drvdata(dai, ssp);
 
-	work_init(&ssp->work, ssp_drain_work, dai, WORK_ASYNC);
 	spinlock_init(&ssp->lock);
 
-	ssp->state[DAI_DIR_PLAYBACK] = SSP_STATE_INIT;
-	ssp->state[DAI_DIR_CAPTURE] = SSP_STATE_INIT;
+	ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_READY;
+	ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY;
 
 	return 0;
 }
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h
index d7ea29a..d092210 100644
--- a/src/include/reef/audio/component.h
+++ b/src/include/reef/audio/component.h
@@ -44,20 +44,29 @@
 #include <reef/audio/pipeline.h>
 #include <uapi/ipc.h>
 
-/* audio component states
- * the states may transform as below:
- *        new()         params()          start()
- * none	-----> init ------> setup -----> running
- * none	<----- init <------ setup <----- running
- *        free()          reset()             stop()
+/*
+ * Audio Component States
+ *
+ * States may transform as below:-
+ *
+ * 1) i.e. Initialisation to playback and pause/release
+ * init --> setup --> preprare --> active <-> paused --+
+ *                       ^                             |
+ *                       +-----------------------------+
+ *
+ * 2) i.e. Suspend
+ *
+ * setup --> suspend --> setup OR
+ * prepare --> suspend -> prepare OR
+ * paused --> suspend --> paused
  */
+
 #define COMP_STATE_INIT		0	/* component being initialised */
-#define COMP_STATE_SETUP       1       /* component inactive, but ready */
-#define COMP_STATE_SUSPEND     2       /* component suspended */
-#define COMP_STATE_DRAINING	3	/* component draining */
-#define COMP_STATE_PREPARE	4	/* component prepared */
-#define COMP_STATE_PAUSED	5	/* component paused */
-#define COMP_STATE_RUNNING	6	/* component active */
+#define COMP_STATE_READY	1       /* component inactive, but ready */
+#define COMP_STATE_SUSPEND	2       /* component suspended */
+#define COMP_STATE_PREPARE	3	/* component prepared */
+#define COMP_STATE_PAUSED	4	/* component paused */
+#define COMP_STATE_ACTIVE	5	/* component active */
 
 /*
  * standard component stream commands
diff --git a/src/include/reef/dma.h b/src/include/reef/dma.h
index 6311260..881332f 100644
--- a/src/include/reef/dma.h
+++ b/src/include/reef/dma.h
@@ -45,16 +45,6 @@
 #define DMA_DIR_DEV_TO_MEM	4
 #define DMA_DIR_DEV_TO_DEV	5
 
-/* DMA status flags */
-#define DMA_STATUS_FREE		0
-#define DMA_STATUS_IDLE		1
-#define DMA_STATUS_RUNNING	2
-#define DMA_STATUS_DRAINING	4
-#define DMA_STATUS_CLOSING	5
-#define DMA_STATUS_PAUSED	6
-#define DMA_STATUS_PAUSING	7
-#define DMA_STATUS_STOPPING	8
-
 /* DMA IRQ types */
 #define DMA_IRQ_TYPE_BLOCK	(1 << 0)
 #define DMA_IRQ_TYPE_LLIST	(1 << 1)
@@ -101,7 +91,7 @@ struct dma_ops {
 	void (*channel_put)(struct dma *dma, int channel);
 
 	int (*start)(struct dma *dma, int channel);
-	int (*stop)(struct dma *dma, int channel, int drain);
+	int (*stop)(struct dma *dma, int channel);
 	int (*pause)(struct dma *dma, int channel);
 	int (*release)(struct dma *dma, int channel);
 	int (*status)(struct dma *dma, int channel,
@@ -180,9 +170,9 @@ static inline int dma_start(struct dma *dma, int channel)
 	return dma->ops->start(dma, channel);
 }
 
-static inline int dma_stop(struct dma *dma, int channel, int drain)
+static inline int dma_stop(struct dma *dma, int channel)
 {
-	return dma->ops->stop(dma, channel, drain);
+	return dma->ops->stop(dma, channel);
 }
 
 static inline int dma_pause(struct dma *dma, int channel)
diff --git a/src/include/reef/ssp.h b/src/include/reef/ssp.h
index 42efb14..70113df 100644
--- a/src/include/reef/ssp.h
+++ b/src/include/reef/ssp.h
@@ -149,14 +149,6 @@ extern const struct dai_ops ssp_ops;
 #define SFIFOTT_TX(x)		(x - 1)
 #define SFIFOTT_RX(x)		((x - 1) << 16)
 
-/* SSP port status */
-#define SSP_STATE_INIT			0
-#define SSP_STATE_RUNNING		1
-#define SSP_STATE_IDLE			2
-#define SSP_STATE_DRAINING		3
-#define SSP_STATE_PAUSING		4
-#define SSP_STATE_PAUSED		5
-
 /* tracing */
 #define trace_ssp(__e)	trace_event(TRACE_CLASS_SSP, __e)
 #define trace_ssp_error(__e)	trace_error(TRACE_CLASS_SSP, __e)
@@ -167,7 +159,6 @@ struct ssp_pdata {
 	uint32_t sscr0;
 	uint32_t sscr1;
 	uint32_t psp;
-	struct work work;
 	spinlock_t lock;
 	uint32_t state[2];		/* SSP_STATE_ for each direction */
 	completion_t drain_complete;
-- 
2.11.0



More information about the Sound-open-firmware mailing list