diff options
Diffstat (limited to 'sound/soc/codecs/rt5640.c')
| -rw-r--r-- | sound/soc/codecs/rt5640.c | 659 | 
1 files changed, 349 insertions, 310 deletions
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index c26a8f814b1..de80e89b5fd 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1,5 +1,5 @@  /* - * rt5640.c  --  RT5640 ALSA SoC audio codec driver + * rt5640.c  --  RT5640/RT5639 ALSA SoC audio codec driver   *   * Copyright 2011 Realtek Semiconductor Corp.   * Author: Johnny Hsu <johnnyhsu@realtek.com> @@ -18,9 +18,11 @@  #include <linux/gpio.h>  #include <linux/i2c.h>  #include <linux/regmap.h> +#include <linux/of.h>  #include <linux/of_gpio.h>  #include <linux/platform_device.h>  #include <linux/spi/spi.h> +#include <linux/acpi.h>  #include <sound/core.h>  #include <sound/pcm.h>  #include <sound/pcm_params.h> @@ -29,6 +31,7 @@  #include <sound/initval.h>  #include <sound/tlv.h> +#include "rl6231.h"  #include "rt5640.h"  #define RT5640_DEVICE_ID 0x6231 @@ -58,7 +61,7 @@ static struct reg_default init_list[] = {  };  #define RT5640_INIT_REG_LEN ARRAY_SIZE(init_list) -static const struct reg_default rt5640_reg[RT5640_VENDOR_ID2 + 1] = { +static const struct reg_default rt5640_reg[] = {  	{ 0x00, 0x000e },  	{ 0x01, 0xc8c8 },  	{ 0x02, 0xc8c8 }, @@ -360,25 +363,24 @@ static unsigned int bst_tlv[] = {  static const char * const rt5640_data_select[] = {  	"Normal", "left copy to right", "right copy to left", "Swap"}; -static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, -				RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, -				RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, -				RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, -				RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); +static SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, +			    RT5640_IF2_ADC_SEL_SFT, rt5640_data_select);  /* Class D speaker gain ratio */  static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x",  	"2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"}; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, -	RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); +static SOC_ENUM_SINGLE_DECL(rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, +			    RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);  static const struct snd_kcontrol_new rt5640_snd_controls[] = {  	/* Speaker Output Volume */ @@ -398,18 +400,13 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {  		RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),  	SOC_DOUBLE_TLV("OUT Playback Volume", RT5640_OUTPUT,  		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv), -	/* MONO Output Control */ -	SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, -				RT5640_L_MUTE_SFT, 1, 1), +  	/* DAC Digital Volume */  	SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL,  		RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1),  	SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL,  			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT,  			175, 0, dac_vol_tlv), -	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL, -			RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, -			175, 0, dac_vol_tlv),  	/* IN1/IN2 Control */  	SOC_SINGLE_TLV("IN1 Boost", RT5640_IN1_IN2,  		RT5640_BST_SFT1, 8, 0, bst_tlv), @@ -441,6 +438,15 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {  	SOC_ENUM("DAC IF2 Data Switch", rt5640_if2_dac_enum),  }; +static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = { +	/* MONO Output Control */ +	SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT, +		1, 1), + +	SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL, +		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv), +}; +  /**   * set_dmic_clk - Set parameter of dmic.   * @@ -448,30 +454,16 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = {   * @kcontrol: The kcontrol of this widget.   * @event: Event id.   * - * Choose dmic clock between 1MHz and 3MHz. - * It is better for clock to approximate 3MHz.   */  static int set_dmic_clk(struct snd_soc_dapm_widget *w,  	struct snd_kcontrol *kcontrol, int event)  {  	struct snd_soc_codec *codec = w->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	int div[] = {2, 3, 4, 6, 8, 12}; -	int idx = -EINVAL, i; -	int rate, red, bound, temp; - -	rate = rt5640->sysclk; -	red = 3000000 * 12; -	for (i = 0; i < ARRAY_SIZE(div); i++) { -		bound = div[i] * 3000000; -		if (rate > bound) -			continue; -		temp = bound - rate; -		if (temp < red) { -			red = temp; -			idx = i; -		} -	} +	int idx = -EINVAL; + +	idx = rl6231_calc_dmic_clk(rt5640->sysclk); +  	if (idx < 0)  		dev_err(codec->dev, "Failed to set DMIC clock\n");  	else @@ -480,14 +472,14 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,  	return idx;  } -static int check_sysclk1_source(struct snd_soc_dapm_widget *source, +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,  			 struct snd_soc_dapm_widget *sink)  {  	unsigned int val;  	val = snd_soc_read(source->codec, RT5640_GLB_CLK);  	val &= RT5640_SCLK_SRC_MASK; -	if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T) +	if (val == RT5640_SCLK_SRC_PLL1)  		return 1;  	else  		return 0; @@ -554,6 +546,20 @@ static const struct snd_kcontrol_new rt5640_sto_dac_r_mix[] = {  			RT5640_M_ANC_DAC_R_SFT, 1, 1),  }; +static const struct snd_kcontrol_new rt5639_sto_dac_l_mix[] = { +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_L1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L2 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5639_sto_dac_r_mix[] = { +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_R1_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R2 Switch", RT5640_STO_DAC_MIXER, +			RT5640_M_DAC_R2_SFT, 1, 1), +}; +  static const struct snd_kcontrol_new rt5640_mono_dac_l_mix[] = {  	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_MONO_DAC_MIXER,  			RT5640_M_DAC_L1_MONO_L_SFT, 1, 1), @@ -676,6 +682,30 @@ static const struct snd_kcontrol_new rt5640_out_r_mix[] = {  			RT5640_M_DAC_R1_OM_R_SFT, 1, 1),  }; +static const struct snd_kcontrol_new rt5639_out_l_mix[] = { +	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_BST1_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_IN_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("REC MIXL Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_RM_L_OM_L_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_OUT_L3_MIXER, +			RT5640_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5639_out_r_mix[] = { +	SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_BST4_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_BST1_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_IN_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("REC MIXR Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_RM_R_OM_R_SFT, 1, 1), +	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_OUT_R3_MIXER, +			RT5640_M_DAC_R1_OM_R_SFT, 1, 1), +}; +  static const struct snd_kcontrol_new rt5640_spo_l_mix[] = {  	SOC_DAPM_SINGLE("DAC R1 Switch", RT5640_SPO_L_MIXER,  			RT5640_M_DAC_R1_SPM_L_SFT, 1, 1), @@ -707,6 +737,13 @@ static const struct snd_kcontrol_new rt5640_hpo_mix[] = {  			RT5640_M_HPVOL_HM_SFT, 1, 1),  }; +static const struct snd_kcontrol_new rt5639_hpo_mix[] = { +	SOC_DAPM_SINGLE("HPO MIX DAC1 Switch", RT5640_HPO_MIXER, +			RT5640_M_DAC1_HM_SFT, 1, 1), +	SOC_DAPM_SINGLE("HPO MIX HPVOL Switch", RT5640_HPO_MIXER, +			RT5640_M_HPVOL_HM_SFT, 1, 1), +}; +  static const struct snd_kcontrol_new rt5640_lout_mix[] = {  	SOC_DAPM_SINGLE("DAC L1 Switch", RT5640_LOUT_MIXER,  			RT5640_M_DAC_L1_LM_SFT, 1, 1), @@ -752,9 +789,8 @@ static const char * const rt5640_stereo_adc1_src[] = {  	"DIG MIX", "ADC"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, -	RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, +			    RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src);  static const struct snd_kcontrol_new rt5640_sto_adc_1_mux =  	SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum); @@ -763,9 +799,8 @@ static const char * const rt5640_stereo_adc2_src[] = {  	"DMIC1", "DMIC2", "DIG MIX"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, -	RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, +			    RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src);  static const struct snd_kcontrol_new rt5640_sto_adc_2_mux =  	SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum); @@ -775,9 +810,8 @@ static const char * const rt5640_mono_adc_l1_src[] = {  	"Mono DAC MIXL", "ADCL"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src);  static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux =  	SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum); @@ -786,9 +820,8 @@ static const char * const rt5640_mono_adc_l2_src[] = {  	"DMIC L1", "DMIC L2", "Mono DAC MIXL"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src);  static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux =  	SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum); @@ -797,9 +830,8 @@ static const char * const rt5640_mono_adc_r1_src[] = {  	"Mono DAC MIXR", "ADCR"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src);  static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux =  	SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum); @@ -808,9 +840,8 @@ static const char * const rt5640_mono_adc_r2_src[] = {  	"DMIC R1", "DMIC R2", "Mono DAC MIXR"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, -	RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); +static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, +			    RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src);  static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux =  	SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum); @@ -825,12 +856,12 @@ static int rt5640_dac_l2_values[] = {  	3,  }; -static const SOC_VALUE_ENUM_SINGLE_DECL( -	rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, -	0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum, +				  RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, +				  0x3, rt5640_dac_l2_src, rt5640_dac_l2_values);  static const struct snd_kcontrol_new rt5640_dac_l2_mux = -	SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); +	SOC_DAPM_ENUM("DAC2 left channel source", rt5640_dac_l2_enum);  static const char * const rt5640_dac_r2_src[] = {  	"IF2", @@ -840,9 +871,9 @@ static int rt5640_dac_r2_values[] = {  	0,  }; -static const SOC_VALUE_ENUM_SINGLE_DECL( -	rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, -	0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_r2_enum, +				  RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, +				  0x3, rt5640_dac_r2_src, rt5640_dac_r2_values);  static const struct snd_kcontrol_new rt5640_dac_r2_mux =  	SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum); @@ -859,74 +890,26 @@ static int rt5640_dai_iis_map_values[] = {  	7,  }; -static const SOC_VALUE_ENUM_SINGLE_DECL( -	rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, -	0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum, +				  RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, +				  0x7, rt5640_dai_iis_map, +				  rt5640_dai_iis_map_values);  static const struct snd_kcontrol_new rt5640_dai_mux = -	SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); +	SOC_DAPM_ENUM("DAI select", rt5640_dai_iis_map_enum);  /* SDI select */  static const char * const rt5640_sdi_sel[] = {  	"IF1", "IF2"  }; -static const SOC_ENUM_SINGLE_DECL( -	rt5640_sdi_sel_enum, RT5640_I2S2_SDP, -	RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); +static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP, +			    RT5640_I2S2_SDI_SFT, rt5640_sdi_sel);  static const struct snd_kcontrol_new rt5640_sdi_mux =  	SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); -static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w, -	struct snd_kcontrol *kcontrol, int event) -{ -	struct snd_soc_codec *codec = w->codec; - -	switch (event) { -	case SND_SOC_DAPM_PRE_PMU: -		snd_soc_update_bits(codec, RT5640_GPIO_CTRL1, -			RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK, -			RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA); -		snd_soc_update_bits(codec, RT5640_DMIC, -			RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK | -			RT5640_DMIC_1_DP_MASK, -			RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING | -			RT5640_DMIC_1_DP_IN1P); -		break; - -	default: -		return 0; -	} - -	return 0; -} - -static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w, -	struct snd_kcontrol *kcontrol, int event) -{ -	struct snd_soc_codec *codec = w->codec; - -	switch (event) { -	case SND_SOC_DAPM_PRE_PMU: -		snd_soc_update_bits(codec, RT5640_GPIO_CTRL1, -			RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK, -			RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA); -		snd_soc_update_bits(codec, RT5640_DMIC, -			RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK | -			RT5640_DMIC_2_DP_MASK, -			RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING | -			RT5640_DMIC_2_DP_IN1N); -		break; - -	default: -		return 0; -	} - -	return 0; -} - -void hp_amp_power_on(struct snd_soc_codec *codec) +static void hp_amp_power_on(struct snd_soc_codec *codec)  {  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); @@ -1060,12 +1043,10 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,  		set_dmic_clk, SND_SOC_DAPM_PRE_PMU), -	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, -		RT5640_DMIC_1_EN_SFT, 0, rt5640_set_dmic1_event, -		SND_SOC_DAPM_PRE_PMU), -	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, -		RT5640_DMIC_2_EN_SFT, 0, rt5640_set_dmic2_event, -		SND_SOC_DAPM_PRE_PMU), +	SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5640_DMIC, RT5640_DMIC_1_EN_SFT, 0, +		NULL, 0), +	SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5640_DMIC, RT5640_DMIC_2_EN_SFT, 0, +		NULL, 0),  	/* Boost */  	SND_SOC_DAPM_PGA("BST1", RT5640_PWR_ANLG2,  		RT5640_PWR_BST1_BIT, 0, NULL, 0), @@ -1152,26 +1133,15 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),  	SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), -	/* Audio DSP */ -	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), -	/* ANC */ -	SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0), +  	/* Output Side */  	/* DAC mixer before sound effect  */  	SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0,  		rt5640_dac_l_mix, ARRAY_SIZE(rt5640_dac_l_mix)),  	SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0,  		rt5640_dac_r_mix, ARRAY_SIZE(rt5640_dac_r_mix)), -	/* DAC2 channel Mux */ -	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, -				&rt5640_dac_l2_mux), -	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, -				&rt5640_dac_r2_mux), +  	/* DAC Mixer */ -	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, -		rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)), -	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, -		rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)),  	SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0,  		rt5640_mono_dac_l_mix, ARRAY_SIZE(rt5640_mono_dac_l_mix)),  	SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, @@ -1183,21 +1153,14 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	/* DACs */  	SND_SOC_DAPM_DAC("DAC L1", NULL, RT5640_PWR_DIG1,  			RT5640_PWR_DAC_L1_BIT, 0), -	SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, -			RT5640_PWR_DAC_L2_BIT, 0),  	SND_SOC_DAPM_DAC("DAC R1", NULL, RT5640_PWR_DIG1,  			RT5640_PWR_DAC_R1_BIT, 0), -	SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, -			RT5640_PWR_DAC_R2_BIT, 0), +  	/* SPK/OUT Mixer */  	SND_SOC_DAPM_MIXER("SPK MIXL", RT5640_PWR_MIXER, RT5640_PWR_SM_L_BIT,  		0, rt5640_spk_l_mix, ARRAY_SIZE(rt5640_spk_l_mix)),  	SND_SOC_DAPM_MIXER("SPK MIXR", RT5640_PWR_MIXER, RT5640_PWR_SM_R_BIT,  		0, rt5640_spk_r_mix, ARRAY_SIZE(rt5640_spk_r_mix)), -	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, -		0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)), -	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, -		0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)),  	/* Ouput Volume */  	SND_SOC_DAPM_PGA("SPKVOL L", RT5640_PWR_VOL,  		RT5640_PWR_SV_L_BIT, 0, NULL, 0), @@ -1216,16 +1179,8 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  		0, rt5640_spo_l_mix, ARRAY_SIZE(rt5640_spo_l_mix)),  	SND_SOC_DAPM_MIXER("SPOR MIX", SND_SOC_NOPM, 0,  		0, rt5640_spo_r_mix, ARRAY_SIZE(rt5640_spo_r_mix)), -	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, -		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), -	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, -		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)),  	SND_SOC_DAPM_MIXER("LOUT MIX", RT5640_PWR_ANLG1, RT5640_PWR_LM_BIT, 0,  		rt5640_lout_mix, ARRAY_SIZE(rt5640_lout_mix)), -	SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0, -		rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), -	SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, -		RT5640_PWR_MA_BIT, 0, NULL, 0),  	SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,  		0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),  	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, @@ -1257,10 +1212,69 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {  	SND_SOC_DAPM_OUTPUT("HPOR"),  	SND_SOC_DAPM_OUTPUT("LOUTL"),  	SND_SOC_DAPM_OUTPUT("LOUTR"), +}; + +static const struct snd_soc_dapm_widget rt5640_specific_dapm_widgets[] = { +	/* Audio DSP */ +	SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), +	/* ANC */ +	SND_SOC_DAPM_PGA("ANC", SND_SOC_NOPM, 0, 0, NULL, 0), + +	/* DAC2 channel Mux */ +	SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_l2_mux), +	SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5640_dac_r2_mux), + +	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5640_sto_dac_l_mix, ARRAY_SIZE(rt5640_sto_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5640_sto_dac_r_mix, ARRAY_SIZE(rt5640_sto_dac_r_mix)), + +	SND_SOC_DAPM_DAC("DAC R2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_R2_BIT, +		0), +	SND_SOC_DAPM_DAC("DAC L2", NULL, RT5640_PWR_DIG1, RT5640_PWR_DAC_L2_BIT, +		0), + +	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, +		0, rt5640_out_l_mix, ARRAY_SIZE(rt5640_out_l_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, +		0, rt5640_out_r_mix, ARRAY_SIZE(rt5640_out_r_mix)), + +	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, +		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), +	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, +		rt5640_hpo_mix, ARRAY_SIZE(rt5640_hpo_mix)), + +	SND_SOC_DAPM_MIXER("Mono MIX", RT5640_PWR_ANLG1, RT5640_PWR_MM_BIT, 0, +		rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)), +	SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1, +		RT5640_PWR_MA_BIT, 0, NULL, 0), +  	SND_SOC_DAPM_OUTPUT("MONOP"),  	SND_SOC_DAPM_OUTPUT("MONON"),  }; +static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = { +	SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, +		rt5639_sto_dac_l_mix, ARRAY_SIZE(rt5639_sto_dac_l_mix)), +	SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, +		rt5639_sto_dac_r_mix, ARRAY_SIZE(rt5639_sto_dac_r_mix)), + +	SND_SOC_DAPM_SUPPLY("DAC L2 Filter", RT5640_PWR_DIG1, +		RT5640_PWR_DAC_L2_BIT, 0, NULL, 0), +	SND_SOC_DAPM_SUPPLY("DAC R2 Filter", RT5640_PWR_DIG1, +		RT5640_PWR_DAC_R2_BIT, 0, NULL, 0), + +	SND_SOC_DAPM_MIXER("OUT MIXL", RT5640_PWR_MIXER, RT5640_PWR_OM_L_BIT, +		0, rt5639_out_l_mix, ARRAY_SIZE(rt5639_out_l_mix)), +	SND_SOC_DAPM_MIXER("OUT MIXR", RT5640_PWR_MIXER, RT5640_PWR_OM_R_BIT, +		0, rt5639_out_r_mix, ARRAY_SIZE(rt5639_out_r_mix)), + +	SND_SOC_DAPM_MIXER("HPO MIX L", SND_SOC_NOPM, 0, 0, +		rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)), +	SND_SOC_DAPM_MIXER("HPO MIX R", SND_SOC_NOPM, 0, 0, +		rt5639_hpo_mix, ARRAY_SIZE(rt5639_hpo_mix)), +}; +  static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"IN1P", NULL, "LDO2"},  	{"IN2P", NULL, "LDO2"}, @@ -1329,22 +1343,22 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"Stereo ADC MIXL", "ADC1 Switch", "Stereo ADC L1 Mux"},  	{"Stereo ADC MIXL", "ADC2 Switch", "Stereo ADC L2 Mux"},  	{"Stereo ADC MIXL", NULL, "Stereo Filter"}, -	{"Stereo Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"Stereo ADC MIXR", "ADC1 Switch", "Stereo ADC R1 Mux"},  	{"Stereo ADC MIXR", "ADC2 Switch", "Stereo ADC R2 Mux"},  	{"Stereo ADC MIXR", NULL, "Stereo Filter"}, -	{"Stereo Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Stereo Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"},  	{"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"},  	{"Mono ADC MIXL", NULL, "Mono Left Filter"}, -	{"Mono Left Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Mono Left Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"},  	{"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"},  	{"Mono ADC MIXR", NULL, "Mono Right Filter"}, -	{"Mono Right Filter", NULL, "PLL1", check_sysclk1_source}, +	{"Mono Right Filter", NULL, "PLL1", is_sys_clk_from_pll},  	{"IF2 ADC L", NULL, "Mono ADC MIXL"},  	{"IF2 ADC R", NULL, "Mono ADC MIXR"}, @@ -1402,71 +1416,38 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"DAC MIXR", "Stereo ADC Switch", "Stereo ADC MIXR"},  	{"DAC MIXR", "INF1 Switch", "IF1 DAC R"}, -	{"ANC", NULL, "Stereo ADC MIXL"}, -	{"ANC", NULL, "Stereo ADC MIXR"}, - -	{"Audio DSP", NULL, "DAC MIXL"}, -	{"Audio DSP", NULL, "DAC MIXR"}, - -	{"DAC L2 Mux", "IF2", "IF2 DAC L"}, -	{"DAC L2 Mux", "Base L/R", "Audio DSP"}, - -	{"DAC R2 Mux", "IF2", "IF2 DAC R"}, -  	{"Stereo DAC MIXL", "DAC L1 Switch", "DAC MIXL"}, -	{"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, -	{"Stereo DAC MIXL", "ANC Switch", "ANC"},  	{"Stereo DAC MIXR", "DAC R1 Switch", "DAC MIXR"}, -	{"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, -	{"Stereo DAC MIXR", "ANC Switch", "ANC"},  	{"Mono DAC MIXL", "DAC L1 Switch", "DAC MIXL"}, -	{"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, -	{"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"},  	{"Mono DAC MIXR", "DAC R1 Switch", "DAC MIXR"}, -	{"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, -	{"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"},  	{"DIG MIXL", "DAC L1 Switch", "DAC MIXL"}, -	{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"},  	{"DIG MIXR", "DAC R1 Switch", "DAC MIXR"}, -	{"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"},  	{"DAC L1", NULL, "Stereo DAC MIXL"}, -	{"DAC L1", NULL, "PLL1", check_sysclk1_source}, +	{"DAC L1", NULL, "PLL1", is_sys_clk_from_pll},  	{"DAC R1", NULL, "Stereo DAC MIXR"}, -	{"DAC R1", NULL, "PLL1", check_sysclk1_source}, -	{"DAC L2", NULL, "Mono DAC MIXL"}, -	{"DAC L2", NULL, "PLL1", check_sysclk1_source}, -	{"DAC R2", NULL, "Mono DAC MIXR"}, -	{"DAC R2", NULL, "PLL1", check_sysclk1_source}, +	{"DAC R1", NULL, "PLL1", is_sys_clk_from_pll},  	{"SPK MIXL", "REC MIXL Switch", "RECMIXL"},  	{"SPK MIXL", "INL Switch", "INL VOL"},  	{"SPK MIXL", "DAC L1 Switch", "DAC L1"}, -	{"SPK MIXL", "DAC L2 Switch", "DAC L2"},  	{"SPK MIXL", "OUT MIXL Switch", "OUT MIXL"},  	{"SPK MIXR", "REC MIXR Switch", "RECMIXR"},  	{"SPK MIXR", "INR Switch", "INR VOL"},  	{"SPK MIXR", "DAC R1 Switch", "DAC R1"}, -	{"SPK MIXR", "DAC R2 Switch", "DAC R2"},  	{"SPK MIXR", "OUT MIXR Switch", "OUT MIXR"}, -	{"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"},  	{"OUT MIXL", "BST1 Switch", "BST1"},  	{"OUT MIXL", "INL Switch", "INL VOL"},  	{"OUT MIXL", "REC MIXL Switch", "RECMIXL"}, -	{"OUT MIXL", "DAC R2 Switch", "DAC R2"}, -	{"OUT MIXL", "DAC L2 Switch", "DAC L2"},  	{"OUT MIXL", "DAC L1 Switch", "DAC L1"}, -	{"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"},  	{"OUT MIXR", "BST2 Switch", "BST2"},  	{"OUT MIXR", "BST1 Switch", "BST1"},  	{"OUT MIXR", "INR Switch", "INR VOL"},  	{"OUT MIXR", "REC MIXR Switch", "RECMIXR"}, -	{"OUT MIXR", "DAC L2 Switch", "DAC L2"}, -	{"OUT MIXR", "DAC R2 Switch", "DAC R2"},  	{"OUT MIXR", "DAC R1 Switch", "DAC R1"},  	{"SPKVOL L", NULL, "SPK MIXL"}, @@ -1485,11 +1466,9 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"SPOR MIX", "SPKVOL R Switch", "SPKVOL R"},  	{"SPOR MIX", "BST1 Switch", "BST1"}, -	{"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},  	{"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},  	{"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},  	{"HPO MIX L", NULL, "HP L Amp"}, -	{"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},  	{"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},  	{"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},  	{"HPO MIX R", NULL, "HP R Amp"}, @@ -1499,12 +1478,6 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"},  	{"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"}, -	{"Mono MIX", "DAC R2 Switch", "DAC R2"}, -	{"Mono MIX", "DAC L2 Switch", "DAC L2"}, -	{"Mono MIX", "OUTVOL R Switch", "OUTVOL R"}, -	{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, -	{"Mono MIX", "BST1 Switch", "BST1"}, -  	{"HP Amp", NULL, "HPO MIX L"},  	{"HP Amp", NULL, "HPO MIX R"}, @@ -1529,11 +1502,82 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {  	{"HPOR", NULL, "HP R Playback"},  	{"LOUTL", NULL, "LOUT MIX"},  	{"LOUTR", NULL, "LOUT MIX"}, +}; + +static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { +	{"ANC", NULL, "Stereo ADC MIXL"}, +	{"ANC", NULL, "Stereo ADC MIXR"}, + +	{"Audio DSP", NULL, "DAC MIXL"}, +	{"Audio DSP", NULL, "DAC MIXR"}, + +	{"DAC L2 Mux", "IF2", "IF2 DAC L"}, +	{"DAC L2 Mux", "Base L/R", "Audio DSP"}, + +	{"DAC R2 Mux", "IF2", "IF2 DAC R"}, + +	{"Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Stereo DAC MIXL", "ANC Switch", "ANC"}, +	{"Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, +	{"Stereo DAC MIXR", "ANC Switch", "ANC"}, + +	{"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, +	{"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + +	{"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, +	{"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, + +	{"DIG MIXR", "DAC R2 Switch", "DAC R2 Mux"}, +	{"DIG MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + +	{"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", "DAC L2 Switch", "DAC L2"}, +	{"SPK MIXR", "DAC R2 Switch", "DAC R2"}, + +	{"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"}, +	{"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"}, + +	{"OUT MIXL", "DAC R2 Switch", "DAC R2"}, +	{"OUT MIXL", "DAC L2 Switch", "DAC L2"}, + +	{"OUT MIXR", "DAC L2 Switch", "DAC L2"}, +	{"OUT MIXR", "DAC R2 Switch", "DAC R2"}, + +	{"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"}, +	{"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"}, + +	{"Mono MIX", "DAC R2 Switch", "DAC R2"}, +	{"Mono MIX", "DAC L2 Switch", "DAC L2"}, +	{"Mono MIX", "OUTVOL R Switch", "OUTVOL R"}, +	{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"}, +	{"Mono MIX", "BST1 Switch", "BST1"}, +  	{"MONOP", NULL, "Mono MIX"},  	{"MONON", NULL, "Mono MIX"},  	{"MONOP", NULL, "Improve MONO Amp Drv"},  }; +static const struct snd_soc_dapm_route rt5639_specific_dapm_routes[] = { +	{"Stereo DAC MIXL", "DAC L2 Switch", "IF2 DAC L"}, +	{"Stereo DAC MIXR", "DAC R2 Switch", "IF2 DAC R"}, + +	{"Mono DAC MIXL", "DAC L2 Switch", "IF2 DAC L"}, +	{"Mono DAC MIXL", "DAC R2 Switch", "IF2 DAC R"}, + +	{"Mono DAC MIXR", "DAC R2 Switch", "IF2 DAC R"}, +	{"Mono DAC MIXR", "DAC L2 Switch", "IF2 DAC L"}, + +	{"DIG MIXL", "DAC L2 Switch", "IF2 DAC L"}, +	{"DIG MIXR", "DAC R2 Switch", "IF2 DAC R"}, + +	{"IF2 DAC L", NULL, "DAC L2 Filter"}, +	{"IF2 DAC R", NULL, "DAC R2 Filter"}, +}; +  static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)  {  	int ret = 0, val; @@ -1582,34 +1626,19 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)  	return ret;  } -static int get_clk_info(int sclk, int rate) -{ -	int i, pd[] = {1, 2, 3, 4, 6, 8, 12, 16}; - -	if (sclk <= 0 || rate <= 0) -		return -EINVAL; - -	rate = rate << 8; -	for (i = 0; i < ARRAY_SIZE(pd); i++) -		if (sclk == rate * pd[i]) -			return i; - -	return -EINVAL; -} -  static int rt5640_hw_params(struct snd_pcm_substream *substream,  	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)  { -	struct snd_soc_pcm_runtime *rtd = substream->private_data; -	struct snd_soc_codec *codec = rtd->codec; +	struct snd_soc_codec *codec = dai->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	unsigned int val_len = 0, val_clk, mask_clk, dai_sel; -	int pre_div, bclk_ms, frame_size; +	unsigned int val_len = 0, val_clk, mask_clk; +	int dai_sel, pre_div, bclk_ms, frame_size;  	rt5640->lrck[dai->id] = params_rate(params); -	pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]); +	pre_div = rl6231_get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);  	if (pre_div < 0) { -		dev_err(codec->dev, "Unsupported clock setting\n"); +		dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", +			rt5640->lrck[dai->id], dai->id);  		return -EINVAL;  	}  	frame_size = snd_soc_params_to_frame_size(params); @@ -1628,16 +1657,16 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,  	dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n",  				bclk_ms, pre_div, dai->id); -	switch (params_format(params)) { -	case SNDRV_PCM_FORMAT_S16_LE: +	switch (params_width(params)) { +	case 16:  		break; -	case SNDRV_PCM_FORMAT_S20_3LE: +	case 20:  		val_len |= RT5640_I2S_DL_20;  		break; -	case SNDRV_PCM_FORMAT_S24_LE: +	case 24:  		val_len |= RT5640_I2S_DL_24;  		break; -	case SNDRV_PCM_FORMAT_S8: +	case 8:  		val_len |= RT5640_I2S_DL_8;  		break;  	default: @@ -1673,7 +1702,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)  {  	struct snd_soc_codec *codec = dai->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	unsigned int reg_val = 0, dai_sel; +	unsigned int reg_val = 0; +	int dai_sel;  	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {  	case SND_SOC_DAIFMT_CBM_CFM: @@ -1749,12 +1779,6 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,  	case RT5640_SCLK_S_PLL1:  		reg_val |= RT5640_SCLK_SRC_PLL1;  		break; -	case RT5640_SCLK_S_PLL1_TK: -		reg_val |= RT5640_SCLK_SRC_PLL1T; -		break; -	case RT5640_SCLK_S_RCCLK: -		reg_val |= RT5640_SCLK_SRC_RCCLK; -		break;  	default:  		dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);  		return -EINVAL; @@ -1768,65 +1792,12 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,  	return 0;  } -/** - * rt5640_pll_calc - Calculate PLL M/N/K code. - * @freq_in: external clock provided to codec. - * @freq_out: target clock which codec works on. - * @pll_code: Pointer to structure with M, N, K and bypass flag. - * - * Calculate M/N/K code to configure PLL for codec. And K is assigned to 2 - * which make calculation more efficiently. - * - * Returns 0 for success or negative error code. - */ -static int rt5640_pll_calc(const unsigned int freq_in, -	const unsigned int freq_out, struct rt5640_pll_code *pll_code) -{ -	int max_n = RT5640_PLL_N_MAX, max_m = RT5640_PLL_M_MAX; -	int n = 0, m = 0, red, n_t, m_t, in_t, out_t; -	int red_t = abs(freq_out - freq_in); -	bool bypass = false; - -	if (RT5640_PLL_INP_MAX < freq_in || RT5640_PLL_INP_MIN > freq_in) -		return -EINVAL; - -	for (n_t = 0; n_t <= max_n; n_t++) { -		in_t = (freq_in >> 1) + (freq_in >> 2) * n_t; -		if (in_t < 0) -			continue; -		if (in_t == freq_out) { -			bypass = true; -			n = n_t; -			goto code_find; -		} -		for (m_t = 0; m_t <= max_m; m_t++) { -			out_t = in_t / (m_t + 2); -			red = abs(out_t - freq_out); -			if (red < red_t) { -				n = n_t; -				m = m_t; -				if (red == 0) -					goto code_find; -				red_t = red; -			} -		} -	} -	pr_debug("Only get approximation about PLL\n"); - -code_find: -	pll_code->m_bp = bypass; -	pll_code->m_code = m; -	pll_code->n_code = n; -	pll_code->k_code = 2; -	return 0; -} -  static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  			unsigned int freq_in, unsigned int freq_out)  {  	struct snd_soc_codec *codec = dai->codec;  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	struct rt5640_pll_code *pll_code = &rt5640->pll_code; +	struct rl6231_pll_code pll_code;  	int ret, dai_sel;  	if (source == rt5640->pll_src && freq_in == rt5640->pll_in && @@ -1870,20 +1841,21 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  		return -EINVAL;  	} -	ret = rt5640_pll_calc(freq_in, freq_out, pll_code); +	ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);  	if (ret < 0) {  		dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);  		return ret;  	} -	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=2\n", pll_code->m_bp, -		(pll_code->m_bp ? 0 : pll_code->m_code), pll_code->n_code); +	dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", +		pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), +		pll_code.n_code, pll_code.k_code);  	snd_soc_write(codec, RT5640_PLL_CTRL1, -		pll_code->n_code << RT5640_PLL_N_SFT | pll_code->k_code); +		pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code);  	snd_soc_write(codec, RT5640_PLL_CTRL2, -		(pll_code->m_bp ? 0 : pll_code->m_code) << RT5640_PLL_M_SFT | -		pll_code->m_bp << RT5640_PLL_M_BP_SFT); +		(pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT | +		pll_code.m_bp << RT5640_PLL_M_BP_SFT);  	rt5640->pll_in = freq_in;  	rt5640->pll_out = freq_out; @@ -1895,11 +1867,9 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,  static int rt5640_set_bias_level(struct snd_soc_codec *codec,  			enum snd_soc_bias_level level)  { -	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);  	switch (level) {  	case SND_SOC_BIAS_STANDBY:  		if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { -			regcache_cache_only(rt5640->regmap, false);  			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,  				RT5640_PWR_VREF1 | RT5640_PWR_MB |  				RT5640_PWR_BG | RT5640_PWR_VREF2, @@ -1909,7 +1879,6 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,  			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,  				RT5640_PWR_FV1 | RT5640_PWR_FV2,  				RT5640_PWR_FV1 | RT5640_PWR_FV2); -			regcache_sync(rt5640->regmap);  			snd_soc_update_bits(codec, RT5640_DUMMY1,  						0x0301, 0x0301);  			snd_soc_update_bits(codec, RT5640_MICBIAS, @@ -1940,24 +1909,42 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,  static int rt5640_probe(struct snd_soc_codec *codec)  {  	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); -	int ret;  	rt5640->codec = codec; -	codec->control_data = rt5640->regmap; -	ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); -	if (ret != 0) { -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); -		return ret; -	} - -	codec->dapm.idle_bias_off = 1;  	rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);  	snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);  	snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);  	snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00); +	switch (snd_soc_read(codec, RT5640_RESET) & RT5640_ID_MASK) { +	case RT5640_ID_5640: +	case RT5640_ID_5642: +		snd_soc_add_codec_controls(codec, +			rt5640_specific_snd_controls, +			ARRAY_SIZE(rt5640_specific_snd_controls)); +		snd_soc_dapm_new_controls(&codec->dapm, +			rt5640_specific_dapm_widgets, +			ARRAY_SIZE(rt5640_specific_dapm_widgets)); +		snd_soc_dapm_add_routes(&codec->dapm, +			rt5640_specific_dapm_routes, +			ARRAY_SIZE(rt5640_specific_dapm_routes)); +		break; +	case RT5640_ID_5639: +		snd_soc_dapm_new_controls(&codec->dapm, +			rt5639_specific_dapm_widgets, +			ARRAY_SIZE(rt5639_specific_dapm_widgets)); +		snd_soc_dapm_add_routes(&codec->dapm, +			rt5639_specific_dapm_routes, +			ARRAY_SIZE(rt5639_specific_dapm_routes)); +		break; +	default: +		dev_err(codec->dev, +			"The driver is for RT5639 RT5640 or RT5642 only\n"); +		return -ENODEV; +	} +  	return 0;  } @@ -1977,13 +1964,23 @@ static int rt5640_suspend(struct snd_soc_codec *codec)  	rt5640_reset(codec);  	regcache_cache_only(rt5640->regmap, true);  	regcache_mark_dirty(rt5640->regmap); +	if (gpio_is_valid(rt5640->pdata.ldo1_en)) +		gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0);  	return 0;  }  static int rt5640_resume(struct snd_soc_codec *codec)  { -	rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY); +	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + +	if (gpio_is_valid(rt5640->pdata.ldo1_en)) { +		gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1); +		msleep(400); +	} + +	regcache_cache_only(rt5640->regmap, false); +	regcache_sync(rt5640->regmap);  	return 0;  } @@ -2050,6 +2047,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {  	.suspend = rt5640_suspend,  	.resume = rt5640_resume,  	.set_bias_level = rt5640_set_bias_level, +	.idle_bias_off = true,  	.controls = rt5640_snd_controls,  	.num_controls = ARRAY_SIZE(rt5640_snd_controls),  	.dapm_widgets = rt5640_dapm_widgets, @@ -2076,10 +2074,30 @@ static const struct regmap_config rt5640_regmap = {  static const struct i2c_device_id rt5640_i2c_id[] = {  	{ "rt5640", 0 }, +	{ "rt5639", 0 }, +	{ "rt5642", 0 },  	{ }  };  MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); +#if defined(CONFIG_OF) +static const struct of_device_id rt5640_of_match[] = { +	{ .compatible = "realtek,rt5639", }, +	{ .compatible = "realtek,rt5640", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, rt5640_of_match); +#endif + +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5640_acpi_match[] = { +	{ "INT33CA", 0 }, +	{ "10EC5640", 0 }, +	{ }, +}; +MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); +#endif +  static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)  {  	rt5640->pdata.in1_diff = of_property_read_bool(np, @@ -2155,7 +2173,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,  	}  	regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); -	if ((val != RT5640_DEVICE_ID)) { +	if (val != RT5640_DEVICE_ID) {  		dev_err(&i2c->dev,  			"Device with ID register %x is not rt5640/39\n", val);  		return -ENODEV; @@ -2176,6 +2194,25 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,  		regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,  					RT5640_IN_DF2, RT5640_IN_DF2); +	if (rt5640->pdata.dmic_en) { +		regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, +			RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); + +		if (rt5640->pdata.dmic1_data_pin) { +			regmap_update_bits(rt5640->regmap, RT5640_DMIC, +				RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); +			regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, +				RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); +		} + +		if (rt5640->pdata.dmic2_data_pin) { +			regmap_update_bits(rt5640->regmap, RT5640_DMIC, +				RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); +			regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, +				RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); +		} +	} +  	rt5640->hp_mute = 1;  	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, @@ -2199,6 +2236,8 @@ static struct i2c_driver rt5640_i2c_driver = {  	.driver = {  		.name = "rt5640",  		.owner = THIS_MODULE, +		.acpi_match_table = ACPI_PTR(rt5640_acpi_match), +		.of_match_table = of_match_ptr(rt5640_of_match),  	},  	.probe = rt5640_i2c_probe,  	.remove   = rt5640_i2c_remove, @@ -2206,6 +2245,6 @@ static struct i2c_driver rt5640_i2c_driver = {  };  module_i2c_driver(rt5640_i2c_driver); -MODULE_DESCRIPTION("ASoC RT5640 driver"); +MODULE_DESCRIPTION("ASoC RT5640/RT5639 driver");  MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");  MODULE_LICENSE("GPL v2");  | 
