示例#1
0
/*
 * Should only be called when port is inactive.
 * although can be called multiple times by upper layers.
 */
static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params,
			     struct snd_soc_dai *cpu_dai)
{
	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
	struct mxs_saif *master_saif;
	u32 scr, stat;
	int ret;

	master_saif = mxs_saif_get_master(saif);
	if (!master_saif)
		return -EINVAL;

	/* mclk should already be set */
	if (!saif->mclk && saif->mclk_in_use) {
		dev_err(cpu_dai->dev, "set mclk first\n");
		return -EINVAL;
	}

	stat = __raw_readl(saif->base + SAIF_STAT);
	if (stat & BM_SAIF_STAT_BUSY) {
		dev_err(cpu_dai->dev, "error: busy\n");
		return -EBUSY;
	}

	/*
	 * Set saif clk based on sample rate.
	 * If mclk is used, we also set mclk, if not, saif->mclk is
	 * default 0, means not used.
	 */
	ret = mxs_saif_set_clk(saif, saif->mclk, params_rate(params));
	if (ret) {
		dev_err(cpu_dai->dev, "unable to get proper clk\n");
		return ret;
	}

	/* prepare clk in hw_param, enable in trigger */
	clk_prepare(saif->clk);
	if (saif != master_saif) {
		/*
		* Set an initial clock rate for the saif internal logic to work
		* properly. This is important when working in EXTMASTER mode
		* that uses the other saif's BITCLK&LRCLK but it still needs a
		* basic clock which should be fast enough for the internal
		* logic.
		*/
		clk_enable(saif->clk);
		ret = clk_set_rate(saif->clk, 24000000);
		clk_disable(saif->clk);
		if (ret)
			return ret;

		clk_prepare(master_saif->clk);
	}

	scr = __raw_readl(saif->base + SAIF_CTRL);

	scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
	scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
		break;
	default:
		return -EINVAL;
	}

	/* Tx/Rx config */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		/* enable TX mode */
		scr &= ~BM_SAIF_CTRL_READ_MODE;
	} else {
		/* enable RX mode */
		scr |= BM_SAIF_CTRL_READ_MODE;
	}

	__raw_writel(scr, saif->base + SAIF_CTRL);
	return 0;
}
示例#2
0
文件: uda134x.c 项目: DenisLug/mptcp
static int uda134x_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params,
	struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
	unsigned int hw_params = 0;

	if (substream == uda134x->slave_substream) {
		pr_debug("%s ignoring hw_params for slave substream\n",
			 __func__);
		return 0;
	}

	pr_debug("%s sysclk: %d, rate:%d\n", __func__,
		 uda134x->sysclk, params_rate(params));

	/* set SYSCLK / fs ratio */
	switch (uda134x->sysclk / params_rate(params)) {
	case 512:
		break;
	case 384:
		hw_params |= (1<<4);
		break;
	case 256:
		hw_params |= (1<<5);
		break;
	default:
		printk(KERN_ERR "%s unsupported fs\n", __func__);
		return -EINVAL;
	}

	pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
		 uda134x->dai_fmt, params_format(params));

	/* set DAI format and word length */
	switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		switch (params_width(params)) {
		case 16:
			hw_params |= (1<<1);
			break;
		case 18:
			hw_params |= (1<<2);
			break;
		case 20:
			hw_params |= ((1<<2) | (1<<1));
			break;
		default:
			printk(KERN_ERR "%s unsupported format (right)\n",
			       __func__);
			return -EINVAL;
		}
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		hw_params |= (1<<3);
		break;
	default:
		printk(KERN_ERR "%s unsupported format\n", __func__);
		return -EINVAL;
	}

	return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0,
		STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params);
}
示例#3
0
static int rk29_aif2_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	unsigned int pll_out = 0; 
	int div_bclk,div_mclk;
	int ret;
	struct clk	*general_pll;

	//change to 8Khz
//	params->intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL].min = 8000;	

	DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
	
//	if (params_rate(params) != 8000)
//		return -EINVAL;

	/* set codec DAI configuration */
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
			SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
	{
		printk("%s: snd_soc_dai_set_fmt err =%d\n",__FUNCTION__,ret);
		return ret;
	}
	switch(params_rate(params)) {
		case 8000:
		case 16000:
		case 24000:
		case 32000:
		case 48000:
			pll_out = 12288000;
			break;
		case 11025:
		case 22050:
		case 44100:
			pll_out = 11289600;
			break;
		default:
			DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
			return -EINVAL;
	}
	
	general_pll=clk_get(NULL, "general_pll");
	if(clk_get_rate(general_pll)>260000000)
	{
		div_bclk=(pll_out/4)/params_rate(params)-1;
		div_mclk=3;
	}
	else if(clk_get_rate(general_pll)>130000000)
	{
		div_bclk=(pll_out/2)/params_rate(params)-1;
		div_mclk=1;
	}
	else
	{//96M
		pll_out=pll_out/4;
		div_bclk=(pll_out)/params_rate(params)-1;
		div_mclk=0;
	}

	DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",
			__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
	
	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
	if(ret < 0)
	{
		DBG("rk29_hw_params_wm8994:failed to set the cpu sysclk for codec side\n"); 
		return ret;
	}
	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
	DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));

	/* set the codec FLL */
	ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, WM8994_FLL_SRC_MCLK1, pll_out,
			8000 * 256);
	if (ret < 0)
	{
		printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
		return ret;
	}
	/* set the codec system clock */
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
			8000 * 256, SND_SOC_CLOCK_IN);
	if (ret < 0)
	{
		printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
		return ret;
	}

	return ret;
}
/* Note that PCM works __only__ in AP-Master mode */
static int smdk_socpcm_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 *cpu_dai = rtd->dai->cpu_dai;
	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
	int rfs, ret;
	unsigned long epll_out_rate;

	switch (params_rate(params)) {
	case 8000:
	case 12000:
	case 16000:
	case 24000:
	case 32000:
	case 48000:
	case 64000:
	case 96000:
		epll_out_rate = 49152000;
		break;
	case 11025:
	case 22050:
	case 44100:
	case 88200:
		epll_out_rate = 67738000;
		break;
	default:
		printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n",
			__func__, __LINE__, params_rate(params));
		return -EINVAL;
	}

	switch (params_rate(params)) {
	case 16000:
	case 22050:
	case 22025:
	case 32000:
	case 44100:
	case 48000:
	case 96000:
	case 24000:
		rfs = 256;
		break;
	case 64000:
		rfs = 384;
		break;
	case 8000:
	case 11025:
	case 12000:
		rfs = 512;
		break;
	case 88200:
		rfs = 128;
		break;
	default:
		printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n",
			__func__, __LINE__, params_rate(params));
		return -EINVAL;
	}

	/* Set the Codec DAI configuration */
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
					 | SND_SOC_DAIFMT_IB_NF
					 | SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		return ret;

	/* Set the AP DAI configuration */
	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
					 | SND_SOC_DAIFMT_IB_NF
					 | SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		return ret;

	/* Set MUX for PCM clock source to audio-bus */
	ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
					0, SND_SOC_CLOCK_OUT);
	if (ret < 0)
		return ret;

	/* Set EPLL clock rate */
	ret = set_epll_rate(epll_out_rate);
	if (ret < 0)
		return ret;

	/* Set SCLK_DIV for making bclk */
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
	if (ret < 0)
		return ret;

	/* Set WM8580 to drive MCLK from PLLA */
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
					WM8580_CLKSRC_PLLA);
	if (ret < 0)
		return ret;

	/* Explicitly set WM8580-DAC to source from MCLK */
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
					WM8580_CLKSRC_MCLK);
	if (ret < 0)
		return ret;

	/* Explicitly set WM8580-ADC to source from MCLK */
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_ADC_CLKSEL,
					WM8580_CLKSRC_ADCMCLK);
	if (ret < 0)
		return ret;

	ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
					SMDK_WM8580_XTI_FREQ,
					params_rate(params) * rfs);
	if (ret < 0)
		return ret;

	return 0;
}
示例#5
0
文件: sta529.c 项目: 3null/linux
static int sta529_hw_params(struct snd_pcm_substream *substream,
		struct snd_pcm_hw_params *params,
		struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	int pdata, play_freq_val, record_freq_val;
	int bclk_to_fs_ratio;

	switch (params_width(params)) {
	case 16:
		pdata = 1;
		bclk_to_fs_ratio = 0;
		break;
	case 24:
		pdata = 2;
		bclk_to_fs_ratio = 1;
		break;
	case 32:
		pdata = 3;
		bclk_to_fs_ratio = 2;
		break;
	default:
		dev_err(codec->dev, "Unsupported format\n");
		return -EINVAL;
	}

	switch (params_rate(params)) {
	case 8000:
	case 11025:
		play_freq_val = 0;
		record_freq_val = 2;
		break;
	case 16000:
	case 22050:
		play_freq_val = 1;
		record_freq_val = 0;
		break;

	case 32000:
	case 44100:
	case 48000:
		play_freq_val = 2;
		record_freq_val = 0;
		break;
	default:
		dev_err(codec->dev, "Unsupported rate\n");
		return -EINVAL;
	}

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		snd_soc_update_bits(codec, STA529_S2PCFG1, PDATA_LEN_MSK,
				pdata << 6);
		snd_soc_update_bits(codec, STA529_S2PCFG1, BCLK_TO_FS_MSK,
				bclk_to_fs_ratio << 4);
		snd_soc_update_bits(codec, STA529_MISC, PLAY_FREQ_RANGE_MSK,
				play_freq_val << 4);
	} else {
		snd_soc_update_bits(codec, STA529_P2SCFG1, PDATA_LEN_MSK,
				pdata << 6);
		snd_soc_update_bits(codec, STA529_P2SCFG1, BCLK_TO_FS_MSK,
				bclk_to_fs_ratio << 4);
		snd_soc_update_bits(codec, STA529_MISC, CAP_FREQ_RANGE_MSK,
				record_freq_val << 2);
	}

	return 0;
}
示例#6
0
static int zylonite_voice_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	unsigned int pll_out = 0;
	unsigned int wm9713_div = 0;
	int ret = 0;
	int rate = params_rate(params);
	int width = snd_pcm_format_physical_width(params_format(params));

	/* Only support ratios that we can generate neatly from the AC97
	 * based master clock - in particular, this excludes 44.1kHz.
	 * In most applications the voice DAC will be used for telephony
	 * data so multiples of 8kHz will be the common case.
	 */
	switch (rate) {
	case 8000:
		wm9713_div = 12;
		break;
	case 16000:
		wm9713_div = 6;
		break;
	case 48000:
		wm9713_div = 2;
		break;
	default:
		/* Don't support OSS emulation */
		return -EINVAL;
	}

	/* Add 1 to the width for the leading clock cycle */
	pll_out = rate * (width + 1) * 8;

	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
	if (ret < 0)
		return ret;

	ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out);
	if (ret < 0)
		return ret;

	if (clk_pout)
		ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV,
					     WM9713_PCMDIV(wm9713_div));
	else
		ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
					     WM9713_PCMDIV(wm9713_div));
	if (ret < 0)
		return ret;

	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		return ret;

	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
	if (ret < 0)
		return ret;

	return 0;
}
static int msm_hdmi_audio_codec_rx_dai_hw_params(
    struct snd_pcm_substream *substream,
    struct snd_pcm_hw_params *params,
    struct snd_soc_dai *dai)
{
    u32 channel_allocation = 0;
    u32 level_shift  = 0; /* 0dB */
    bool down_mix = 0;
    u32 num_channels = params_channels(params);
    int rv = 0;

