Merge remote-tracking branches 'asoc/topic/mc13783', 'asoc/topic/msm8916', 'asoc...
[linux-2.6-block.git] / sound / soc / codecs / nau8540.c
index f9c9933acffb60ee50c9c7ec062e3cc278bedf60..b08fb7e243c3ce3ca75d08a78f79a4e7ce6b8e4f 100644 (file)
@@ -233,6 +233,41 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new digital_ch1_mux =
        SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum);
 
+static int adc_power_control(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               msleep(300);
+               /* DO12 and DO34 pad output enable */
+               regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+                       NAU8540_I2S_DO12_TRI, 0);
+               regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+                       NAU8540_I2S_DO34_TRI, 0);
+       } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+                       NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI);
+               regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+                       NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
+       }
+       return 0;
+}
+
+static int aiftx_power_control(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+       if (SND_SOC_DAPM_EVENT_OFF(event)) {
+               regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0001);
+               regmap_write(nau8540->regmap, NAU8540_REG_RST, 0x0000);
+       }
+       return 0;
+}
+
 static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0),
@@ -247,14 +282,18 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0),
        SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0),
 
-       SND_SOC_DAPM_ADC("ADC1", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 0, 0),
-       SND_SOC_DAPM_ADC("ADC2", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 1, 0),
-       SND_SOC_DAPM_ADC("ADC3", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 2, 0),
-       SND_SOC_DAPM_ADC("ADC4", NULL,
-               NAU8540_REG_POWER_MANAGEMENT, 3, 0),
+       SND_SOC_DAPM_ADC_E("ADC1", NULL,
+               NAU8540_REG_POWER_MANAGEMENT, 0, 0, adc_power_control,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_ADC_E("ADC2", NULL,
+               NAU8540_REG_POWER_MANAGEMENT, 1, 0, adc_power_control,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_ADC_E("ADC3", NULL,
+               NAU8540_REG_POWER_MANAGEMENT, 2, 0, adc_power_control,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_ADC_E("ADC4", NULL,
+               NAU8540_REG_POWER_MANAGEMENT, 3, 0, adc_power_control,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
        SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0),
@@ -270,7 +309,8 @@ static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("Digital CH1 Mux",
                SND_SOC_NOPM, 0, 0, &digital_ch1_mux),
 
-       SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT_E("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0,
+               aiftx_power_control, SND_SOC_DAPM_POST_PMD),
 };
 
 static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
@@ -575,7 +615,8 @@ static void nau8540_fll_apply(struct regmap *regmap,
                NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK,
                NAU8540_CLK_SRC_MCLK | fll_param->mclk_src);
        regmap_update_bits(regmap, NAU8540_REG_FLL1,
-               NAU8540_FLL_RATIO_MASK, fll_param->ratio);
+               NAU8540_FLL_RATIO_MASK | NAU8540_ICTRL_LATCH_MASK,
+               fll_param->ratio | (0x6 << NAU8540_ICTRL_LATCH_SFT));
        /* FLL 16-bit fractional input */
        regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac);
        /* FLL 10-bit integer input */
@@ -596,13 +637,14 @@ static void nau8540_fll_apply(struct regmap *regmap,
                        NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
                        NAU8540_FLL_FTR_SW_FILTER);
                regmap_update_bits(regmap, NAU8540_REG_FLL6,
-                       NAU8540_SDM_EN, NAU8540_SDM_EN);
+                       NAU8540_SDM_EN | NAU8540_CUTOFF500,
+                       NAU8540_SDM_EN | NAU8540_CUTOFF500);
        } else {
                regmap_update_bits(regmap, NAU8540_REG_FLL5,
                        NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
                        NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU);
-               regmap_update_bits(regmap,
-                       NAU8540_REG_FLL6, NAU8540_SDM_EN, 0);
+               regmap_update_bits(regmap, NAU8540_REG_FLL6,
+                       NAU8540_SDM_EN | NAU8540_CUTOFF500, 0);
        }
 }
 
@@ -617,17 +659,22 @@ static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
        switch (pll_id) {
        case NAU8540_CLK_FLL_MCLK:
                regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
-                       NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_MCLK);
+                       NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+                       NAU8540_FLL_CLK_SRC_MCLK | 0);
                break;
 
        case NAU8540_CLK_FLL_BLK:
                regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
-                       NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK);
+                       NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+                       NAU8540_FLL_CLK_SRC_BLK |
+                       (0xf << NAU8540_GAIN_ERR_SFT));
                break;
 
        case NAU8540_CLK_FLL_FS:
                regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
-                       NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS);
+                       NAU8540_FLL_CLK_SRC_MASK | NAU8540_GAIN_ERR_MASK,
+                       NAU8540_FLL_CLK_SRC_FS |
+                       (0xf << NAU8540_GAIN_ERR_SFT));
                break;
 
        default:
@@ -710,9 +757,24 @@ static void nau8540_init_regs(struct nau8540 *nau8540)
        regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
                NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN,
                NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN);
-       /* ADC OSR selection, CLK_ADC = Fs * OSR */
+       /* ADC OSR selection, CLK_ADC = Fs * OSR;
+        * Channel time alignment enable.
+        */
        regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE,
-               NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64);
+               NAU8540_CH_SYNC | NAU8540_ADC_OSR_MASK,
+               NAU8540_CH_SYNC | NAU8540_ADC_OSR_64);
+       /* PGA input mode selection */
+       regmap_update_bits(regmap, NAU8540_REG_FEPGA1,
+               NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT,
+               NAU8540_FEPGA1_MODCH2_SHT | NAU8540_FEPGA1_MODCH1_SHT);
+       regmap_update_bits(regmap, NAU8540_REG_FEPGA2,
+               NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT,
+               NAU8540_FEPGA2_MODCH4_SHT | NAU8540_FEPGA2_MODCH3_SHT);
+       /* DO12 and DO34 pad output disable */
+       regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL1,
+               NAU8540_I2S_DO12_TRI, NAU8540_I2S_DO12_TRI);
+       regmap_update_bits(regmap, NAU8540_REG_PCM_CTRL2,
+               NAU8540_I2S_DO34_TRI, NAU8540_I2S_DO34_TRI);
 }
 
 static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec)