예제 #1
0
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;
}
예제 #2
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;
}
예제 #3
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;
}
예제 #4
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;
}
예제 #5
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--;
}
예제 #6
0
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(&params->input_complete);
		complete(&params->output_complete);
		complete(&params->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;
}