Merge branch 'topic/rt5645' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-intel
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 27141e2..debf16c 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -31,6 +31,7 @@
 #include "rt5645.h"
 
 #define RT5645_DEVICE_ID 0x6308
+#define RT5650_DEVICE_ID 0x6419
 
 #define RT5645_PR_RANGE_BASE (0xff + 1)
 #define RT5645_PR_SPACING 0x100
@@ -59,6 +60,10 @@
 };
 #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
 
+static const struct reg_default rt5650_init_list[] = {
+	{0xf6,	0x0100},
+};
+
 static const struct reg_default rt5645_reg[] = {
 	{ 0x00, 0x0000 },
 	{ 0x01, 0xc8c8 },
@@ -86,6 +91,7 @@
 	{ 0x2a, 0x5656 },
 	{ 0x2b, 0x5454 },
 	{ 0x2c, 0xaaa0 },
+	{ 0x2d, 0x0000 },
 	{ 0x2f, 0x1002 },
 	{ 0x31, 0x5000 },
 	{ 0x32, 0x0000 },
@@ -193,6 +199,8 @@
 	{ 0xdb, 0x0003 },
 	{ 0xdc, 0x0049 },
 	{ 0xdd, 0x001b },
+	{ 0xdf, 0x0008 },
+	{ 0xe0, 0x4000 },
 	{ 0xe6, 0x8000 },
 	{ 0xe7, 0x0200 },
 	{ 0xec, 0xb300 },
@@ -242,6 +250,7 @@
 	case RT5645_IRQ_CTRL3:
 	case RT5645_INT_IRQ_ST:
 	case RT5645_IL_CMD:
+	case RT5650_4BTN_IL_CMD1:
 	case RT5645_VENDOR_ID:
 	case RT5645_VENDOR_ID1:
 	case RT5645_VENDOR_ID2:
@@ -287,6 +296,7 @@
 	case RT5645_STO_DAC_MIXER:
 	case RT5645_MONO_DAC_MIXER:
 	case RT5645_DIG_MIXER:
+	case RT5650_A_DAC_SOUR:
 	case RT5645_DIG_INF1_DATA:
 	case RT5645_PDM_OUT_CTRL:
 	case RT5645_REC_L1_MIXER:
@@ -378,6 +388,8 @@
 	case RT5645_IL_CMD:
 	case RT5645_IL_CMD2:
 	case RT5645_IL_CMD3:
+	case RT5650_4BTN_IL_CMD1:
+	case RT5650_4BTN_IL_CMD2:
 	case RT5645_DRC1_HL_CTRL1:
 	case RT5645_DRC2_HL_CTRL1:
 	case RT5645_ADC_MONO_HP_CTRL1:
@@ -601,6 +613,87 @@
 
 }
 
