Ejemplo n.º 1
0
static int wm8961_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 wm8961_priv *wm8961 = snd_soc_codec_get_drvdata(codec);
	int i, best, target, fs;
	u16 reg;

	fs = params_rate(params);

	if (!wm8961->sysclk) {
		dev_err(codec->dev, "MCLK has not been specified\n");
		return -EINVAL;
	}

	/* Find the closest sample rate for the filters */
	best = 0;
	for (i = 0; i < ARRAY_SIZE(wm8961_srate); i++) {
		if (abs(wm8961_srate[i].rate - fs) <
		    abs(wm8961_srate[best].rate - fs))
			best = i;
	}
	reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_3);
	reg &= ~WM8961_SAMPLE_RATE_MASK;
	reg |= wm8961_srate[best].val;
	snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg);
	dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n",
		wm8961_srate[best].rate, fs);

	/* Select a CLK_SYS/fs ratio equal to or higher than required */
	target = wm8961->sysclk / fs;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && target < 64) {
		dev_err(codec->dev,
			"SYSCLK must be at least 64*fs for DAC\n");
		return -EINVAL;
	}
	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && target < 256) {
		dev_err(codec->dev,
			"SYSCLK must be at least 256*fs for ADC\n");
		return -EINVAL;
	}

	for (i = 0; i < ARRAY_SIZE(wm8961_clk_sys_ratio); i++) {
		if (wm8961_clk_sys_ratio[i].ratio >= target)
			break;
	}
	if (i == ARRAY_SIZE(wm8961_clk_sys_ratio)) {
		dev_err(codec->dev, "Unable to generate CLK_SYS_RATE\n");
		return -EINVAL;
	}
	dev_dbg(codec->dev, "Selected CLK_SYS_RATE of %d for %d/%d=%d\n",
		wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs,
		wm8961->sysclk / fs);

	reg = snd_soc_read(codec, WM8961_CLOCKING_4);
	reg &= ~WM8961_CLK_SYS_RATE_MASK;
	reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT;
	snd_soc_write(codec, WM8961_CLOCKING_4, reg);

	reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);
	reg &= ~WM8961_WL_MASK;
	switch (params_width(params)) {
	case 16:
		break;
	case 20:
		reg |= 1 << WM8961_WL_SHIFT;
		break;
	case 24:
		reg |= 2 << WM8961_WL_SHIFT;
		break;
	case 32:
		reg |= 3 << WM8961_WL_SHIFT;
		break;
	default:
		return -EINVAL;
	}
	snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, reg);

	/* Sloping stop-band filter is recommended for <= 24kHz */
	reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2);
	if (fs <= 24000)
		reg |= WM8961_DACSLOPE;
	else
		reg &= ~WM8961_DACSLOPE;
	snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);

	return 0;
}
Ejemplo n.º 2
0
/**
 * sta32x_hw_params - program the STA32X 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.
 */
static int sta32x_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 sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
	unsigned int rate;
	int i, mcs = -1, ir = -1;
	u8 confa, confb;

	rate = params_rate(params);
	pr_debug("rate: %u\n", rate);
	for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
		if (interpolation_ratios[i].fs == rate) {
			ir = interpolation_ratios[i].ir;
			break;
		}
	if (ir < 0)
		return -EINVAL;
	for (i = 0; mclk_ratios[ir][i].ratio; i++)
		if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
			mcs = mclk_ratios[ir][i].mcs;
			break;
		}
	if (mcs < 0)
		return -EINVAL;

	confa = snd_soc_read(codec, STA32X_CONFA);
	confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK);
	confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT);

	confb = snd_soc_read(codec, STA32X_CONFB);
	confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB);
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S24_LE:
	case SNDRV_PCM_FORMAT_S24_BE:
	case SNDRV_PCM_FORMAT_S24_3LE:
	case SNDRV_PCM_FORMAT_S24_3BE:
		pr_debug("24bit\n");
		/* fall through */
	case SNDRV_PCM_FORMAT_S32_LE:
	case SNDRV_PCM_FORMAT_S32_BE:
		pr_debug("24bit or 32bit\n");
		switch (sta32x->format) {
		case SND_SOC_DAIFMT_I2S:
			confb |= 0x0;
			break;
		case SND_SOC_DAIFMT_LEFT_J:
			confb |= 0x1;
			break;
		case SND_SOC_DAIFMT_RIGHT_J:
			confb |= 0x2;
			break;
		}

		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
	case SNDRV_PCM_FORMAT_S20_3BE:
		pr_debug("20bit\n");
		switch (sta32x->format) {
		case SND_SOC_DAIFMT_I2S:
			confb |= 0x4;
			break;
		case SND_SOC_DAIFMT_LEFT_J:
			confb |= 0x5;
			break;
		case SND_SOC_DAIFMT_RIGHT_J:
			confb |= 0x6;
			break;
		}

		break;
	case SNDRV_PCM_FORMAT_S18_3LE:
	case SNDRV_PCM_FORMAT_S18_3BE:
		pr_debug("18bit\n");
		switch (sta32x->format) {
		case SND_SOC_DAIFMT_I2S:
			confb |= 0x8;
			break;
		case SND_SOC_DAIFMT_LEFT_J:
			confb |= 0x9;
			break;
		case SND_SOC_DAIFMT_RIGHT_J:
			confb |= 0xa;
			break;
		}

		break;
	case SNDRV_PCM_FORMAT_S16_LE:
	case SNDRV_PCM_FORMAT_S16_BE:
		pr_debug("16bit\n");
		switch (sta32x->format) {
		case SND_SOC_DAIFMT_I2S:
			confb |= 0x0;
			break;
		case SND_SOC_DAIFMT_LEFT_J:
			confb |= 0xd;
			break;
		case SND_SOC_DAIFMT_RIGHT_J:
			confb |= 0xe;
			break;
		}

		break;
	default:
		return -EINVAL;
	}

	snd_soc_write(codec, STA32X_CONFA, confa);
	snd_soc_write(codec, STA32X_CONFB, confb);
	return 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;
	int err;
#if 0
	struct snd_soc_codec *codec = codec_dai->codec;
	int CtrlReg = 0;
	int VolumeCtrlReg = 0;
	int SidetoneCtrlReg = 0;
	int SideToneAtenuation = 0;
#endif

	err = snd_soc_dai_set_fmt(codec_dai,
					SND_SOC_DAIFMT_I2S | \
					SND_SOC_DAIFMT_NB_NF | \
					SND_SOC_DAIFMT_CBS_CFS);
	if (err < 0) {
		printk(KERN_ERR "codec_dai fmt not set \n");
		return err;
	}

	err = snd_soc_dai_set_fmt(cpu_dai,
					SND_SOC_DAIFMT_I2S | \
					SND_SOC_DAIFMT_NB_NF | \
					SND_SOC_DAIFMT_CBS_CFS);
	if (err < 0) {
		printk(KERN_ERR "cpu_dai fmt not set \n");
		return err;
	}

	err = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1,
				I2S1_CLK, SND_SOC_CLOCK_IN);
	if (err < 0) {
		printk(KERN_ERR "codec_dai clock not set\n");
		return err;
	}

	err = snd_soc_dai_set_sysclk(cpu_dai, 0, I2S1_CLK, SND_SOC_CLOCK_IN);
	if (err < 0) {
		printk(KERN_ERR "cpu_dai clock not set\n");
		return err;
	}

