diff options
author | Alan Tull <alan.tull@freescale.com> | 2011-07-19 11:32:32 -0500 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2011-09-02 16:43:11 +0800 |
commit | 8693921dde0328175053dcfc72f32a1aaa0159eb (patch) | |
tree | cc66fbec60b7dad139c01a368f55c5bb9121da3d /sound | |
parent | c52e6e820a7329516996321337987286fe9801d8 (diff) |
ENGR00153424-1 turn on ddr clock for audio buffers in external ram
Audio is broken if buffers are in external ram and the external
ram clock is turned off. To fix it:
* In platform data, ext_ram is replaced with two settings:
ext_ram_rx and ext_ram_tx which control whether the buffer
will be in iram or external ram.
* imx-pcm.c no longer hardwired to put all capture streams in
external ram.
* if IRAM is disabled in the defconfig or if iram_alloc fails,
then ext_ram_rx or ext_ram_tx are updated so they will
show whether the buffers were allocated in external ram
or iram.
* During audio playback or capture, enable external ram clock
if the buffer is in external ram.
Signed-off-by: Alan Tull <alan.tull@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/imx/imx-3stack-sgtl5000.c | 3 | ||||
-rw-r--r-- | sound/soc/imx/imx-pcm.c | 129 | ||||
-rw-r--r-- | sound/soc/imx/imx-pcm.h | 2 |
3 files changed, 100 insertions, 34 deletions
diff --git a/sound/soc/imx/imx-3stack-sgtl5000.c b/sound/soc/imx/imx-3stack-sgtl5000.c index d820d802ec11..0ba1b90085a2 100644 --- a/sound/soc/imx/imx-3stack-sgtl5000.c +++ b/sound/soc/imx/imx-3stack-sgtl5000.c @@ -609,6 +609,9 @@ static int __devinit imx_3stack_sgtl5000_probe(struct platform_device *pdev) imx_3stack_dai.cpu_dai = sgtl5000_cpu_dai; + /* get mxc_audio_platform_data for pcm */ + imx_3stack_dai.cpu_dai->dev = &pdev->dev; + ret = driver_create_file(pdev->dev.driver, &driver_attr_headphone); if (ret < 0) { pr_err("%s:failed to create driver_attr_headphone\n", __func__); diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/imx/imx-pcm.c index 4df2f8fea0a7..39371557a99c 100644 --- a/sound/soc/imx/imx-pcm.c +++ b/sound/soc/imx/imx-pcm.c @@ -23,6 +23,7 @@ #include <linux/dma-mapping.h> #include <linux/iram_alloc.h> #include <linux/fsl_devices.h> +#include <linux/clk.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -461,6 +462,44 @@ static int imx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } +/* + * Get value of ext_ram for the capture/playback stream + */ +static int get_ext_ram(struct snd_soc_dai *cpu_dai, int stream) +{ + struct mxc_audio_platform_data *dev_data = cpu_dai->dev->platform_data; + struct clk *ext_ram_clk = dev_data->ext_ram_clk; + int ext_ram = 0; + + if (stream == SNDRV_PCM_STREAM_CAPTURE) + ext_ram = dev_data->ext_ram_rx; + else + ext_ram = dev_data->ext_ram_tx; + + WARN(ext_ram && ((ext_ram_clk == NULL) || IS_ERR(ext_ram_clk)), + "%s: Need a valid pointer to external ram clock\n", __func__); + + return ext_ram; +} + +/* + * Update the value of ext_ram for the capture/playback stream to + * show whether the buffer is actually in external ram or iram. + */ +static void update_ext_ram(struct snd_soc_dai *cpu_dai, int stream, int ext_ram) +{ + struct mxc_audio_platform_data *dev_data = cpu_dai->dev->platform_data; + struct clk *ext_ram_clk = dev_data->ext_ram_clk; + + if (stream == SNDRV_PCM_STREAM_CAPTURE) + dev_data->ext_ram_rx = ext_ram; + else + dev_data->ext_ram_tx = ext_ram; + + WARN(ext_ram && ((ext_ram_clk == NULL) || IS_ERR(ext_ram_clk)), + "%s: Need a valid pointer to external ram clock\n", __func__); +} + static int imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct mxc_runtime_data *prtd = substream->runtime->private_data; @@ -522,9 +561,17 @@ static snd_pcm_uframes_t imx_pcm_pointer(struct static int imx_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_dai *cpu_dai = socdev->card->dai_link->cpu_dai; + struct mxc_audio_platform_data *dev_data = cpu_dai->dev->platform_data; struct mxc_runtime_data *prtd; int ret; + /* if audio buffer is in external ram, enable the clock */ + if (get_ext_ram(cpu_dai, substream->stream)) + clk_enable(dev_data->ext_ram_clk); + snd_soc_set_runtime_hwparams(substream, &imx_pcm_hardware); ret = snd_pcm_hw_constraint_integer(runtime, @@ -544,6 +591,13 @@ static int imx_pcm_close(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct mxc_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_dai *cpu_dai = socdev->card->dai_link->cpu_dai; + struct mxc_audio_platform_data *dev_data = cpu_dai->dev->platform_data; + + if (get_ext_ram(cpu_dai, substream->stream)) + clk_disable(dev_data->ext_ram_clk); kfree(prtd); return 0; @@ -556,22 +610,17 @@ imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai *cpu_dai = socdev->card->dai_link->cpu_dai; - struct mxc_audio_platform_data *dev_data; int ext_ram = 0; int ret = 0; - dbg("+imx_pcm_mmap:" - "UseIram=%d dma_addr=%x dma_area=%x dma_bytes=%d\n", - UseIram, (unsigned int)runtime->dma_addr, - runtime->dma_area, runtime->dma_bytes); + ext_ram = get_ext_ram(cpu_dai, substream->stream); - if (cpu_dai->dev && cpu_dai->dev->platform_data) { - dev_data = cpu_dai->dev->platform_data; - ext_ram = dev_data->ext_ram; - } + dbg("%s: UseIram=%d ext_ram=%d dma_addr=%x dma_area=%x dma_bytes=%d\n", + __func__, UseIram, ext_ram, (unsigned int)runtime->dma_addr, + runtime->dma_area, runtime->dma_bytes); - if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) - || ext_ram || !UseIram) { + if (ext_ram || !UseIram) { + update_ext_ram(cpu_dai, substream->stream, 1); ret = dma_mmap_writecombine(substream->pcm->card-> dev, vma, @@ -579,8 +628,10 @@ imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) runtime->dma_addr, runtime->dma_bytes); return ret; - } else + } else { + update_ext_ram(cpu_dai, substream->stream, 0); return imx_iram_audio_playback_mmap(substream, vma); + } } struct snd_pcm_ops imx_pcm_ops = { @@ -602,33 +653,29 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai *cpu_dai = socdev->card->dai_link->cpu_dai; - struct mxc_audio_platform_data *dev_data; unsigned long buf_paddr; int ext_ram = 0; size_t size = imx_pcm_hardware.buffer_bytes_max; - if (cpu_dai->dev && cpu_dai->dev->platform_data) { - dev_data = cpu_dai->dev->platform_data; - ext_ram = dev_data->ext_ram; - } + ext_ram = get_ext_ram(cpu_dai, stream); buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; buf->private_data = NULL; - pr_err("capture=%d ext_ram=%d UseIram=%d\n", - (stream == SNDRV_PCM_STREAM_CAPTURE), ext_ram, UseIram); - - if ((stream == SNDRV_PCM_STREAM_CAPTURE) || ext_ram || !UseIram) + if (ext_ram || !UseIram) { + update_ext_ram(cpu_dai, substream->stream, 1); buf->area = dma_alloc_writecombine(pcm->card->dev, size, &buf->addr, GFP_KERNEL); - else { + } else { + update_ext_ram(cpu_dai, substream->stream, 0); buf->area = iram_alloc(size, &buf_paddr); buf->addr = buf_paddr; if (!buf->area) { pr_warning("imx-pcm: Falling back to external ram.\n"); + update_ext_ram(cpu_dai, substream->stream, 1); UseIram = 0; buf->area = dma_alloc_writecombine(pcm->card->dev, size, @@ -639,9 +686,15 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) if (!buf->area) return -ENOMEM; buf->bytes = size; - printk(KERN_INFO "DMA Sound Buffers Allocated:" - "UseIram=%d buf->addr=%x buf->area=%p size=%d\n", - UseIram, buf->addr, buf->area, size); + + if (stream == SNDRV_PCM_STREAM_CAPTURE) + printk(KERN_INFO "DMA Sound Buffer Allocated: Capture " + "UseIram=%d ext_ram=%d buf->addr=%x buf->area=%p size=%d\n", + UseIram, ext_ram, buf->addr, buf->area, size); + else + printk(KERN_INFO "DMA Sound Buffer Allocated: Playback " + "UseIram=%d ext_ram=%d buf->addr=%x buf->area=%p size=%d\n", + UseIram, ext_ram, buf->addr, buf->area, size); return 0; } @@ -652,15 +705,9 @@ static void imx_pcm_free_dma_buffers(struct snd_pcm *pcm) struct snd_soc_pcm_runtime *rtd = pcm->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai *cpu_dai = socdev->card->dai_link->cpu_dai; - struct mxc_audio_platform_data *dev_data; int ext_ram = 0; int stream; - if (cpu_dai->dev && cpu_dai->dev->platform_data) { - dev_data = cpu_dai->dev->platform_data; - ext_ram = dev_data->ext_ram; - } - for (stream = 0; stream < 2; stream++) { substream = pcm->streams[stream].substream; if (!substream) @@ -670,8 +717,8 @@ static void imx_pcm_free_dma_buffers(struct snd_pcm *pcm) if (!buf->area) continue; - if ((stream == SNDRV_PCM_STREAM_CAPTURE) - || ext_ram || !UseIram) + ext_ram = get_ext_ram(cpu_dai, stream); + if (ext_ram) dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area, buf->addr); else { @@ -686,8 +733,24 @@ static u64 imx_pcm_dmamask = 0xffffffff; static int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, struct snd_pcm *pcm) { + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_dai *cpu_dai = socdev->card->dai_link->cpu_dai; + struct mxc_audio_platform_data *dev_data; + struct clk *ext_ram_clk; int ret = 0; + /* must have platform data (mxc_audio_platform_data) */ + BUG_ON(!cpu_dai->dev || !cpu_dai->dev->platform_data); + + /* if buffer is in external ram, we need the external ram clock */ + dev_data = cpu_dai->dev->platform_data; + ext_ram_clk = dev_data->ext_ram_clk; + if (dev_data->ext_ram_tx || dev_data->ext_ram_rx) + WARN((ext_ram_clk == NULL) || IS_ERR(ext_ram_clk), + "%s: Need a valid pointer to external ram clock\n", + __func__); + if (!card->dev->dma_mask) card->dev->dma_mask = &imx_pcm_dmamask; if (!card->dev->coherent_dma_mask) diff --git a/sound/soc/imx/imx-pcm.h b/sound/soc/imx/imx-pcm.h index 5a7efa171a71..3d4ce5b48372 100644 --- a/sound/soc/imx/imx-pcm.h +++ b/sound/soc/imx/imx-pcm.h @@ -2,7 +2,7 @@ * imx-pcm.h :- ASoC platform header for Freescale i.MX * * Copyright 2006 Wolfson Microelectronics PLC. - * Copyright 2006, 2009-2010 Freescale Semiconductor, Inc. + * Copyright 2006, 2009-2011 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as |