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

Commit bee3e020 authored by Jack Yu's avatar Jack Yu Committed by Mark Brown
Browse files

ASoC: rt5640: add ASRC support

parent 8005c49d
Loading
Loading
Loading
Loading
+102 −0
Original line number Original line Diff line number Diff line
@@ -488,6 +488,18 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
		return 0;
		return 0;
}
}


static int is_using_asrc(struct snd_soc_dapm_widget *source,
			 struct snd_soc_dapm_widget *sink)
{
	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);

	if (!rt5640->asrc_en)
		return 0;

	return 1;
}

/* Digital Mixer */
/* Digital Mixer */
static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = {
	SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
	SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER,
@@ -1059,6 +1071,20 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
	SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
	SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
			RT5640_PWR_PLL_BIT, 0, NULL, 0),
			RT5640_PWR_PLL_BIT, 0, NULL, 0),

	/* ASRC */
	SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1,
			 15, 0, NULL, 0),
	SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1,
			 12, 0, NULL, 0),
	SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1,
			 11, 0, NULL, 0),
	SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1,
			 9, 0, NULL, 0),
	SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1,
			 8, 0, NULL, 0),


	/* Input Side */
	/* Input Side */
	/* micbias */
	/* micbias */
	SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
	SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1,
@@ -1319,6 +1345,12 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = {
};
};


static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
	{ "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc },
	{ "I2S2", NULL, "I2S2 ASRC", is_using_asrc },
	{ "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc },
	{ "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc },
	{ "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc },

	{"IN1P", NULL, "LDO2"},
	{"IN1P", NULL, "LDO2"},
	{"IN2P", NULL, "LDO2"},
	{"IN2P", NULL, "LDO2"},
	{"IN3P", NULL, "LDO2"},
	{"IN3P", NULL, "LDO2"},
@@ -1981,6 +2013,76 @@ int rt5640_dmic_enable(struct snd_soc_codec *codec,
}
}
EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
EXPORT_SYMBOL_GPL(rt5640_dmic_enable);


int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
		unsigned int filter_mask, unsigned int clk_src)
{
	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
	unsigned int asrc2_mask = 0;
	unsigned int asrc2_value = 0;

	switch (clk_src) {
	case RT5640_CLK_SEL_SYS:
	case RT5640_CLK_SEL_ASRC:
		break;

	default:
		return -EINVAL;
	}

	if (!filter_mask)
		return -EINVAL;

	if (filter_mask & RT5640_DA_STEREO_FILTER) {
		asrc2_mask |= RT5640_STO_DAC_M_MASK;
		asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK)
			| (clk_src << RT5640_STO_DAC_M_SFT);
	}

	if (filter_mask & RT5640_DA_MONO_L_FILTER) {
		asrc2_mask |= RT5640_MDA_L_M_MASK;
		asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK)
			| (clk_src << RT5640_MDA_L_M_SFT);
	}

	if (filter_mask & RT5640_DA_MONO_R_FILTER) {
		asrc2_mask |= RT5640_MDA_R_M_MASK;
		asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK)
			| (clk_src << RT5640_MDA_R_M_SFT);
	}

	if (filter_mask & RT5640_AD_STEREO_FILTER) {
		asrc2_mask |= RT5640_ADC_M_MASK;
		asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK)
			| (clk_src << RT5640_ADC_M_SFT);
	}

	if (filter_mask & RT5640_AD_MONO_L_FILTER) {
		asrc2_mask |= RT5640_MAD_L_M_MASK;
		asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK)
			| (clk_src << RT5640_MAD_L_M_SFT);
	}

	if (filter_mask & RT5640_AD_MONO_R_FILTER)  {
		asrc2_mask |= RT5640_MAD_R_M_MASK;
		asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK)
			| (clk_src << RT5640_MAD_R_M_SFT);
	}

	snd_soc_update_bits(codec, RT5640_ASRC_2,
		asrc2_mask, asrc2_value);

	if (snd_soc_read(codec, RT5640_ASRC_2)) {
		rt5640->asrc_en = true;
		snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3);
	} else {
		rt5640->asrc_en = false;
		snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0);
	}

	return 0;
}
EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src);

static int rt5640_probe(struct snd_soc_codec *codec)
static int rt5640_probe(struct snd_soc_codec *codec)
{
{
	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+17 −0
Original line number Original line Diff line number Diff line
@@ -1033,6 +1033,10 @@
#define RT5640_DMIC_2_M_NOR			(0x0 << 8)
#define RT5640_DMIC_2_M_NOR			(0x0 << 8)
#define RT5640_DMIC_2_M_ASYN			(0x1 << 8)
#define RT5640_DMIC_2_M_ASYN			(0x1 << 8)


/* ASRC clock source selection (0x84) */
#define RT5640_CLK_SEL_SYS			(0x0)
#define RT5640_CLK_SEL_ASRC			(0x1)

/* ASRC Control 2 (0x84) */
/* ASRC Control 2 (0x84) */
#define RT5640_MDA_L_M_MASK			(0x1 << 15)
#define RT5640_MDA_L_M_MASK			(0x1 << 15)
#define RT5640_MDA_L_M_SFT			15
#define RT5640_MDA_L_M_SFT			15
@@ -2079,6 +2083,16 @@ enum {
	RT5640_DMIC2,
	RT5640_DMIC2,
};
};


/* filter mask */
enum {
	RT5640_DA_STEREO_FILTER = 0x1,
	RT5640_DA_MONO_L_FILTER = (0x1 << 1),
	RT5640_DA_MONO_R_FILTER = (0x1 << 2),
	RT5640_AD_STEREO_FILTER = (0x1 << 3),
	RT5640_AD_MONO_L_FILTER = (0x1 << 4),
	RT5640_AD_MONO_R_FILTER = (0x1 << 5),
};

struct rt5640_priv {
struct rt5640_priv {
	struct snd_soc_codec *codec;
	struct snd_soc_codec *codec;
	struct rt5640_platform_data pdata;
	struct rt5640_platform_data pdata;
@@ -2095,9 +2109,12 @@ struct rt5640_priv {
	int pll_out;
	int pll_out;


	bool hp_mute;
	bool hp_mute;
	bool asrc_en;
};
};


int rt5640_dmic_enable(struct snd_soc_codec *codec,
int rt5640_dmic_enable(struct snd_soc_codec *codec,
		       bool dmic1_data_pin, bool dmic2_data_pin);
		       bool dmic1_data_pin, bool dmic2_data_pin);
int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec,
		unsigned int filter_mask, unsigned int clk_src);


#endif
#endif