aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Mack <zonque@gmail.com>2012-03-19 04:12:53 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-03-19 08:47:25 -0400
commit273b72c8ce6b28df6b49423d775c3e59072c73c5 (patch)
treeb96da830969b5c433ad672cb5f87a350fb9ff447
parent70ac07bb633dee75ac554195b9a4d69adfa7803c (diff)
ASoC: pxa-ssp: atomically set stream active masks
PXA's SSP engine fails to take its current channel phase into account when enabling a stream while the engine is already running. This results in randomly swapped left/right channels on either the record or the playback side, depending on which one was enabled first. The following patch fixes this by factoring out the bit field modifications in question to a separate function that pauses the engine temporarily, modifies the bits and kicks it off again afterwards. Appearantly, a transition of SSCR0_SSE syncs both directions properly. The patch has been rolled out to quite a number of devices over the last weeks and seems to fix the issue reliably. Signed-off-by: Daniel Mack <zonque@gmail.com> Reported-and-tested-by: Sven Neumann <s.neumann@raumfeld.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Cc: stable@vger.kernel.org
-rw-r--r--sound/soc/pxa/pxa-ssp.c61
1 files changed, 36 insertions, 25 deletions
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index a16df0fa6eff..fd04ce139031 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -668,6 +668,38 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
668 return 0; 668 return 0;
669} 669}
670 670
671static void pxa_ssp_set_running_bit(struct snd_pcm_substream *substream,
672 struct ssp_device *ssp, int value)
673{
674 uint32_t sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
675 uint32_t sscr1 = pxa_ssp_read_reg(ssp, SSCR1);
676 uint32_t sspsp = pxa_ssp_read_reg(ssp, SSPSP);
677 uint32_t sssr = pxa_ssp_read_reg(ssp, SSSR);
678
679 if (value && (sscr0 & SSCR0_SSE))
680 pxa_ssp_write_reg(ssp, SSCR0, sscr0 & ~SSCR0_SSE);
681
682 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
683 if (value)
684 sscr1 |= SSCR1_TSRE;
685 else
686 sscr1 &= ~SSCR1_TSRE;
687 } else {
688 if (value)
689 sscr1 |= SSCR1_RSRE;
690 else
691 sscr1 &= ~SSCR1_RSRE;
692 }
693
694 pxa_ssp_write_reg(ssp, SSCR1, sscr1);
695
696 if (value) {
697 pxa_ssp_write_reg(ssp, SSSR, sssr);
698 pxa_ssp_write_reg(ssp, SSPSP, sspsp);
699 pxa_ssp_write_reg(ssp, SSCR0, sscr0 | SSCR0_SSE);
700 }
701}
702
671static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, 703static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
672 struct snd_soc_dai *cpu_dai) 704 struct snd_soc_dai *cpu_dai)
673{ 705{
@@ -681,42 +713,21 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
681 pxa_ssp_enable(ssp); 713 pxa_ssp_enable(ssp);
682 break; 714 break;
683 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 715 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
684 val = pxa_ssp_read_reg(ssp, SSCR1); 716 pxa_ssp_set_running_bit(substream, ssp, 1);
685 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
686 val |= SSCR1_TSRE;
687 else
688 val |= SSCR1_RSRE;
689 pxa_ssp_write_reg(ssp, SSCR1, val);
690 val = pxa_ssp_read_reg(ssp, SSSR); 717 val = pxa_ssp_read_reg(ssp, SSSR);
691 pxa_ssp_write_reg(ssp, SSSR, val); 718 pxa_ssp_write_reg(ssp, SSSR, val);
692 break; 719 break;
693 case SNDRV_PCM_TRIGGER_START: 720 case SNDRV_PCM_TRIGGER_START:
694 val = pxa_ssp_read_reg(ssp, SSCR1); 721 pxa_ssp_set_running_bit(substream, ssp, 1);
695 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
696 val |= SSCR1_TSRE;
697 else
698 val |= SSCR1_RSRE;
699 pxa_ssp_write_reg(ssp, SSCR1, val);
700 pxa_ssp_enable(ssp);
701 break; 722 break;
702 case SNDRV_PCM_TRIGGER_STOP: 723 case SNDRV_PCM_TRIGGER_STOP:
703 val = pxa_ssp_read_reg(ssp, SSCR1); 724 pxa_ssp_set_running_bit(substream, ssp, 0);
704 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
705 val &= ~SSCR1_TSRE;
706 else
707 val &= ~SSCR1_RSRE;
708 pxa_ssp_write_reg(ssp, SSCR1, val);
709 break; 725 break;
710 case SNDRV_PCM_TRIGGER_SUSPEND: 726 case SNDRV_PCM_TRIGGER_SUSPEND:
711 pxa_ssp_disable(ssp); 727 pxa_ssp_disable(ssp);
712 break; 728 break;
713 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 729 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
714 val = pxa_ssp_read_reg(ssp, SSCR1); 730 pxa_ssp_set_running_bit(substream, ssp, 0);
715 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
716 val &= ~SSCR1_TSRE;
717 else
718 val &= ~SSCR1_RSRE;
719 pxa_ssp_write_reg(ssp, SSCR1, val);
720 break; 731 break;
721 732
722 default: 733 default: