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; }
static long asrc_ioctl_release_pair(struct asrc_pair_params *params, void __user *user) { enum asrc_pair_index index; unsigned long lock_flags; long ret; ret = copy_from_user(&index, user, sizeof(index)); if (ret) { dev_err(asrc->dev, "failed to get index from user space: %ld\n", ret); return ret; } /* index might be not valid due to some application failure. */ if (index < 0) return -EINVAL; params->asrc_active = 0; spin_lock_irqsave(&pair_lock, lock_flags); params->pair_hold = 0; spin_unlock_irqrestore(&pair_lock, lock_flags); if (params->input_dma_channel) dma_release_channel(params->input_dma_channel); if (params->output_dma_channel) dma_release_channel(params->output_dma_channel); mxc_free_dma_buf(params); asrc_release_pair(index); asrc_finish_conv(index); return 0; }
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; }
static int imx_3stack_surround_hw_free(struct snd_pcm_substream *substream) { struct imx_pcm_runtime_data *iprtd = substream->runtime->private_data; if (iprtd->asrc_enable) { if (iprtd->asrc_index != -1) { asrc_release_pair(iprtd->asrc_index); asrc_finish_conv(iprtd->asrc_index); } iprtd->asrc_index = -1; } return 0; }
static void imx_3stack_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *pcm_link = rtd->dai; #if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE) if (asrc_esai_data.output_sample_rate >= 32000) { struct snd_soc_dai *cpu_dai = pcm_link->cpu_dai; codec_dai->playback.rates = asrc_esai_data.codec_dai_rates; cpu_dai->playback.rates = asrc_esai_data.cpu_dai_rates; asrc_release_pair(asrc_esai_data.asrc_index); } #endif clk_state.lr_clk_active--; }
static int mxc_asrc_close(struct inode *inode, struct file *file) { struct asrc_pair_params *params; unsigned long lock_flags; params = file->private_data; if (!params) return 0; if (params->asrc_active) { params->asrc_active = 0; dmaengine_terminate_all(params->input_dma_channel); dmaengine_terminate_all(params->output_dma_channel); asrc_stop_conv(params->index); complete(¶ms->input_complete); complete(¶ms->output_complete); complete(¶ms->lastperiod_complete); } if (params->pair_hold) { spin_lock_irqsave(&pair_lock, lock_flags); params->pair_hold = 0; spin_unlock_irqrestore(&pair_lock, lock_flags); if (params->input_dma_channel) dma_release_channel(params->input_dma_channel); if (params->output_dma_channel) dma_release_channel(params->output_dma_channel); mxc_free_dma_buf(params); asrc_release_pair(params->index); asrc_finish_conv(params->index); } kfree(params); file->private_data = NULL; return 0; }
static void imx_3stack_shutdown(struct snd_pcm_substream *substream) { struct imx_3stack_priv *priv = &card_priv; #if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (asrc_ssi_data.output_sample_rate != 0) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *pcm_link = rtd->dai; struct snd_soc_dai *cpu_dai = pcm_link->cpu_dai; struct snd_soc_dai *codec_dai = pcm_link->codec_dai; codec_dai->playback.rates = asrc_ssi_data.codec_dai_rates; cpu_dai->playback.rates = asrc_ssi_data.cpu_dai_rates; asrc_release_pair(asrc_ssi_data.asrc_index); } } #endif priv->hw = 0; }
static int imx_3stack_surround_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *pcm_link = rtd->dai; struct snd_soc_dai *cpu_dai = pcm_link->cpu_dai; struct snd_soc_dai *codec_dai = pcm_link->codec_dai; unsigned int rate = params_rate(params); u32 dai_format; unsigned int lrclk_ratio = 0; #if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE) unsigned int channel = params_channels(params); #endif struct imx_esai *esai_mode = (struct imx_esai *)cpu_dai->private_data; if (clk_state.lr_clk_active > 1) return 0; #if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE) if (asrc_esai_data.output_sample_rate >= 32000) { unsigned int asrc_input_rate = rate; struct mxc_runtime_data *pcm_data = substream->runtime->private_data; struct asrc_config config; int retVal = 0;; retVal = asrc_req_pair(channel, &asrc_esai_data.asrc_index); if (retVal < 0) { pr_err("Fail to request asrc pair\n"); return -1; } config.pair = asrc_esai_data.asrc_index; config.channel_num = channel; config.input_sample_rate = asrc_input_rate; config.output_sample_rate = asrc_esai_data.output_sample_rate; config.inclk = INCLK_NONE; config.word_width = 32; config.outclk = OUTCLK_ESAI_TX; retVal = asrc_config_pair(&config); if (retVal < 0) { pr_err("Fail to config asrc\n"); asrc_release_pair(asrc_esai_data.asrc_index); return retVal; } rate = asrc_esai_data.output_sample_rate; pcm_data->asrc_index = asrc_esai_data.asrc_index; pcm_data->asrc_enable = 1; } #endif switch (rate) { case 32000: lrclk_ratio = 3; break; case 48000: lrclk_ratio = 3; break; case 64000: lrclk_ratio = 1; break; case 96000: lrclk_ratio = 1; break; case 128000: lrclk_ratio = 1; break; case 44100: lrclk_ratio = 3; break; case 88200: lrclk_ratio = 1; break; case 176400: lrclk_ratio = 0; break; case 192000: lrclk_ratio = 0; break; default: pr_info("Rate not support.\n"); return -EINVAL;; } dai_format = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; esai_mode->sync_mode = 0; esai_mode->network_mode = 1; /* set cpu DAI configuration */ snd_soc_dai_set_fmt(cpu_dai, dai_format); /* set i.MX active slot mask */ snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32); /* set the ESAI system clock as output */ snd_soc_dai_set_sysclk(cpu_dai, ESAI_CLK_EXTAL, mclk_freq, SND_SOC_CLOCK_OUT); /* set the ratio */ snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PSR, 1); snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PM, 0); snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_FP, lrclk_ratio); snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PSR, 1); snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PM, 0); snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_FP, lrclk_ratio); /* set codec DAI configuration */ snd_soc_dai_set_fmt(codec_dai, dai_format); /* set codec Master clock */ snd_soc_dai_set_sysclk(codec_dai, 0, mclk_freq, SND_SOC_CLOCK_IN); return 0; }
static int imx_3stack_audio_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct imx_3stack_priv *priv = &card_priv; unsigned int rate = params_rate(params); struct imx_ssi *ssi_mode = (struct imx_ssi *)cpu_dai->private_data; int ret = 0; unsigned int channels = params_channels(params); u32 dai_format; /* only need to do this once as capture and playback are sync */ if (priv->hw) return 0; priv->hw = 1; #if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE) if ((asrc_ssi_data.output_sample_rate != 0) && (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) { unsigned int asrc_input_rate = rate; unsigned int channel = params_channels(params); struct mxc_runtime_data *pcm_data = substream->runtime->private_data; struct asrc_config config; struct mxc_audio_platform_data *plat; struct imx_3stack_priv *priv = &card_priv; int retVal = 0; retVal = asrc_req_pair(channel, &asrc_ssi_data.asrc_index); if (retVal < 0) { pr_err("asrc_req_pair fail\n"); return -1; } config.pair = asrc_ssi_data.asrc_index; config.channel_num = channel; config.input_sample_rate = asrc_input_rate; config.output_sample_rate = asrc_ssi_data.output_sample_rate; config.inclk = INCLK_NONE; config.word_width = 32; plat = priv->pdev->dev.platform_data; if (plat->src_port == 1) config.outclk = OUTCLK_SSI1_TX; else config.outclk = OUTCLK_SSI2_TX; retVal = asrc_config_pair(&config); if (retVal < 0) { pr_err("Fail to config asrc\n"); asrc_release_pair(asrc_ssi_data.asrc_index); return retVal; } rate = asrc_ssi_data.output_sample_rate; pcm_data->asrc_index = asrc_ssi_data.asrc_index; pcm_data->asrc_enable = 1; } #endif snd_soc_dai_set_sysclk(codec_dai, ALC5623_SYSCLK, priv->sysclk, 0); snd_soc_dai_set_sysclk(codec_dai, ALC5623_LRCLK, rate, 0); #if ALC5623_SSI_MASTER dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM; #else dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; #endif ssi_mode->sync_mode = 1; if (channels == 1) ssi_mode->network_mode = 0; else ssi_mode->network_mode = 1; /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, dai_format); if (ret < 0) return ret; /* set i.MX active slot mask */ snd_soc_dai_set_tdm_slot(cpu_dai, channels == 1 ? 0xfffffffe : 0xfffffffc, channels == 1 ? 0xfffffffe : 0xfffffffc, 2, 32); /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); if (ret < 0) return ret; /* set the SSI system clock as input (unused) */ snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN); return 0; }