+/**
+ * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+		unsigned int filter_mask, unsigned int clk_src)
+{
+	unsigned int asrc2_mask = 0;
+	unsigned int asrc2_value = 0;
+	unsigned int asrc3_mask = 0;
+	unsigned int asrc3_value = 0;
+
+	switch (clk_src) {
+	case RT5645_CLK_SEL_SYS:
+	case RT5645_CLK_SEL_I2S1_ASRC:
+	case RT5645_CLK_SEL_I2S2_ASRC:
+	case RT5645_CLK_SEL_SYS2:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (filter_mask & RT5645_DA_STEREO_FILTER) {
+		asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK)
+			| (clk_src << RT5645_DA_STO_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_DA_MONO_L_FILTER) {
+		asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK)
+			| (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_DA_MONO_R_FILTER) {
+		asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK)
+			| (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_AD_STEREO_FILTER) {
+		asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK;
+		asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK)
+			| (clk_src << RT5645_AD_STO1_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_AD_MONO_L_FILTER) {
+		asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK)
+			| (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT);
+	}
+
+	if (filter_mask & RT5645_AD_MONO_R_FILTER)  {
+		asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK;
+		asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK)
+			| (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT);
+	}
+
+	if (asrc2_mask)
+		snd_soc_update_bits(codec, RT5645_ASRC_2,
+			asrc2_mask, asrc2_value);
+
+	if (asrc3_mask)
+		snd_soc_update_bits(codec, RT5645_ASRC_3,
+			asrc3_mask, asrc3_value);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src);
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
 	SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
@@ -1007,6 +1100,44 @@
 static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
 	SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
 
+/* MX-2d [3] [2] */
+static const char * const rt5650_a_dac1_src[] = {
+	"DAC1", "Stereo DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_l_mux =
+	SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_r_mux =
+	SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum);
+
+/* MX-2d [1] [0] */
+static const char * const rt5650_a_dac2_src[] = {
+	"Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_l_mux =
+	SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR,
+	RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_r_mux =
+	SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum);
+
 /* MX-2F [13:12] */
 static const char * const rt5645_if2_adc_in_src[] = {
 	"IF_ADC1", "IF_ADC2", "VAD_ADC"
@@ -1151,11 +1282,16 @@
 	case SND_SOC_DAPM_POST_PMU:
 		hp_amp_power(codec, 1);
 		/* headphone unmute sequence */
-		snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK |
-			RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK,
-			(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
-			(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-			(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+		if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+			snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+		} else {
+			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+				RT5645_CP_FQ3_MASK,
+				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
+				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+				(RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+		}
 		regmap_write(rt5645->regmap,
 			RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
 		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1175,12 +1311,16 @@
 
 	case SND_SOC_DAPM_PRE_PMD:
 		/* headphone mute sequence */
-		snd_soc_update_bits(codec, RT5645_DEPOP_M3,
-			RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
-			RT5645_CP_FQ3_MASK,
-			(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
-			(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-			(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+		if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+			snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+		} else {
+			snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+				RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+				RT5645_CP_FQ3_MASK,
+				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
+				(RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+				(RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+		}
 		regmap_write(rt5645->regmap,
 			RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
 		snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1574,6 +1714,17 @@
 	SND_SOC_DAPM_OUTPUT("SPOR"),
 };
 
+static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
+	SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac1_l_mux),
+	SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac1_r_mux),
+	SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac2_l_mux),
+	SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM,
+		0, 0, &rt5650_a_dac2_r_mux),
+};
+
 static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
 	{ "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
 	{ "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
@@ -1779,13 +1930,9 @@
 	{ "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
 	{ "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
 
-	{ "DAC L1", NULL, "Stereo DAC MIXL" },
 	{ "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
-	{ "DAC R1", NULL, "Stereo DAC MIXR" },
 	{ "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
-	{ "DAC L2", NULL, "Mono DAC MIXL" },
 	{ "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
-	{ "DAC R2", NULL, "Mono DAC MIXR" },
 	{ "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
 
 	{ "SPK MIXL", "BST1 Switch", "BST1" },
@@ -1874,6 +2021,30 @@
 	{ "SPOR", NULL, "SPK amp" },
 };
 
+static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
+	{ "A DAC1 L Mux", "DAC1",  "DAC1 MIXL"},
+	{ "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+	{ "A DAC1 R Mux", "DAC1",  "DAC1 MIXR"},
+	{ "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+
+	{ "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+	{ "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"},
+	{ "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+	{ "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+	{ "DAC L1", NULL, "A DAC1 L Mux" },
+	{ "DAC R1", NULL, "A DAC1 R Mux" },
+	{ "DAC L2", NULL, "A DAC2 L Mux" },
+	{ "DAC R2", NULL, "A DAC2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
+	{ "DAC L1", NULL, "Stereo DAC MIXL" },
+	{ "DAC R1", NULL, "Stereo DAC MIXR" },
+	{ "DAC L2", NULL, "Mono DAC MIXL" },
+	{ "DAC R2", NULL, "Mono DAC MIXR" },
+};
+
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -2293,6 +2464,22 @@
 
 	rt5645->codec = codec;
 
+	switch (rt5645->codec_type) {
+	case CODEC_TYPE_RT5645:
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5645_specific_dapm_routes,
+			ARRAY_SIZE(rt5645_specific_dapm_routes));
+		break;
+	case CODEC_TYPE_RT5650:
+		snd_soc_dapm_new_controls(&codec->dapm,
+			rt5650_specific_dapm_widgets,
+			ARRAY_SIZE(rt5650_specific_dapm_widgets));
+		snd_soc_dapm_add_routes(&codec->dapm,
+			rt5650_specific_dapm_routes,
+			ARRAY_SIZE(rt5650_specific_dapm_routes));
+		break;
+	}
+
 	rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
@@ -2424,6 +2611,7 @@
 
 static const struct i2c_device_id rt5645_i2c_id[] = {
 	{ "rt5645", 0 },
+	{ "rt5650", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
@@ -2456,9 +2644,18 @@
 	}
 
 	regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
-	if (val != RT5645_DEVICE_ID) {
+
+	switch (val) {
+	case RT5645_DEVICE_ID:
+		rt5645->codec_type = CODEC_TYPE_RT5645;
+		break;
+	case RT5650_DEVICE_ID:
+		rt5645->codec_type = CODEC_TYPE_RT5650;
+		break;
+	default:
 		dev_err(&i2c->dev,
-			"Device with ID register %x is not rt5645\n", val);
+			"Device with ID register %x is not rt5645 or rt5650\n",
+			val);
 		return -ENODEV;
 	}
 
@@ -2469,6 +2666,14 @@
 	if (ret != 0)
 		dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
+	if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+		ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+				    ARRAY_SIZE(rt5650_init_list));
+		if (ret != 0)
+			dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
+					   ret);
+	}
+
 	if (rt5645->pdata.in2_diff)
 		regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
 					RT5645_IN_DF2, RT5645_IN_DF2);
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index a815e36..dbfd98c 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -47,6 +47,7 @@
 #define RT5645_STO_DAC_MIXER			0x2a
 #define RT5645_MONO_DAC_MIXER			0x2b
 #define RT5645_DIG_MIXER			0x2c
+#define RT5650_A_DAC_SOUR			0x2d
 #define RT5645_DIG_INF1_DATA			0x2f
 /* Mixer - PDM */
 #define RT5645_PDM_OUT_CTRL			0x31
@@ -150,6 +151,8 @@
 #define RT5645_IL_CMD				0xdb
 #define RT5645_IL_CMD2				0xdc
 #define RT5645_IL_CMD3				0xdd
+#define RT5650_4BTN_IL_CMD1			0xdf
+#define RT5650_4BTN_IL_CMD2			0xe0
 #define RT5645_DRC1_HL_CTRL1			0xe7
 #define RT5645_DRC2_HL_CTRL1			0xe9
 #define RT5645_MUTI_DRC_CTRL1			0xea
@@ -472,6 +475,12 @@
 #define RT5645_DAC_L2_DAC_R_VOL_MASK		(0x1 << 4)
 #define RT5645_DAC_L2_DAC_R_VOL_SFT		4
 
+/* Analog DAC1/2 Input Source Control (0x2d) */
+#define RT5650_A_DAC1_L_IN_SFT			3
+#define RT5650_A_DAC1_R_IN_SFT			2
+#define RT5650_A_DAC2_L_IN_SFT			1
+#define RT5650_A_DAC2_R_IN_SFT			0
+
 /* Digital Interface Data Control (0x2f) */
 #define RT5645_IF1_ADC2_IN_SEL			(0x1 << 15)
 #define RT5645_IF1_ADC2_IN_SFT			15
@@ -1111,50 +1120,27 @@
 #define RT5645_DMIC_2_M_NOR			(0x0 << 8)
 #define RT5645_DMIC_2_M_ASYN			(0x1 << 8)
 
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5645_CLK_SEL_SYS			(0x0)
+#define RT5645_CLK_SEL_I2S1_ASRC		(0x1)
+#define RT5645_CLK_SEL_I2S2_ASRC		(0x2)
+#define RT5645_CLK_SEL_SYS2			(0x5)
+
 /* ASRC Control 2 (0x84) */
-#define RT5645_MDA_L_M_MASK			(0x1 << 15)
-#define RT5645_MDA_L_M_SFT			15
-#define RT5645_MDA_L_M_NOR			(0x0 << 15)
-#define RT5645_MDA_L_M_ASYN			(0x1 << 15)
-#define RT5645_MDA_R_M_MASK			(0x1 << 14)
-#define RT5645_MDA_R_M_SFT			14
-#define RT5645_MDA_R_M_NOR			(0x0 << 14)
-#define RT5645_MDA_R_M_ASYN			(0x1 << 14)
-#define RT5645_MAD_L_M_MASK			(0x1 << 13)
-#define RT5645_MAD_L_M_SFT			13
-#define RT5645_MAD_L_M_NOR			(0x0 << 13)
-#define RT5645_MAD_L_M_ASYN			(0x1 << 13)
-#define RT5645_MAD_R_M_MASK			(0x1 << 12)
-#define RT5645_MAD_R_M_SFT			12
-#define RT5645_MAD_R_M_NOR			(0x0 << 12)
-#define RT5645_MAD_R_M_ASYN			(0x1 << 12)
-#define RT5645_ADC_M_MASK			(0x1 << 11)
-#define RT5645_ADC_M_SFT			11
-#define RT5645_ADC_M_NOR			(0x0 << 11)
-#define RT5645_ADC_M_ASYN			(0x1 << 11)
-#define RT5645_STO_DAC_M_MASK			(0x1 << 5)
-#define RT5645_STO_DAC_M_SFT			5
-#define RT5645_STO_DAC_M_NOR			(0x0 << 5)
-#define RT5645_STO_DAC_M_ASYN			(0x1 << 5)
-#define RT5645_I2S1_R_D_MASK			(0x1 << 4)
-#define RT5645_I2S1_R_D_SFT			4
-#define RT5645_I2S1_R_D_DIS			(0x0 << 4)
-#define RT5645_I2S1_R_D_EN			(0x1 << 4)
-#define RT5645_I2S2_R_D_MASK			(0x1 << 3)
-#define RT5645_I2S2_R_D_SFT			3
-#define RT5645_I2S2_R_D_DIS			(0x0 << 3)
-#define RT5645_I2S2_R_D_EN			(0x1 << 3)
-#define RT5645_PRE_SCLK_MASK			(0x3)
-#define RT5645_PRE_SCLK_SFT			0
-#define RT5645_PRE_SCLK_512			(0x0)
-#define RT5645_PRE_SCLK_1024			(0x1)
-#define RT5645_PRE_SCLK_2048			(0x2)
+#define RT5645_DA_STO_CLK_SEL_MASK		(0xf << 12)
+#define RT5645_DA_STO_CLK_SEL_SFT		12
+#define RT5645_DA_MONOL_CLK_SEL_MASK		(0xf << 8)
+#define RT5645_DA_MONOL_CLK_SEL_SFT		8
+#define RT5645_DA_MONOR_CLK_SEL_MASK		(0xf << 4)
+#define RT5645_DA_MONOR_CLK_SEL_SFT		4
+#define RT5645_AD_STO1_CLK_SEL_MASK		(0xf << 0)
+#define RT5645_AD_STO1_CLK_SEL_SFT		0
 
 /* ASRC Control 3 (0x85) */
-#define RT5645_I2S1_RATE_MASK			(0xf << 12)
-#define RT5645_I2S1_RATE_SFT			12
-#define RT5645_I2S2_RATE_MASK			(0xf << 8)
-#define RT5645_I2S2_RATE_SFT			8
+#define RT5645_AD_MONOL_CLK_SEL_MASK		(0xf << 4)
+#define RT5645_AD_MONOL_CLK_SEL_SFT		4
+#define RT5645_AD_MONOR_CLK_SEL_MASK		(0xf << 0)
+#define RT5645_AD_MONOR_CLK_SEL_SFT		0
 
 /* ASRC Control 4 (0x89) */
 #define RT5645_I2S1_PD_MASK			(0x7 << 12)
@@ -2175,6 +2161,24 @@
 	RT5645_DMIC_DATA_GPIO11,
 };
 
+enum {
+	CODEC_TYPE_RT5645,
+	CODEC_TYPE_RT5650,
+};
+
+/* filter mask */
+enum {
+	RT5645_DA_STEREO_FILTER = 0x1,
+	RT5645_DA_MONO_L_FILTER = (0x1 << 1),
+	RT5645_DA_MONO_R_FILTER = (0x1 << 2),
+	RT5645_AD_STEREO_FILTER = (0x1 << 3),
+	RT5645_AD_MONO_L_FILTER = (0x1 << 4),
+	RT5645_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+		unsigned int filter_mask, unsigned int clk_src);
+
 struct rt5645_priv {
 	struct snd_soc_codec *codec;
 	struct rt5645_platform_data pdata;
@@ -2184,6 +2188,7 @@
 	struct snd_soc_jack *mic_jack;
 	struct delayed_work jack_detect_work;
 
+	int codec_type;
 	int sysclk;
 	int sysclk_src;
 	int lrck[RT5645_AIFS];