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; }
/** * 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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); }
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); }
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; }
/* 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; }
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; }
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; }
static int wm8955_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, WM8955_RESET, 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); }
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; }
static int wm8985_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0); }
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; }
/* 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)); }
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; }
static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec) { snd_soc_write(codec, SN95031_BTNCTRL2, 0x00); }
/** * 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; }
/* * 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; }