return 0;
}
+
+/**
+ * rt5670_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 RT5670 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 rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src)
+{
+ unsigned int asrc2_mask = 0, asrc2_value = 0;
+ unsigned int asrc3_mask = 0, asrc3_value = 0;
+
+ if (clk_src > RT5670_CLK_SEL_SYS3)
+ return -EINVAL;
+
+ if (filter_mask & RT5670_DA_STEREO_FILTER) {
+ asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK)
+ | (clk_src << RT5670_DA_STO_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_DA_MONO_L_FILTER) {
+ asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5670_DA_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_DA_MONO_R_FILTER) {
+ asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5670_DA_MONOR_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_AD_STEREO_FILTER) {
+ asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK;
+ asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK)
+ | (clk_src << RT5670_AD_STO1_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_AD_MONO_L_FILTER) {
+ asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK)
+ | (clk_src << RT5670_AD_MONOL_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_AD_MONO_R_FILTER) {
+ asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK)
+ | (clk_src << RT5670_AD_MONOR_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_UP_RATE_FILTER) {
+ asrc3_mask |= RT5670_UP_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK)
+ | (clk_src << RT5670_UP_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5670_DOWN_RATE_FILTER) {
+ asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK;
+ asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK)
+ | (clk_src << RT5670_DOWN_CLK_SEL_SFT);
+ }
+
+ if (asrc2_mask)
+ snd_soc_update_bits(codec, RT5670_ASRC_2,
+ asrc2_mask, asrc2_value);
+
+ if (asrc3_mask)
+ snd_soc_update_bits(codec, RT5670_ASRC_3,
+ asrc3_mask, asrc3_value);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src);
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
RT5670_DMIC_DATA_GPIO5,
};
+/* filter mask */
+enum {
+ RT5670_DA_STEREO_FILTER = 0x1,
+ RT5670_DA_MONO_L_FILTER = (0x1 << 1),
+ RT5670_DA_MONO_R_FILTER = (0x1 << 2),
+ RT5670_AD_STEREO_FILTER = (0x1 << 3),
+ RT5670_AD_MONO_L_FILTER = (0x1 << 4),
+ RT5670_AD_MONO_R_FILTER = (0x1 << 5),
+ RT5670_UP_RATE_FILTER = (0x1 << 6),
+ RT5670_DOWN_RATE_FILTER = (0x1 << 7),
+};
+
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+ unsigned int filter_mask, unsigned int clk_src);
+
struct rt5670_priv {
struct snd_soc_codec *codec;
struct rt5670_platform_data pdata;