#if 0
	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
		snd_soc_write(codec, WM8903_ANALOGUE_LEFT_INPUT_0, 0X7);
		snd_soc_write(codec, WM8903_ANALOGUE_RIGHT_INPUT_0, 0X7);
		// Mic Bias enable
		CtrlReg = (0x1<<B00_MICBIAS_ENA) | (0x1<<B01_MICDET_ENA);
		snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, CtrlReg);
		// Enable DRC
		CtrlReg = snd_soc_read(codec, WM8903_DRC_0);
		CtrlReg |= (1<<B15_DRC_ENA);
		snd_soc_write(codec, WM8903_DRC_0, CtrlReg);
		// Single Ended Mic
		CtrlReg = (0x0<<B06_IN_CM_ENA) |
			(0x0<<B00_MODE) | (0x0<<B04_IP_SEL_N)
					| (0x1<<B02_IP_SEL_P);
		VolumeCtrlReg = (0x1C << B00_IN_VOL);
		// Mic Setting
		snd_soc_write(codec, WM8903_ANALOGUE_LEFT_INPUT_1, CtrlReg);
		snd_soc_write(codec, WM8903_ANALOGUE_RIGHT_INPUT_1, CtrlReg);
		// voulme for single ended mic
		snd_soc_write(codec, WM8903_ANALOGUE_LEFT_INPUT_0,
				VolumeCtrlReg);
		snd_soc_write(codec, WM8903_ANALOGUE_RIGHT_INPUT_0,
				VolumeCtrlReg);
		// replicate mic setting on both channels
		CtrlReg = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_0);
		CtrlReg  = SET_REG_VAL(CtrlReg, 0x1, B06_AIF_ADCR, 0x0);
		CtrlReg  = SET_REG_VAL(CtrlReg, 0x1, B06_AIF_ADCL, 0x0);
		snd_soc_write(codec, WM8903_AUDIO_INTERFACE_0, CtrlReg);
		// Enable analog inputs
		CtrlReg = (0x1<<B01_INL_ENA) | (0x1<<B00_INR_ENA);
		snd_soc_write(codec, WM8903_POWER_MANAGEMENT_0, CtrlReg);
		// ADC Settings
		CtrlReg = snd_soc_read(codec, WM8903_ADC_DIGITAL_0);
		CtrlReg |= (0x1<<B04_ADC_HPF_ENA);
		snd_soc_write(codec, WM8903_ADC_DIGITAL_0, CtrlReg);
		SidetoneCtrlReg = 0;
		snd_soc_write(codec, R20_SIDETONE_CTRL, SidetoneCtrlReg);
		// Enable ADC
		CtrlReg = snd_soc_read(codec, WM8903_POWER_MANAGEMENT_6);
		CtrlReg |= (0x1<<B00_ADCR_ENA)|(0x1<<B01_ADCL_ENA);
		snd_soc_write(codec, WM8903_POWER_MANAGEMENT_6, CtrlReg);
		// Enable Sidetone
		SidetoneCtrlReg = (0x1<<2) | (0x2<<0);
		SideToneAtenuation = 12 ; // sidetone 0 db
		SidetoneCtrlReg |= (SideToneAtenuation<<8)
				| (SideToneAtenuation<<4);
		snd_soc_write(codec, R20_SIDETONE_CTRL, SidetoneCtrlReg);
		CtrlReg = snd_soc_read(codec, R29_DRC_1);
		CtrlReg |= 0x3; //mic volume 18 db
		snd_soc_write(codec, R29_DRC_1, CtrlReg);
	}
#endif

	return 0;
}
static int aic31xx_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params,
			     struct snd_soc_dai *tmp)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_codec *codec = rtd->codec;
	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
	u8 data = 0;
	int i;

	dev_dbg(codec->dev, "## %s: format %d rate %d\n",
		__func__, params_format(params), params_rate(params));

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		data = (AIC31XX_WORD_LEN_20BITS <<
			AIC31XX_IFACE1_DATALEN_SHIFT);
		break;
	case SNDRV_PCM_FORMAT_S24_3LE:
		data = (AIC31XX_WORD_LEN_24BITS <<
			AIC31XX_IFACE1_DATALEN_SHIFT);
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		data = (AIC31XX_WORD_LEN_32BITS <<
			AIC31XX_IFACE1_DATALEN_SHIFT);
	break;
	}

	snd_soc_update_bits(codec, AIC31XX_IFACE1,
			    AIC31XX_IFACE1_DATALEN_MASK,
			    data);

	/* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */
	snd_soc_update_bits(codec, AIC31XX_CLKMUX,
			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
	snd_soc_update_bits(codec, AIC31XX_IFACE2, AIC31XX_BDIVCLK_MASK,
			    AIC31XX_DACMOD2BCLK);

	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
		if ((aic31xx_divs[i].rate == params_rate(params))
		    && (aic31xx_divs[i].mclk == aic31xx->sysclk)) {
			break;
		}
	}

	if (i == ARRAY_SIZE(aic31xx_divs)) {
		dev_err(codec->dev, "%s: Sampling rate %u not supported\n",
			__func__, params_rate(params));
		return -EINVAL;
	}

	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
			    (aic31xx_divs[i].p_val << 4) | 0x01);
	snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);

	snd_soc_write(codec, AIC31XX_PLLDMSB, (aic31xx_divs[i].pll_d >> 8));
	snd_soc_write(codec, AIC31XX_PLLDLSB,
		      (aic31xx_divs[i].pll_d & 0xff));

	/* NDAC divider value */
	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].ndac);

	/* MDAC divider value */
	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].mdac);

	/* DOSR MSB & LSB values */
	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
	snd_soc_write(codec, AIC31XX_DOSRLSB,
		      (aic31xx_divs[i].dosr & 0xff));
	/* NADC divider value */
	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].nadc);
	/* MADC divider value */
	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].madc);
	/* AOSR value */
	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
	/* BCLK N divider */
	snd_soc_update_bits(codec, AIC31XX_BCLKN, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].bclk_n);

	return 0;
}
Ejemplo n.º 5
0
static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
			   struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_codec *codec = w->codec;
	u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		/* Clamp headphone outputs */
		hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
			WM8900_REG_HPCTL1_HP_CLAMP_OP;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
		break;

	case SND_SOC_DAPM_POST_PMU:
		/* Enable the input stage */
		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_IP;
		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
			WM8900_REG_HPCTL1_HP_SHORT2 |
			WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);

		msleep(400);

		/* Enable the output stage */
		hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
		hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);

		/* Remove the shorts */
		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
		hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
		break;

	case SND_SOC_DAPM_PRE_PMD:
		/* Short the output */
		hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);

		/* Disable the output stage */
		hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);

		/* Clamp the outputs and power down input */
		hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
			WM8900_REG_HPCTL1_HP_CLAMP_OP;
		hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
		snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
		break;

	case SND_SOC_DAPM_POST_PMD:
		/* Disable everything */
		snd_soc_write(codec, WM8900_REG_HPCTL1, 0);
		break;

	default:
		BUG();
	}

	return 0;
}
static int aic32x4_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 aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
	u8 data;
	int i;

	i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
	if (i < 0) {
		printk(KERN_ERR "aic32x4: sampling rate not supported\n");
		return i;
	}

	
	snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_PLLCLKIN);
	snd_soc_write(codec, AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK);

	
	data = snd_soc_read(codec, AIC32X4_PLLPR);
	data &= ~(7 << 4);
	snd_soc_write(codec, AIC32X4_PLLPR,
		      (data | (aic32x4_divs[i].p_val << 4) | 0x01));

	snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);

	snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
	snd_soc_write(codec, AIC32X4_PLLDLSB,
		      (aic32x4_divs[i].pll_d & 0xff));

	
	data = snd_soc_read(codec, AIC32X4_NDAC);
	data &= ~(0x7f);
	snd_soc_write(codec, AIC32X4_NDAC, data | aic32x4_divs[i].ndac);

	
	data = snd_soc_read(codec, AIC32X4_MDAC);
	data &= ~(0x7f);
	snd_soc_write(codec, AIC32X4_MDAC, data | aic32x4_divs[i].mdac);

	
	snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
	snd_soc_write(codec, AIC32X4_DOSRLSB,
		      (aic32x4_divs[i].dosr & 0xff));

	
	data = snd_soc_read(codec, AIC32X4_NADC);
	data &= ~(0x7f);
	snd_soc_write(codec, AIC32X4_NADC, data | aic32x4_divs[i].nadc);

	
	data = snd_soc_read(codec, AIC32X4_MADC);
	data &= ~(0x7f);
	snd_soc_write(codec, AIC32X4_MADC, data | aic32x4_divs[i].madc);

	
	snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr);

	
	data = snd_soc_read(codec, AIC32X4_BCLKN);
	data &= ~(0x7f);
	snd_soc_write(codec, AIC32X4_BCLKN, data | aic32x4_divs[i].blck_N);

	data = snd_soc_read(codec, AIC32X4_IFACE1);
	data = data & ~(3 << 4);
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		data |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_DOSRMSB_SHIFT);
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		data |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_DOSRMSB_SHIFT);
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		data |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_DOSRMSB_SHIFT);
		break;
	}
	snd_soc_write(codec, AIC32X4_IFACE1, data);

	return 0;
}
Ejemplo n.º 7
0
static int hpdrv_ev(struct snd_soc_dapm_widget *w,
		struct snd_kcontrol *kcontrol, int event)
{
	dev_dbg(w->codec->dev, "%s called, event = %d\n", __func__, event);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		cod3022x_hp_playback_init(w->codec);
		break;

	case SND_SOC_DAPM_POST_PMU:
		snd_soc_update_bits(w->codec, COD3022X_17_PWAUTO_DA,
				PW_AUTO_DA_MASK | APW_HP_MASK,
				(0x1 << PW_AUTO_DA_SHIFT) |
				(0x1 << APW_HP_SHIFT));
		msleep(10);

		snd_soc_update_bits(w->codec, COD3022X_1C_SV_DA,
				EN_HP_SV_MASK, 0);
		cod3022x_usleep(100);

