[alsa-devel] [PATCH] ASoC: rt5640: change widget sequence for depop
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
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.
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
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.
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 1:21 AM To: Mark Brown Cc: Bard Liao; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widget sequence fordepop
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
I think I need to use SND_SOC_DAPM_SWITCH with SOC_DAPM_SINGLE_AUTODISABLE for this control. Am I right? I am trying to do that, but meet a problem. If I set speaker switch unmute before playing music, dapm will mute it automatically in power on sequence. The only way I can unmute speaker is set speaker switch unmute while playing music. Did I miss something?
------Please consider the environment before printing this e-mail.
On 08/06/2013 10:07 AM, Bard Liao wrote:
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 1:21 AM To: Mark Brown Cc: Bard Liao; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widget sequence fordepop
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
I think I need to use SND_SOC_DAPM_SWITCH with SOC_DAPM_SINGLE_AUTODISABLE for this control. Am I right? I am trying to do that, but meet a problem. If I set speaker switch unmute before playing music, dapm will mute it automatically in power on sequence. The only way I can unmute speaker is set speaker switch unmute while playing music.
DAPM should unmute the switch on power up and mute it on power down. The Speaker Channel Switch control has the invert flag set did you also set the invert flag for the new autodisable control?
- Lars
I think I need to use SND_SOC_DAPM_SWITCH with
SOC_DAPM_SINGLE_AUTODISABLE for this control.
Am I right? I am trying to do that, but meet a problem. If I set speaker switch unmute before playing music, dapm will mute it
automatically in power on sequence.
The only way I can unmute speaker is set speaker switch unmute while
playing music.
DAPM should unmute the switch on power up and mute it on power down. The Speaker Channel Switch control has the invert flag set did you also set the invert flag for the new autodisable control?
Yes, the related code is as below. 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);
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),
I tried set SND_SOC_DAPM_SWITCH invert flag, but it comes the same result. I will do some more experiments about it.
- Lars
------Please consider the environment before printing this e-mail.
On 08/06/2013 11:13 AM, Bard Liao wrote:
I think I need to use SND_SOC_DAPM_SWITCH with
SOC_DAPM_SINGLE_AUTODISABLE for this control.
Am I right? I am trying to do that, but meet a problem. If I set speaker switch unmute before playing music, dapm will mute it
automatically in power on sequence.
The only way I can unmute speaker is set speaker switch unmute while
playing music.
DAPM should unmute the switch on power up and mute it on power down. The Speaker Channel Switch control has the invert flag set did you also set the invert flag for the new autodisable control?
Yes, the related code is as below. 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);
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),
Looks good. Maybe I got the invert = 1 case wrong somewhere. Can you add a couple of printks and send me the result?
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2da258b..18c62ae 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -229,6 +229,9 @@ template.id = snd_soc_dapm_kcontrol; template.name = kcontrol->id.name;
+ printk("new control: %s %d\n", template->name, + template->off_val); + data->widget = snd_soc_dapm_new_control(widget->dapm, &template); if (!data->widget) { @@ -337,8 +340,10 @@ if (data->value == value) return false;
- if (data->widget) + if (data->widget) { data->widget->on_val = value; + printk("%s->on_val = %d\n", data->widget->name, value); + }
data->value = value;
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 5:36 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/06/2013 11:13 AM, Bard Liao wrote:
I think I need to use SND_SOC_DAPM_SWITCH with
SOC_DAPM_SINGLE_AUTODISABLE for this control.
Am I right? I am trying to do that, but meet a problem. If I set speaker switch unmute before playing music, dapm will mute it
automatically in power on sequence.
The only way I can unmute speaker is set speaker switch unmute while
playing music.
DAPM should unmute the switch on power up and mute it on power down. The Speaker Channel Switch control has the invert flag set did you also set the invert flag for the new autodisable control?
Yes, the related code is as below. 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);
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),
Looks good. Maybe I got the invert = 1 case wrong somewhere. Can you add a couple of printks and send me the result?
The result is as below.
[ 9.418738] new control: Speaker R Playback Switch 1 [ 9.423949] new control: Speaker L Playback Switch 1
root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 0 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=off root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 163.717158] Speaker L Playback Switch->on_val = 1 root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 1 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=on root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 174.482833] Speaker L Playback Switch->on_val = 0
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2da258b..18c62ae 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -229,6 +229,9 @@ template.id = snd_soc_dapm_kcontrol; template.name = kcontrol->id.name;
printk("new control: %s %d\n", template->name,
template->off_val);
data->widget = snd_soc_dapm_new_control(widget->dapm, &template); if (!data->widget) {
@@ -337,8 +340,10 @@ if (data->value == value) return false;
- if (data->widget)
if (data->widget) { data->widget->on_val = value;
printk("%s->on_val = %d\n", data->widget->name, value);
}
data->value = value;
------Please consider the environment before printing this e-mail.
On 08/06/2013 12:07 PM, Bard Liao wrote:
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 5:36 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/06/2013 11:13 AM, Bard Liao wrote:
I think I need to use SND_SOC_DAPM_SWITCH with
SOC_DAPM_SINGLE_AUTODISABLE for this control.
Am I right? I am trying to do that, but meet a problem. If I set speaker switch unmute before playing music, dapm will mute it
automatically in power on sequence.
The only way I can unmute speaker is set speaker switch unmute while
playing music.
DAPM should unmute the switch on power up and mute it on power down. The Speaker Channel Switch control has the invert flag set did you also set the invert flag for the new autodisable control?
Yes, the related code is as below. 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);
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),
Looks good. Maybe I got the invert = 1 case wrong somewhere. Can you add a couple of printks and send me the result?
The result is as below.
[ 9.418738] new control: Speaker R Playback Switch 1 [ 9.423949] new control: Speaker L Playback Switch 1
root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 0 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=off root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 163.717158] Speaker L Playback Switch->on_val = 1 root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 1 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=on root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 174.482833] Speaker L Playback Switch->on_val = 0
That looks right, right? on_val is what is going to be written to the control's register. And in your case this needs to be 0 for unmute and 1 for mute. So why would DAPM mute the control on power-up?
- Lars
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 6:17 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/06/2013 12:07 PM, Bard Liao wrote:
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 5:36 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com;
Flove
Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/06/2013 11:13 AM, Bard Liao wrote:
I think I need to use SND_SOC_DAPM_SWITCH with
SOC_DAPM_SINGLE_AUTODISABLE for this control.
Am I right? I am trying to do that, but meet a problem. If I set speaker switch unmute before playing music, dapm will mute it
automatically in power on sequence.
The only way I can unmute speaker is set speaker switch unmute while
playing music.
DAPM should unmute the switch on power up and mute it on power
down.
The Speaker Channel Switch control has the invert flag set did you also set the invert flag for the new autodisable control?
Yes, the related code is as below. 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);
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),
Looks good. Maybe I got the invert = 1 case wrong somewhere. Can you add a couple of printks and send me the result?
The result is as below.
[ 9.418738] new control: Speaker R Playback Switch 1 [ 9.423949] new control: Speaker L Playback Switch 1
root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 0 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=off root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 163.717158] Speaker L Playback Switch->on_val = 1 root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 1 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=on root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 174.482833] Speaker L Playback Switch->on_val = 0
That looks right, right? on_val is what is going to be written to the control's register. And in your case this needs to be 0 for unmute and 1 for mute. So why would DAPM mute the control on power-up?
I think the issue is that the on_val is set to be off_val in dapm_kcontrol_data_alloc. And if I launch "amixer cget name="Speaker L Playback Switch" after the system boot up immediately it will show values=on. I think it should show values=off, since the dapm path is actually disconnected. If I launch " amixer cset name="Speaker L Playback Switch" 1", the dapm path will be connected. But dapm_kcontrol_set_value will return false in if (data->value == value) condition. So the on_val will not be set in dapm_kcontrol_set_value, and will equal to off_val still. If I set "Speaker L Playback Switch" off and on, the issue will disappear.
- Lars
------Please consider the environment before printing this e-mail.
On 08/06/2013 01:04 PM, Bard Liao wrote:
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 6:17 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/06/2013 12:07 PM, Bard Liao wrote:
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Tuesday, August 06, 2013 5:36 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com;
Flove
Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/06/2013 11:13 AM, Bard Liao wrote:
> I think I need to use SND_SOC_DAPM_SWITCH with SOC_DAPM_SINGLE_AUTODISABLE for this control. > Am I right? > I am trying to do that, but meet a problem. > If I set speaker switch unmute before playing music, dapm will > mute it automatically in power on sequence. > The only way I can unmute speaker is set speaker switch unmute > while playing music.
DAPM should unmute the switch on power up and mute it on power
down.
The Speaker Channel Switch control has the invert flag set did you also set the invert flag for the new autodisable control?
Yes, the related code is as below. 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);
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),
Looks good. Maybe I got the invert = 1 case wrong somewhere. Can you add a couple of printks and send me the result?
The result is as below.
[ 9.418738] new control: Speaker R Playback Switch 1 [ 9.423949] new control: Speaker L Playback Switch 1
root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 0 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=off root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 163.717158] Speaker L Playback Switch->on_val = 1 root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# amixer cset name="Speaker L Playback Switch" 1 numid=25,iface=MIXER,name='Speaker L Playback Switch' ; type=BOOLEAN,access=rw------,values=1 : values=on root@tegra-ubuntu:/home/ubuntu# root@tegra-ubuntu:/home/ubuntu# dmesg -c [ 174.482833] Speaker L Playback Switch->on_val = 0
That looks right, right? on_val is what is going to be written to the control's register. And in your case this needs to be 0 for unmute and 1 for mute. So why would DAPM mute the control on power-up?
I think the issue is that the on_val is set to be off_val in dapm_kcontrol_data_alloc. And if I launch "amixer cget name="Speaker L Playback Switch" after the system boot up immediately it will show values=on. I think it should show values=off, since the dapm path is actually disconnected. If I launch " amixer cset name="Speaker L Playback Switch" 1", the dapm path will be connected. But dapm_kcontrol_set_value will return false in if (data->value == value) condition. So the on_val will not be set in dapm_kcontrol_set_value, and will equal to off_val still. If I set "Speaker L Playback Switch" off and on, the issue will disappear.
Makes sense. So this should fix it, I guess:
--- 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) {
Makes sense. So this should fix it, I guess:
--- 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 works. Thanks.
------Please consider the environment before printing this e-mail.
Is there any way to run an event when power up/down a snd_soc_dapm_kcontrol type widgt? Because we need to do something with mute/unmute headphone. e.g. rt5640_pmu_depop is what we need when unmute headphone. We need to set something before and after set the hp mute bit.
If there is an event to do that, it will be easier to implement that.
Thanks.
On 08/07/2013 07:40 AM, Bard Liao wrote:
Is there any way to run an event when power up/down a snd_soc_dapm_kcontrol type widgt? Because we need to do something with mute/unmute headphone. e.g. rt5640_pmu_depop is what we need when unmute headphone. We need to set something before and after set the hp mute bit.
If there is an event to do that, it will be easier to implement that.
You can setup a event for the SND_SOC_DAPM_SWITCH, but this will run after setting the mute bit and before clearing the mute bit.
- Lars
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Wednesday, August 07, 2013 3:45 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/07/2013 07:40 AM, Bard Liao wrote:
Is there any way to run an event when power up/down a
snd_soc_dapm_kcontrol type widgt?
Because we need to do something with mute/unmute headphone. e.g. rt5640_pmu_depop is what we need when unmute headphone. We need to set something before and after set the hp mute bit.
If there is an event to do that, it will be easier to implement that.
You can setup a event for the SND_SOC_DAPM_SWITCH, but this will run after setting the mute bit and before clearing the mute bit.
It seems not to be suitable for me. For me, It is better to run before setting the mute bit and after clearing the mute bit, too.
- Lars
------Please consider the environment before printing this e-mail.
On 08/07/2013 10:03 AM, Bard Liao wrote:
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Wednesday, August 07, 2013 3:45 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/07/2013 07:40 AM, Bard Liao wrote:
Is there any way to run an event when power up/down a
snd_soc_dapm_kcontrol type widgt?
Because we need to do something with mute/unmute headphone. e.g. rt5640_pmu_depop is what we need when unmute headphone. We need to set something before and after set the hp mute bit.
If there is an event to do that, it will be easier to implement that.
You can setup a event for the SND_SOC_DAPM_SWITCH, but this will run after setting the mute bit and before clearing the mute bit.
It seems not to be suitable for me. For me, It is better to run before setting the mute bit and after clearing the mute bit, too.
That isn't really supported right now. If muting and unmuting the control is such a complex sequence maybe it is better to stay with you previous solution, without autodisable.
- Lars
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Wednesday, August 07, 2013 4:27 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/07/2013 10:03 AM, Bard Liao wrote:
-----Original Message----- From: Lars-Peter Clausen [mailto:lars@metafoo.de] Sent: Wednesday, August 07, 2013 3:45 PM To: Bard Liao Cc: Mark Brown; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com;
Flove
Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On 08/07/2013 07:40 AM, Bard Liao wrote:
Is there any way to run an event when power up/down a
snd_soc_dapm_kcontrol type widgt?
Because we need to do something with mute/unmute headphone. e.g. rt5640_pmu_depop is what we need when unmute headphone. We need to set something before and after set the hp mute bit.
If there is an event to do that, it will be easier to implement that.
You can setup a event for the SND_SOC_DAPM_SWITCH, but this will run after setting the mute bit and before clearing the mute bit.
It seems not to be suitable for me. For me, It is better to run before setting the mute bit and after clearing the
mute bit, too.
That isn't really supported right now. If muting and unmuting the control is such a complex sequence maybe it is better to stay with you previous solution, without autodisable.
That's fine. I will check with our HW engineer to see if there is a simple sequence for headphone muting and unmuting.
Thanks.
- Lars
------Please consider the environment before printing this e-mail.
On Wed, Aug 07, 2013 at 10:26:35AM +0200, Lars-Peter Clausen wrote:
That isn't really supported right now. If muting and unmuting the control is such a complex sequence maybe it is better to stay with you previous solution, without autodisable.
Adding an event callback shouldn't be hard?
On 08/07/2013 11:36 AM, Mark Brown wrote:
On Wed, Aug 07, 2013 at 10:26:35AM +0200, Lars-Peter Clausen wrote:
That isn't really supported right now. If muting and unmuting the control is such a complex sequence maybe it is better to stay with you previous solution, without autodisable.
Adding an event callback shouldn't be hard?
But tricky. The widget of course can have a event callback, but since the widget is created by the DAPM layer and not the codec driver there is currently no way to setup the callback. And then there is of course the question when do you want to run the callback, only if DAPM unmutes the control, if the user unmutes the control or both.
One thing that could work is to setup SND_SOC_DAPM_{PRE,POST}_REG events for the SWITCH widget. This callback gets called whenever user changes the control (and it is not disabled by DAPM). The next step then would be to set up an internal event callback for kcontrol widgets which then again calls the event callbacks for the kcontrol's widgets like we do in dapm_widget_update(). But I'm not convinced that this is the best way to solve this. I think it makes things more complicated than they need to be. I think having a OUTDRV widget along the path that runs the mute and unmute sequence might be a better option. And then have virtual switch control to let userspace disconnect the path, so that it is still possbile to manually mute it.
- Lars
On Wed, Aug 07, 2013 at 12:47:16PM +0200, Lars-Peter Clausen wrote:
On 08/07/2013 11:36 AM, Mark Brown wrote:
Adding an event callback shouldn't be hard?
But tricky. The widget of course can have a event callback, but since the widget is created by the DAPM layer and not the codec driver there is currently no way to setup the callback. And then there is of course the question when do you want to run the callback, only if DAPM unmutes the control, if the user unmutes the control or both.
I'd expect to run any time we actually interact with the hardware.
One thing that could work is to setup SND_SOC_DAPM_{PRE,POST}_REG events for the SWITCH widget. This callback gets called whenever user changes the control (and it is not disabled by DAPM). The next step then would be to set up an internal event callback for kcontrol widgets which then again calls the event callbacks for the kcontrol's widgets like we do in dapm_widget_update(). But I'm not convinced that this is the best way to solve this. I think it makes things more complicated than they need to be. I think having a OUTDRV widget along the path that runs the mute and unmute sequence might be a better option. And then have virtual switch control to let userspace disconnect the path, so that it is still possbile to manually mute it.
This only works for mute and unmute, it won't work for things like fun sequences to do volume changes.
One thing that could work is to setup SND_SOC_DAPM_{PRE,POST}_REG events for the SWITCH widget. This callback gets called whenever user changes the control (and it is not disabled by DAPM). The next step then would be to set up an internal event callback for kcontrol widgets which then again calls the event callbacks for the kcontrol's widgets like we do in dapm_widget_update(). But I'm not convinced that this is the best way to solve this. I think it makes things more complicated than they need to be. I think having a OUTDRV widget along the path that runs the mute and unmute sequence might be a better option. And then have virtual switch control to let userspace disconnect the path, so that it is still possbile to manually mute it.
Does "virtual switch control" mean a switch control which will not touch the codec's register actually?
- Lars
------Please consider the environment before printing this e-mail.
On 08/09/2013 11:05 AM, Bard Liao wrote:
One thing that could work is to setup SND_SOC_DAPM_{PRE,POST}_REG events for the SWITCH widget. This callback gets called whenever user changes the control (and it is not disabled by DAPM). The next step then would be to set up an internal event callback for kcontrol widgets which then again calls the event callbacks for the kcontrol's widgets like we do in dapm_widget_update(). But I'm not convinced that this is the best way to solve this. I think it makes things more complicated than they need to be. I think having a OUTDRV widget along the path that runs the mute and unmute sequence might be a better option. And then have virtual switch control to let userspace disconnect the path, so that it is still possbile to manually mute it.
Does "virtual switch control" mean a switch control which will not touch the codec's register actually?
Yes. But Mark seems to prefer the solution using {PRE,POST}_REG events.
- Lars
On Fri, Aug 09, 2013 at 03:37:46PM +0200, Lars-Peter Clausen wrote:
On 08/09/2013 11:05 AM, Bard Liao wrote:
Does "virtual switch control" mean a switch control which will not touch the codec's register actually?
Yes. But Mark seems to prefer the solution using {PRE,POST}_REG events.
I don't mind that much, neither way should be a problem for the framework.
-----Original Message----- From: Mark Brown [mailto:broonie@kernel.org] Sent: Friday, August 09, 2013 10:59 PM To: Lars-Peter Clausen Cc: Bard Liao; Oder Chiou; alsa-devel@alsa-project.org; swarren@nvidia.com; swarren@wwwdotorg.org; lgirdwood@gmail.com; Flove Subject: Re: [alsa-devel] [PATCH] ASoC: rt5640: change widgetsequencefordepop
On Fri, Aug 09, 2013 at 03:37:46PM +0200, Lars-Peter Clausen wrote:
On 08/09/2013 11:05 AM, Bard Liao wrote:
Does "virtual switch control" mean a switch control which will not touch
the codec's register actually?
Yes. But Mark seems to prefer the solution using {PRE,POST}_REG events.
I don't mind that much, neither way should be a problem for the framework.
Does SOC_DAPM_SINGLE_AUTODISABLE support SND_SOC_DAPM_{PRE,POST}_REG event? It seems SND_SOC_DAPM_{PRE,POST}_REG event is supported in SOC_DAPM_SINGLE but not in SOC_DAPM_SINGLE_AUTODISABLE.
------Please consider the environment before printing this e-mail.
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
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
participants (5)
-
Bard Liao
-
bardliao@realtek.com
-
Lars-Peter Clausen
-
Mark Brown
-
Stephen Warren