Merge remote-tracking branches 'asoc/topic/rt5665', 'asoc/topic/rt5670', 'asoc/topic...
[sfrench/cifs-2.6.git] / sound / soc / codecs / rt5665.c
index 02493bbb07e14b4b98b368482ffe9ed72a4769d1..f05d362c4e23b859ccc823502751a91d9417c023 100644 (file)
@@ -1381,6 +1381,16 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
        mutex_unlock(&rt5665->calibrate_mutex);
 }
 
+static const char * const rt5665_clk_sync[] = {
+       "I2S1_1", "I2S1_2", "I2S2", "I2S3", "IF2 Slave", "IF3 Slave"
+};
+
+static const struct soc_enum rt5665_enum[] = {
+       SOC_ENUM_SINGLE(RT5665_I2S1_SDP, 11, 5, rt5665_clk_sync),
+       SOC_ENUM_SINGLE(RT5665_I2S2_SDP, 11, 5, rt5665_clk_sync),
+       SOC_ENUM_SINGLE(RT5665_I2S3_SDP, 11, 5, rt5665_clk_sync),
+};
+
 static const struct snd_kcontrol_new rt5665_snd_controls[] = {
        /* Headphone Output Volume */
        SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN,
@@ -1392,6 +1402,9 @@ static const struct snd_kcontrol_new rt5665_snd_controls[] = {
                RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw,
                rt5665_mono_vol_put, mono_vol_tlv),
 
+       SOC_SINGLE_TLV("MONOVOL Playback Volume", RT5665_MONO_OUT,
+               RT5665_L_VOL_SFT, 39, 1, out_vol_tlv),
+
        /* Output Volume */
        SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT,
                RT5665_R_VOL_SFT, 39, 1, out_vol_tlv),
@@ -1446,6 +1459,11 @@ static const struct snd_kcontrol_new rt5665_snd_controls[] = {
        SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST,
                RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT,
                3, 0, adc_bst_tlv),
+
+       /* I2S3 CLK Source */
+       SOC_ENUM("I2S1 Master Clk Sel", rt5665_enum[0]),
+       SOC_ENUM("I2S2 Master Clk Sel", rt5665_enum[1]),
+       SOC_ENUM("I2S3 Master Clk Sel", rt5665_enum[2]),
 };
 
 /**
@@ -4098,9 +4116,12 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
        rt5665->lrck[dai->id] = params_rate(params);
        pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]);
        if (pre_div < 0) {
-               dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
-                       rt5665->lrck[dai->id], dai->id);
-               return -EINVAL;
+               dev_warn(codec->dev, "Force using PLL");
+               snd_soc_codec_set_pll(codec, 0, RT5665_PLL1_S_MCLK,
+                       rt5665->sysclk, rt5665->lrck[dai->id] * 512);
+               snd_soc_codec_set_sysclk(codec, RT5665_SCLK_S_PLL1, 0,
+                       rt5665->lrck[dai->id] * 512, 0);
+               pre_div = 1;
        }
        frame_size = snd_soc_params_to_frame_size(params);
        if (frame_size < 0) {
@@ -4183,6 +4204,15 @@ static int rt5665_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
+       if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
+               snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+                       RT5665_I2S2_M_PD_MASK, pre_div << RT5665_I2S2_M_PD_SFT);
+       }
+       if (rt5665->master[RT5665_AIF3]) {
+               snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+                       RT5665_I2S3_M_PD_MASK, pre_div << RT5665_I2S3_M_PD_SFT);
+       }
+
        return 0;
 }
 
@@ -4259,7 +4289,7 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
                                   int source, unsigned int freq, int dir)
 {
        struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec);
-       unsigned int reg_val = 0;
+       unsigned int reg_val = 0, src = 0;
 
        if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src)
                return 0;
@@ -4267,12 +4297,15 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
        switch (clk_id) {
        case RT5665_SCLK_S_MCLK:
                reg_val |= RT5665_SCLK_SRC_MCLK;
+               src = RT5665_CLK_SRC_MCLK;
                break;
        case RT5665_SCLK_S_PLL1:
                reg_val |= RT5665_SCLK_SRC_PLL1;
+               src = RT5665_CLK_SRC_PLL1;
                break;
        case RT5665_SCLK_S_RCCLK:
                reg_val |= RT5665_SCLK_SRC_RCCLK;
+               src = RT5665_CLK_SRC_RCCLK;
                break;
        default:
                dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
@@ -4280,6 +4313,16 @@ static int rt5665_set_codec_sysclk(struct snd_soc_codec *codec, int clk_id,
        }
        snd_soc_update_bits(codec, RT5665_GLB_CLK,
                RT5665_SCLK_SRC_MASK, reg_val);
+
+       if (rt5665->master[RT5665_AIF2_1] || rt5665->master[RT5665_AIF2_2]) {
+               snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+                       RT5665_I2S2_SRC_MASK, src << RT5665_I2S2_SRC_SFT);
+       }
+       if (rt5665->master[RT5665_AIF3]) {
+               snd_soc_update_bits(codec, RT5665_I2S_M_CLK_CTRL_1,
+                       RT5665_I2S3_SRC_MASK, src << RT5665_I2S3_SRC_SFT);
+       }
+
        rt5665->sysclk = freq;
        rt5665->sysclk_src = clk_id;
 
@@ -4927,7 +4970,7 @@ MODULE_DEVICE_TABLE(of, rt5665_of_match);
 #endif
 
 #ifdef CONFIG_ACPI
-static struct acpi_device_id rt5665_acpi_match[] = {
+static const struct acpi_device_id rt5665_acpi_match[] = {
        {"10EC5665", 0,},
        {"10EC5666", 0,},
        {"10EC5668", 0,},