		snd_soc_write(w->codec, COD3022X_30_VOL_HPL, 0x1E);
		snd_soc_write(w->codec, COD3022X_31_VOL_HPR, 0x1E);
		cod3022x_usleep(100);

		snd_soc_update_bits(w->codec, COD3022X_1C_SV_DA,
				EN_HP_SV_MASK,
				0x1 << EN_HP_SV_SHIFT);
		cod3022x_usleep(100);

		snd_soc_write(w->codec, COD3022X_30_VOL_HPL, 0x18);
		snd_soc_write(w->codec, COD3022X_31_VOL_HPR, 0x18);
		cod3022x_usleep(100);

		/* Limiter level selection -0.2dB (defult) */
		snd_soc_update_bits(w->codec, COD3022X_54_DNC1,
				EN_DNC_MASK | DNC_START_GAIN_MASK |
				DNC_LIMIT_SEL_MASK,
				((0x1 << EN_DNC_SHIFT) |
				(0x1 < DNC_START_GAIN_SHIFT) | 0x1));
		break;

	case SND_SOC_DAPM_PRE_PMD:
		snd_soc_update_bits(w->codec, COD3022X_54_DNC1,
				EN_DNC_MASK , 0);
		cod3022x_usleep(100);

		snd_soc_write(w->codec, COD3022X_30_VOL_HPL, 0x1E);
		snd_soc_write(w->codec, COD3022X_31_VOL_HPR, 0x1E);
		cod3022x_usleep(100);

		snd_soc_update_bits(w->codec, COD3022X_1C_SV_DA,
				EN_HP_SV_MASK, 0);
		cod3022x_usleep(100);

		snd_soc_write(w->codec, COD3022X_30_VOL_HPL, 0x26);
		snd_soc_write(w->codec, COD3022X_31_VOL_HPR, 0x26);
		cod3022x_usleep(100);

		snd_soc_update_bits(w->codec, COD3022X_1C_SV_DA,
				EN_HP_SV_MASK,
				0x1 << EN_HP_SV_SHIFT);
		cod3022x_usleep(100);

		snd_soc_update_bits(w->codec, COD3022X_17_PWAUTO_DA,
				PW_AUTO_DA_MASK | APW_HP_MASK, 0);
		cod3022x_usleep(100);

		snd_soc_update_bits(w->codec, COD3022X_36_MIX_DA1,
				EN_HP_MIXL_DCTL_MASK | EN_HP_MIXR_DCTR_MASK, 0);
		break;

	default:
		break;
	}

	return 0;
}
Ejemplo n.º 8
0
static int wm8940_i2s_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;
    u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
    u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
    u16 companding =  snd_soc_read(codec,
                                   WM8940_COMPANDINGCTL) & 0xFFDF;
    int ret;

    /* LoutR control */
    if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
            && params_channels(params) == 2)
        iface |= (1 << 9);

    switch (params_rate(params)) {
    case 8000:
        addcntrl |= (0x5 << 1);
        break;
    case 11025:
        addcntrl |= (0x4 << 1);
        break;
    case 16000:
        addcntrl |= (0x3 << 1);
        break;
    case 22050:
        addcntrl |= (0x2 << 1);
        break;
    case 32000:
        addcntrl |= (0x1 << 1);
        break;
    case 44100:
    case 48000:
        break;
    }
    ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl);
    if (ret)
        goto error_ret;

    switch (params_format(params)) {
    case SNDRV_PCM_FORMAT_S8:
        companding = companding | (1 << 5);
        break;
    case SNDRV_PCM_FORMAT_S16_LE:
        break;
    case SNDRV_PCM_FORMAT_S20_3LE:
        iface |= (1 << 5);
        break;
    case SNDRV_PCM_FORMAT_S24_LE:
        iface |= (2 << 5);
        break;
    case SNDRV_PCM_FORMAT_S32_LE:
        iface |= (3 << 5);
        break;
    }
    ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding);
    if (ret)
        goto error_ret;
    ret = snd_soc_write(codec, WM8940_IFACE, iface);

