OSDN Git Service

ASoC: rt5670: add API to select ASRC clock source
authorMengdong Lin <mengdong.lin@intel.com>
Wed, 7 Jan 2015 02:19:12 +0000 (10:19 +0800)
committerMark Brown <broonie@kernel.org>
Wed, 7 Jan 2015 17:40:01 +0000 (17:40 +0000)
When codec is in slave mode, ASRC can suppress noise for asynchronous
MCLK and LRCLK or special I2S format. This patch defines an API to select
the clock source for specified filters.  And the codec driver will turn on ASRC
for these filters if ASRC is selected as their clock source.

Signed-off-by: Bard Liao <bardliao@realtek.com>
Signed-off-by: Mengdong Lin <mengdong.lin@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5670.h

index 0a027bc..0632b74 100644 (file)
@@ -590,6 +590,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
        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,
index ec38d8f..21f8e18 100644 (file)
@@ -1966,6 +1966,21 @@ enum {
        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;