diff options
author | Xinyu Chen <xinyu.chen@freescale.com> | 2012-04-09 13:34:16 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2012-04-09 13:34:16 +0800 |
commit | 52c5341f1302a0b328e7dd5890c12729406256fc (patch) | |
tree | 687adeb27a395f512c2a0fa373bd173c437f9321 /sound/soc/imx/imx-cs42888.c | |
parent | bee5f57f1e3e5174aa5390a330052e772afdc453 (diff) | |
parent | 3ec8c998827be5729ff98a0d7c097f7ad9ddbc6e (diff) |
Merge remote branch 'fsl-linux-sdk/imx_3.0.15' into imx_3.0.15_android
Diffstat (limited to 'sound/soc/imx/imx-cs42888.c')
-rw-r--r-- | sound/soc/imx/imx-cs42888.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/sound/soc/imx/imx-cs42888.c b/sound/soc/imx/imx-cs42888.c index dc46fa676386..c58af0c46f25 100644 --- a/sound/soc/imx/imx-cs42888.c +++ b/sound/soc/imx/imx-cs42888.c @@ -21,12 +21,14 @@ #include <linux/regulator/consumer.h> #include <linux/fsl_devices.h> #include <linux/gpio.h> +#include <linux/mxc_asrc.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> #include <sound/soc-dai.h> +#include <sound/pcm_params.h> #include <mach/hardware.h> #include <mach/clock.h> @@ -34,6 +36,99 @@ #include "imx-esai.h" #include "../codecs/cs42888.h" +#include "imx-pcm.h" + +#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_IMX_HAVE_PLATFORM_IMX_ASRC) +struct asrc_esai { + unsigned int cpu_dai_rates; + unsigned int codec_dai_rates; + enum asrc_pair_index asrc_index; + unsigned int output_sample_rate; +}; +static struct asrc_esai asrc_esai_data; +static bool asrc_support = 1; + +static int get_format_width(struct snd_pcm_hw_params *params) +{ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: + return 8; + case SNDRV_PCM_FORMAT_U16: + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + return 16; + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_3BE: + case SNDRV_PCM_FORMAT_U24_3LE: + return 24; + case SNDRV_PCM_FORMAT_S32: + case SNDRV_PCM_FORMAT_U32: + return 32; + default: + pr_err("Format is not support!\r\n"); + return -EINVAL; + } +} + +static int config_asrc(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + unsigned int rate = params_rate(params); + unsigned int channel = params_channels(params); + unsigned int wordwidth = get_format_width(params); + struct imx_pcm_runtime_data *pcm_data = + substream->runtime->private_data; + struct asrc_config config = {0}; + int ret = 0; + + if (rate <= 32000 || rate == asrc_esai_data.output_sample_rate) + return -EINVAL; + + if (channel != 2) + return -EINVAL; + + if (wordwidth != 24) + return -EINVAL; + + ret = asrc_req_pair(channel, &asrc_esai_data.asrc_index); + if (ret < 0) { + pr_err("Fail to request asrc pair\n"); + asrc_release_pair(asrc_esai_data.asrc_index); + asrc_finish_conv(asrc_esai_data.asrc_index); + return -EINVAL; + } + + config.pair = asrc_esai_data.asrc_index; + config.channel_num = channel; + config.input_sample_rate = rate; + config.output_sample_rate = asrc_esai_data.output_sample_rate; + config.inclk = OUTCLK_ASRCK1_CLK; + config.word_width = wordwidth; + config.outclk = OUTCLK_ESAI_TX; + + ret = asrc_config_pair(&config); + if (ret < 0) { + pr_err("Fail to config asrc\n"); + asrc_release_pair(asrc_esai_data.asrc_index); + asrc_finish_conv(asrc_esai_data.asrc_index); + return ret; + } + pcm_data->asrc_index = asrc_esai_data.asrc_index; + pcm_data->asrc_enable = 1; + + return 0; +} +#else +static bool asrc_support; +#endif struct imx_priv_state { int hw; @@ -42,6 +137,7 @@ struct imx_priv_state { static struct imx_priv_state hw_state; unsigned int mclk_freq; + static int imx_3stack_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -51,6 +147,14 @@ static int imx_3stack_startup(struct snd_pcm_substream *substream) hw_state.hw = 0; } + if (asrc_support) { + struct snd_soc_dai *codec_dai = rtd->codec_dai; + asrc_esai_data.cpu_dai_rates = + cpu_dai->driver->playback.rates; + asrc_esai_data.codec_dai_rates = + codec_dai->driver->playback.rates; + } + return 0; } @@ -58,6 +162,24 @@ static void imx_3stack_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + + if (asrc_support) { + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct imx_pcm_runtime_data *pcm_data = + substream->runtime->private_data; + if (pcm_data->asrc_enable) { + asrc_release_pair(asrc_esai_data.asrc_index); + asrc_finish_conv(asrc_esai_data.asrc_index); + } + pcm_data->asrc_enable = 0; + asrc_esai_data.asrc_index = -1; + + codec_dai->driver->playback.rates = + asrc_esai_data.codec_dai_rates; + cpu_dai->driver->playback.rates = + asrc_esai_data.cpu_dai_rates; + } + if (!cpu_dai->active) hw_state.hw = 0; } @@ -75,6 +197,12 @@ static int imx_3stack_surround_hw_params(struct snd_pcm_substream *substream, if (hw_state.hw) return 0; hw_state.hw = 1; + + if (asrc_support && + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && + !config_asrc(substream, params)) { + rate = asrc_esai_data.output_sample_rate; + } if (cpu_is_mx53() || machine_is_mx6q_sabreauto()) { switch (rate) { case 32000: @@ -211,6 +339,9 @@ static int imx_3stack_cs42888_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; + if (asrc_support) + asrc_esai_data.output_sample_rate = 44100; + snd_soc_dapm_new_controls(&codec->dapm, imx_3stack_dapm_widgets, ARRAY_SIZE(imx_3stack_dapm_widgets)); |