error_ret:
    return ret;
}
Ejemplo n.º 9
0
static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
			  unsigned int Fref, unsigned int Fout)
{
	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
	u16 reg1, reg4, reg5;
	struct _fll_div fll_div;
	int ret;
	int clk_sys_reg;

	/* Any change? */
	if (Fref == wm9081->fll_fref && Fout == wm9081->fll_fout)
		return 0;

	/* Disable the FLL */
	if (Fout == 0) {
		dev_dbg(codec->dev, "FLL disabled\n");
		wm9081->fll_fref = 0;
		wm9081->fll_fout = 0;

		return 0;
	}

	ret = fll_factors(&fll_div, Fref, Fout);
	if (ret != 0)
		return ret;

	reg5 = snd_soc_read(codec, WM9081_FLL_CONTROL_5);
	reg5 &= ~WM9081_FLL_CLK_SRC_MASK;

	switch (fll_id) {
	case WM9081_SYSCLK_FLL_MCLK:
		reg5 |= 0x1;
		break;

	default:
		dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
		return -EINVAL;
	}

	/* Disable CLK_SYS while we reconfigure */
	clk_sys_reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
		snd_soc_write(codec, WM9081_CLOCK_CONTROL_3,
			     clk_sys_reg & ~WM9081_CLK_SYS_ENA);

	/* Any FLL configuration change requires that the FLL be
	 * disabled first. */
	reg1 = snd_soc_read(codec, WM9081_FLL_CONTROL_1);
	reg1 &= ~WM9081_FLL_ENA;
	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);

	/* Apply the configuration */
	if (fll_div.k)
		reg1 |= WM9081_FLL_FRAC_MASK;
	else
		reg1 &= ~WM9081_FLL_FRAC_MASK;
	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);

	snd_soc_write(codec, WM9081_FLL_CONTROL_2,
		     (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
		     (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
	snd_soc_write(codec, WM9081_FLL_CONTROL_3, fll_div.k);

	reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4);
	reg4 &= ~WM9081_FLL_N_MASK;
	reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
	snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4);

	reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
	reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
	snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5);

	/* Set gain to the recommended value */
	snd_soc_update_bits(codec, WM9081_FLL_CONTROL_4,
			    WM9081_FLL_GAIN_MASK, 0);

	/* Enable the FLL */
	snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);

	/* Then bring CLK_SYS up again if it was disabled */
	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
		snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg);

	dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);

	wm9081->fll_fref = Fref;
	wm9081->fll_fout = Fout;

	return 0;
}
Ejemplo n.º 10
0
static int STA381xx_resume(struct snd_soc_codec *codec)
{
	snd_soc_write(codec, STA381xx_MAPSEL, 0x00);
	STA381xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	return 0;
}
Ejemplo n.º 11
0
static int STA381xx_probe(struct snd_soc_codec *codec)
{
	struct STA381xx_priv *STA381xx = snd_soc_codec_get_drvdata(codec);
	int i, ret = 0;

    ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
    if (ret != 0) {
        dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
        return ret;
    }

	STA381xx->codec = codec;
	/* Chip documentation explicitly requires that the reset values
	 * of reserved register bits are left untouched.
	 * Write the register default value to cache for reserved registers,
	 * so the write to the these registers are suppressed by the cache
	 * restore code when it skips writes of default registers.
	 */
	 
	snd_soc_write(codec, STA381xx_MAPSEL, 0x00);
	snd_soc_write(codec, STA381xx_CONFA, 0x67);
	snd_soc_write(codec, STA381xx_CONFB, 0x80);
	snd_soc_write(codec, STA381xx_CONFC, 0x9F);
	snd_soc_write(codec, STA381xx_CONFD, 0x18);
	snd_soc_write(codec, STA381xx_CONFE, 0x82);
	snd_soc_write(codec, STA381xx_CONFF, 0x5D);
	snd_soc_write(codec, STA381xx_MMUTE, 0x40);
	snd_soc_write(codec, STA381xx_MVOL, 0xFE);
	snd_soc_write(codec, STA381xx_C1VOL, 0x47);
	snd_soc_write(codec, STA381xx_C2VOL, 0x47);
	snd_soc_write(codec, STA381xx_C3VOL, 0x56);
	snd_soc_write(codec, STA381xx_C1CFG, 0x00);
	snd_soc_write(codec, STA381xx_C2CFG, 0x40);
	snd_soc_write(codec, STA381xx_C3CFG, 0x80);
	snd_soc_write(codec, STA381xx_C1CFG, 0x00);
	//subwoofer
	snd_soc_write(codec, STA381xx_TONE, 0x7F);
	snd_soc_write(codec, STA381xx_AUTO2, 0x70);

	snd_soc_update_bits(codec, STA381xx_CONFF,
		STA381xx_CONFF_EAPD, STA381xx_CONFF_EAPD);
	snd_soc_write(codec, STA381xx_MVOL, 0x00);
	
	//snd_soc_write(codec, STA381xx_F3XCON2, 0x6D);
	//snd_soc_write(codec, STA381xx_HPCONFIG, 0x09);
	
	/* set thermal warning adjustment and recovery */
	//if (!(STA381xx->pdata->thermal_conf & STA381xx_THERMAL_ADJUSTMENT_ENABLE))
	//	thermal |= STA381xx_CONFA_TWAB;
	//if (!(STA381xx->pdata->thermal_conf & STA381xx_THERMAL_RECOVERY_ENABLE))
	//	thermal |= STA381xx_CONFA_TWRB;
	//snd_soc_update_bits(codec, STA381xx_CONFA,
	//		    STA381xx_CONFA_TWAB | STA381xx_CONFA_TWRB,
	//		    thermal);
#if 0
	/* select output configuration  */
	snd_soc_update_bits(codec, STA381xx_CONFF,
			    STA381xx_CONFF_OCFG_MASK,
			    STA381xx->pdata->output_conf
			    << STA381xx_CONFF_OCFG_SHIFT);

	/* channel to output mapping */
	snd_soc_update_bits(codec, STA381xx_C1CFG,
			    STA381xx_CxCFG_OM_MASK,
			    STA381xx->pdata->ch1_output_mapping
			    << STA381xx_CxCFG_OM_SHIFT);
	snd_soc_update_bits(codec, STA381xx_C2CFG,
			    STA381xx_CxCFG_OM_MASK,
			    STA381xx->pdata->ch2_output_mapping
			    << STA381xx_CxCFG_OM_SHIFT);
	snd_soc_update_bits(codec, STA381xx_C3CFG,
			    STA381xx_CxCFG_OM_MASK,
			    STA381xx->pdata->ch3_output_mapping
			    << STA381xx_CxCFG_OM_SHIFT);
#endif
	/* initialize coefficient shadow RAM with reset values */
	for (i = 4; i <= 39; i += 5)
		STA381xx->coef_shadow[i] = 0x100000;
	for (i = 44; i <= 49; i += 5)
		STA381xx->coef_shadow[i] = 0x400000;
	for (i = 50; i <= 54; i++)
		STA381xx->coef_shadow[i] = 0x7fffff;
	
	STA381xx->coef_shadow[55] = 0x5a9df7;
	STA381xx->coef_shadow[56] = 0x7fffff;
	STA381xx->coef_shadow[59] = 0x7fffff;
	STA381xx->coef_shadow[60] = 0x400000;
	STA381xx->coef_shadow[61] = 0x400000;

	STA381xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	/* Bias level configuration will have done an extra enable */
	//regulator_bulk_disable(ARRAY_SIZE(STA381xx->supplies), STA381xx->supplies);

	return 0;
}
Ejemplo n.º 12
0
static int cs42l51_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_codec *codec = rtd->codec;
	struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
	int ret;
	unsigned int i;
	unsigned int rate;
	unsigned int ratio;
	struct cs42l51_ratios *ratios = NULL;
	int nr_ratios = 0;
	int intf_ctl, power_ctl, fmt;

	switch (cs42l51->func) {
	case MODE_MASTER:
		return -EINVAL;
	case MODE_SLAVE:
		ratios = slave_ratios;
		nr_ratios = ARRAY_SIZE(slave_ratios);
		break;
	case MODE_SLAVE_AUTO:
		ratios = slave_auto_ratios;
		nr_ratios = ARRAY_SIZE(slave_auto_ratios);
		break;
	}

	
	rate = params_rate(params);     
	ratio = cs42l51->mclk / rate;    
	for (i = 0; i < nr_ratios; i++) {
		if (ratios[i].ratio == ratio)
			break;
	}

	if (i == nr_ratios) {
		
		dev_err(codec->dev, "could not find matching ratio\n");
		return -EINVAL;
	}

	intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
	power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);

	intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
			| CS42L51_INTF_CTL_DAC_FORMAT(7));
	power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
			| CS42L51_MIC_POWER_CTL_MCLK_DIV2);

	switch (cs42l51->func) {
	case MODE_MASTER:
		intf_ctl |= CS42L51_INTF_CTL_MASTER;
		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
		break;
	case MODE_SLAVE:
		power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
		break;
	case MODE_SLAVE_AUTO:
		power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
		break;
	}

	switch (cs42l51->audio_mode) {
	case SND_SOC_DAIFMT_I2S:
		intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		switch (params_format(params)) {
		case SNDRV_PCM_FORMAT_S16_LE:
		case SNDRV_PCM_FORMAT_S16_BE:
			fmt = CS42L51_DAC_DIF_RJ16;
			break;
		case SNDRV_PCM_FORMAT_S18_3LE:
		case SNDRV_PCM_FORMAT_S18_3BE:
			fmt = CS42L51_DAC_DIF_RJ18;
			break;
		case SNDRV_PCM_FORMAT_S20_3LE:
		case SNDRV_PCM_FORMAT_S20_3BE:
			fmt = CS42L51_DAC_DIF_RJ20;
			break;
		case SNDRV_PCM_FORMAT_S24_LE:
		case SNDRV_PCM_FORMAT_S24_BE:
			fmt = CS42L51_DAC_DIF_RJ24;
			break;
		default:
			dev_err(codec->dev, "unknown format\n");
			return -EINVAL;
		}
		intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
		break;
	default:
		dev_err(codec->dev, "unknown format\n");
		return -EINVAL;
	}

	if (ratios[i].mclk)
		power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;

	ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
	if (ret < 0)
		return ret;

	ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
	if (ret < 0)
		return ret;

	return 0;
}
Ejemplo n.º 13
0
static int aic31xx_setup_pll(struct snd_soc_codec *codec,
			     struct snd_pcm_hw_params *params)
{
	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
	int bclk_score = snd_soc_params_to_frame_size(params);
	int mclk_p = aic31xx->sysclk / aic31xx->p_div;
	int bclk_n = 0;
	int match = -1;
	int i;

