This driver does not properly map jack pins to kcontrols that PulseAudio and PipeWire need to handle jack detection events. The RT5682, RT5682s, NAU8825 and NAU8821 codecs used here can detect Headphone and Headset Mic connections. Expose both to userspace as kcontrols and add the necessary widgets. Split the jack and pin structs per-codec to accommodate for per-codec differences. Signed-off-by: Alper Nebi Yasak <alpernebiyasak@xxxxxxxxx> --- Do I have to keep the lowercase "jack" in the last one instead? Should the SND_JACK_LINEOUT be removed from the jack_new_pins calls? I don't know why it was split as vg_headset / pco_jack, maybe everything could be merged instead? sound/soc/amd/acp/acp-mach-common.c | 226 ++++++++++++++++++++++------ 1 file changed, 182 insertions(+), 44 deletions(-) diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index ff5cbc4a6427..f3abaa182fbb 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -28,7 +28,6 @@ #include "../../codecs/nau8821.h" #include "acp-mach.h" -static struct snd_soc_jack vg_headset; #define PCO_PLAT_CLK 48000000 #define RT5682_PLL_FREQ (48000 * 512) #define DUAL_CHANNEL 2 @@ -52,8 +51,6 @@ const struct dmi_system_id acp_quirk_table[] = { }; EXPORT_SYMBOL_GPL(acp_quirk_table); -static struct snd_soc_jack pco_jack; - static const unsigned int channels[] = { DUAL_CHANNEL, }; @@ -87,6 +84,28 @@ static int acp_clk_enable(struct acp_card_drvdata *drvdata, SND_SOC_DAILINK_DEF(rt5682, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); +static struct snd_soc_jack rt5682_jack; +static struct snd_soc_jack_pin rt5682_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -110,22 +129,38 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets, + ARRAY_SIZE(rt5682_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682_controls, + ARRAY_SIZE(rt5682_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &rt5682_jack, + rt5682_jack_pins, + ARRAY_SIZE(rt5682_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -275,6 +310,28 @@ static const struct snd_soc_ops acp_card_rt5682_ops = { SND_SOC_DAILINK_DEF(rt5682s, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1"))); +static struct snd_soc_jack rt5682s_jack; +static struct snd_soc_jack_pin rt5682s_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new rt5682s_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget rt5682s_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route rt5682s_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -299,22 +356,38 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); } - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + ret = snd_soc_dapm_new_controls(&card->dapm, rt5682s_widgets, + ARRAY_SIZE(rt5682s_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5682s_controls, + ARRAY_SIZE(rt5682s_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &rt5682s_jack, + rt5682s_jack_pins, + ARRAY_SIZE(rt5682s_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(rt5682s_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &rt5682s_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -762,6 +835,28 @@ static const struct snd_soc_ops acp_max98388_ops = { SND_SOC_DAILINK_DEF(nau8825, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); +static struct snd_soc_jack nau8825_jack; +static struct snd_soc_jack_pin nau8825_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8825_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget nau8825_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + static const struct snd_soc_dapm_route nau8825_map[] = { { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -780,22 +875,38 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd) if (drvdata->hs_codec_id != NAU8825) return -EINVAL; - ret = snd_soc_card_jack_new(card, "Headset Jack", + ret = snd_soc_dapm_new_controls(&card->dapm, nau8825_widgets, + ARRAY_SIZE(nau8825_widgets)); + if (ret) { + dev_err(rtd->dev, "unable to add widget dapm controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, nau8825_controls, + ARRAY_SIZE(nau8825_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, - &pco_jack); + &nau8825_jack, + nau8825_jack_pins, + ARRAY_SIZE(nau8825_jack_pins)); if (ret) { dev_err(card->dev, "HP jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8825_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + ret = snd_soc_component_set_jack(component, &nau8825_jack, NULL); if (ret) { dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); return ret; @@ -921,8 +1032,25 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return ret; } +static struct snd_soc_jack nau8821_jack; +static struct snd_soc_jack_pin nau8821_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static const struct snd_kcontrol_new nau8821_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + static const struct snd_soc_dapm_widget nau8821_widgets[] = { - SND_SOC_DAPM_HP("Headphone jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, @@ -932,12 +1060,12 @@ static const struct snd_soc_dapm_widget nau8821_widgets[] = { static const struct snd_soc_dapm_route nau8821_audio_route[] = { /* HP jack connectors - unknown if we have jack detection */ - { "Headphone jack", NULL, "HPOL" }, - { "Headphone jack", NULL, "HPOR" }, + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, { "MICL", NULL, "Headset Mic" }, { "MICR", NULL, "Headset Mic" }, { "DMIC", NULL, "Int Mic" }, - { "Headphone jack", NULL, "Platform Clock" }, + { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, { "Int Mic", NULL, "Platform Clock" }, }; @@ -966,21 +1094,31 @@ static int acp_8821_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ret = snd_soc_card_jack_new(card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &vg_headset); + ret = snd_soc_add_card_controls(card, nau8821_controls, + ARRAY_SIZE(nau8821_controls)); + if (ret) { + dev_err(rtd->dev, "unable to add card controls, ret %d\n", ret); + return ret; + } + + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &nau8821_jack, + nau8821_jack_pins, + ARRAY_SIZE(nau8821_jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - nau8821_enable_jack_detect(component, &vg_headset); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(nau8821_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + nau8821_enable_jack_detect(component, &nau8821_jack); return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8821_audio_route, ARRAY_SIZE(nau8821_audio_route)); -- 2.40.1