From f911217e6edd48de4277eec2f112449d61fe710e Mon Sep 17 00:00:00 2001 From: Alison Wang Date: Mon, 29 Sep 2014 17:29:46 +0800 Subject: ls102xa: audio: Workaround for SAI data transfer endian issue Transmit Data Register(TDR) used as the destination address of EDMA transaction is in big-endian mode. The audio data in memory and EDMA transaction are in little-endian mode. For S16_LE format data, a workaround is to swap the original 16-bit data, and then write into the higher 16 bit of TDR. Signed-off-by: Alison Wang Change-Id: Ib15832743e9a4c69792f2dad4cb00fbbc1d2daaa Reviewed-on: http://git.am.freescale.net:8181/21063 Tested-by: Review Code-CDREVIEW Reviewed-by: Jingchang Lu Reviewed-by: Zhengxiong Jin diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 84b10f9..a07b670 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -418,6 +418,8 @@ struct snd_pcm_substream { #endif /* misc flags */ unsigned int hw_opened: 1; + /* data swapped flags */ + unsigned int data_swapped; }; #define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a210467..f1fe6e6 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1962,6 +1962,9 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; int err; char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); + int i; + char tmp; + if (substream->ops->copy) { if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) return err; @@ -1969,6 +1972,22 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) return -EFAULT; + + if (substream->data_swapped) { + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + for (i = 0; + i < frames_to_bytes(runtime, frames); + i = i + 2) { + tmp = *(hwbuf + i); + *(hwbuf + i) = *(hwbuf + i + 1); + *(hwbuf + i + 1) = tmp; + } + break; + default: + return -EINVAL; + } + } } return 0; } @@ -2184,11 +2203,30 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; int err; char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); + int i; + char tmp; + if (substream->ops->copy) { if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) return err; } else { char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); + if (substream->data_swapped) { + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + for (i = 0; + i < frames_to_bytes(runtime, frames); + i = i + 2) { + tmp = *(hwbuf + i); + *(hwbuf + i) = *(hwbuf + i + 1); + *(hwbuf + i + 1) = tmp; + } + break; + default: + return -EINVAL; + } + } + if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) return -EFAULT; } diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 7286824..ff86daf 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -334,6 +334,9 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); u32 reg; + if (sai->big_endian_regs) + substream->data_swapped = 1; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = FSL_SAI_TCR3; else @@ -549,8 +552,14 @@ static int fsl_sai_probe(struct platform_device *pdev) return PTR_ERR(sai->regmap); } - sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; - sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; + if (sai->big_endian_regs) { + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR + 2; + sai->dma_params_tx.addr = res->start + FSL_SAI_TDR + 2; + } else { + sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; + sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; + } + sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; -- cgit v0.10.2