	/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
	snd_soc_update_bits(codec, AIC31XX_CLKMUX,
			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
	snd_soc_update_bits(codec, AIC31XX_IFACE2,
			    AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK);

	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
		if (aic31xx_divs[i].rate == params_rate(params) &&
		    aic31xx_divs[i].mclk_p == mclk_p) {
			int s =	(aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) %
				snd_soc_params_to_frame_size(params);
			int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) /
				snd_soc_params_to_frame_size(params);
			if (s < bclk_score && bn > 0) {
				match = i;
				bclk_n = bn;
				bclk_score = s;
			}
		}
	}

	if (match == -1) {
		dev_err(codec->dev,
			"%s: Sample rate (%u) and format not supported\n",
			__func__, params_rate(params));
		/* See bellow for details how fix this. */
		return -EINVAL;
	}
	if (bclk_score != 0) {
		dev_warn(codec->dev, "Can not produce exact bitclock");
		/* This is fine if using dsp format, but if using i2s
		   there may be trouble. To fix the issue edit the
		   aic31xx_divs table for your mclk and sample
		   rate. Details can be found from:
		   http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf
		   Section: 5.6 CLOCK Generation and PLL
		*/
	}
	i = match;

	/* PLL configuration */
	snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
			    (aic31xx->p_div << 4) | 0x01);
	snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);

	snd_soc_write(codec, AIC31XX_PLLDMSB,
		      aic31xx_divs[i].pll_d >> 8);
	snd_soc_write(codec, AIC31XX_PLLDLSB,
		      aic31xx_divs[i].pll_d & 0xff);

	/* DAC dividers configuration */
	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].ndac);
	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].mdac);

	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
	snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);

	/* ADC dividers configuration. Write reset value 1 if not used. */
	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
			    aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);

	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);

	/* Bit clock divider configuration. */
	snd_soc_update_bits(codec, AIC31XX_BCLKN,
			    AIC31XX_PLL_MASK, bclk_n);

	aic31xx->rate_div_line = i;

	dev_dbg(codec->dev,
		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
		aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
		aic31xx->p_div, aic31xx_divs[i].dosr,
		aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
		aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
		aic31xx_divs[i].madc, bclk_n);

	return 0;
}
Ejemplo n.º 14
0
static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
	struct snd_soc_codec *codec = dai->codec;
	u16 aif = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);

	aif &= ~(WM8961_BCLKINV | WM8961_LRP |
		 WM8961_MS | WM8961_FORMAT_MASK);

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBM_CFM:
		aif |= WM8961_MS;
		break;
	case SND_SOC_DAIFMT_CBS_CFS:
		break;
	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_RIGHT_J:
		break;

	case SND_SOC_DAIFMT_LEFT_J:
		aif |= 1;
		break;

	case SND_SOC_DAIFMT_I2S:
		aif |= 2;
		break;

	case SND_SOC_DAIFMT_DSP_B:
		aif |= WM8961_LRP;
	case SND_SOC_DAIFMT_DSP_A:
		aif |= 3;
		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
		case SND_SOC_DAIFMT_NB_NF:
		case SND_SOC_DAIFMT_IB_NF:
			break;
		default:
			return -EINVAL;
		}
		break;

	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_NB_NF:
		break;
	case SND_SOC_DAIFMT_NB_IF:
		aif |= WM8961_LRP;
		break;
	case SND_SOC_DAIFMT_IB_NF:
		aif |= WM8961_BCLKINV;
		break;
	case SND_SOC_DAIFMT_IB_IF:
		aif |= WM8961_BCLKINV | WM8961_LRP;
		break;
	default:
		return -EINVAL;
	}

	return snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, aif);
}
Ejemplo n.º 15
0
static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
{
	snd_soc_write(codec, SN95031_BTNCTRL1, 0x77);
	snd_soc_write(codec, SN95031_BTNCTRL2, 0x01);
}
Ejemplo n.º 16
0
static int configure_clock(struct snd_soc_codec *codec)
{
	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
	int new_sysclk, i, target;
	unsigned int reg;
	int ret = 0;
	int mclkdiv = 0;
	int fll = 0;

	switch (wm9081->sysclk_source) {
	case WM9081_SYSCLK_MCLK:
		if (wm9081->mclk_rate > 12225000) {
			mclkdiv = 1;
			wm9081->sysclk_rate = wm9081->mclk_rate / 2;
		} else {
			wm9081->sysclk_rate = wm9081->mclk_rate;
		}
		wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK, 0, 0);
		break;

	case WM9081_SYSCLK_FLL_MCLK:
		/* If we have a sample rate calculate a CLK_SYS that
		 * gives us a suitable DAC configuration, plus BCLK.
		 * Ideally we would check to see if we can clock
		 * directly from MCLK and only use the FLL if this is
		 * not the case, though care must be taken with free
		 * running mode.
		 */
		if (wm9081->master && wm9081->bclk) {
			/* Make sure we can generate CLK_SYS and BCLK
			 * and that we've got 3MHz for optimal
			 * performance. */
			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
				target = wm9081->fs * clk_sys_rates[i].ratio;
				new_sysclk = target;
				if (target >= wm9081->bclk &&
				    target > 3000000)
					break;
			}

			if (i == ARRAY_SIZE(clk_sys_rates))
				return -EINVAL;

		} else if (wm9081->fs) {
			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
				new_sysclk = clk_sys_rates[i].ratio
					* wm9081->fs;
				if (new_sysclk > 3000000)
					break;
			}

			if (i == ARRAY_SIZE(clk_sys_rates))
				return -EINVAL;

		} else {
			new_sysclk = 12288000;
		}

		ret = wm9081_set_fll(codec, WM9081_SYSCLK_FLL_MCLK,
				     wm9081->mclk_rate, new_sysclk);
		if (ret == 0) {
			wm9081->sysclk_rate = new_sysclk;

			/* Switch SYSCLK over to FLL */
			fll = 1;
		} else {
			wm9081->sysclk_rate = wm9081->mclk_rate;
		}
		break;

	default:
		return -EINVAL;
	}

	reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_1);
	if (mclkdiv)
		reg |= WM9081_MCLKDIV2;
	else
		reg &= ~WM9081_MCLKDIV2;
	snd_soc_write(codec, WM9081_CLOCK_CONTROL_1, reg);

	reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
	if (fll)
		reg |= WM9081_CLK_SRC_SEL;
	else
		reg &= ~WM9081_CLK_SRC_SEL;
	snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, reg);

	dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);

	return ret;
}
Ejemplo n.º 17
0
/* codec registration */
static int sn95031_codec_probe(struct snd_soc_codec *codec)
{
	pr_debug("codec_probe called\n");

	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
	codec->dapm.idle_bias_off = 1;

	/* PCM interface config
	 * This sets the pcm rx slot conguration to max 6 slots
	 * for max 4 dais (2 stereo and 2 mono)
	 */
	snd_soc_write(codec, SN95031_PCM2RXSLOT01, 0x10);
	snd_soc_write(codec, SN95031_PCM2RXSLOT23, 0x32);
	snd_soc_write(codec, SN95031_PCM2RXSLOT45, 0x54);
	snd_soc_write(codec, SN95031_PCM2TXSLOT01, 0x10);
	snd_soc_write(codec, SN95031_PCM2TXSLOT23, 0x32);
	/* pcm port setting
	 * This sets the pcm port to slave and clock at 19.2Mhz which
	 * can support 6slots, sampling rate set per stream in hw-params
	 */
	snd_soc_write(codec, SN95031_PCM1C1, 0x00);
	snd_soc_write(codec, SN95031_PCM2C1, 0x01);
	snd_soc_write(codec, SN95031_PCM2C2, 0x0A);
	snd_soc_write(codec, SN95031_HSMIXER, BIT(0)|BIT(4));
	/* vendor vibra workround, the vibras are muted by
	 * custom register so unmute them
	 */
	snd_soc_write(codec, SN95031_SSR5, 0x80);
	snd_soc_write(codec, SN95031_SSR6, 0x80);
	snd_soc_write(codec, SN95031_VIB1C5, 0x00);
	snd_soc_write(codec, SN95031_VIB2C5, 0x00);
	/* configure vibras for pcm port */
	snd_soc_write(codec, SN95031_VIB1C3, 0x00);
	snd_soc_write(codec, SN95031_VIB2C3, 0x00);

	/* soft mute ramp time */
	snd_soc_write(codec, SN95031_SOFTMUTE, 0x3);
	/* fix the initial volume at 1dB,
	 * default in +9dB,
	 * 1dB give optimal swing on DAC, amps
	 */
	snd_soc_write(codec, SN95031_HSLVOLCTRL, 0x08);
	snd_soc_write(codec, SN95031_HSRVOLCTRL, 0x08);
	snd_soc_write(codec, SN95031_IHFLVOLCTRL, 0x08);
	snd_soc_write(codec, SN95031_IHFRVOLCTRL, 0x08);
	/* dac mode and lineout workaround */
	snd_soc_write(codec, SN95031_SSR2, 0x10);
	snd_soc_write(codec, SN95031_SSR3, 0x40);

	snd_soc_add_controls(codec, sn95031_snd_controls,
			     ARRAY_SIZE(sn95031_snd_controls));

	return 0;
}
Ejemplo n.º 18
0
static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
			      unsigned int fmt)
{
	struct snd_soc_codec *codec = dai->codec;
	struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
	unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);

	aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
		  WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		wm9081->master = 0;
		break;
	case SND_SOC_DAIFMT_CBS_CFM:
		aif2 |= WM9081_LRCLK_DIR;
		wm9081->master = 1;
		break;
	case SND_SOC_DAIFMT_CBM_CFS:
		aif2 |= WM9081_BCLK_DIR;
		wm9081->master = 1;
		break;
	case SND_SOC_DAIFMT_CBM_CFM:
		aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR;
		wm9081->master = 1;
		break;
	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_DSP_B:
		aif2 |= WM9081_AIF_LRCLK_INV;
	case SND_SOC_DAIFMT_DSP_A:
		aif2 |= 0x3;
		break;
	case SND_SOC_DAIFMT_I2S:
		aif2 |= 0x2;
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		aif2 |= 0x1;
		break;
	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_DSP_A:
	case SND_SOC_DAIFMT_DSP_B:
		/* frame inversion not valid for DSP modes */
		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
		case SND_SOC_DAIFMT_NB_NF:
			break;
		case SND_SOC_DAIFMT_IB_NF:
			aif2 |= WM9081_AIF_BCLK_INV;
			break;
		default:
			return -EINVAL;
		}
		break;

	case SND_SOC_DAIFMT_I2S:
	case SND_SOC_DAIFMT_RIGHT_J:
	case SND_SOC_DAIFMT_LEFT_J:
		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
		case SND_SOC_DAIFMT_NB_NF:
			break;
		case SND_SOC_DAIFMT_IB_IF:
			aif2 |= WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV;
			break;
		case SND_SOC_DAIFMT_IB_NF:
			aif2 |= WM9081_AIF_BCLK_INV;
			break;
		case SND_SOC_DAIFMT_NB_IF:
			aif2 |= WM9081_AIF_LRCLK_INV;
			break;
		default:
			return -EINVAL;
		}
		break;
	default:
		return -EINVAL;
	}

	snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);

	return 0;
}
Ejemplo n.º 19
0
static void tegra_audio_route(struct tegra_audio_data* audio_data,
			      int device_new, int is_call_mode_new)
{
	int play_device_new = device_new & TEGRA_AUDIO_DEVICE_OUT_ALL;
	int capture_device_new = device_new & TEGRA_AUDIO_DEVICE_IN_ALL;
	int codec_con = audio_data->codec_con;
	int is_bt_sco_mode =
		(play_device_new & TEGRA_AUDIO_DEVICE_OUT_BT_SCO) ||
		(capture_device_new & TEGRA_AUDIO_DEVICE_IN_BT_SCO);
	int was_bt_sco_mode =
		(audio_data->play_device & TEGRA_AUDIO_DEVICE_OUT_BT_SCO) ||
		(audio_data->capture_device & TEGRA_AUDIO_DEVICE_IN_BT_SCO);

	if (play_device_new) {
		codec_con &= ~(TEGRA_HEADPHONE | TEGRA_LINEOUT |
			TEGRA_SPK | TEGRA_EAR_SPK | TEGRA_HEADSET);

		if ((play_device_new & TEGRA_AUDIO_DEVICE_OUT_HEADPHONE)&&(play_device_new & TEGRA_AUDIO_DEVICE_OUT_SPEAKER)) {
			codec_con |= TEGRA_HEADPHONE;
			codec_con |= TEGRA_SPK;
			printk("Routing to Headphone and Speaker output\n");
			need_spk = true;
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_4, 0x0003); /* MIXSPK Enable*/
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_5, 0x0003); /* SPK Enable*/
			if(boot_finish)
				snd_soc_write(audio_data->codec, WM8903_GPIO_CONTROL_3, 0x0033); /* GPIO3 configure: EN_SPK*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_SPK_MIX_LEFT_0, 0x0008); /* DACR_TO_MIXSPK Enable*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 0x0004); /* DACL_TO_MIXSPK Enable*/
			if(PRJ_ID == EP_101){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_LEFT,audio_params[EP101].analog_speaker_volume | 0x80); /* SPKL Volume: 4dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_RIGHT,audio_params[EP101].analog_speaker_volume | 0x80); /* SPKR Volume: 4dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_LEFT,audio_params[EP101].analog_headset_volume | 0x80); /* HPOUTL Volume: -2dB */
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_RIGHT,audio_params[EP101].analog_headset_volume | 0x80); /* HPOUTR Volume: -2dB */
			}else if(PRJ_ID == EP_102){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_LEFT,audio_params[EP102].analog_speaker_volume | 0x80); /* SPKL Volume: 0dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_RIGHT,audio_params[EP102].analog_speaker_volume | 0x80); /* SPKR Volume: 0dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_LEFT,audio_params[EP102].analog_headset_volume | 0x80); /* HPOUTL Volume: -16dB */
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_RIGHT, audio_params[EP102].analog_headset_volume | 0x80); /* HPOUTR Volume: -16dB */
			}
		}
		else if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_HEADPHONE) {
			codec_con |= TEGRA_HEADPHONE;
			printk("Routing to Headphone output\n");
			need_spk = false;
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_4, 0x0000); /* MIXSPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_5, 0x0000); /* SPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_GPIO_CONTROL_3, 0x0000); /* Media stream, Mute the speaker */
			if(PRJ_ID == EP_101){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_LEFT, audio_params[EP101].analog_headset_volume | 0x80); /* HPOUTL Volume: -2dB */
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_RIGHT,audio_params[EP101].analog_headset_volume | 0x80); /* HPOUTR Volume: -2dB */
			}else if(PRJ_ID == EP_102){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_LEFT,audio_params[EP102].analog_headset_volume | 0x80); /* HPOUTL Volume: -16dB */
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_RIGHT,audio_params[EP102].analog_headset_volume | 0x80); /* HPOUTR Volume: -16dB */
			}
		}
		else if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_HEADSET) {
			codec_con |= TEGRA_HEADSET;
			printk("Routing to Headset output\n");
			need_spk = false;
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_4, 0x0000); /* MIXSPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_5, 0x0000); /* SPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_GPIO_CONTROL_3, 0x0000); /* Media stream, Mute the speaker */
			if(PRJ_ID == EP_101){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_LEFT,audio_params[EP101].analog_headset_volume | 0x80); /* HPOUTL Volume: -2dB */
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_RIGHT,audio_params[EP101].analog_headset_volume | 0x80); /* HPOUTR Volume: -2dB */
			}else if(PRJ_ID == EP_102){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_LEFT,audio_params[EP102].analog_headset_volume | 0x80); /* HPOUTL Volume: -16dB */
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT1_RIGHT,audio_params[EP102].analog_headset_volume | 0x80); /* HPOUTR Volume: -16dB */
			}
		}
		else if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_LINE) {
			codec_con |= TEGRA_LINEOUT;
			printk("Routing to Line output\n");
			need_spk = false;
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_4, 0x0000); /* MIXSPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_5, 0x0000); /* SPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_GPIO_CONTROL_3, 0x0000); /* Media stream, Mute the speaker */
		}

		if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_SPEAKER) {
			codec_con |= TEGRA_SPK;
			printk("Routing to Speaker output\n");
			need_spk = true;
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_4, 0x0003); /* MIXSPK Enable*/
			if(PRJ_ID == EP_101){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_LEFT,audio_params[EP101].analog_speaker_volume | 0x80); /* SPKL Volume: 4dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_RIGHT,audio_params[EP101].analog_speaker_volume | 0x80); /* SPKR Volume: 4dB*/
			}else if(PRJ_ID == EP_102){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_LEFT,audio_params[EP102].analog_speaker_volume | 0x80); /* SPKL Volume: 0dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_RIGHT,audio_params[EP102].analog_speaker_volume | 0x80); /* SPKR Volume: 0dB*/
			}
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_5, 0x0003); /* SPK Enable*/
			if(boot_finish)
				snd_soc_write(audio_data->codec, WM8903_GPIO_CONTROL_3, 0x0033); /* GPIO3 configure: EN_SPK*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_SPK_MIX_LEFT_0, 0x0008); /* DACR_TO_MIXSPK Enable*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 0x0004); /* DACL_TO_MIXSPK Enable*/
		}
		else if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_EAR_SPEAKER) {
			codec_con |= TEGRA_EAR_SPK;
			printk("Routing to Ear Speaker output\n");
			need_spk = true;
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_4, 0x0003); /* MIXSPK Enable*/
			if(PRJ_ID == EP_101){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_LEFT,audio_params[EP101].analog_speaker_volume | 0x80); /* SPKL Volume: 4dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_RIGHT,audio_params[EP101].analog_speaker_volume | 0x80); /* SPKR Volume: 4dB*/
			}else if(PRJ_ID == EP_102){
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_LEFT,audio_params[EP102].analog_speaker_volume | 0x80); /* SPKL Volume: 0dB*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_OUT3_RIGHT,audio_params[EP102].analog_speaker_volume | 0x80); /* SPKR Volume: 0dB*/
			}
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_5, 0x0003); /* SPK Enable*/
			if(boot_finish)
				snd_soc_write(audio_data->codec, WM8903_GPIO_CONTROL_3, 0x0033); /* GPIO3 configure: EN_SPK*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_SPK_MIX_LEFT_0, 0x0008); /* DACR_TO_MIXSPK Enable*/
			snd_soc_write(audio_data->codec, WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 0x0004); /* DACL_TO_MIXSPK Enable*/
		}
		else {
			printk("Routing to unknown output\n");
			need_spk = false;
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_4, 0x0000); /* MIXSPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_POWER_MANAGEMENT_5, 0x0000); /* SPK Disable*/
			snd_soc_write(audio_data->codec, WM8903_GPIO_CONTROL_3, 0x0000); /* Mute the speaker */
		}

		tegra_ext_control(audio_data->codec, codec_con);
		audio_data->play_device = play_device_new;
	}

	if (capture_device_new != audio_data->capture_device) {
		codec_con &= ~(TEGRA_INT_MIC | TEGRA_EXT_MIC |
			TEGRA_LINEIN | TEGRA_HEADSET);

		if (capture_device_new & (TEGRA_AUDIO_DEVICE_IN_BUILTIN_MIC |
			TEGRA_AUDIO_DEVICE_IN_BACK_MIC))
			codec_con |= TEGRA_INT_MIC;

		if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_MIC)
			codec_con |= TEGRA_EXT_MIC;

		if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_LINE)
			codec_con |= TEGRA_LINEIN;

		if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_HEADSET)
			codec_con |= TEGRA_HEADSET;

		tegra_ext_control(audio_data->codec, codec_con);
		audio_data->capture_device = capture_device_new;
	}

	if ((is_call_mode_new != audio_data->is_call_mode) ||
		(is_bt_sco_mode != was_bt_sco_mode)) {
		if (is_call_mode_new && is_bt_sco_mode) {
			tegra_das_set_connection
				(tegra_das_port_con_id_voicecall_with_bt);
		}
		else if (is_call_mode_new && !is_bt_sco_mode) {
			tegra_das_set_connection
				(tegra_das_port_con_id_voicecall_no_bt);
		}
		else if (!is_call_mode_new && is_bt_sco_mode) {
			tegra_das_set_connection
				(tegra_das_port_con_id_bt_codec);
		}
		else {
			tegra_das_set_connection
				(tegra_das_port_con_id_hifi);
		}
		audio_data->is_call_mode = is_call_mode_new;
	}
}
/*
 * Startup calibration of the DC servo
 */
