diff options
author | Nicolin Chen <Guangyu.Chen@freescale.com> | 2014-03-31 23:17:06 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-04-14 12:26:05 -0400 |
commit | e6b398465821fb8e08d208bd4ef2b5b73ce87b58 (patch) | |
tree | 1fca8b6e236ff2fb13869df4ac3b060dea446794 /sound/soc/fsl | |
parent | 413312aa17ceefe7003ad690778ab72f023128f0 (diff) |
ASoC: fsl_sai: Fix buggy configurations in trigger()
The current trigger() has two crucial problems:
1) The DMA request enabling operations (FSL_SAI_CSR_FRDE) for Tx and Rx are
now totally exclusive: It would fail to run simultaneous Tx-Rx cases.
2) The TERE disabling operation depends on an incorrect condition -- active
reference count that only gets increased in snd_pcm_open() and decreased
in snd_pcm_close(): The TERE would never get cleared.
So this patch overwrites the trigger function by following these rules:
A) We continue to support tx-async-while-rx-sync-to-tx case alone, which's
originally limited by this fsl_sai driver, but we make the code easy to
modify for the further support of the opposite case.
B) We enable both TE and RE for PLAYBACK stream or CAPTURE stream but only
enabling the DMA request bit (FSL_SAI_CSR_FRDE) of the current direction
due to the requirement of SAI -- For tx-async-while-rx-sync-to-tx case,
the receiver is enabled only when both the transmitter and receiver are
enabled.
Tested cases:
a) aplay test.wav -d5
b) arecord -r44100 -c2 -fS16_LE test.wav -d5
c) arecord -r44100 -c2 -fS16_LE -d5 | aplay
d) (aplay test2.wav &); sleep 1; arecord -r44100 -c2 -fS16_LE test.wav -d1
e) (arecord -r44100 -c2 -fS16_LE test.wav -d5 &); sleep 1; aplay test.wav -d1
Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
Acked-by: Xiubo Li <Li.Xiubo@freescale.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/fsl_sai.c | 35 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.h | 10 |
2 files changed, 27 insertions, 18 deletions
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 7194d9280020..80cca7bb2a11 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c | |||
@@ -365,6 +365,7 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
365 | struct snd_soc_dai *cpu_dai) | 365 | struct snd_soc_dai *cpu_dai) |
366 | { | 366 | { |
367 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 367 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
368 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
368 | u32 tcsr, rcsr; | 369 | u32 tcsr, rcsr; |
369 | 370 | ||
370 | /* | 371 | /* |
@@ -379,14 +380,6 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
379 | regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); | 380 | regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); |
380 | regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); | 381 | regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); |
381 | 382 | ||
382 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
383 | tcsr |= FSL_SAI_CSR_FRDE; | ||
384 | rcsr &= ~FSL_SAI_CSR_FRDE; | ||
385 | } else { | ||
386 | rcsr |= FSL_SAI_CSR_FRDE; | ||
387 | tcsr &= ~FSL_SAI_CSR_FRDE; | ||
388 | } | ||
389 | |||
390 | /* | 383 | /* |
391 | * It is recommended that the transmitter is the last enabled | 384 | * It is recommended that the transmitter is the last enabled |
392 | * and the first disabled. | 385 | * and the first disabled. |
@@ -395,22 +388,28 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
395 | case SNDRV_PCM_TRIGGER_START: | 388 | case SNDRV_PCM_TRIGGER_START: |
396 | case SNDRV_PCM_TRIGGER_RESUME: | 389 | case SNDRV_PCM_TRIGGER_RESUME: |
397 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 390 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
398 | tcsr |= FSL_SAI_CSR_TERE; | 391 | if (!(tcsr & FSL_SAI_CSR_FRDE || rcsr & FSL_SAI_CSR_FRDE)) { |
399 | rcsr |= FSL_SAI_CSR_TERE; | 392 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, |
393 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); | ||
394 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, | ||
395 | FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE); | ||
396 | } | ||
400 | 397 | ||
401 | regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); | 398 | regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), |
402 | regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); | 399 | FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE); |
403 | break; | 400 | break; |
404 | case SNDRV_PCM_TRIGGER_STOP: | 401 | case SNDRV_PCM_TRIGGER_STOP: |
405 | case SNDRV_PCM_TRIGGER_SUSPEND: | 402 | case SNDRV_PCM_TRIGGER_SUSPEND: |
406 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 403 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
407 | if (!(cpu_dai->playback_active || cpu_dai->capture_active)) { | 404 | regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx), |
408 | tcsr &= ~FSL_SAI_CSR_TERE; | 405 | FSL_SAI_CSR_FRDE, 0); |
409 | rcsr &= ~FSL_SAI_CSR_TERE; | 406 | |
407 | if (!(tcsr & FSL_SAI_CSR_FRDE || rcsr & FSL_SAI_CSR_FRDE)) { | ||
408 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, | ||
409 | FSL_SAI_CSR_TERE, 0); | ||
410 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, | ||
411 | FSL_SAI_CSR_TERE, 0); | ||
410 | } | 412 | } |
411 | |||
412 | regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); | ||
413 | regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); | ||
414 | break; | 413 | break; |
415 | default: | 414 | default: |
416 | return -EINVAL; | 415 | return -EINVAL; |
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index a264185c7138..64b6fe72cd08 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h | |||
@@ -35,6 +35,16 @@ | |||
35 | #define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ | 35 | #define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ |
36 | #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ | 36 | #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ |
37 | 37 | ||
38 | #define FSL_SAI_xCSR(tx) (tx ? FSL_SAI_TCSR : FSL_SAI_RCSR) | ||
39 | #define FSL_SAI_xCR1(tx) (tx ? FSL_SAI_TCR1 : FSL_SAI_RCR1) | ||
40 | #define FSL_SAI_xCR2(tx) (tx ? FSL_SAI_TCR2 : FSL_SAI_RCR2) | ||
41 | #define FSL_SAI_xCR3(tx) (tx ? FSL_SAI_TCR3 : FSL_SAI_RCR3) | ||
42 | #define FSL_SAI_xCR4(tx) (tx ? FSL_SAI_TCR4 : FSL_SAI_RCR4) | ||
43 | #define FSL_SAI_xCR5(tx) (tx ? FSL_SAI_TCR5 : FSL_SAI_RCR5) | ||
44 | #define FSL_SAI_xDR(tx) (tx ? FSL_SAI_TDR : FSL_SAI_RDR) | ||
45 | #define FSL_SAI_xFR(tx) (tx ? FSL_SAI_TFR : FSL_SAI_RFR) | ||
46 | #define FSL_SAI_xMR(tx) (tx ? FSL_SAI_TMR : FSL_SAI_RMR) | ||
47 | |||
38 | /* SAI Transmit/Recieve Control Register */ | 48 | /* SAI Transmit/Recieve Control Register */ |
39 | #define FSL_SAI_CSR_TERE BIT(31) | 49 | #define FSL_SAI_CSR_TERE BIT(31) |
40 | #define FSL_SAI_CSR_FR BIT(25) | 50 | #define FSL_SAI_CSR_FR BIT(25) |