Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8c47ba3 authored by Mengdong Lin's avatar Mengdong Lin Committed by Mark Brown
Browse files

ASoC: rt5670: add API to select ASRC clock source



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: default avatarBard Liao <bardliao@realtek.com>
Signed-off-by: default avatarMengdong Lin <mengdong.lin@intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent b7ed9f1d
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
@@ -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,
+15 −0
Original line number Diff line number Diff line
@@ -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;