static void calibrate_dc_servo(struct snd_soc_codec *codec)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	s8 offset;
	u16 reg, reg_l, reg_r, dcs_cfg;

	/* If we're using a digital only path and have a previously
	 * callibrated DC servo offset stored then use that. */
	if (hubs->class_w && hubs->class_w_dcs) {
		dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
			hubs->class_w_dcs);
		snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs);
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_DAC_WR_0 |
				  WM8993_DCS_TRIG_DAC_WR_1);
		return;
	}

	/* Devices not using a DCS code correction have startup mode */
	if (hubs->dcs_codes) {
		/* Set for 32 series updates */
		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
				    WM8993_DCS_SERIES_NO_01_MASK,
				    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_SERIES_0 |
				  WM8993_DCS_TRIG_SERIES_1);
	} else {
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_STARTUP_0 |
				  WM8993_DCS_TRIG_STARTUP_1);
	}

	/* Different chips in the family support different readback
	 * methods.
	 */
	switch (hubs->dcs_readback_mode) {
	case 0:
		reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
			& WM8993_DCS_INTEG_CHAN_0_MASK;
		reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
			& WM8993_DCS_INTEG_CHAN_1_MASK;
		break;
	case 1:
		reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
		reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
		reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
		break;
	default:
		WARN(1, "Unknown DCS readback method\n");
		break;
	}

	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);

	/* Apply correction to DC servo result */
	if (hubs->dcs_codes) {
		dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
			hubs->dcs_codes);

		/* HPOUT1L */
		offset = reg_l;
		offset += hubs->dcs_codes;
		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;

		/* HPOUT1R */
		offset = reg_r;
		offset += hubs->dcs_codes;
		dcs_cfg |= (u8)offset;

		dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);

		/* Do it */
		snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_DAC_WR_0 |
				  WM8993_DCS_TRIG_DAC_WR_1);
	} else {
		dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
		dcs_cfg |= reg_r;
	}

	/* Save the callibrated offset if we're in class W mode and
	 * therefore don't have any analogue signal mixed in. */
	if (hubs->class_w)
		hubs->class_w_dcs = dcs_cfg;
}
Ejemplo n.º 21
0
static int wm8955_reset(struct snd_soc_codec *codec)
{
	return snd_soc_write(codec, WM8955_RESET, 0);
}
Ejemplo n.º 22
0
static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
			     struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
	u8 reg_val, adc_left, adc_right, mic_left, mic_right;
	int avg_left_data, avg_right_data, offset_l, offset_r;

	if (ucontrol->value.integer.value[0]) {
		/*
		 * While enabling ALC (or ALC sync mode), calibration of the DC
		 * offsets must be done first
		 */

		/* Save current values from Mic control registers */
		mic_left = snd_soc_read(codec, DA9055_MIC_L_CTRL);
		mic_right = snd_soc_read(codec, DA9055_MIC_R_CTRL);

		/* Mute Mic PGA Left and Right */
		snd_soc_update_bits(codec, DA9055_MIC_L_CTRL,
				    DA9055_MIC_L_MUTE_EN, DA9055_MIC_L_MUTE_EN);
		snd_soc_update_bits(codec, DA9055_MIC_R_CTRL,
				    DA9055_MIC_R_MUTE_EN, DA9055_MIC_R_MUTE_EN);

		/* Save current values from ADC control registers */
		adc_left = snd_soc_read(codec, DA9055_ADC_L_CTRL);
		adc_right = snd_soc_read(codec, DA9055_ADC_R_CTRL);

		/* Enable ADC Left and Right */
		snd_soc_update_bits(codec, DA9055_ADC_L_CTRL,
				    DA9055_ADC_L_EN, DA9055_ADC_L_EN);
		snd_soc_update_bits(codec, DA9055_ADC_R_CTRL,
				    DA9055_ADC_R_EN, DA9055_ADC_R_EN);

		/* Calculate average for Left and Right data */
		/* Left Data */
		avg_left_data = da9055_get_alc_data(codec,
				DA9055_ALC_CIC_OP_CHANNEL_LEFT);
		/* Right Data */
		avg_right_data = da9055_get_alc_data(codec,
				 DA9055_ALC_CIC_OP_CHANNEL_RIGHT);

		/* Calculate DC offset */
		offset_l = -avg_left_data;
		offset_r = -avg_right_data;

		reg_val = (offset_l & DA9055_ALC_OFFSET_15_8) >> 8;
		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_L, reg_val);
		reg_val = (offset_l & DA9055_ALC_OFFSET_17_16) >> 16;
		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_L, reg_val);

		reg_val = (offset_r & DA9055_ALC_OFFSET_15_8) >> 8;
		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_R, reg_val);
		reg_val = (offset_r & DA9055_ALC_OFFSET_17_16) >> 16;
		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_R, reg_val);

		/* Restore original values of ADC control registers */
		snd_soc_write(codec, DA9055_ADC_L_CTRL, adc_left);
		snd_soc_write(codec, DA9055_ADC_R_CTRL, adc_right);

		/* Restore original values of Mic control registers */
		snd_soc_write(codec, DA9055_MIC_L_CTRL, mic_left);
		snd_soc_write(codec, DA9055_MIC_R_CTRL, mic_right);
	}
