* [PATCH] ASoC: rt5640: change widget sequence for depop
@ 2013-08-02 2:38 bardliao
2013-08-02 15:53 ` Stephen Warren
0 siblings, 1 reply; 14+ messages in thread
From: bardliao @ 2013-08-02 2:38 UTC (permalink / raw)
To: broonie, lgirdwood
Cc: oder_chiou, alsa-devel, swarren, swarren, bardliao, flove
From: Bard Liao <bardliao@realtek.com>
Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
Signed-off-by: Bard Liao <bardliao@realtek.com>
---
sound/soc/codecs/rt5640.c | 387 ++++++++++++++++++++++++++++++++++++++++------
sound/soc/codecs/rt5640.h | 15 ++
2 files changed, 352 insertions(+), 50 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 4db7314..3490f38 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -378,21 +378,119 @@ static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
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 char * const rt5640_mute_mode[] = {"mute", "unmute"};
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_hp_enum, 0, 0, rt5640_mute_mode);
+static const SOC_ENUM_SINGLE_DECL(rt5640_spo_enum, 0, 0, rt5640_mute_mode);
+
static const SOC_ENUM_SINGLE_DECL(
rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT,
RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);
+static int rt5640_spo_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = !rt5640->spo_l_mute;
+ ucontrol->value.integer.value[1] = !rt5640->spo_r_mute;
+
+ return 0;
+}
+
+static int rt5640_spo_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ unsigned int pow;
+
+ pow = snd_soc_read(codec, RT5640_PWR_DIG1) & RT5640_PWR_CLS_D;
+
+ if (ucontrol->value.integer.value[0]) {
+ rt5640->spo_l_mute = false;
+ if (pow)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE, 0);
+ } else {
+ rt5640->spo_l_mute = true;
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE,
+ RT5640_L_MUTE);
+ }
+ if (ucontrol->value.integer.value[1]) {
+ rt5640->spo_r_mute = false;
+ if (pow)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE, 0);
+ } else {
+ rt5640->spo_r_mute = true;
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE,
+ RT5640_R_MUTE);
+ }
+
+ return 0;
+}
+
+static int rt5640_hp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = !rt5640->hp_l_mute;
+ ucontrol->value.integer.value[1] = !rt5640->hp_r_mute;
+
+ return 0;
+}
+
+static int rt5640_hp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ unsigned int pow;
+
+ pow = snd_soc_read(codec, RT5640_PWR_ANLG1);
+
+ if (ucontrol->value.integer.value[0]) {
+ rt5640->hp_l_mute = false;
+ if (pow & RT5640_PWR_HP_L)
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_L_MUTE, 0);
+ } else {
+ rt5640->hp_l_mute = true;
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_L_MUTE, RT5640_L_MUTE);
+ }
+ if (ucontrol->value.integer.value[1]) {
+ rt5640->hp_r_mute = false;
+ if (pow & RT5640_PWR_HP_R)
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_R_MUTE, 0);
+ } else {
+ rt5640->hp_r_mute = true;
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_R_MUTE, RT5640_R_MUTE);
+ }
+
+
+ return 0;
+}
+
static const struct snd_kcontrol_new rt5640_snd_controls[] = {
/* Speaker Output Volume */
- SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_EXT("Speaker Playback Switch", SND_SOC_NOPM,
+ 0, 1, 1, 0, rt5640_spo_get, rt5640_spo_put),
SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
/* Headphone Output Volume */
- SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_EXT("HP Playback Switch", SND_SOC_NOPM,
+ 0, 1, 1, 0, rt5640_hp_get, rt5640_hp_put),
SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
@@ -868,33 +966,6 @@ static const SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5640_sdi_mux =
SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
-static int spk_event(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);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
- 0x0001, 0x0001);
- regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
- 0xf000, 0xf000);
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
- 0xf000, 0x0000);
- regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
- 0x0001, 0x0000);
- break;
-
- default:
- return 0;
- }
- return 0;
-}
-
static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -943,6 +1014,216 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5640_spo_r_event(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);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (!rt5640->spo_r_mute)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE,
+ RT5640_R_MUTE);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5640_spo_l_event(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);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (!rt5640->spo_l_mute)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE, RT5640_L_MUTE);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+void hp_amp_power_on(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ /* depop parameters */
+ regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+ RT5640_CHPUMP_INT_REG1, 0x0700, 0x0200);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+ RT5640_DEPOP_MASK,
+ RT5640_DEPOP_MAN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_CP_MASK |
+ RT5640_HP_SG_MASK |
+ RT5640_HP_CB_MASK,
+ RT5640_HP_CP_PU | RT5640_HP_SG_DIS |
+ RT5640_HP_CB_PU);
+ regmap_write(rt5640->regmap, RT5640_PR_BASE + RT5640_HP_DCC_INT1,
+ 0x9f00);
+ /* headphone amp power on */
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_HA,
+ RT5640_PWR_HA);
+ usleep_range(20000, 25000);
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2);
+
+ regmap_update_bits(rt5640->regmap, RT5640_CHARGE_PUMP,
+ RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_CO_MASK |
+ RT5640_HP_SG_MASK,
+ RT5640_HP_CO_EN | RT5640_HP_SG_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+ RT5640_CHPUMP_INT_REG1, 0x0700, 0x0400);
+}
+
+static void rt5640_pmu_depop(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = 0, pow;
+
+ regmap_read(rt5640->regmap, RT5640_PWR_ANLG1, &pow);
+ if (rt5640->hp_l_mute || !(pow & RT5640_PWR_HP_L))
+ val |= RT5640_L_MUTE;
+ if (rt5640->hp_r_mute || !(pow & RT5640_PWR_HP_R))
+ val |= RT5640_R_MUTE;
+ /* headphone unmute sequence */
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
+ RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK |
+ RT5640_CP_FQ3_MASK,
+ (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
+ (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+ (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
+ regmap_write(rt5640->regmap,
+ RT5640_PR_BASE + RT5640_MAMP_INT_REG2, 0xfc00);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_SMT_TRIG_MASK, RT5640_SMT_TRIG_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTN_MASK, RT5640_RSTN_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTN_MASK | RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK,
+ RT5640_RSTN_DIS | RT5640_HP_L_SMT_EN |
+ RT5640_HP_R_SMT_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_HP_VOL,
+ RT5640_L_MUTE | RT5640_R_MUTE, val);
+ usleep_range(40000, 45000);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_SG_MASK | RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK, RT5640_HP_SG_DIS |
+ RT5640_HP_L_SMT_DIS | RT5640_HP_R_SMT_DIS);
+
+}
+
+static void rt5640_pmd_depop(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ /* headphone mute sequence */
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
+ RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK |
+ RT5640_CP_FQ3_MASK,
+ (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ1_SFT) |
+ (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+ (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ3_SFT));
+ regmap_write(rt5640->regmap,
+ RT5640_PR_BASE + RT5640_MAMP_INT_REG2, 0xfc00);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_SG_MASK, RT5640_HP_SG_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTP_MASK, RT5640_RSTP_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTP_MASK | RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK, RT5640_RSTP_DIS |
+ RT5640_HP_L_SMT_EN | RT5640_HP_R_SMT_EN);
+
+ regmap_update_bits(rt5640->regmap, RT5640_HP_VOL,
+ RT5640_L_MUTE | RT5640_R_MUTE,
+ RT5640_L_MUTE | RT5640_R_MUTE);
+ usleep_range(40000, 45000);
+
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_SG_MASK |
+ RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK,
+ RT5640_HP_SG_DIS |
+ RT5640_HP_L_SMT_DIS |
+ RT5640_HP_R_SMT_DIS);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_SMT_TRIG_MASK |
+ RT5640_HP_CD_PD_MASK |
+ RT5640_HP_CO_MASK |
+ RT5640_HP_CP_MASK |
+ RT5640_HP_SG_MASK |
+ RT5640_HP_CB_MASK,
+ RT5640_SMT_TRIG_DIS |
+ RT5640_HP_CD_PD_EN |
+ RT5640_HP_CO_DIS | RT5640_HP_CP_PD |
+ RT5640_HP_SG_EN | RT5640_HP_CB_PD);
+}
+
+static int rt5640_hp_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_POST_PMU:
+ rt5640_pmu_depop(codec);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ rt5640_pmd_depop(codec);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5640_hp_power_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_POST_PMU:
+ hp_amp_power_on(codec);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
RT5640_PWR_PLL_BIT, 0, NULL, 0),
@@ -1132,15 +1413,23 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
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("Improve HP Amp Drv", RT5640_PWR_ANLG1,
- SND_SOC_NOPM, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1,
+ 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,
+ rt5640_hp_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_L_BIT, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1,
+ SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("SPO L Amp", SND_SOC_NOPM,
+ 0, 0, NULL, 0, rt5640_spo_l_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("SPO R Amp", SND_SOC_NOPM,
+ 0, 0, NULL, 0, rt5640_spo_r_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
- SND_SOC_NOPM, 0, spk_event,
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ RT5640_PWR_CLS_D_BIT, 0, NULL, 0),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("SPOLP"),
SND_SOC_DAPM_OUTPUT("SPOLN"),
@@ -1396,13 +1685,15 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
{"Mono MIX", "BST1 Switch", "BST1"},
- {"HP L Amp", NULL, "HPO MIX L"},
- {"HP R Amp", NULL, "HPO MIX R"},
+ {"HP Amp", NULL, "HPO MIX L"},
+ {"HP Amp", NULL, "HPO MIX R"},
- {"SPOLP", NULL, "SPOL MIX"},
- {"SPOLN", NULL, "SPOL MIX"},
- {"SPORP", NULL, "SPOR MIX"},
- {"SPORN", NULL, "SPOR MIX"},
+ {"SPO L Amp", NULL, "SPOL MIX"},
+ {"SPO R Amp", NULL, "SPOR MIX"},
+ {"SPOLP", NULL, "SPO L Amp"},
+ {"SPOLN", NULL, "SPO L Amp"},
+ {"SPORP", NULL, "SPO R Amp"},
+ {"SPORN", NULL, "SPO R Amp"},
{"SPOLP", NULL, "Improve SPK Amp Drv"},
{"SPOLN", NULL, "Improve SPK Amp Drv"},
@@ -1412,7 +1703,9 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"HPOL", NULL, "Improve HP Amp Drv"},
{"HPOR", NULL, "Improve HP Amp Drv"},
+ {"HPOL", NULL, "HP Amp"},
{"HPOL", NULL, "HP L Amp"},
+ {"HPOR", NULL, "HP Amp"},
{"HPOR", NULL, "HP R Amp"},
{"LOUTL", NULL, "LOUT MIX"},
{"LOUTR", NULL, "LOUT MIX"},
@@ -1792,17 +2085,13 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
RT5640_PWR_BG | RT5640_PWR_VREF2,
RT5640_PWR_VREF1 | RT5640_PWR_MB |
RT5640_PWR_BG | RT5640_PWR_VREF2);
- mdelay(10);
+ usleep_range(15000, 20000);
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_DEPOP_M1,
- 0x001d, 0x0019);
- snd_soc_update_bits(codec, RT5640_DEPOP_M2,
- 0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS,
0x0030, 0x0030);
}
@@ -1846,8 +2135,6 @@ static int rt5640_probe(struct snd_soc_codec *codec)
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
- snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019);
- snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index c48286d..cb6bce9 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -145,6 +145,8 @@
/* Index of Codec Private Register definition */
+#define RT5640_CHPUMP_INT_REG1 0x24
+#define RT5640_MAMP_INT_REG2 0x37
#define RT5640_3D_SPK 0x63
#define RT5640_WND_1 0x6c
#define RT5640_WND_2 0x6d
@@ -153,6 +155,7 @@
#define RT5640_WND_5 0x70
#define RT5640_WND_8 0x73
#define RT5640_DIP_SPK_INF 0x75
+#define RT5640_HP_DCC_INT1 0x77
#define RT5640_EQ_BW_LOP 0xa0
#define RT5640_EQ_GN_LOP 0xa1
#define RT5640_EQ_FC_BP1 0xa2
@@ -1201,6 +1204,14 @@
#define RT5640_CP_FQ2_SFT 4
#define RT5640_CP_FQ3_MASK (0x7)
#define RT5640_CP_FQ3_SFT 0
+#define RT5640_CP_FQ_1_5_KHZ 0
+#define RT5640_CP_FQ_3_KHZ 1
+#define RT5640_CP_FQ_6_KHZ 2
+#define RT5640_CP_FQ_12_KHZ 3
+#define RT5640_CP_FQ_24_KHZ 4
+#define RT5640_CP_FQ_48_KHZ 5
+#define RT5640_CP_FQ_96_KHZ 6
+#define RT5640_CP_FQ_192_KHZ 7
/* HPOUT charge pump (0x91) */
#define RT5640_OSW_L_MASK (0x1 << 11)
@@ -2087,6 +2098,10 @@ struct rt5640_priv {
int pll_out;
int dmic_en;
+ bool spo_l_mute;
+ bool spo_r_mute;
+ bool hp_l_mute;
+ bool hp_r_mute;
};
#endif
--
1.8.1.1.439.g50a6b54
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-02 2:38 bardliao
@ 2013-08-02 15:53 ` Stephen Warren
2013-08-05 3:34 ` Bard Liao
0 siblings, 1 reply; 14+ messages in thread
From: Stephen Warren @ 2013-08-02 15:53 UTC (permalink / raw)
To: bardliao; +Cc: oder_chiou, alsa-devel, swarren, lgirdwood, broonie, flove
On 08/01/2013 08:38 PM, bardliao@realtek.com wrote:
> From: Bard Liao <bardliao@realtek.com>
>
> Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
So, this does seem to improve (remove) pop noise on headphones. However,
it also completely prevents speakers from working. Do you know what the
problem is there?
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-02 15:53 ` Stephen Warren
@ 2013-08-05 3:34 ` Bard Liao
0 siblings, 0 replies; 14+ messages in thread
From: Bard Liao @ 2013-08-05 3:34 UTC (permalink / raw)
To: Stephen Warren
Cc: Oder Chiou, alsa-devel@alsa-project.org, swarren@nvidia.com,
lgirdwood@gmail.com, broonie@kernel.org, Flove
> -----Original Message-----
> From: Stephen Warren [mailto:swarren@wwwdotorg.org]
> Sent: Friday, August 02, 2013 11:54 PM
> To: Bard Liao
> Cc: broonie@kernel.org; lgirdwood@gmail.com; alsa-devel@alsa-project.org;
> Flove; Oder Chiou; swarren@nvidia.com
> Subject: Re: [PATCH] ASoC: rt5640: change widget sequence for depop
>
> On 08/01/2013 08:38 PM, bardliao@realtek.com wrote:
> > From: Bard Liao <bardliao@realtek.com>
> >
> > Add mute/unmute control in widget event and modify the power on/off
> sequence to avoid pop noise.
>
> So, this does seem to improve (remove) pop noise on headphones. However, it
> also completely prevents speakers from working. Do you know what the
> problem is there?
I am sorry about that.
I tested it without a physical speaker connected but only checked the reg values.
Now, I have a speaker connected on my T40 board.
I will update the patch in a short time.
Thanks.
>
> ------Please consider the environment before printing this e-mail.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] ASoC: rt5640: change widget sequence for depop
@ 2013-08-05 4:19 bardliao
2013-08-05 14:48 ` Mark Brown
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: bardliao @ 2013-08-05 4:19 UTC (permalink / raw)
To: broonie, lgirdwood
Cc: oder_chiou, alsa-devel, swarren, swarren, bardliao, flove
From: Bard Liao <bardliao@realtek.com>
Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
Signed-off-by: Bard Liao <bardliao@realtek.com>
---
Please ignore the previous patch.
I have tested speaker and headphone playback on this patch.
---
sound/soc/codecs/rt5640.c | 389 +++++++++++++++++++++++++++++++++++++++-------
sound/soc/codecs/rt5640.h | 15 ++
2 files changed, 352 insertions(+), 52 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 4db7314..cae3f46 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -50,8 +50,6 @@ static const struct regmap_range_cfg rt5640_ranges[] = {
static struct reg_default init_list[] = {
{RT5640_PR_BASE + 0x3d, 0x3600},
- {RT5640_PR_BASE + 0x1c, 0x0D21},
- {RT5640_PR_BASE + 0x1b, 0x0000},
{RT5640_PR_BASE + 0x12, 0x0aa8},
{RT5640_PR_BASE + 0x14, 0x0aaa},
{RT5640_PR_BASE + 0x20, 0x6110},
@@ -378,21 +376,119 @@ static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
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 char * const rt5640_mute_mode[] = {"mute", "unmute"};
+
+static const SOC_ENUM_SINGLE_DECL(rt5640_hp_enum, 0, 0, rt5640_mute_mode);
+static const SOC_ENUM_SINGLE_DECL(rt5640_spo_enum, 0, 0, rt5640_mute_mode);
+
static const SOC_ENUM_SINGLE_DECL(
rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT,
RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio);
+static int rt5640_spo_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = !rt5640->spo_l_mute;
+ ucontrol->value.integer.value[1] = !rt5640->spo_r_mute;
+
+ return 0;
+}
+
+static int rt5640_spo_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ unsigned int pow;
+
+ pow = snd_soc_read(codec, RT5640_PWR_DIG1) & RT5640_PWR_CLS_D;
+
+ if (ucontrol->value.integer.value[0]) {
+ rt5640->spo_l_mute = false;
+ if (pow)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE, 0);
+ } else {
+ rt5640->spo_l_mute = true;
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE,
+ RT5640_L_MUTE);
+ }
+ if (ucontrol->value.integer.value[1]) {
+ rt5640->spo_r_mute = false;
+ if (pow)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE, 0);
+ } else {
+ rt5640->spo_r_mute = true;
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE,
+ RT5640_R_MUTE);
+ }
+
+ return 0;
+}
+
+static int rt5640_hp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = !rt5640->hp_l_mute;
+ ucontrol->value.integer.value[1] = !rt5640->hp_r_mute;
+
+ return 0;
+}
+
+static int rt5640_hp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ unsigned int pow;
+
+ pow = snd_soc_read(codec, RT5640_PWR_ANLG1);
+
+ if (ucontrol->value.integer.value[0]) {
+ rt5640->hp_l_mute = false;
+ if (pow & RT5640_PWR_HP_L)
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_L_MUTE, 0);
+ } else {
+ rt5640->hp_l_mute = true;
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_L_MUTE, RT5640_L_MUTE);
+ }
+ if (ucontrol->value.integer.value[1]) {
+ rt5640->hp_r_mute = false;
+ if (pow & RT5640_PWR_HP_R)
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_R_MUTE, 0);
+ } else {
+ rt5640->hp_r_mute = true;
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_R_MUTE, RT5640_R_MUTE);
+ }
+
+
+ return 0;
+}
+
static const struct snd_kcontrol_new rt5640_snd_controls[] = {
/* Speaker Output Volume */
- SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_EXT("Speaker Playback Switch", SND_SOC_NOPM,
+ 0, 1, 1, 0, rt5640_spo_get, rt5640_spo_put),
SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
/* Headphone Output Volume */
- SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_EXT("HP Playback Switch", SND_SOC_NOPM,
+ 0, 1, 1, 0, rt5640_hp_get, rt5640_hp_put),
SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
@@ -868,33 +964,6 @@ static const SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5640_sdi_mux =
SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
-static int spk_event(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);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
- 0x0001, 0x0001);
- regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
- 0xf000, 0xf000);
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
- 0xf000, 0x0000);
- regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
- 0x0001, 0x0000);
- break;
-
- default:
- return 0;
- }
- return 0;
-}
-
static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -943,6 +1012,216 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5640_spo_r_event(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);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (!rt5640->spo_r_mute)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_R_MUTE,
+ RT5640_R_MUTE);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5640_spo_l_event(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);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (!rt5640->spo_l_mute)
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE, 0);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5640_SPK_VOL,
+ RT5640_L_MUTE, RT5640_L_MUTE);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+void hp_amp_power_on(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ /* depop parameters */
+ regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+ RT5640_CHPUMP_INT_REG1, 0x0700, 0x0200);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+ RT5640_DEPOP_MASK,
+ RT5640_DEPOP_MAN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_CP_MASK |
+ RT5640_HP_SG_MASK |
+ RT5640_HP_CB_MASK,
+ RT5640_HP_CP_PU | RT5640_HP_SG_DIS |
+ RT5640_HP_CB_PU);
+ regmap_write(rt5640->regmap, RT5640_PR_BASE + RT5640_HP_DCC_INT1,
+ 0x9f00);
+ /* headphone amp power on */
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_HA,
+ RT5640_PWR_HA);
+ usleep_range(20000, 25000);
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2);
+
+ regmap_update_bits(rt5640->regmap, RT5640_CHARGE_PUMP,
+ RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_CO_MASK |
+ RT5640_HP_SG_MASK,
+ RT5640_HP_CO_EN | RT5640_HP_SG_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+ RT5640_CHPUMP_INT_REG1, 0x0700, 0x0400);
+}
+
+static void rt5640_pmu_depop(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = 0, pow;
+
+ regmap_read(rt5640->regmap, RT5640_PWR_ANLG1, &pow);
+ if (rt5640->hp_l_mute || !(pow & RT5640_PWR_HP_L))
+ val |= RT5640_L_MUTE;
+ if (rt5640->hp_r_mute || !(pow & RT5640_PWR_HP_R))
+ val |= RT5640_R_MUTE;
+ /* headphone unmute sequence */
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
+ RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK |
+ RT5640_CP_FQ3_MASK,
+ (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
+ (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+ (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
+ regmap_write(rt5640->regmap,
+ RT5640_PR_BASE + RT5640_MAMP_INT_REG2, 0xfc00);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_SMT_TRIG_MASK, RT5640_SMT_TRIG_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTN_MASK, RT5640_RSTN_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTN_MASK | RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK,
+ RT5640_RSTN_DIS | RT5640_HP_L_SMT_EN |
+ RT5640_HP_R_SMT_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_HP_VOL,
+ RT5640_L_MUTE | RT5640_R_MUTE, val);
+ usleep_range(40000, 45000);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_SG_MASK | RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK, RT5640_HP_SG_DIS |
+ RT5640_HP_L_SMT_DIS | RT5640_HP_R_SMT_DIS);
+
+}
+
+static void rt5640_pmd_depop(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+ /* headphone mute sequence */
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
+ RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK |
+ RT5640_CP_FQ3_MASK,
+ (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ1_SFT) |
+ (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+ (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ3_SFT));
+ regmap_write(rt5640->regmap,
+ RT5640_PR_BASE + RT5640_MAMP_INT_REG2, 0xfc00);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_SG_MASK, RT5640_HP_SG_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTP_MASK, RT5640_RSTP_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_RSTP_MASK | RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK, RT5640_RSTP_DIS |
+ RT5640_HP_L_SMT_EN | RT5640_HP_R_SMT_EN);
+
+ regmap_update_bits(rt5640->regmap, RT5640_HP_VOL,
+ RT5640_L_MUTE | RT5640_R_MUTE,
+ RT5640_L_MUTE | RT5640_R_MUTE);
+ usleep_range(40000, 45000);
+
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_SG_MASK |
+ RT5640_HP_L_SMT_MASK |
+ RT5640_HP_R_SMT_MASK,
+ RT5640_HP_SG_DIS |
+ RT5640_HP_L_SMT_DIS |
+ RT5640_HP_R_SMT_DIS);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_SMT_TRIG_MASK |
+ RT5640_HP_CD_PD_MASK |
+ RT5640_HP_CO_MASK |
+ RT5640_HP_CP_MASK |
+ RT5640_HP_SG_MASK |
+ RT5640_HP_CB_MASK,
+ RT5640_SMT_TRIG_DIS |
+ RT5640_HP_CD_PD_EN |
+ RT5640_HP_CO_DIS | RT5640_HP_CP_PD |
+ RT5640_HP_SG_EN | RT5640_HP_CB_PD);
+}
+
+static int rt5640_hp_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_POST_PMU:
+ rt5640_pmu_depop(codec);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ rt5640_pmd_depop(codec);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5640_hp_power_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_POST_PMU:
+ hp_amp_power_on(codec);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
RT5640_PWR_PLL_BIT, 0, NULL, 0),
@@ -1132,15 +1411,23 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
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("Improve HP Amp Drv", RT5640_PWR_ANLG1,
- SND_SOC_NOPM, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1,
+ 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,
+ rt5640_hp_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_L_BIT, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1,
+ SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("SPO L Amp", SND_SOC_NOPM,
+ 0, 0, NULL, 0, rt5640_spo_l_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("SPO R Amp", SND_SOC_NOPM,
+ 0, 0, NULL, 0, rt5640_spo_r_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
- SND_SOC_NOPM, 0, spk_event,
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ RT5640_PWR_CLS_D_BIT, 0, NULL, 0),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("SPOLP"),
SND_SOC_DAPM_OUTPUT("SPOLN"),
@@ -1396,13 +1683,15 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
{"Mono MIX", "BST1 Switch", "BST1"},
- {"HP L Amp", NULL, "HPO MIX L"},
- {"HP R Amp", NULL, "HPO MIX R"},
+ {"HP Amp", NULL, "HPO MIX L"},
+ {"HP Amp", NULL, "HPO MIX R"},
- {"SPOLP", NULL, "SPOL MIX"},
- {"SPOLN", NULL, "SPOL MIX"},
- {"SPORP", NULL, "SPOR MIX"},
- {"SPORN", NULL, "SPOR MIX"},
+ {"SPO L Amp", NULL, "SPOL MIX"},
+ {"SPO R Amp", NULL, "SPOR MIX"},
+ {"SPOLP", NULL, "SPO L Amp"},
+ {"SPOLN", NULL, "SPO L Amp"},
+ {"SPORP", NULL, "SPO R Amp"},
+ {"SPORN", NULL, "SPO R Amp"},
{"SPOLP", NULL, "Improve SPK Amp Drv"},
{"SPOLN", NULL, "Improve SPK Amp Drv"},
@@ -1412,7 +1701,9 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"HPOL", NULL, "Improve HP Amp Drv"},
{"HPOR", NULL, "Improve HP Amp Drv"},
+ {"HPOL", NULL, "HP Amp"},
{"HPOL", NULL, "HP L Amp"},
+ {"HPOR", NULL, "HP Amp"},
{"HPOR", NULL, "HP R Amp"},
{"LOUTL", NULL, "LOUT MIX"},
{"LOUTR", NULL, "LOUT MIX"},
@@ -1792,17 +2083,13 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
RT5640_PWR_BG | RT5640_PWR_VREF2,
RT5640_PWR_VREF1 | RT5640_PWR_MB |
RT5640_PWR_BG | RT5640_PWR_VREF2);
- mdelay(10);
+ usleep_range(15000, 20000);
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_DEPOP_M1,
- 0x001d, 0x0019);
- snd_soc_update_bits(codec, RT5640_DEPOP_M2,
- 0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS,
0x0030, 0x0030);
}
@@ -1846,8 +2133,6 @@ static int rt5640_probe(struct snd_soc_codec *codec)
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
- snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019);
- snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index c48286d..cb6bce9 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -145,6 +145,8 @@
/* Index of Codec Private Register definition */
+#define RT5640_CHPUMP_INT_REG1 0x24
+#define RT5640_MAMP_INT_REG2 0x37
#define RT5640_3D_SPK 0x63
#define RT5640_WND_1 0x6c
#define RT5640_WND_2 0x6d
@@ -153,6 +155,7 @@
#define RT5640_WND_5 0x70
#define RT5640_WND_8 0x73
#define RT5640_DIP_SPK_INF 0x75
+#define RT5640_HP_DCC_INT1 0x77
#define RT5640_EQ_BW_LOP 0xa0
#define RT5640_EQ_GN_LOP 0xa1
#define RT5640_EQ_FC_BP1 0xa2
@@ -1201,6 +1204,14 @@
#define RT5640_CP_FQ2_SFT 4
#define RT5640_CP_FQ3_MASK (0x7)
#define RT5640_CP_FQ3_SFT 0
+#define RT5640_CP_FQ_1_5_KHZ 0
+#define RT5640_CP_FQ_3_KHZ 1
+#define RT5640_CP_FQ_6_KHZ 2
+#define RT5640_CP_FQ_12_KHZ 3
+#define RT5640_CP_FQ_24_KHZ 4
+#define RT5640_CP_FQ_48_KHZ 5
+#define RT5640_CP_FQ_96_KHZ 6
+#define RT5640_CP_FQ_192_KHZ 7
/* HPOUT charge pump (0x91) */
#define RT5640_OSW_L_MASK (0x1 << 11)
@@ -2087,6 +2098,10 @@ struct rt5640_priv {
int pll_out;
int dmic_en;
+ bool spo_l_mute;
+ bool spo_r_mute;
+ bool hp_l_mute;
+ bool hp_r_mute;
};
#endif
--
1.8.1.1.439.g50a6b54
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-05 4:19 bardliao
@ 2013-08-05 14:48 ` Mark Brown
2013-08-05 17:21 ` Lars-Peter Clausen
2013-08-05 17:17 ` Stephen Warren
2013-08-05 17:19 ` Lars-Peter Clausen
2 siblings, 1 reply; 14+ messages in thread
From: Mark Brown @ 2013-08-05 14:48 UTC (permalink / raw)
To: bardliao; +Cc: oder_chiou, alsa-devel, swarren, swarren, lgirdwood, flove
[-- Attachment #1.1: Type: text/plain, Size: 473 bytes --]
On Mon, Aug 05, 2013 at 12:19:03PM +0800, bardliao@realtek.com wrote:
> From: Bard Liao <bardliao@realtek.com>
>
> Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
This looks like you should be using Lars-Peter's patch for controls that
are disabled while a widget isn't powered - as far as I can tell from a
quick read through all this does is keep the speaker/headphone muted
while the outputs are powered down.
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-05 4:19 bardliao
2013-08-05 14:48 ` Mark Brown
@ 2013-08-05 17:17 ` Stephen Warren
2013-08-05 17:19 ` Lars-Peter Clausen
2 siblings, 0 replies; 14+ messages in thread
From: Stephen Warren @ 2013-08-05 17:17 UTC (permalink / raw)
To: bardliao; +Cc: oder_chiou, alsa-devel, swarren, lgirdwood, broonie, flove
On 08/04/2013 10:19 PM, bardliao@realtek.com wrote:
> From: Bard Liao <bardliao@realtek.com>
>
> Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
FWIW, this version,
Tested-by: Stephen Warren <swarren@nvidia.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-05 4:19 bardliao
2013-08-05 14:48 ` Mark Brown
2013-08-05 17:17 ` Stephen Warren
@ 2013-08-05 17:19 ` Lars-Peter Clausen
2 siblings, 0 replies; 14+ messages in thread
From: Lars-Peter Clausen @ 2013-08-05 17:19 UTC (permalink / raw)
To: bardliao
Cc: oder_chiou, alsa-devel, swarren, swarren, lgirdwood, broonie,
flove
On 08/05/2013 06:19 AM, bardliao@realtek.com wrote:
> From: Bard Liao <bardliao@realtek.com>
>
> Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
>
> Signed-off-by: Bard Liao <bardliao@realtek.com>
> ---
> Please ignore the previous patch.
> I have tested speaker and headphone playback on this patch.
> ---
> sound/soc/codecs/rt5640.c | 389 +++++++++++++++++++++++++++++++++++++++-------
> sound/soc/codecs/rt5640.h | 15 ++
> 2 files changed, 352 insertions(+), 52 deletions(-)
>
> diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
> index 4db7314..cae3f46 100644
> --- a/sound/soc/codecs/rt5640.c
> +++ b/sound/soc/codecs/rt5640.c
> @@ -50,8 +50,6 @@ static const struct regmap_range_cfg rt5640_ranges[] = {
>
> static struct reg_default init_list[] = {
> {RT5640_PR_BASE + 0x3d, 0x3600},
> - {RT5640_PR_BASE + 0x1c, 0x0D21},
> - {RT5640_PR_BASE + 0x1b, 0x0000},
> {RT5640_PR_BASE + 0x12, 0x0aa8},
> {RT5640_PR_BASE + 0x14, 0x0aaa},
> {RT5640_PR_BASE + 0x20, 0x6110},
> @@ -378,21 +376,119 @@ static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA,
> 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 char * const rt5640_mute_mode[] = {"mute", "unmute"};
> +
> +static const SOC_ENUM_SINGLE_DECL(rt5640_hp_enum, 0, 0, rt5640_mute_mode);
> +static const SOC_ENUM_SINGLE_DECL(rt5640_spo_enum, 0, 0, rt5640_mute_mode);
> +
These enums seem to be unused. (And switches should be used for mutes and enums)
- Lars
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-05 14:48 ` Mark Brown
@ 2013-08-05 17:21 ` Lars-Peter Clausen
2013-08-05 17:58 ` Mark Brown
0 siblings, 1 reply; 14+ messages in thread
From: Lars-Peter Clausen @ 2013-08-05 17:21 UTC (permalink / raw)
To: Mark Brown
Cc: oder_chiou, alsa-devel, swarren, swarren, lgirdwood, bardliao,
flove
On 08/05/2013 04:48 PM, Mark Brown wrote:
> On Mon, Aug 05, 2013 at 12:19:03PM +0800, bardliao@realtek.com wrote:
>> From: Bard Liao <bardliao@realtek.com>
>>
>> Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
>
> This looks like you should be using Lars-Peter's patch for controls that
> are disabled while a widget isn't powered - as far as I can tell from a
> quick read through all this does is keep the speaker/headphone muted
> while the outputs are powered down.
The driver is using stereo controls though. So either support for stereo
controls needs to be added to DAPM (which shouldn't be too hard) or the
control needs to be split into two mono controls.
- Lars
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-05 17:21 ` Lars-Peter Clausen
@ 2013-08-05 17:58 ` Mark Brown
0 siblings, 0 replies; 14+ messages in thread
From: Mark Brown @ 2013-08-05 17:58 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: oder_chiou, alsa-devel, swarren, swarren, lgirdwood, bardliao,
flove
[-- Attachment #1.1: Type: text/plain, Size: 693 bytes --]
On Mon, Aug 05, 2013 at 07:21:21PM +0200, Lars-Peter Clausen wrote:
> On 08/05/2013 04:48 PM, Mark Brown wrote:
> > This looks like you should be using Lars-Peter's patch for controls that
> > are disabled while a widget isn't powered - as far as I can tell from a
> > quick read through all this does is keep the speaker/headphone muted
> > while the outputs are powered down.
> The driver is using stereo controls though. So either support for stereo
> controls needs to be added to DAPM (which shouldn't be too hard) or the
> control needs to be split into two mono controls.
Yes, I think we should get the stereo support done - this sort of thing
is the main use case I can see for it.
[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] ASoC: rt5640: change widget sequence for depop
@ 2013-08-19 12:18 bardliao
2013-08-19 17:29 ` Stephen Warren
0 siblings, 1 reply; 14+ messages in thread
From: bardliao @ 2013-08-19 12:18 UTC (permalink / raw)
To: broonie, lgirdwood
Cc: oder_chiou, alsa-devel, swarren, swarren, bardliao, flove
From: Bard Liao <bardliao@realtek.com>
Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
Signed-off-by: Bard Liao <bardliao@realtek.com>
---
sound/soc/codecs/rt5640.c | 200 +++++++++++++++++++++++++++++++++-------------
sound/soc/codecs/rt5640.h | 11 +++
2 files changed, 157 insertions(+), 54 deletions(-)
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 4db7314..218aae2 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -50,8 +50,6 @@ static const struct regmap_range_cfg rt5640_ranges[] = {
static struct reg_default init_list[] = {
{RT5640_PR_BASE + 0x3d, 0x3600},
- {RT5640_PR_BASE + 0x1c, 0x0D21},
- {RT5640_PR_BASE + 0x1b, 0x0000},
{RT5640_PR_BASE + 0x12, 0x0aa8},
{RT5640_PR_BASE + 0x14, 0x0aaa},
{RT5640_PR_BASE + 0x20, 0x6110},
@@ -384,15 +382,11 @@ static const SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5640_snd_controls[] = {
/* Speaker Output Volume */
- SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
/* Headphone Output Volume */
- SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
- RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
@@ -737,6 +731,22 @@ static const struct snd_kcontrol_new rt5640_mono_mix[] = {
RT5640_M_BST1_MM_SFT, 1, 1),
};
+static const struct snd_kcontrol_new spk_l_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
+ RT5640_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new spk_r_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
+ RT5640_R_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_l_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
+ RT5640_L_MUTE_SFT, 1, 1);
+
+static const struct snd_kcontrol_new hp_r_enable_control =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
+ RT5640_R_MUTE_SFT, 1, 1);
+
/* Stereo ADC source */
static const char * const rt5640_stereo_adc1_src[] = {
"DIG MIX", "ADC"
@@ -868,33 +878,6 @@ static const SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5640_sdi_mux =
SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
-static int spk_event(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);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
- 0x0001, 0x0001);
- regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
- 0xf000, 0xf000);
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
- 0xf000, 0x0000);
- regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
- 0x0001, 0x0000);
- break;
-
- default:
- return 0;
- }
- return 0;
-}
-
static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -943,6 +926,103 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
return 0;
}
+void hp_amp_power_on(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ /* depop parameters */
+ regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+ RT5640_CHPUMP_INT_REG1, 0x0700, 0x0200);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+ RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
+ RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
+ regmap_write(rt5640->regmap, RT5640_PR_BASE + RT5640_HP_DCC_INT1,
+ 0x9f00);
+ /* headphone amp power on */
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_HA,
+ RT5640_PWR_HA);
+ usleep_range(30000, 35000);
+ regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2 ,
+ RT5640_PWR_FV1 | RT5640_PWR_FV2);
+}
+
+static void rt5640_pmu_depop(struct snd_soc_codec *codec)
+{
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+ RT5640_DEPOP_MASK | RT5640_DIG_DP_MASK,
+ RT5640_DEPOP_AUTO | RT5640_DIG_DP_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_CHARGE_PUMP,
+ RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
+
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
+ RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
+ (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
+ (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+ (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
+
+ regmap_write(rt5640->regmap, RT5640_PR_BASE +
+ RT5640_MAMP_INT_REG2, 0x1c00);
+ regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+ RT5640_HP_CP_MASK | RT5640_HP_SG_MASK,
+ RT5640_HP_CP_PD | RT5640_HP_SG_EN);
+ regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+ RT5640_CHPUMP_INT_REG1, 0x0700, 0x0400);
+}
+
+static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int val = 0, pow;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt5640_pmu_depop(codec);
+ pow = snd_soc_read(codec, RT5640_PWR_ANLG1);
+ if (!(pow & RT5640_PWR_HP_L))
+ val |= RT5640_L_MUTE;
+ if (!(pow & RT5640_PWR_HP_R))
+ val |= RT5640_R_MUTE;
+ snd_soc_update_bits(codec, RT5640_HP_VOL,
+ RT5640_L_MUTE | RT5640_R_MUTE, val);
+ usleep_range(35000, 40000);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ usleep_range(70000, 75000);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5640_hp_power_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_POST_PMU:
+ hp_amp_power_on(codec);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
RT5640_PWR_PLL_BIT, 0, NULL, 0),
@@ -1132,15 +1212,27 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
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("Improve HP Amp Drv", RT5640_PWR_ANLG1,
- SND_SOC_NOPM, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1,
+ 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,
+ rt5640_hp_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_L_BIT, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1,
+ SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1,
RT5640_PWR_HP_R_BIT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
- SND_SOC_NOPM, 0, spk_event,
- SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ RT5640_PWR_CLS_D_BIT, 0, NULL, 0),
+
+ /* Output Switch */
+ SND_SOC_DAPM_SWITCH("Speaker L Playback", SND_SOC_NOPM, 0, 0,
+ &spk_l_enable_control),
+ SND_SOC_DAPM_SWITCH("Speaker R Playback", SND_SOC_NOPM, 0, 0,
+ &spk_r_enable_control),
+ SND_SOC_DAPM_SWITCH("HP L Playback", SND_SOC_NOPM, 0, 0,
+ &hp_l_enable_control),
+ SND_SOC_DAPM_SWITCH("HP R Playback", SND_SOC_NOPM, 0, 0,
+ &hp_r_enable_control),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("SPOLP"),
SND_SOC_DAPM_OUTPUT("SPOLN"),
@@ -1381,9 +1473,11 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"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"},
{"LOUT MIX", "DAC L1 Switch", "DAC L1"},
{"LOUT MIX", "DAC R1 Switch", "DAC R1"},
@@ -1396,13 +1490,15 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
{"Mono MIX", "BST1 Switch", "BST1"},
- {"HP L Amp", NULL, "HPO MIX L"},
- {"HP R Amp", NULL, "HPO MIX R"},
+ {"HP Amp", NULL, "HPO MIX L"},
+ {"HP Amp", NULL, "HPO MIX R"},
- {"SPOLP", NULL, "SPOL MIX"},
- {"SPOLN", NULL, "SPOL MIX"},
- {"SPORP", NULL, "SPOR MIX"},
- {"SPORN", NULL, "SPOR MIX"},
+ {"Speaker L Playback", "Switch", "SPOL MIX"},
+ {"Speaker R Playback", "Switch", "SPOR MIX"},
+ {"SPOLP", NULL, "Speaker L Playback"},
+ {"SPOLN", NULL, "Speaker L Playback"},
+ {"SPORP", NULL, "Speaker R Playback"},
+ {"SPORN", NULL, "Speaker R Playback"},
{"SPOLP", NULL, "Improve SPK Amp Drv"},
{"SPOLN", NULL, "Improve SPK Amp Drv"},
@@ -1412,8 +1508,10 @@ static const struct snd_soc_dapm_route rt5640_dapm_routes[] = {
{"HPOL", NULL, "Improve HP Amp Drv"},
{"HPOR", NULL, "Improve HP Amp Drv"},
- {"HPOL", NULL, "HP L Amp"},
- {"HPOR", NULL, "HP R Amp"},
+ {"HP L Playback", "Switch", "HP Amp"},
+ {"HP R Playback", "Switch", "HP Amp"},
+ {"HPOL", NULL, "HP L Playback"},
+ {"HPOR", NULL, "HP R Playback"},
{"LOUTL", NULL, "LOUT MIX"},
{"LOUTR", NULL, "LOUT MIX"},
{"MONOP", NULL, "Mono MIX"},
@@ -1792,17 +1890,13 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
RT5640_PWR_BG | RT5640_PWR_VREF2,
RT5640_PWR_VREF1 | RT5640_PWR_MB |
RT5640_PWR_BG | RT5640_PWR_VREF2);
- mdelay(10);
+ usleep_range(15000, 20000);
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_DEPOP_M1,
- 0x001d, 0x0019);
- snd_soc_update_bits(codec, RT5640_DEPOP_M2,
- 0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS,
0x0030, 0x0030);
}
@@ -1846,8 +1940,6 @@ static int rt5640_probe(struct snd_soc_codec *codec)
rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
- snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019);
- snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000);
snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index c48286d..4d2cfe7 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -145,6 +145,8 @@
/* Index of Codec Private Register definition */
+#define RT5640_CHPUMP_INT_REG1 0x24
+#define RT5640_MAMP_INT_REG2 0x37
#define RT5640_3D_SPK 0x63
#define RT5640_WND_1 0x6c
#define RT5640_WND_2 0x6d
@@ -153,6 +155,7 @@
#define RT5640_WND_5 0x70
#define RT5640_WND_8 0x73
#define RT5640_DIP_SPK_INF 0x75
+#define RT5640_HP_DCC_INT1 0x77
#define RT5640_EQ_BW_LOP 0xa0
#define RT5640_EQ_GN_LOP 0xa1
#define RT5640_EQ_FC_BP1 0xa2
@@ -1201,6 +1204,14 @@
#define RT5640_CP_FQ2_SFT 4
#define RT5640_CP_FQ3_MASK (0x7)
#define RT5640_CP_FQ3_SFT 0
+#define RT5640_CP_FQ_1_5_KHZ 0
+#define RT5640_CP_FQ_3_KHZ 1
+#define RT5640_CP_FQ_6_KHZ 2
+#define RT5640_CP_FQ_12_KHZ 3
+#define RT5640_CP_FQ_24_KHZ 4
+#define RT5640_CP_FQ_48_KHZ 5
+#define RT5640_CP_FQ_96_KHZ 6
+#define RT5640_CP_FQ_192_KHZ 7
/* HPOUT charge pump (0x91) */
#define RT5640_OSW_L_MASK (0x1 << 11)
--
1.8.1.1.439.g50a6b54
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-19 12:18 [PATCH] ASoC: rt5640: change widget sequence for depop bardliao
@ 2013-08-19 17:29 ` Stephen Warren
2013-08-20 2:36 ` Bard Liao
0 siblings, 1 reply; 14+ messages in thread
From: Stephen Warren @ 2013-08-19 17:29 UTC (permalink / raw)
To: bardliao; +Cc: oder_chiou, alsa-devel, swarren, lgirdwood, broonie, flove
On 08/19/2013 06:18 AM, bardliao@realtek.com wrote:
> From: Bard Liao <bardliao@realtek.com>
>
> Add mute/unmute control in widget event and modify the power on/off sequence to avoid pop noise.
This version breaks both headphone and speaker output. I see the
following issues:
1)
After a reboot, if all of "{HP,Speaker} [LR] Playback Switch" are
on/unmuted, and I start playback, then something sets all those controls
to off/muted. I suspect this is related to function rt5640_hp_event()
twiddling the same RT5640_[LR]_MUTE bits that the hp_[lr]_enable_control
controls twiddle.
2)
If playback is running, and (1) has caused all output to be muted, and I
then run alsamixer and enable/unmute "HP L Playback Switch", I hear
sound on both the L and R headphone channels for a very brief time, then
output switches to the L channel only. Similar happens if I unmute "HP R
Playback Switch" first. Unmuting both switches does produce stereo sound
as expected.
I don't know if this also happens for the speaker output, since the
board is too far away from me to easily tell which speakers are playing.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-19 17:29 ` Stephen Warren
@ 2013-08-20 2:36 ` Bard Liao
2013-08-20 16:15 ` Stephen Warren
0 siblings, 1 reply; 14+ messages in thread
From: Bard Liao @ 2013-08-20 2:36 UTC (permalink / raw)
To: Stephen Warren
Cc: Oder Chiou, alsa-devel@alsa-project.org, swarren@nvidia.com,
lgirdwood@gmail.com, broonie@kernel.org, Flove
> -----Original Message-----
> From: Stephen Warren [mailto:swarren@wwwdotorg.org]
> Sent: Tuesday, August 20, 2013 1:30 AM
> To: Bard Liao
> Cc: broonie@kernel.org; lgirdwood@gmail.com; alsa-devel@alsa-project.org;
> Flove; Oder Chiou; swarren@nvidia.com
> Subject: Re: [PATCH] ASoC: rt5640: change widget sequence for depop
>
> On 08/19/2013 06:18 AM, bardliao@realtek.com wrote:
> > From: Bard Liao <bardliao@realtek.com>
> >
> > Add mute/unmute control in widget event and modify the power on/off
> sequence to avoid pop noise.
>
> This version breaks both headphone and speaker output. I see the following
> issues:
>
> 1)
>
> After a reboot, if all of "{HP,Speaker} [LR] Playback Switch" are on/unmuted,
> and I start playback, then something sets all those controls to off/muted. I
> suspect this is related to function rt5640_hp_event() twiddling the same
> RT5640_[LR]_MUTE bits that the hp_[lr]_enable_control controls twiddle.
>
> 2)
>
> If playback is running, and (1) has caused all output to be muted, and I then
> run alsamixer and enable/unmute "HP L Playback Switch", I hear sound on
> both the L and R headphone channels for a very brief time, then output
> switches to the L channel only. Similar happens if I unmute "HP R Playback
> Switch" first. Unmuting both switches does produce stereo sound as expected.
>
> I don't know if this also happens for the speaker output, since the board is too
> far away from me to easily tell which speakers are playing.
I think you didn't apply Lars-Peter's patch as below.
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -229,6 +229,8 @@ static int dapm_kcontrol_data_alloc(struct
template.id = snd_soc_dapm_kcontrol;
template.name = kcontrol->id.name;
+ data->value = template.on_val;
+
data->widget = snd_soc_dapm_new_control(widget->dapm,
&template);
if (!data->widget) {
It should be able to solve this issue.
If I remove this patch I can reproduce the issue.
Sorry for not informing you about that.
>
> ------Please consider the environment before printing this e-mail.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-20 2:36 ` Bard Liao
@ 2013-08-20 16:15 ` Stephen Warren
2013-08-21 19:56 ` Lars-Peter Clausen
0 siblings, 1 reply; 14+ messages in thread
From: Stephen Warren @ 2013-08-20 16:15 UTC (permalink / raw)
To: Bard Liao
Cc: Oder Chiou, alsa-devel@alsa-project.org, Lars-Peter Clausen,
swarren@nvidia.com, lgirdwood@gmail.com, broonie@kernel.org,
Flove
On 08/19/2013 08:36 PM, Bard Liao wrote:
>> -----Original Message-----
>> From: Stephen Warren [mailto:swarren@wwwdotorg.org]
>> Sent: Tuesday, August 20, 2013 1:30 AM
>> To: Bard Liao
>> Cc: broonie@kernel.org; lgirdwood@gmail.com; alsa-devel@alsa-project.org;
>> Flove; Oder Chiou; swarren@nvidia.com
>> Subject: Re: [PATCH] ASoC: rt5640: change widget sequence for depop
>>
>> On 08/19/2013 06:18 AM, bardliao@realtek.com wrote:
>>> From: Bard Liao <bardliao@realtek.com>
>>>
>>> Add mute/unmute control in widget event and modify the power on/off
>> sequence to avoid pop noise.
>>
>> This version breaks both headphone and speaker output. I see the following
>> issues:
>>
>> 1)
>>
>> After a reboot, if all of "{HP,Speaker} [LR] Playback Switch" are on/unmuted,
>> and I start playback, then something sets all those controls to off/muted. I
>> suspect this is related to function rt5640_hp_event() twiddling the same
>> RT5640_[LR]_MUTE bits that the hp_[lr]_enable_control controls twiddle.
>>
>> 2)
>>
>> If playback is running, and (1) has caused all output to be muted, and I then
>> run alsamixer and enable/unmute "HP L Playback Switch", I hear sound on
>> both the L and R headphone channels for a very brief time, then output
>> switches to the L channel only. Similar happens if I unmute "HP R Playback
>> Switch" first. Unmuting both switches does produce stereo sound as expected.
>>
>> I don't know if this also happens for the speaker output, since the board is too
>> far away from me to easily tell which speakers are playing.
>
> I think you didn't apply Lars-Peter's patch as below.
> --- a/sound/soc/soc-dapm.c
> +++ b/sound/soc/soc-dapm.c
> @@ -229,6 +229,8 @@ static int dapm_kcontrol_data_alloc(struct
> template.id = snd_soc_dapm_kcontrol;
> template.name = kcontrol->id.name;
>
> + data->value = template.on_val;
> +
> data->widget = snd_soc_dapm_new_control(widget->dapm,
> &template);
> if (!data->widget) {
>
> It should be able to solve this issue.
> If I remove this patch I can reproduce the issue.
> Sorry for not informing you about that.
As far as I can tell, Lars-Peter hasn't actually sent such a patch to
the list; he simply mentioned this change inline in the middle of a
thread following an earlier version of this patch.
Lars-Peter, are you planning on sending the change above as a patch for
Mark to apply?
With that patch also applied, symptom (1) I mentioned above is indeed
fixed. However, symptom is still observed.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] ASoC: rt5640: change widget sequence for depop
2013-08-20 16:15 ` Stephen Warren
@ 2013-08-21 19:56 ` Lars-Peter Clausen
0 siblings, 0 replies; 14+ messages in thread
From: Lars-Peter Clausen @ 2013-08-21 19:56 UTC (permalink / raw)
To: Stephen Warren
Cc: Oder Chiou, alsa-devel@alsa-project.org, swarren@nvidia.com,
lgirdwood@gmail.com, broonie@kernel.org, Bard Liao, Flove
On 08/20/2013 06:15 PM, Stephen Warren wrote:
[...]
> Lars-Peter, are you planning on sending the change above as a patch for
> Mark to apply?
I will send the patch next week, once I'm back from vacation.
- Lars
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2013-08-21 19:55 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-19 12:18 [PATCH] ASoC: rt5640: change widget sequence for depop bardliao
2013-08-19 17:29 ` Stephen Warren
2013-08-20 2:36 ` Bard Liao
2013-08-20 16:15 ` Stephen Warren
2013-08-21 19:56 ` Lars-Peter Clausen
-- strict thread matches above, loose matches on Subject: below --
2013-08-05 4:19 bardliao
2013-08-05 14:48 ` Mark Brown
2013-08-05 17:21 ` Lars-Peter Clausen
2013-08-05 17:58 ` Mark Brown
2013-08-05 17:17 ` Stephen Warren
2013-08-05 17:19 ` Lars-Peter Clausen
2013-08-02 2:38 bardliao
2013-08-02 15:53 ` Stephen Warren
2013-08-05 3:34 ` Bard Liao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).