    struct msm_hdmi_audio_codec_rx_data *codec_data =
        dev_get_drvdata(dai->codec->dev);

    rv = codec_data->hdmi_ops.hdmi_cable_status(
             codec_data->hdmi_core_pdev, 1);
    if (IS_ERR_VALUE(rv)) {
        dev_err(dai->dev,
                "%s() HDMI core is not ready\n", __func__);
        return rv;
    }

    switch (num_channels) {
    case 2:
        channel_allocation  = 0;
        break;
    case 3:
        channel_allocation  = 0x02;//default to FL/FR/FC
        break;
    case 4:
        channel_allocation  = 0x06;//default to FL/FR/FC/RC
        break;
    case 5:
        channel_allocation  = 0x0A;//default to FL/FR/FC/RR/RL
        break;
    case 6:
        channel_allocation  = 0x0B;
        break;
    case 7:
        channel_allocation  = 0x12;//default to FL/FR/FC/RL/RR/RRC/RLC
        break;
    case 8:
        channel_allocation  = 0x13;
        break;
    default:
        dev_err(dai->dev, "invalid Channels = %u\n", num_channels);
        return -EINVAL;
    }

    dev_dbg(dai->dev,
            "%s() num_ch %u  samplerate %u channel_allocation = %u\n",
            __func__, num_channels, params_rate(params),
            channel_allocation);

    rv = codec_data->hdmi_ops.audio_info_setup(
             codec_data->hdmi_core_pdev,
             params_rate(params), num_channels,
             channel_allocation, level_shift, down_mix);
    if (IS_ERR_VALUE(rv)) {
        dev_err(dai->dev,
                "%s() HDMI core is not ready\n", __func__);
    }

    return rv;
}
示例#8
0
static int archos_wm8985_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 *codec_dai = rtd->dai->codec_dai;
    struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
    int ret,i;

    /* Set codec DAI configuration */
    ret = snd_soc_dai_set_fmt(codec_dai,
                              SND_SOC_DAIFMT_DSP_A |
                              SND_SOC_DAIFMT_NB_NF |
                              SND_SOC_DAIFMT_CBM_CFM);
    if (ret < 0) {
        printk(KERN_ERR "can't set codec DAI fmt configuration\n");
        return ret;
    }

    /* Set cpu DAI configuration */
    if (archos_spdif_func) {
        /* SPDIF Enabled, we need to configure MCBSP as a SPDIF output */
        ret = snd_soc_dai_set_fmt(cpu_dai,
                                  SND_SOC_DAIFMT_SPDIF |
                                  SND_SOC_DAIFMT_NB_IF |
                                  SND_SOC_DAIFMT_CBM_CFM);
    } else {
        /* SPDIF Disable, we need to configure MCBSP as a PCM output */
        ret = snd_soc_dai_set_fmt(cpu_dai,
                                  SND_SOC_DAIFMT_DSP_A |
                                  SND_SOC_DAIFMT_NB_IF |
                                  SND_SOC_DAIFMT_CBM_CFM);
    }

    if (ret < 0) {
        printk(KERN_ERR "can't set cpu DAI configuration\n");
        return ret;
    }

    /* Set PPL and divisor here and not in the codec,
    	since it's our board which requires these settings */
    //printk(KERN_INFO "archos_wm8985_hw_params : freq = %d, channels = %d\n", params_rate(params), params_channels(params));
    for(i = 0; i < sample_count; i++) {
        if (params_rate(params) == sample_info[i].sample_rate) {
            //printk(KERN_INFO "archos_hw_params : selected id = %d\n", i);

            /* PPL (WM8985 is Master) */
            ret = snd_soc_dai_set_pll(codec_dai, 0, mclk,sample_info[i].out_hz);
            if (ret < 0) {
                printk(KERN_ERR "can't set codec DAI ppl configuration\n");
                return ret;
            }

            /* MCLK/BCLK stuff */
            ret = snd_soc_dai_set_clkdiv(codec_dai,WM8985_MCLKSEL,
                                         WM8985_MCLK_PLL);
            if (ret < 0) {
                printk(KERN_ERR "can't set codec DAI MCLKSEL configuration\n");
                return ret;
            }
            ret = snd_soc_dai_set_clkdiv(codec_dai,WM8985_MCLKDIV,
                                         sample_info[i].mclk_div << 5);
            if (ret < 0) {
                printk(KERN_ERR "can't set codec DAI MCLKDIV configuration\n");
                return ret;
            }
            ret = snd_soc_dai_set_clkdiv(codec_dai,WM8985_BCLKDIV,
                                         sample_info[i].bclk_div << 2);
            if (ret < 0) {
                printk(KERN_ERR "can't set codec DAI BCLKDIV configuration\n");
                return ret;
            }
        }
    }


    /* The codec may need to know the MCLK (Sample Rate for DAC and ADC are set by the codec) */
    ret = snd_soc_dai_set_sysclk(codec_dai, WM8985_ID_MCLK, mclk,
                                 SND_SOC_CLOCK_IN);
    if (ret < 0) {
        printk(KERN_ERR "can't set codec system clock\n");
        return ret;
    }

    return 0;
}
示例#9
0
static void set_st_params(struct oxygen *chip,
			  struct snd_pcm_hw_params *params)
{
	update_cs2000_rate(chip, params_rate(params));
	set_pcm1796_params(chip, params);
}
示例#10
0
static int tegra_rt5631_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct snd_soc_codec *codec = rtd->codec;
	struct snd_soc_card *card = codec->card;
	struct tegra_rt5631 *machine = snd_soc_card_get_drvdata(card);
	int srate, mclk, i2s_daifmt;
	int err;

	srate = params_rate(params);
	switch (srate) {
	case 64000:
	case 88200:
	case 96000:
		mclk = 128 * srate;
		break;
	default:
		mclk = 384 * srate;
		break;
	}
	/* FIXME: Codec only requires >= 3MHz if OSR==0 */
	while (mclk < 6000000)
		mclk *= 2;

	err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
	if (err < 0) {
		dev_err(card->dev, "Can't configure clocks\n");
		return err;
	}

	i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
		     SND_SOC_DAIFMT_CBS_CFS;

	/* Use DSP mode for mono on Tegra20 */
	if ((params_channels(params) != 2) &&
	    (machine_is_ventana() || machine_is_harmony() ||
	    machine_is_kaen() || machine_is_aebl()))
		i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
	else
		i2s_daifmt |= SND_SOC_DAIFMT_I2S;

	err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
	if (err < 0) {
		dev_err(card->dev, "codec_dai fmt not set\n");
		return err;
	}

	err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt);
	if (err < 0) {
		dev_err(card->dev, "cpu_dai fmt not set\n");
		return err;
	}

	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
					SND_SOC_CLOCK_IN);
	if (err < 0) {
		dev_err(card->dev, "codec_dai clock not set\n");
		return err;
	}

	return 0;
}
示例#11
0
static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *params,
                                   struct snd_soc_dai *dai)
{
    int err = 0;
    struct snd_aes_iec958 iec;
    struct snd_cea_861_aud_if cea;