Ejemplo n.º 23
0
static int hp_ev(struct snd_soc_dapm_widget *w,
		 struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_codec *codec = w->codec;
	unsigned int reg = snd_soc_read(codec, WM9090_ANALOGUE_HP_0);

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		snd_soc_update_bits(codec, WM9090_CHARGE_PUMP_1,
				    WM9090_CP_ENA, WM9090_CP_ENA);

		msleep(5);

		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA);

		reg |= WM9090_HPOUT1L_DLY | WM9090_HPOUT1R_DLY;
		snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);

		/* Start the DC servo.  We don't currently use the
		 * ability to save the state since we don't have full
		 * control of the analogue paths and they can change
		 * DC offsets; see the WM8904 driver for an example of
		 * doing so.
		 */
		snd_soc_write(codec, WM9090_DC_SERVO_0,
			      WM9090_DCS_ENA_CHAN_0 |
			      WM9090_DCS_ENA_CHAN_1 |
			      WM9090_DCS_TRIG_STARTUP_1 |
			      WM9090_DCS_TRIG_STARTUP_0);
		wait_for_dc_servo(codec);

		reg |= WM9090_HPOUT1R_OUTP | WM9090_HPOUT1R_RMV_SHORT |
			WM9090_HPOUT1L_OUTP | WM9090_HPOUT1L_RMV_SHORT;
		snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);
		break;

	case SND_SOC_DAPM_PRE_PMD:
		reg &= ~(WM9090_HPOUT1L_RMV_SHORT |
			 WM9090_HPOUT1L_DLY |
			 WM9090_HPOUT1L_OUTP |
			 WM9090_HPOUT1R_RMV_SHORT |
			 WM9090_HPOUT1R_DLY |
			 WM9090_HPOUT1R_OUTP);

		snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);

		snd_soc_write(codec, WM9090_DC_SERVO_0, 0);

		snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
				    WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
				    0);

		snd_soc_update_bits(codec, WM9090_CHARGE_PUMP_1,
				    WM9090_CP_ENA, 0);
		break;
	}

	return 0;
}
Ejemplo n.º 24
0
Archivo: wm8985.c Proyecto: 3null/linux
static int wm8985_reset(struct snd_soc_codec *codec)
{
	return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0);
}
Ejemplo n.º 25
0
static void calibrate_dc_servo(struct snd_soc_codec *codec)
{
	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
	s8 offset;
	u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;

	switch (hubs->dcs_readback_mode) {
	case 2:
		dcs_reg = WM8994_DC_SERVO_4E;
		break;
	default:
		dcs_reg = WM8993_DC_SERVO_3;
		break;
	}

	/*                                                         
                                                      */
	if (hubs->class_w && hubs->class_w_dcs) {
		dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
			hubs->class_w_dcs);
		snd_soc_write(codec, dcs_reg, hubs->class_w_dcs);
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_DAC_WR_0 |
				  WM8993_DCS_TRIG_DAC_WR_1);
		return;
	}

	if (hubs->series_startup) {
		/*                           */
		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
				    WM8993_DCS_SERIES_NO_01_MASK,
				    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_SERIES_0 |
				  WM8993_DCS_TRIG_SERIES_1);
	} else {
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_STARTUP_0 |
				  WM8993_DCS_TRIG_STARTUP_1);
	}

	/*                                                         
            
  */
	switch (hubs->dcs_readback_mode) {
	case 0:
		reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
			& WM8993_DCS_INTEG_CHAN_0_MASK;
		reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
			& WM8993_DCS_INTEG_CHAN_1_MASK;
		break;
	case 2:
	case 1:
		reg = snd_soc_read(codec, dcs_reg);
		reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
			>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
		reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
		break;
	default:
		WARN(1, "Unknown DCS readback method\n");
		return;
	}

	dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);

	/*                                     */
	if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
		dev_dbg(codec->dev,
			"Applying %d/%d code DC servo correction\n",
			hubs->dcs_codes_l, hubs->dcs_codes_r);

		/*         */
		offset = reg_r;
		offset += hubs->dcs_codes_r;
		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;

		/*         */
		offset = reg_l;
		offset += hubs->dcs_codes_l;
		dcs_cfg |= (u8)offset;

		dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);

		/*       */
		snd_soc_write(codec, dcs_reg, dcs_cfg);
		wait_for_dc_servo(codec,
				  WM8993_DCS_TRIG_DAC_WR_0 |
				  WM8993_DCS_TRIG_DAC_WR_1);
	} else {
		dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
		dcs_cfg |= reg_l;
	}

	/*                                                         
                                                       */
	if (hubs->class_w && !hubs->no_cache_class_w)
		hubs->class_w_dcs = dcs_cfg;
}
Ejemplo n.º 26
0
/* enables mic bias voltage */
static void sn95031_enable_mic_bias(struct snd_soc_codec *codec)
{
	snd_soc_write(codec, SN95031_VAUD, BIT(2)|BIT(1)|BIT(0));
	snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2));
}
Ejemplo n.º 27
0
static int sta32x_probe(struct snd_soc_codec *codec)
{
	struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
	int i, ret = 0, thermal = 0;

	sta32x->codec = codec;
	sta32x->pdata = dev_get_platdata(codec->dev);

	ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
				    sta32x->supplies);
	if (ret != 0) {
		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
		return ret;
	}

	/* Chip documentation explicitly requires that the reset values
	 * of reserved register bits are left untouched.
	 * Write the register default value to cache for reserved registers,
	 * so the write to the these registers are suppressed by the cache
	 * restore code when it skips writes of default registers.
	 */
	regcache_cache_only(sta32x->regmap, true);
	snd_soc_write(codec, STA32X_CONFC, 0xc2);
	snd_soc_write(codec, STA32X_CONFE, 0xc2);
	snd_soc_write(codec, STA32X_CONFF, 0x5c);
	snd_soc_write(codec, STA32X_MMUTE, 0x10);
	snd_soc_write(codec, STA32X_AUTO1, 0x60);
	snd_soc_write(codec, STA32X_AUTO3, 0x00);
	snd_soc_write(codec, STA32X_C3CFG, 0x40);
	regcache_cache_only(sta32x->regmap, false);

	/* set thermal warning adjustment and recovery */
	if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
		thermal |= STA32X_CONFA_TWAB;
	if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE))
		thermal |= STA32X_CONFA_TWRB;
	snd_soc_update_bits(codec, STA32X_CONFA,
			    STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
			    thermal);

	/* select output configuration  */
	snd_soc_update_bits(codec, STA32X_CONFF,
			    STA32X_CONFF_OCFG_MASK,
			    sta32x->pdata->output_conf
			    << STA32X_CONFF_OCFG_SHIFT);

	/* channel to output mapping */
	snd_soc_update_bits(codec, STA32X_C1CFG,
			    STA32X_CxCFG_OM_MASK,
			    sta32x->pdata->ch1_output_mapping
			    << STA32X_CxCFG_OM_SHIFT);
	snd_soc_update_bits(codec, STA32X_C2CFG,
			    STA32X_CxCFG_OM_MASK,
			    sta32x->pdata->ch2_output_mapping
			    << STA32X_CxCFG_OM_SHIFT);
	snd_soc_update_bits(codec, STA32X_C3CFG,
			    STA32X_CxCFG_OM_MASK,
			    sta32x->pdata->ch3_output_mapping
			    << STA32X_CxCFG_OM_SHIFT);

	/* initialize coefficient shadow RAM with reset values */
	for (i = 4; i <= 49; i += 5)
		sta32x->coef_shadow[i] = 0x400000;
	for (i = 50; i <= 54; i++)
		sta32x->coef_shadow[i] = 0x7fffff;
	sta32x->coef_shadow[55] = 0x5a9df7;
	sta32x->coef_shadow[56] = 0x7fffff;
	sta32x->coef_shadow[59] = 0x7fffff;
	sta32x->coef_shadow[60] = 0x400000;
	sta32x->coef_shadow[61] = 0x400000;

	if (sta32x->pdata->needs_esd_watchdog)
		INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);

	sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	/* Bias level configuration will have done an extra enable */
	regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);

	return 0;
}
Ejemplo n.º 28
0
static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec)
{
	snd_soc_write(codec, SN95031_BTNCTRL2, 0x00);
}
Ejemplo n.º 29
0
/**
 * cs4270_hw_params - program the CS4270 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 cs4270_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 cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
	int ret;
	unsigned int i;
	unsigned int rate;
	unsigned int ratio;
	int reg;

	/* Figure out which MCLK/LRCK ratio to use */

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

	for (i = 0; i < NUM_MCLK_RATIOS; i++) {
		if (cs4270_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;
	}

	/* Set the sample rate */

	reg = snd_soc_read(codec, CS4270_MODE);
	reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK);
	reg |= cs4270_mode_ratios[i].mclk;

	if (cs4270->slave_mode)
		reg |= CS4270_MODE_SLAVE;
	else
		reg |= cs4270_mode_ratios[i].speed_mode;

	ret = snd_soc_write(codec, CS4270_MODE, reg);
	if (ret < 0) {
		dev_err(codec->dev, "i2c write failed\n");
		return ret;
	}

	/* Set the DAI format */

	reg = snd_soc_read(codec, CS4270_FORMAT);
	reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK);

	switch (cs4270->mode) {
	case SND_SOC_DAIFMT_I2S:
		reg |= CS4270_FORMAT_DAC_I2S | CS4270_FORMAT_ADC_I2S;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ;
		break;
	default:
		dev_err(codec->dev, "unknown dai format\n");
		return -EINVAL;
	}

	ret = snd_soc_write(codec, CS4270_FORMAT, reg);
	if (ret < 0) {
		dev_err(codec->dev, "i2c write failed\n");
		return ret;
	}

	return ret;
}
Ejemplo n.º 30
0
/*
 * The headphone output supports special anti-pop sequences giving
 * silent power up and power down.
 */
static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
			   struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
	u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0);
	u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1);
	u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
	u16 dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
	int timeout = 500;

	if (event & SND_SOC_DAPM_POST_PMU) {
		/* Make sure the output is shorted */
		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);

		/* Enable the charge pump */
		cp_reg |= WM8961_CP_ENA;
		snd_soc_write(codec, WM8961_CHARGE_PUMP_1, cp_reg);
		mdelay(5);

		/* Enable the PGA */
		pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA;
		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);

		/* Enable the amplifier */
		hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA;
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);

		/* Second stage enable */
		hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY;
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);

		/* Enable the DC servo & trigger startup */
		dcs_reg |=
			WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_TRIG_STARTUP_HPR |
			WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL;
		dev_dbg(codec->dev, "Enabling DC servo\n");

		snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);
		do {
			msleep(1);
			dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
		} while (--timeout &&
			 dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
				WM8961_DCS_TRIG_STARTUP_HPL));
		if (dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
			       WM8961_DCS_TRIG_STARTUP_HPL))
			dev_err(codec->dev, "DC servo timed out\n");
		else
			dev_dbg(codec->dev, "DC servo startup complete\n");

		/* Enable the output stage */
		hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP;
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);

		/* Remove the short on the output stage */
		hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT;
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
	}

	if (event & SND_SOC_DAPM_PRE_PMD) {
		/* Short the output */
		hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);

		/* Disable the output stage */
		hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP);
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);

		/* Disable DC offset cancellation */
		dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR |
			     WM8961_DCS_ENA_CHAN_HPL);
		snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);

		/* Finish up */
		hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA |
			    WM8961_HPL_ENA_DLY | WM8961_HPL_ENA);
		snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);

		/* Disable the PGA */
		pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA);
		snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);

		/* Disable the charge pump */
		dev_dbg(codec->dev, "Disabling charge pump\n");
		snd_soc_write(codec, WM8961_CHARGE_PUMP_1,
			     cp_reg & ~WM8961_CP_ENA);
	}

	return 0;
}