summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorChen Liangjun <b36089@freescale.com>2012-06-05 16:47:26 +0800
committerChen Liangjun <b36089@freescale.com>2012-06-07 10:41:28 +0800
commitcb265b28e40aabab2585ffeb2f0e6a3ef817269e (patch)
tree31efa574021dce4c3f458295049aec0ce92335e2 /sound
parentc2180cb55d4246fa9b552ad6927fe52e528d98bc (diff)
ENGR00180390 ESAI: add amixer ASRC p2p API(ALSALIB)
If we want to use ESAI call ASRC, we need to know the input sample rate as well as the output sample rate. however, cause of ALSA-LIB, the input sample rate pass down to ALSA-DRIVER is not accurate. For example, if the ALSA-DRIVER only support 48KHz playback and we want to play an 16KHz audio file, the sample rate params the ALSA DRIVER see is 48KHz but not 16KHz. So, the ALSA-DRIVER do not know the original sample rate, and thus unable to config ASRC properly. In this patch, we add an amixer control interface for alsa lib plugin to config the input sample rate before playback. If no plugin, user can call the amixer control interface to manually use ASRC for rate convert. For example, if we need to playback an 24bit_24K audio wav file without call the plug. The sound card is 0. 1 Get the ASRC capability: amixer sget "ASRC" 1 Set the input samplerate: amixer sset "ASRC" "24KHz" 2 Play; aplay -Dhw:0 audio_24k24S-S24_LE.wav Signed-off-by: Chen Liangjun <b36089@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/imx/imx-cs42888.c87
-rw-r--r--sound/soc/imx/imx-esai.c46
-rw-r--r--sound/soc/imx/imx-pcm-dma-mx2.c4
-rw-r--r--sound/soc/imx/imx-pcm.h3
4 files changed, 116 insertions, 24 deletions
diff --git a/sound/soc/imx/imx-cs42888.c b/sound/soc/imx/imx-cs42888.c
index c58af0c46f25..3fc420cbf59e 100644
--- a/sound/soc/imx/imx-cs42888.c
+++ b/sound/soc/imx/imx-cs42888.c
@@ -39,14 +39,60 @@
#include "imx-pcm.h"
#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_IMX_HAVE_PLATFORM_IMX_ASRC)
+static unsigned int asrc_rates[] = {
+ 0,
+ 24000,
+ 32000,
+ 44100,
+ 48000,
+ 64000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+};
struct asrc_esai {
unsigned int cpu_dai_rates;
unsigned int codec_dai_rates;
enum asrc_pair_index asrc_index;
- unsigned int output_sample_rate;
+ unsigned int input_sample_rate;
};
static struct asrc_esai asrc_esai_data;
static bool asrc_support = 1;
+static int asrc_func;
+
+static const char *asrc_function[] = {
+ "disable", "24KHz", "32KHz", "44.1KHz",
+ "48KHz", "64KHz", "88.2KHz", "96KHz", "176.4KHz", "192KHz"
+};
+
+static const struct soc_enum asrc_enum[] = {
+ SOC_ENUM_SINGLE_EXT(9, asrc_function),
+};
+
+static int asrc_get_rate(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = asrc_func;
+ return 0;
+}
+
+static int asrc_set_rate(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ if (asrc_func == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ asrc_func = ucontrol->value.enumerated.item[0];
+ asrc_esai_data.input_sample_rate = asrc_rates[asrc_func];
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new asrc_controls[] = {
+ SOC_ENUM_EXT("ASRC", asrc_enum[0], asrc_get_rate,
+ asrc_set_rate),
+};
static int get_format_width(struct snd_pcm_hw_params *params)
{
@@ -89,7 +135,7 @@ static int config_asrc(struct snd_pcm_substream *substream,
struct asrc_config config = {0};
int ret = 0;
- if (rate <= 32000 || rate == asrc_esai_data.output_sample_rate)
+ if ((rate == asrc_esai_data.input_sample_rate) || (asrc_func == 0))
return -EINVAL;
if (channel != 2)
@@ -108,8 +154,8 @@ static int config_asrc(struct snd_pcm_substream *substream,
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.input_sample_rate = asrc_esai_data.input_sample_rate;
+ config.output_sample_rate = rate;
config.inclk = OUTCLK_ASRCK1_CLK;
config.word_width = wordwidth;
config.outclk = OUTCLK_ESAI_TX;
@@ -121,6 +167,8 @@ static int config_asrc(struct snd_pcm_substream *substream,
asrc_finish_conv(asrc_esai_data.asrc_index);
return ret;
}
+ /*now our asrc driver support 24bit output*/
+ pcm_data->output_bit = 24;
pcm_data->asrc_index = asrc_esai_data.asrc_index;
pcm_data->asrc_enable = 1;
@@ -178,6 +226,8 @@ static void imx_3stack_shutdown(struct snd_pcm_substream *substream)
asrc_esai_data.codec_dai_rates;
cpu_dai->driver->playback.rates =
asrc_esai_data.cpu_dai_rates;
+ asrc_func = 0;
+ asrc_esai_data.input_sample_rate = asrc_rates[asrc_func];
}
if (!cpu_dai->active)
@@ -198,11 +248,9 @@ static int imx_3stack_surround_hw_params(struct snd_pcm_substream *substream,
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 (asrc_support && (substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+ config_asrc(substream, params);
+
if (cpu_is_mx53() || machine_is_mx6q_sabreauto()) {
switch (rate) {
case 32000:
@@ -339,8 +387,25 @@ 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;
+ if (asrc_support) {
+ struct snd_card *card = codec->card->snd_card;
+ int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(asrc_controls); i++) {
+ ret = snd_ctl_add(card,
+ snd_soc_cnew(&asrc_controls[i],
+ codec, asrc_controls[i].name,
+ codec->name_prefix));
+ if (ret < 0)
+ return ret;
+ }
+ /*asrc_func is inited 0.
+ * it means asrc would not
+ * be called defaultly*/
+ asrc_func = 0;
+ asrc_esai_data.input_sample_rate = asrc_rates[asrc_func];
+ }
snd_soc_dapm_new_controls(&codec->dapm, imx_3stack_dapm_widgets,
ARRAY_SIZE(imx_3stack_dapm_widgets));
diff --git a/sound/soc/imx/imx-esai.c b/sound/soc/imx/imx-esai.c
index 5f95ecce842e..67eedfad54bc 100644
--- a/sound/soc/imx/imx-esai.c
+++ b/sound/soc/imx/imx-esai.c
@@ -36,6 +36,7 @@
#include <mach/esai.h>
#include "imx-esai.h"
+#include "imx-pcm.h"
static struct imx_esai *local_esai;
@@ -301,6 +302,8 @@ static int imx_esai_hw_tx_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
+ struct imx_pcm_runtime_data *iprtd = substream->runtime->private_data;
+
struct imx_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
u32 tcr, tfcr;
unsigned int channels;
@@ -314,19 +317,40 @@ static int imx_esai_hw_tx_params(struct snd_pcm_substream *substream,
/* DAI data (word) size */
tfcr &= ESAI_TFCR_TWA_MASK;
tcr &= ESAI_TCR_TSWS_MASK;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- tfcr |= ESAI_WORD_LEN_16;
- tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL16;
- break;
- case SNDRV_PCM_FORMAT_S20_3LE:
- tfcr |= ESAI_WORD_LEN_20;
- tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL20;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
+
+ if (iprtd->asrc_enable) {
+ switch (iprtd->output_bit) {
+ case 16:
+ tfcr |= ESAI_WORD_LEN_16;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL16;
+ break;
+ case 24:
+ tfcr |= ESAI_WORD_LEN_24;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL24;
+ break;
+ default:
+ return -EINVAL;
+
+ }
tfcr |= ESAI_WORD_LEN_24;
tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL24;
- break;
+ } else {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ tfcr |= ESAI_WORD_LEN_16;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ tfcr |= ESAI_WORD_LEN_20;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ tfcr |= ESAI_WORD_LEN_24;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL24;
+ break;
+ default:
+ return -EINVAL;
+ }
}
channels = params_channels(params);
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
index 386bd26564a8..2547d2bb8fdb 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -134,7 +134,9 @@ static int imx_ssi_asrc_dma_alloc(struct snd_pcm_substream *substream,
if (!iprtd->asrc_p2p_dma_chan)
goto error;
- slave_config.direction = DMA_DEV_TO_DEV;;
+ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ slave_config.direction = DMA_DEV_TO_DEV;
slave_config.src_addr = asrc_get_per_addr(iprtd->asrc_index, 0);
slave_config.src_addr_width = buswidth;
slave_config.src_maxburst = dma_params->burstsize * buswidth;
diff --git a/sound/soc/imx/imx-pcm.h b/sound/soc/imx/imx-pcm.h
index 274af8ff7dcc..ede1382a2e04 100644
--- a/sound/soc/imx/imx-pcm.h
+++ b/sound/soc/imx/imx-pcm.h
@@ -53,16 +53,17 @@ struct imx_pcm_runtime_data {
struct dma_async_tx_descriptor *desc;
struct dma_chan *dma_chan;
struct imx_dma_data dma_data;
+ int asrc_enable;
#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_IMX_HAVE_PLATFORM_IMX_ASRC)
int asrc_index;
- int asrc_enable;
struct dma_async_tx_descriptor *asrc_desc;
struct dma_chan *asrc_dma_chan;
struct imx_dma_data asrc_dma_data;
struct dma_async_tx_descriptor *asrc_p2p_desc;
struct dma_chan *asrc_p2p_dma_chan;
struct imx_dma_data asrc_p2p_dma_data;
+ unsigned int output_bit;
#endif
};
#endif