    switch (params_format(params)) {
    case SNDRV_PCM_FORMAT_S16_LE:
        omap_hdmi_dai_dma_params.packet_size = 16;
        break;
    case SNDRV_PCM_FORMAT_S24_LE:
        omap_hdmi_dai_dma_params.packet_size = 32;
        break;
    default:
        err = -EINVAL;
    }

    omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;

    snd_soc_dai_set_dma_data(dai, substream,
                             &omap_hdmi_dai_dma_params);

    /* Fill IEC 60958 channel status word */
    /* TODO: no need to fill with zeros when using kzalloc */
    iec.status[0] = 0;
    iec.status[1] = 0;
    iec.status[2] = 0;
    iec.status[3] = 0;
    iec.status[4] = 0;
    iec.status[5] = 0;
    /* Fill CEA 861 audio infoframe */
    /* here fill commercial use (0) */
    iec.status[0] &= ~IEC958_AES0_PROFESSIONAL;
    /* here fill lpcm audio (0) */
    iec.status[0] &= ~IEC958_AES0_NONAUDIO;
    /* here fill copyright info */
    iec.status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
    /* here fill emphasis info */
    iec.status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
    /* here fill mode info */
    iec.status[0] |= IEC958_AES1_PRO_MODE_NOTID;

    /* here fill category */
    iec.status[1] = IEC958_AES1_CON_GENERAL;

    /* here fill the source number */
    iec.status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
    /* here fill the channel number */
    iec.status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;

    /* here fill sampling rate */
    switch (params_rate(params)) {
    case 32000:
        iec.status[3] |= IEC958_AES3_CON_FS_32000;
        break;
    case 44100:
        iec.status[3] |= IEC958_AES3_CON_FS_44100;
        break;
    case 48000:
        iec.status[3] |= IEC958_AES3_CON_FS_48000;
        break;
    case 88200:
        iec.status[3] |= IEC958_AES3_CON_FS_88200;
        break;
    case 96000:
        iec.status[3] |= IEC958_AES3_CON_FS_96000;
        break;
    case 176400:
        iec.status[3] |= IEC958_AES3_CON_FS_176400;
        break;
    case 192000:
        iec.status[3] |= IEC958_AES3_CON_FS_192000;
        break;
    default:
        return -EINVAL;
    }

    /* here fill the clock accuracy */
    iec.status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;

    /* here fill the word length */
    switch (params_format(params)) {
    case SNDRV_PCM_FORMAT_S16_LE:
        iec.status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
        iec.status[4] |= 0; /* replace with word max define */
        break;
    case SNDRV_PCM_FORMAT_S24_LE:
        iec.status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
        iec.status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
        break;
    default:
        err = -EINVAL;
    }

    /* Fill the CEA 861 audio infoframe. Refer to the specification
     * for details.
     * The OMAP HDMI IP requires to use the 8-channel channel code when
     * transmitting more than two channels.
     */
    if (params_channels(params) == 2)
        cea.db4_ca = 0x0;
    else
        cea.db4_ca = 0x13;
    cea.db1_ct_cc = (params_channels(params) - 1)
                    & CEA861_AUDIO_INFOFRAME_DB1CC;
    cea.db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
    cea.db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
    cea.db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
    cea.db3 = 0; /* not used, all zeros */
    cea.db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
    cea.db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);

    hdmi.iec = iec;
    hdmi.cea = cea;

    err = hdmi.dssdev->driver->audio_config(hdmi.dssdev, &hdmi.iec,
                                            &hdmi.cea);

    return err;
}
示例#12
0
static int rk29_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
#else
        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
#endif
	int ret;
	unsigned int pll_out = 0; 
	int div_bclk,div_mclk;
//	struct clk	*general_pll;
	
	DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
	/*by Vincent Hsiung for EQ Vol Change*/
	#define HW_PARAMS_FLAG_EQVOL_ON 0x21
	#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
	if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
	{
		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
		ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
		#else
		ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent
		#endif
		DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
	}
	else
	{
		/* set codec DAI configuration */
		DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
		#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
		ret = codec_dai->driver->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 
		#else
		ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 
		#endif
		#endif	
		#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
		ret = codec_dai->driver->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); 
		#else
		ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); 
		#endif
		#endif
		if (ret < 0)
			  return ret; 
		/* set cpu DAI configuration */
		DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
		#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
		ret = cpu_dai->driver->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
		#else
		ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
		#endif
		#endif	
		#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
		#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
		ret = cpu_dai->driver->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);	
		#else
		ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);	
		#endif
		#endif		
		if (ret < 0)
			  return ret;
	}
	
	switch(params_rate(params)) {
        case 8000:
        case 16000:
        case 24000:
        case 32000:
        case 48000:
        case 96000:
            pll_out = 12288000;
            break;
        case 11025:
        case 22050:
        case 44100:
        case 88200:
            pll_out = 11289600;
            break;
        case 176400:
			pll_out = 11289600*2;
        	break;
        case 192000:
        	pll_out = 12288000*2;
        	break;
        default:
            DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
            return -EINVAL;
            break;
	}
	DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
	snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
	
	#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 	
		snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
	#endif	
	
	#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)

		div_bclk = 63;
		div_mclk = pll_out/(params_rate(params)*64) - 1;
		
//		DBG("func is%s,gpll=%ld,pll_out=%ld,div_mclk=%ld\n",
//				__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
		snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
		snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
		snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
