Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit faf907c7 authored by Shine Liu's avatar Shine Liu Committed by Mark Brown
Browse files

ASoC: S3C platform: Fix s3c2410_dma_started() called at improper time



s3c24xx dma has the auto reload feature, when the the trnasfer is done,
CURR_TC(DSTAT[19:0], current value of transfer count) reaches 0, and DMA
ACK becomes 1, and then, TC(DCON[19:0]) will be loaded into CURR_TC. So
the transmission is repeated.

IRQ is issued while auto reload occurs. We change the DISRC and
DCON[19:0] in the ISR, but at this time, the auto reload has been
performed already. The first block is being re-transmitted by the DMA.

So we need rewrite the DISRC and DCON[19:0] for the next block
immediatly after the this block has been started to be transported.

The function s3c2410_dma_started() is for this perpose, which is called
in the form of "s3c2410_dma_ctrl(prtd->params->channel,
S3C2410_DMAOP_STARTED);" in s3c24xx_pcm_trigger().

But it is not correct. DMA transmission won't start until DMA REQ signal
arrived, it is the time s3c24xx_snd_txctrl(1) or s3c24xx_snd_rxctrl(1)
is called in s3c24xx_i2s_trigger().

In the current framework, s3c24xx_pcm_trigger() is always called before
s3c24xx_pcm_trigger(). So the s3c2410_dma_started() should be called in
s3c24xx_pcm_trigger() after s3c24xx_snd_txctrl(1) or
s3c24xx_snd_rxctrl(1) is called in this function.

However, s3c2410_dma_started() is dma related, to call this function we
should provide the channel number, which is given by
substream->runtime->private_data->params->channel. The private_data
points to a struct s3c24xx_runtime_data object, which is define in
s3c24xx_pcm.c, so s3c2410_dma_started() can't be called in s3c24xx_i2s.c

Fix this by moving the call to signal the DMA started to the DAI
drivers.

Signed-off-by: default avatarShine Liu <liuxian@redflag-linux.com>
Signed-off-by: default avatarShine Liu <shinel@foxmail.com>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent d09a2afc
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -387,6 +387,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
	unsigned long irqs;
	unsigned long irqs;
	int ret = 0;
	int ret = 0;
	int channel = ((struct s3c24xx_pcm_dma_params *)
		  rtd->dai->cpu_dai->dma_data)->channel;


	pr_debug("Entered %s\n", __func__);
	pr_debug("Entered %s\n", __func__);


@@ -416,6 +418,14 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
			s3c2412_snd_txctrl(i2s, 1);
			s3c2412_snd_txctrl(i2s, 1);


		local_irq_restore(irqs);
		local_irq_restore(irqs);

		/*
		 * Load the next buffer to DMA to meet the reqirement
		 * of the auto reload mechanism of S3C24XX.
		 * This call won't bother S3C64XX.
		 */
		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);

		break;
		break;


	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_STOP:
+10 −0
Original line number Original line Diff line number Diff line
@@ -290,6 +290,9 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
				struct snd_soc_dai *dai)
				struct snd_soc_dai *dai)
{
{
	u32 ac_glbctrl;
	u32 ac_glbctrl;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	int channel = ((struct s3c24xx_pcm_dma_params *)
		  rtd->dai->cpu_dai->dma_data)->channel;


	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
	switch (cmd) {
	switch (cmd) {
@@ -312,6 +315,8 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
	}
	}
	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);


	s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);

	return 0;
	return 0;
}
}


@@ -334,6 +339,9 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
				    int cmd, struct snd_soc_dai *dai)
				    int cmd, struct snd_soc_dai *dai)
{
{
	u32 ac_glbctrl;
	u32 ac_glbctrl;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	int channel = ((struct s3c24xx_pcm_dma_params *)
		  rtd->dai->cpu_dai->dma_data)->channel;


	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
	ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
	switch (cmd) {
	switch (cmd) {
@@ -349,6 +357,8 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
	}
	}
	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
	writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);


	s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);

	return 0;
	return 0;
}
}


+5 −0
Original line number Original line Diff line number Diff line
@@ -279,6 +279,9 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
			       struct snd_soc_dai *dai)
			       struct snd_soc_dai *dai)
{
{
	int ret = 0;
	int ret = 0;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	int channel = ((struct s3c24xx_pcm_dma_params *)
		  rtd->dai->cpu_dai->dma_data)->channel;


	pr_debug("Entered %s\n", __func__);
	pr_debug("Entered %s\n", __func__);


@@ -296,6 +299,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
			s3c24xx_snd_rxctrl(1);
			s3c24xx_snd_rxctrl(1);
		else
		else
			s3c24xx_snd_txctrl(1);
			s3c24xx_snd_txctrl(1);

		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
		break;
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_SUSPEND:
+0 −1
Original line number Original line Diff line number Diff line
@@ -255,7 +255,6 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		prtd->state |= ST_RUNNING;
		prtd->state |= ST_RUNNING;
		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
		s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STARTED);
		break;
		break;


	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_STOP: