]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00180390 ESAI: add amixer ASRC p2p API(ALSALIB)
authorChen Liangjun <b36089@freescale.com>
Tue, 5 Jun 2012 08:47:26 +0000 (16:47 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:47 +0000 (08:34 +0200)
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>
sound/soc/imx/imx-cs42888.c
sound/soc/imx/imx-esai.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/imx/imx-pcm.h

index c58af0c46f25527a89254ae308578059e648d684..3fc420cbf59e64f820b5938c5e23e0af813f8249 100644 (file)
 #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));
index 5f95ecce842e4a8e6e9e249ad293a09d1a45fc9f..67eedfad54bc2cf475762b324b787bc1b538458d 100644 (file)
@@ -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);
index 386bd26564a8c4c0a47962445a13f551559fd07a..2547d2bb8fdb8d7311a1622e1b5c3cf2d98b2fef 100644 (file)
@@ -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;
index 274af8ff7dcccf4db6c5b01544f2c9d177b3f174..ede1382a2e04c368a9767ac09f63eab72ec4e62f 100644 (file)
@@ -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