//		DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));		
	#endif
    return 0;
}
示例#13
0
static int tegra_hifi_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct snd_soc_codec *codec = rtd->codec;
	struct snd_soc_card *card = codec->card;
	struct tegra_aic3008 *machine = snd_soc_card_get_drvdata(card);
	int dai_flag = 0, mclk, srate;
	int err;

	AUD_DBG("Start tegra_hifi_hw_params()\n");
	AUD_DBG("set I2S Master\n");

	dai_flag |= SND_SOC_DAIFMT_I2S; 	// i2s mode
	dai_flag |= SND_SOC_DAIFMT_CBM_CFM; // bclk and frame master

	srate = params_rate(params);
	switch (srate) {
	case 64000:
	case 88200:
	case 96000:
		mclk = 128 * srate;
		break;
	default:
		mclk = 256 * srate;
		break;
	}
	/* FIXME: Codec only requires >= 3MHz if OSR==0 */
	while (mclk < 6000000)
		mclk *= 2;

	mclk = 12288000;
	err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
	if (err < 0) {
		dev_err(card->dev, "Can't configure clocks\n");
		return err;
	}
	
	// eventually calls audio codec to set dai format, which sets slave
	err = snd_soc_dai_set_fmt(codec_dai, dai_flag);
	if (err < 0) {
		AUD_ERR("codec_dai fmt not set \n");
		return err;
	}
	AUD_DBG("*** snd_soc_dai_set_fmt(codec_dai, dai_flag) ok ***\n");

	// eventually calls t2s driver to set dai format, which sets master
	err = snd_soc_dai_set_fmt(cpu_dai, dai_flag);
	if (err < 0) {
		AUD_ERR("cpu_dai fmt not set \n");
		return err;
	}
	AUD_DBG("*** snd_soc_dai_set_fmt(cpu_dai, dai_flag) ok ***\n");

	// FIXME: not sure this is the right way.
	// Sets the audio codec clks.
	// This should be sample rate times 256 or 128 based on codec need
	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN);
	if (err < 0) {
		AUD_ERR("codec_dai clock not set\n");
		return err;
	}
	AUD_DBG("*** snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN) ok ***\n");

	return 0;
}
示例#14
0
static int tegra_hifi_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 *codec_dai 	= rtd->dai->codec_dai;
	struct snd_soc_dai *cpu_dai 	= rtd->dai->cpu_dai;
	struct adam_audio_priv* ctx 	= rtd->socdev->codec_data;
	
	
	int dai_flag = 0, sys_clk;
	int err;
	int i;	

	/* Get the requested sampling rate */
	unsigned int srate = params_rate(params);
	
	/* I2S <-> DAC <-> DAS <-> DAP <-> CODEC
	   -If DAP is master, codec will be slave */
	int codec_is_master = !tegra_das_is_port_master(tegra_audio_codec_type_hifi);
	
	/* Get DAS dataformat - DAP is connecting to codec */
	enum dac_dap_data_format data_fmt = tegra_das_get_codec_data_fmt(tegra_audio_codec_type_hifi);

	/* We are supporting DSP and I2s format for now */
	if (data_fmt & dac_dap_data_format_i2s)
		dai_flag |= SND_SOC_DAIFMT_I2S;
	else
		dai_flag |= SND_SOC_DAIFMT_DSP_A;
	
	if (codec_is_master)
		dai_flag |= SND_SOC_DAIFMT_CBM_CFM; /* codec is master */
	else
		dai_flag |= SND_SOC_DAIFMT_CBS_CFS;
	
	
	pr_debug("%s(): format: 0x%08x\n", __FUNCTION__,params_format(params));

	/* Set the CPU dai format. This will also set the clock rate in master mode */
	err = snd_soc_dai_set_fmt(cpu_dai, dai_flag);
	if (err < 0) {
		pr_err("cpu_dai fmt not set \n");
		return err;
	}

	err = snd_soc_dai_set_fmt(codec_dai, dai_flag);
	if (err < 0) {
		pr_err("codec_dai fmt not set \n");
		return err;
	}
	
	/* Get system clock */
	sys_clk = clk_get_rate(ctx->dap_mclk);

	/* Set CPU sysclock as the same - in Tegra, seems to be a NOP */
	err = snd_soc_dai_set_sysclk(cpu_dai, 0, sys_clk, SND_SOC_CLOCK_IN);
	if (err < 0) {
		pr_err("cpu_dai clock not set\n");
		return err;
	}
	
	if (codec_is_master) {
		pr_debug("%s(): codec in master mode\n",__FUNCTION__);
		
		/* If using port as slave (=codec as master), then we can use the
		   codec PLL to get the other sampling rates */
		
		/* Try each one until success */
		for (i = 0; i < ARRAY_SIZE(clocktab); i++) {
		
			if (clocktab[i].srate != srate) 
				continue;
				
			if (snd_soc_dai_set_pll(codec_dai, 0, 0, sys_clk, clocktab[i].mclk) >= 0) {
				/* Codec PLL is synthetizing this new clock */
				sys_clk = clocktab[i].mclk;
				break;
			}
		}
		
		if (i >= ARRAY_SIZE(clocktab)) {
			pr_err("%s(): unable to set required MCLK for SYSCLK of %d, sampling rate: %d\n",__FUNCTION__,sys_clk,srate);
			return -EINVAL;
		}
		
	} else {
		pr_debug("%s(): codec in slave mode\n",__FUNCTION__);

		/* Disable codec PLL */
		err = snd_soc_dai_set_pll(codec_dai, 0, 0, sys_clk, sys_clk);
		if (err < 0) {
			pr_err("%s(): unable to disable codec PLL\n",__FUNCTION__);
			return err;
		}
		
		/* Check this sampling rate can be achieved with this sysclk */
		for (i = 0; i < ARRAY_SIZE(clocktab); i++) {
		
			if (clocktab[i].srate != srate) 
				continue;
				
			if (sys_clk == clocktab[i].mclk)
				break;
		}
		
		if (i >= ARRAY_SIZE(clocktab)) {
			pr_err("%s(): unable to get required %d hz sampling rate of %d hz SYSCLK\n",__FUNCTION__,srate,sys_clk);
			return -EINVAL;
		}
	}

	/* Set CODEC sysclk */
	err = snd_soc_dai_set_sysclk(codec_dai, 0, sys_clk, SND_SOC_CLOCK_IN);
	if (err < 0) {
		pr_err("codec_dai clock not set\n");
		return err;
	}
	
	return 0;
}
示例#15
0
/**
 * cs42888_hw_params - program the CS42888 with the given hardware parameters.
 * @substream: the audio stream
 * @params: the hardware parameters to set

 * @dai: the SOC DAI (ignored)
 *
 * This function programs the hardware with the values provided.
 * Specifically, the sample rate and the data format.
 *
 * The .ops functions are used to provide board-specific data, like input
 * frequencies, to this driver.  This function takes that information,
 * combines it with the hardware parameters provided, and programs the
 * hardware accordingly.
 */
static int cs42888_hw_params(struct snd_pcm_substream *substream,
			    struct snd_pcm_hw_params *params,
			    struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_device *socdev = rtd->socdev;
	struct snd_soc_codec *codec = socdev->card->codec;
	struct cs42888_private *cs42888 = codec->private_data;
	int ret;
	unsigned int i;
	unsigned int rate;
	unsigned int ratio;
	u8 val;

	rate = params_rate(params);	/* Sampling rate, in Hz */
	ratio = cs42888->mclk / rate;	/* MCLK/LRCK ratio */

	for (i = 0; i < NUM_MCLK_RATIOS; i++) {
		if (cs42888_mode_ratios[i].ratio == ratio)
			break;
	}

	if (i == NUM_MCLK_RATIOS) {
		/* We did not find a matching ratio */
		dev_err(codec->dev, "could not find matching ratio\n");
		return -EINVAL;
	}

	if (!cs42888->slave_mode) {
		val = cs42888_read_reg_cache(codec, CS42888_MODE);
		val &= ~CS42888_MODE_SPEED_MASK;
		val |= cs42888_mode_ratios[i].speed_mode;
		val &= ~CS42888_MODE_DIV_MASK;
		val |= cs42888_mode_ratios[i].mclk;
	} else {
		val = cs42888_read_reg_cache(codec, CS42888_MODE);
		val &= ~CS42888_MODE_SPEED_MASK;
		val |= CS42888_MODE_SLAVE;
	}
	ret = cs42888_i2c_write(codec, CS42888_MODE, val);
	if (ret < 0) {
		pr_err("i2c write failed\n");
		return ret;
	}

	/* Out of low power state */
	val = cs42888_read_reg_cache(codec, CS42888_PWRCTL);
	val &= ~CS42888_PWRCTL_PDN_MASK;
	ret = cs42888_i2c_write(codec, CS42888_PWRCTL, val);
	if (ret < 0) {
		pr_err("i2c write failed\n");
		return ret;
	}

	/* Unmute all the channels */
	val = cs42888_read_reg_cache(codec, CS42888_MUTE);
	val &= ~CS42888_MUTE_ALL;
	ret = cs42888_i2c_write(codec, CS42888_MUTE, val);
	if (ret < 0) {
		pr_err("i2c write failed\n");
		return ret;
	}

	ret = cs42888_fill_cache(codec);
	if (ret < 0) {
		pr_err("failed to fill register cache\n");
		return ret;
	}

	return ret;
}
示例#16
0
static int smdk6400_hifi_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_codec_dai *codec_dai = rtd->dai->codec_dai;
	struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
	unsigned int pll_out = 0, bclk = 0;
	int ret = 0;
	unsigned int regs;
	unsigned int prescaler=0;

	//s3cdbg("Entered %s, rate = %d\n", __FUNCTION__, params_rate(params));
	printk("Entered %s, rate = %d\n", __FUNCTION__, params_rate(params));

	/* Select Clock source EPLL */
//	regs = ioremap(S3C2410_PA_CLKPWR,0x20);
	regs = readl(S3C2443_CLKSRC);
	regs &= ~(3<<12);
	regs &= ~(3<<14);
	regs |= S3C2450_CLKSRC_I2S1_EPLL;
	regs = (regs & ~(3<<7))|(2<<7);
	writel(regs, S3C2443_CLKSRC);
	regs |= (1<<6);
	writel(regs, S3C2443_CLKSRC);

	regs = readl(S3C2443_SCLKCON);
	regs |= S3C2443_SCLKCON_I2SCLK_1;
	writel(regs, S3C2443_SCLKCON);

	//s3cdbg("%s: %d , params = %d \n", __FUNCTION__, __LINE__, params_rate(params));
	printk("%s: %d , params = %d \n", __FUNCTION__, __LINE__, params_rate(params));

	switch (params_rate(params)) {
	case 8000:
	case 16000:
	case 32000:
	case 48000:
	case 64000:
	case 96000:
		writel(9962, S3C2450_EPLLCON_K);
		writel((49<<16)|(1<<8)|(3<<0) ,S3C2443_EPLLCON);
		break;
	case 11025:
	case 22050:
	case 44100:
	case 88200:
		writel(10381, S3C2450_EPLLCON_K);
		writel((45<<16)|(1<<8)|(2<<0) ,S3C2443_EPLLCON);
		break;
	default:
		printk("Unsupported rate = %d\n", params_rate(params));
		break;
	}

	switch (params_rate(params)) {
	case 8000:
		bclk = WM8753_BCLK_DIV_16;
		pll_out = 18432000;
		prescaler = 24; 
		break;
	case 11025:
		bclk = WM8753_BCLK_DIV_16;
		pll_out = 16934400;
		prescaler = 32; 
		break;
	case 16000:
		bclk = WM8753_BCLK_DIV_8;
		pll_out = 18432000;
		prescaler = 12; 
		break;
	case 22050:
		bclk = WM8753_BCLK_DIV_2;
		pll_out = 16934400;
		prescaler = 16; 
		break;
	case 32000:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 18432000;
		prescaler = 6; 
		break;
	case 44100:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 16934400;
		prescaler = 8; 
		break;
	case 48000:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 18432000;
		prescaler = 4; 
		break;
	case 64000:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 18432000;
		prescaler = 3; 
		break;
	case 88200:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 16934400;
		prescaler = 4; 
		break;
	case 96000:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 18432000;
		prescaler = 2; 
		break;
	}

	/* set codec DAI configuration */
	ret = codec_dai->dai_ops.set_fmt(codec_dai,
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBS_CFS ); 
	if (ret < 0)
		return ret;

	/* set cpu DAI configuration */
	ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBS_CFS ); 
	if (ret < 0)
		return ret;

	/* set the codec system clock for DAC and ADC */
	ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
		SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

	/* set MCLK division for sample rate */
	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
		S3C2410_IISMOD_32FS );
	if (ret < 0)
		return ret;

	/* set codec BCLK division for sample rate */
	ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
	if (ret < 0)
		return ret;

	/* set prescaler division for sample rate */
	ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
		((prescaler/2 - 1) << 0x8));
	if (ret < 0)
		return ret;
#if 0
	/* set the codec register set for capture and play */
	ret = codec_dai->dai_ops.set_tdm_slot(codec_dai, substream->stream, 2);
	if (ret < 0)
		return ret;
#endif

	return 0;
}
示例#17
0
static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params,
				 struct snd_soc_dai *dai)
{
	struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
	unsigned int sampling_rate = params_rate(params);
	unsigned int data_length, data_delay, bclk_ratio;
	unsigned int ch1pos, ch2pos, mode, format;
	uint32_t csreg;

	/*
	 * If a stream is already enabled,
	 * the registers are already set properly.
	 */
	regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);

	if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON))
		return 0;

	/*
	 * Adjust the data length according to the format.
	 * We prefill the half frame length with an integer
	 * divider of 2400 as explained at the clock settings.
	 * Maybe it is overwritten there, if the Integer mode
	 * does not apply.
	 */
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		data_length = 16;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		data_length = 24;
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		data_length = 32;
		break;
	default:
		return -EINVAL;
	}

	/* If bclk_ratio already set, use that one. */
	if (dev->bclk_ratio)
		bclk_ratio = dev->bclk_ratio;
	else
		/* otherwise calculate a fitting block ratio */
		bclk_ratio = 2 * data_length;

	/* Clock should only be set up here if CPU is clock master */
	switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
	case SND_SOC_DAIFMT_CBS_CFM:
		clk_set_rate(dev->clk, sampling_rate * bclk_ratio);
		break;
	default:
		break;
	}

	/* Setup the frame format */
	format = BCM2835_I2S_CHEN;

	if (data_length >= 24)
		format |= BCM2835_I2S_CHWEX;

	format |= BCM2835_I2S_CHWID((data_length-8)&0xf);

	switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		data_delay = 1;
		break;
	default:
		/*
		 * TODO
		 * Others are possible but are not implemented at the moment.
		 */
		dev_err(dev->dev, "%s:bad format\n", __func__);
		return -EINVAL;
	}

	ch1pos = data_delay;
	ch2pos = bclk_ratio / 2 + data_delay;

	switch (params_channels(params)) {
	case 2:
		format = BCM2835_I2S_CH1(format) | BCM2835_I2S_CH2(format);
		format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos));
		format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos));
		break;
	default:
		return -EINVAL;
	}

	/*
	 * Set format for both streams.
	 * We cannot set another frame length
	 * (and therefore word length) anyway,
	 * so the format will be the same.
	 */
	regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format);
	regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format);

	/* Setup the I2S mode */
	mode = 0;

	if (data_length <= 16) {
		/*
		 * Use frame packed mode (2 channels per 32 bit word)
		 * We cannot set another frame length in the second stream
		 * (and therefore word length) anyway,
		 * so the format will be the same.
		 */
		mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP;
	}

	mode |= BCM2835_I2S_FLEN(bclk_ratio - 1);
	mode |= BCM2835_I2S_FSLEN(bclk_ratio / 2);

	/* Master or slave? */
	switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		/* CPU is master */
		break;
	case SND_SOC_DAIFMT_CBM_CFS:
		/*
		 * CODEC is bit clock master
		 * CPU is frame master
		 */
		mode |= BCM2835_I2S_CLKM;
		break;
	case SND_SOC_DAIFMT_CBS_CFM:
		/*
		 * CODEC is frame master
		 * CPU is bit clock master
		 */
		mode |= BCM2835_I2S_FSM;
		break;
	case SND_SOC_DAIFMT_CBM_CFM:
		/* CODEC is master */
		mode |= BCM2835_I2S_CLKM;
		mode |= BCM2835_I2S_FSM;
		break;
	default:
		dev_err(dev->dev, "%s:bad master\n", __func__);
		return -EINVAL;
	}

	/*
	 * Invert clocks?
	 *
	 * The BCM approach seems to be inverted to the classical I2S approach.
	 */
	switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_NB_NF:
		/* None. Therefore, both for BCM */
		mode |= BCM2835_I2S_CLKI;
		mode |= BCM2835_I2S_FSI;
		break;
	case SND_SOC_DAIFMT_IB_IF:
		/* Both. Therefore, none for BCM */
		break;
	case SND_SOC_DAIFMT_NB_IF:
		/*
		 * Invert only frame sync. Therefore,
		 * invert only bit clock for BCM
		 */
		mode |= BCM2835_I2S_CLKI;
		break;
	case SND_SOC_DAIFMT_IB_NF:
		/*
		 * Invert only bit clock. Therefore,
		 * invert only frame sync for BCM
		 */
		mode |= BCM2835_I2S_FSI;
		break;
	default:
		return -EINVAL;
	}

	regmap_write(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, mode);

	/* Setup the DMA parameters */
	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
			BCM2835_I2S_RXTHR(1)
			| BCM2835_I2S_TXTHR(1)
			| BCM2835_I2S_DMAEN, 0xffffffff);

	regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_DREQ_A_REG,
			  BCM2835_I2S_TX_PANIC(0x10)
			| BCM2835_I2S_RX_PANIC(0x30)
			| BCM2835_I2S_TX(0x30)
			| BCM2835_I2S_RX(0x20), 0xffffffff);

	/* Clear FIFOs */
	bcm2835_i2s_clear_fifos(dev, true, true);

	return 0;
}
示例#18
0
文件: arizona.c 项目: LeeShuni/linux
static int arizona_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params,
			     struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
	int base = dai->driver->base;
	const int *rates;
	int i;
	int bclk, lrclk, wl, frame, sr_val;

	if (params_rate(params) % 8000)
		rates = &arizona_44k1_bclk_rates[0];
	else
		rates = &arizona_48k_bclk_rates[0];

	for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
		if (rates[i] >= snd_soc_params_to_bclk(params) &&
		    rates[i] % params_rate(params) == 0) {
			bclk = i;
			break;
		}
	}
	if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
				params_rate(params));
		return -EINVAL;
	}

	for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
		if (arizona_sr_vals[i] == params_rate(params))
			break;
	if (i == ARRAY_SIZE(arizona_sr_vals)) {
		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
				params_rate(params));
		return -EINVAL;
	}
	sr_val = i;

	lrclk = snd_soc_params_to_bclk(params) / params_rate(params);

	arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
			rates[bclk], rates[bclk] / lrclk);

	wl = snd_pcm_format_width(params_format(params));
	frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;

	/*
	 * We will need to be more flexible than this in future,
	 * currently we use a single sample rate for SYSCLK.
	 */
	switch (dai_priv->clk) {
	case ARIZONA_CLK_SYSCLK:
		snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
				    ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
		snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
				    ARIZONA_AIF1_RATE_MASK, 0);
		break;
	case ARIZONA_CLK_ASYNCCLK:
		snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
				    ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
		snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
				    ARIZONA_AIF1_RATE_MASK, 8);
		break;
	default:
		arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
		return -EINVAL;
	}

	snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
			    ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
			    ARIZONA_AIF1TX_BCPF_MASK, lrclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
			    ARIZONA_AIF1RX_BCPF_MASK, lrclk);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
			    ARIZONA_AIF1TX_WL_MASK |
			    ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
	snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
			    ARIZONA_AIF1RX_WL_MASK |
			    ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);

	return 0;
}
示例#19
0
文件: wm8770.c 项目: AllenDou/linux
static int wm8770_hw_params(struct snd_pcm_substream *substream,
			    struct snd_pcm_hw_params *params,
			    struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec;
	struct wm8770_priv *wm8770;
	int i;
	int iface;
	int shift;
	int ratio;

	codec = dai->codec;
	wm8770 = snd_soc_codec_get_drvdata(codec);

	iface = 0;
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		iface |= 0x10;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		iface |= 0x20;
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		iface |= 0x30;
		break;
	}

	switch (substream->stream) {
	case SNDRV_PCM_STREAM_PLAYBACK:
		i = 0;
		shift = 4;
		break;
	case SNDRV_PCM_STREAM_CAPTURE:
		i = 2;
		shift = 0;
		break;
	default:
		return -EINVAL;
	}

	/* Only need to set MCLK/LRCLK ratio if we're master */
	if (snd_soc_read(codec, WM8770_MSTRCTRL) & 0x100) {
		for (; i < ARRAY_SIZE(mclk_ratios); ++i) {
			ratio = wm8770->sysclk / params_rate(params);
			if (ratio == mclk_ratios[i])
				break;
		}

		if (i == ARRAY_SIZE(mclk_ratios)) {
			dev_err(codec->dev,
				"Unable to configure MCLK ratio %d/%d\n",
				wm8770->sysclk, params_rate(params));
			return -EINVAL;
		}

		dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]);

		snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x7 << shift,
				    i << shift);
	}

	snd_soc_update_bits(codec, WM8770_IFACECTRL, 0x30, iface);

	return 0;
}
示例#20
0
static int smdk_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 *cpu_dai = rtd->cpu_dai;
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	unsigned int pll_out;
	int bfs, rfs, ret;

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_U8:
	case SNDRV_PCM_FORMAT_S8:
		bfs = 16;
		break;
	case SNDRV_PCM_FORMAT_U16_LE:
	case SNDRV_PCM_FORMAT_S16_LE:
		bfs = 32;
		break;
	default:
		return -EINVAL;
	}

	/* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
	 * This criterion can't be met if we request PLL output
	 * as {8000x256, 64000x256, 11025x256}Hz.
	 * As a wayout, we rather change rfs to a minimum value that
	 * results in (params_rate(params) * rfs), and itself, acceptable
	 * to both - the CODEC and the CPU.
	 */
	switch (params_rate(params)) {
	case 16000:
	case 22050:
	case 32000:
	case 44100:
	case 48000:
	case 88200:
	case 96000:
		rfs = 256;
		break;
	case 64000:
		rfs = 384;
		break;
	case 8000:
	case 11025:
		rfs = 512;
		break;
	default:
		return -EINVAL;
	}
	pll_out = params_rate(params) * rfs;

	/* Set the Codec DAI configuration */
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
					 | SND_SOC_DAIFMT_NB_NF
					 | SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* Set the AP DAI configuration */
	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
					 | SND_SOC_DAIFMT_NB_NF
					 | SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* Set WM8580 to drive MCLK from its PLLA */
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
					WM8580_CLKSRC_PLLA);
	if (ret < 0)
		return ret;

	ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
					SMDK_WM8580_FREQ, pll_out);
	if (ret < 0)
		return ret;

	ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
				     pll_out, SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

	return 0;
}
static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
				    struct snd_soc_dai *dai, int stream)
{
	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
	u8 pgd_la, inf_la;
	u16 *slave_port_mapping;

	memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
		sizeof(dai_data->port_config.slimbus.slave_port_mapping));

	dai_data->channels = params_channels(params);

	slave_port_mapping = dai_data->port_config.slimbus.slave_port_mapping;

	switch (dai_data->channels) {
	case 4:
		if (dai->id == SLIMBUS_0_TX) {
			slave_port_mapping[0] = 7;
			slave_port_mapping[1] = 8;
			slave_port_mapping[2] = 9;
			slave_port_mapping[3] = 10;
		} else {
			return -EINVAL;
		}
		break;
	case 3:
		if (dai->id == SLIMBUS_0_TX) {
			slave_port_mapping[0] = 7;
			slave_port_mapping[1] = 8;
			slave_port_mapping[2] = 9;
		} else {
			return -EINVAL;
		}
		break;
	case 2:
		if (dai->id == SLIMBUS_0_RX) {
			slave_port_mapping[0] = 1;
			slave_port_mapping[1] = 2;
		} else {
			slave_port_mapping[0] = 7;
			slave_port_mapping[1] = 8;
		}
		break;
	case 1:
		if (dai->id == SLIMBUS_0_RX)
			slave_port_mapping[0] = 1;
		else
			slave_port_mapping[0] = 7;
		break;
	default:
		return -EINVAL;
		break;
	}
	dai_data->rate = params_rate(params);
	tabla_get_logical_addresses(&pgd_la, &inf_la);

	dai_data->port_config.slimbus.slimbus_dev_id =  AFE_SLIMBUS_DEVICE_1;
	dai_data->port_config.slimbus.slave_dev_pgd_la = pgd_la;
	dai_data->port_config.slimbus.slave_dev_intfdev_la = inf_la;
	/* Q6 only supports 16 as now */
	dai_data->port_config.slimbus.bit_width = 16;
	dai_data->port_config.slimbus.data_format = 0;
	dai_data->port_config.slimbus.num_channels = dai_data->channels;
	dai_data->port_config.slimbus.reserved = 0;

	dev_dbg(dai->dev, "slimbus_dev_id  %hu  slave_dev_pgd_la 0x%hx\n"
		"slave_dev_intfdev_la 0x%hx   bit_width %hu   data_format %hu\n"
		"num_channel %hu  slave_port_mapping[0]  %hu\n"
		"slave_port_mapping[1]  %hu slave_port_mapping[2]  %hu\n"
		"sample_rate %d\n",
		dai_data->port_config.slimbus.slimbus_dev_id,
		dai_data->port_config.slimbus.slave_dev_pgd_la,
		dai_data->port_config.slimbus.slave_dev_intfdev_la,
		dai_data->port_config.slimbus.bit_width,
		dai_data->port_config.slimbus.data_format,
		dai_data->port_config.slimbus.num_channels,
		dai_data->port_config.slimbus.slave_port_mapping[0],
		dai_data->port_config.slimbus.slave_port_mapping[1],
		dai_data->port_config.slimbus.slave_port_mapping[2],
		dai_data->rate);

	return 0;
}
static int es705_i2s_hw_params(struct snd_pcm_substream *substream,
			       struct snd_pcm_hw_params *params,
			       struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	/* struct es705_priv *es705 = snd_soc_codec_get_drvdata(codec); */
	int bits_per_sample = 0;
	int rc = 0;

	dev_dbg(codec->dev, "%s(): dai->name = %s, dai->id = %d\n", __func__,
		dai->name, dai->id);
	switch (dai->id) {
	case 0:
		dev_dbg(codec->dev, "%s(): ES705_PORTA_PARAM_ID\n", __func__);
		break;
	case 1:
		dev_dbg(codec->dev, "%s(): ES705_PORTB_PARAM_ID\n", __func__);
		break;
	default:
		dev_dbg(codec->dev, "%s(): unknown port\n", __func__);
		return -EINVAL;
	}

	dev_dbg(codec->dev, "%s(): params_channels(params) = %d\n", __func__,
		params_channels(params));
	switch (params_channels(params)) {
	case 1:
		dev_dbg(codec->dev, "%s(): 1 channel\n", __func__);
		break;
	case 2:
		dev_dbg(codec->dev, "%s(): 2 channels\n", __func__);
		break;
	case 4:
		dev_dbg(codec->dev, "%s(): 4 channels\n", __func__);
		break;
	default:
		dev_dbg(codec->dev, "%s(): unsupported number of channels\n",
			__func__);
		return -EINVAL;
	}

	dev_dbg(codec->dev, "%s(): params_rate(params) = %d\n", __func__,
		params_rate(params));
	switch (params_rate(params)) {
	case 8000:
		dev_dbg(codec->dev, "%s(): 8000Hz\n", __func__);
		break;
	case 11025:
		dev_dbg(codec->dev, "%s(): 11025\n", __func__);
		break;
	case 16000:
		dev_dbg(codec->dev, "%s(): 16000\n", __func__);
		break;
	case 22050:
		dev_dbg(codec->dev, "%s(): 22050\n", __func__);
		break;
	case 32000:
		dev_dbg(codec->dev, "%s(): 32000\n", __func__);
		break;
	case 48000:
		dev_dbg(codec->dev, "%s(): 48000\n", __func__);
		break;
	case 96000:
		dev_dbg(codec->dev, "%s(): 96000\n", __func__);
		break;
	case 192000:
		dev_dbg(codec->dev, "%s(): 96000\n", __func__);
		break;
	default:
		dev_dbg(codec->dev, "%s(): unsupported rate = %d\n", __func__,
			params_rate(params));
		return -EINVAL;
	}

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		dev_dbg(codec->dev, "%s(): S16_LE\n", __func__);
		bits_per_sample = 16;
		break;
	case SNDRV_PCM_FORMAT_S16_BE:
		dev_dbg(codec->dev, "%s(): S16_BE\n", __func__);
		bits_per_sample = 16;
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		dev_dbg(codec->dev, "%s(): S20_3LE\n", __func__);
		bits_per_sample = 20;
		break;
	case SNDRV_PCM_FORMAT_S20_3BE:
		dev_dbg(codec->dev, "%s(): S20_3BE\n", __func__);
		bits_per_sample = 20;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		dev_dbg(codec->dev, "%s(): S24_LE\n", __func__);
		bits_per_sample = 24;
		break;
	case SNDRV_PCM_FORMAT_S24_BE:
		dev_dbg(codec->dev, "%s(): S24_BE\n", __func__);
		bits_per_sample = 24;
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		dev_dbg(codec->dev, "%s(): S32_LE\n", __func__);
		bits_per_sample = 32;
		break;
	case SNDRV_PCM_FORMAT_S32_BE:
		dev_dbg(codec->dev, "%s(): S32_BE\n", __func__);
		bits_per_sample = 32;
		break;
	default:
		dev_dbg(codec->dev, "%s(): unknown format\n", __func__);
		return -EINVAL;
	}
	if (rc) {
		dev_dbg(codec->dev, "%s(): snd_soc_update_bits() failed\n",
			__func__);
		return rc;
	}

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		dev_dbg(codec->dev, "%s(): PLAYBACK\n", __func__);
	else
		dev_dbg(codec->dev, "%s(): CAPTURE\n", __func__);

	return rc;
}
示例#23
0
/*
 * Should only be called when port is inactive.
 * although can be called multiple times by upper layers.
 */
static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params,
			     struct snd_soc_dai *cpu_dai)
{
	struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
	u32 scr, stat;
	int ret;

	/* mclk should already be set */
	if (!saif->mclk && saif->mclk_in_use) {
		dev_err(cpu_dai->dev, "set mclk first\n");
		return -EINVAL;
	}

	stat = __raw_readl(saif->base + SAIF_STAT);
	if (stat & BM_SAIF_STAT_BUSY) {
		dev_err(cpu_dai->dev, "error: busy\n");
		return -EBUSY;
	}

	/*
	 * Set saif clk based on sample rate.
	 * If mclk is used, we also set mclk, if not, saif->mclk is
	 * default 0, means not used.
	 */
	ret = mxs_saif_set_clk(saif, saif->mclk, params_rate(params));
	if (ret) {
		dev_err(cpu_dai->dev, "unable to get proper clk\n");
		return ret;
	}

	scr = __raw_readl(saif->base + SAIF_CTRL);

	scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
	scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
		scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
		break;
	default:
		return -EINVAL;
	}

	/* Tx/Rx config */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		/* enable TX mode */
		scr &= ~BM_SAIF_CTRL_READ_MODE;
	} else {
		/* enable RX mode */
		scr |= BM_SAIF_CTRL_READ_MODE;
	}

	__raw_writel(scr, saif->base + SAIF_CTRL);
	return 0;
}
示例#24
0
static int tegra_bt_sco_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 *cpu_dai = rtd->cpu_dai;
	struct snd_soc_card *card = rtd->card;
	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
	int srate, mclk, min_mclk;
	int err;

	srate = params_rate(params);
	switch (srate) {
	case 11025:
	case 22050:
	case 44100:
	case 88200:
		mclk = 11289600;
		break;
	case 8000:
	case 16000:
	case 32000:
	case 48000:
	case 64000:
	case 96000:
		mclk = 12288000;
		break;
	default:
		return -EINVAL;
	}
	min_mclk = 64 * srate;

	err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
	if (err < 0) {
		if (!(machine->util_data.set_mclk % min_mclk))
			mclk = machine->util_data.set_mclk;
		else {
			dev_err(card->dev, "Can't configure clocks\n");
			return err;
		}
	}

	tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);

	err = snd_soc_dai_set_fmt(cpu_dai,
					SND_SOC_DAIFMT_DSP_A |
					SND_SOC_DAIFMT_NB_NF |
					SND_SOC_DAIFMT_CBS_CFS);
	if (err < 0) {
		dev_err(card->dev, "cpu_dai fmt not set\n");
		return err;
	}

#ifdef CONFIG_ARCH_TEGRA_2x_SOC
	err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC2,
					TEGRA20_DAS_DAP_ID_4);
	if (err < 0) {
		dev_err(card->dev, "failed to set dac-dap path\n");
		return err;
	}

	err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_4,
					TEGRA20_DAS_DAP_SEL_DAC2);
	if (err < 0) {
		dev_err(card->dev, "failed to set dac-dap path\n");
		return err;
	}
#endif
	return 0;
}
示例#25
0
static int rk29_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	unsigned int pll_out = 0;
	int ret;

	DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
	/*by Vincent Hsiung for EQ Vol Change*/
	#define HW_PARAMS_FLAG_EQVOL_ON 0x21
	#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
	if (codec_dai->driver->ops->hw_params && ((params->flags == HW_PARAMS_FLAG_EQVOL_ON) || (params->flags == HW_PARAMS_FLAG_EQVOL_OFF)))
	{
		ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
		DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
	} else {
                
		/* set codec DAI configuration */
		#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 

		ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
		                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
		#endif	
		#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 

		ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
		                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); 
		#endif
		if (ret < 0)
			return ret; 

		/* set cpu DAI configuration */
		#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
		                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
		#endif	
		#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
		ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
		                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);	
		#endif		
		if (ret < 0)
			return ret;
	}

	switch(params_rate(params)) {
		case 8000:
		case 16000:
		case 24000:
		case 32000:
		case 48000:
			pll_out = 12288000;
			break;
		case 11025:
		case 22050:
		case 44100:
			pll_out = 11289600;
			break;
		default:
			DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));
			return -EINVAL;
			break;
	}

	DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));

	/*Set the system clk for codec*/
	ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
	if (ret < 0)
	{
		DBG("rk29_hw_params_rt3261:failed to set the sysclk for codec side\n"); 
		return ret;
	}

	snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);

	DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));
 
	return 0;
}
示例#26
0
static int tegra_wm8903_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct snd_soc_codec *codec = rtd->codec;
	struct snd_soc_card *card = codec->card;
	struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
	int srate, mclk, i2s_daifmt;
	int err;
	struct clk *clk_m;
	int rate;

	srate = params_rate(params);
	switch (srate) {
	case 64000:
	case 88200:
	case 96000:
		mclk = 128 * srate;
		break;
	default:
		mclk = 256 * srate;
		break;
	}



	clk_m = clk_get_sys(NULL, "clk_m");
	if (IS_ERR(clk_m)) {
		dev_err(card->dev, "Can't retrieve clk clk_m\n");
		err = PTR_ERR(clk_m);
		return err;
	}
	rate = clk_get_rate(clk_m);
	printk("extern1 rate=%d\n",rate);

#if TEGRA30_I2S_MASTER_PLAYBACK
	/* FIXME: Codec only requires >= 3MHz if OSR==0 */
	while (mclk < 6000000)
		mclk *= 2;

	i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
		     SND_SOC_DAIFMT_CBS_CFS;
#else
	mclk = rate;

	i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
		     SND_SOC_DAIFMT_CBM_CFM;
#endif


	err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
	if (err < 0) {
		if (!(machine->util_data.set_mclk % mclk))
			mclk = machine->util_data.set_mclk;
		else {
			dev_err(card->dev, "Can't configure clocks\n");
			return err;
		}
	}

	tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);

	/* Use DSP mode for mono on Tegra20 */
	if ((params_channels(params) != 2) &&
	    (machine_is_ventana() || machine_is_harmony() ||
	    machine_is_kaen() || machine_is_aebl() ||
	    machine_is_eva()))
		i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
	else
		i2s_daifmt |= SND_SOC_DAIFMT_I2S;

	err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
	if (err < 0) {
		dev_err(card->dev, "codec_dai fmt not set\n");
		return err;
	}

	err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt);
	if (err < 0) {
		dev_err(card->dev, "cpu_dai fmt not set\n");
		return err;
	}

	err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
					SND_SOC_CLOCK_IN);
	if (err < 0) {
		dev_err(card->dev, "codec_dai clock not set\n");
		return err;
	}

#ifdef CONFIG_ARCH_TEGRA_2x_SOC
	err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC1,
					TEGRA20_DAS_DAP_ID_1);
	if (err < 0) {
		dev_err(card->dev, "failed to set dap-dac path\n");
		return err;
	}

	err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1,
					TEGRA20_DAS_DAP_SEL_DAC1);
	if (err < 0) {
		dev_err(card->dev, "failed to set dac-dap path\n");
		return err;
	}
#endif
	return 0;
}
示例#27
0
static int max9867_dai_hw_params(struct snd_pcm_substream *substream,
		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
	unsigned int ni_h, ni_l;
	int value;

	value = get_ni_value(max9867->sysclk, params_rate(params));
	if (value < 0)
		return value;

	ni_h = (0xFF00 & value) >> 8;
	ni_l = 0x00FF & value;
	/* set up the ni value */
	regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
		MAX9867_NI_HIGH_MASK, ni_h);
	regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
		MAX9867_NI_LOW_MASK, ni_l);
	if (!max9867->master) {
		/*
		 * digital pll locks on to any externally supplied LRCLK signal
		 * and also enable rapid lock mode.
		 */
		regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKLOW,
			MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK);
		regmap_update_bits(max9867->regmap, MAX9867_AUDIOCLKHIGH,
			MAX9867_PLL, MAX9867_PLL);
	} else {
		unsigned long int bclk_rate, pclk_bclk_ratio;
		int bclk_value;

		bclk_rate = params_rate(params) * 2 * params_width(params);
		pclk_bclk_ratio = max9867->pclk/bclk_rate;
		switch (params_width(params)) {
		case 8:
		case 16:
			switch (pclk_bclk_ratio) {
			case 2:
				bclk_value = MAX9867_IFC1B_PCLK_2;
				break;
			case 4:
				bclk_value = MAX9867_IFC1B_PCLK_4;
				break;
			case 8:
				bclk_value = MAX9867_IFC1B_PCLK_8;
				break;
			case 16:
				bclk_value = MAX9867_IFC1B_PCLK_16;
				break;
			default:
				dev_err(codec->dev,
					"unsupported sampling rate\n");
				return -EINVAL;
			}
			break;
		case 24:
			bclk_value = MAX9867_IFC1B_24BIT;
			break;
		case 32:
			bclk_value = MAX9867_IFC1B_32BIT;
			break;
		default:
			dev_err(codec->dev, "unsupported sampling rate\n");
			return -EINVAL;
		}
		regmap_update_bits(max9867->regmap, MAX9867_IFC1B,
			MAX9867_IFC1B_BCLK_MASK, bclk_value);
	}
	return 0;
}
示例#28
0
static int neo1973_hifi_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	unsigned int pll_out = 0, bclk = 0;
	int ret = 0;
	unsigned long iis_clkrate;

	iis_clkrate = s3c24xx_i2s_get_clockrate();

	switch (params_rate(params)) {
	case 8000:
	case 16000:
		pll_out = 12288000;
		break;
	case 48000:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 12288000;
		break;
	case 96000:
		bclk = WM8753_BCLK_DIV_2;
		pll_out = 12288000;
		break;
	case 11025:
		bclk = WM8753_BCLK_DIV_16;
		pll_out = 11289600;
		break;
	case 22050:
		bclk = WM8753_BCLK_DIV_8;
		pll_out = 11289600;
		break;
	case 44100:
		bclk = WM8753_BCLK_DIV_4;
		pll_out = 11289600;
		break;
	case 88200:
		bclk = WM8753_BCLK_DIV_2;
		pll_out = 11289600;
		break;
	}

	/* set codec DAI configuration */
	ret = snd_soc_dai_set_fmt(codec_dai,
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* set cpu DAI configuration */
	ret = snd_soc_dai_set_fmt(cpu_dai,
		SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
		SND_SOC_DAIFMT_CBM_CFM);
	if (ret < 0)
		return ret;

	/* set the codec system clock for DAC and ADC */
	ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
		SND_SOC_CLOCK_IN);
	if (ret < 0)
		return ret;

	/* set MCLK division for sample rate */
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
		S3C2410_IISMOD_32FS);
	if (ret < 0)
		return ret;

	/* set codec BCLK division for sample rate */
	ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
	if (ret < 0)
		return ret;

	/* set prescaler division for sample rate */
	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
		S3C24XX_PRESCALE(4, 4));
	if (ret < 0)
		return ret;

	/* codec PLL input is PCLK/4 */
	ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
		iis_clkrate / 4, pll_out);
	if (ret < 0)
		return ret;

	return 0;
}
示例#29
0
static int rk29_aif1_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 *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	unsigned int pll_out = 0; 
	int div_bclk,div_mclk;
	int ret;
	struct clk	*general_pll;


	DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);

	/* set codec DAI configuration */
#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
	DBG("Set codec_dai slave\n");
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
	 	SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
#endif	
#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 			   
	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
	DBG("Set codec_dai master\n");
#endif
	if (ret < 0)
		return ret; 

	/* set cpu DAI configuration */
#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
	DBG("Set cpu_dai master\n");
	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
#endif	
#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)  
	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);	
	DBG("Set cpu_dai slave\n"); 
#endif		
	if (ret < 0)
		return ret;

	switch(params_rate(params)) {
		case 8000:
		case 16000:
		case 24000:
		case 32000:
		case 48000:
			pll_out = 12288000;
			break;
		case 11025:
		case 22050:
		case 44100:
			pll_out = 11289600;
			break;
		default:
			DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
			return -EINVAL;
	}

//	DBG("Enter:%s, %d, rate=%d,pll_out = %d\n",__FUNCTION__,__LINE__,params_rate(params),pll_out);	
	general_pll=clk_get(NULL, "general_pll");
	if(clk_get_rate(general_pll)>260000000)
	{
		div_bclk=(pll_out/4)/params_rate(params)-1;
		div_mclk=3;
	}
	else if(clk_get_rate(general_pll)>130000000)
	{
		div_bclk=(pll_out/2)/params_rate(params)-1;
		div_mclk=1;
	}
	else
	{//96M
		pll_out=pll_out/4;
		div_bclk=(pll_out)/params_rate(params)-1;
		div_mclk=0;
	}

	DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
	if(ret < 0)
	{
		DBG("rk29_hw_params_wm8994:failed to set the cpu sysclk for codec side\n"); 
		return ret;
	}
	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
	snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
	DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));

	if(div_mclk== 3)
	{//MCLK == 11289600 or 12288000
		ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, pll_out, 0);
		if (ret < 0) {
			DBG("rk29_hw_params_wm8994:failed to set the sysclk for codec side\n"); 
			return ret;
		}
	}
	else
	{
		/* set the codec FLL */
		ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, pll_out,
				params_rate(params) * 256);
		if (ret < 0)
		{
			printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
			return ret;
		}
		/* set the codec system clock */
		ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
				params_rate(params) * 256, SND_SOC_CLOCK_IN);
		if (ret < 0)
		{
			printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
			return ret;
		}
	}

	return 0;
}
示例#30
0
static int adau1977_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec);
	unsigned int rate = params_rate(params);
	unsigned int slot_width;
	unsigned int ctrl0, ctrl0_mask;
	unsigned int ctrl1;
	int mcs, fs;
	int ret;

	fs = adau1977_lookup_fs(rate);
	if (fs < 0)
		return fs;

	if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) {
		mcs = adau1977_lookup_mcs(adau1977, rate, fs);
		if (mcs < 0)
			return mcs;
	} else {
		mcs = 0;
	}

	ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK;
	ctrl0 = fs;

	if (adau1977->right_j) {
		switch (params_width(params)) {
		case 16:
			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT;
			break;
		case 24:
			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
			break;
		default:
			return -EINVAL;
		}
		ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK;
	}

	if (adau1977->master) {
		switch (params_width(params)) {
		case 16:
			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT;
			slot_width = 16;
			break;
		case 24:
		case 32:
			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT;
			slot_width = 32;
			break;
		default:
			return -EINVAL;
		}

		/* In TDM mode there is a fixed slot width */
		if (adau1977->slot_width)
			slot_width = adau1977->slot_width;

		if (slot_width == 16)
			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16;
		else
			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32;

		ret = regmap_update_bits(adau1977->regmap,
			ADAU1977_REG_SAI_CTRL1,
			ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK |
			ADAU1977_SAI_CTRL1_BCLKRATE_MASK,
			ctrl1);
		if (ret < 0)
			return ret;
	}

	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
				ctrl0_mask, ctrl0);
	if (ret < 0)
		return ret;

	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
				ADAU1977_PLL_MCS_MASK, mcs);
}