[alsa-devel] [PATCH 1/2] ALSA: HDA: Support single 3-pin jack without VREF on the actual pin
Some ASUS device has a single 3-pin jack that can either be a mic or a headphone, but the pin does not have VREF capabilities. We've been told by Realtek to instead enable VREF on pin 0x18 in that case.
BugLink: https://bugs.launchpad.net/bugs/1018262 Tested-by: Chih-Hsyuan Ho chih.ho@canonical.com Signed-off-by: David Henningsson david.henningsson@canonical.com --- sound/pci/hda/patch_realtek.c | 49 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-)
Alsa info: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1018262/+attachment/320...
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5c81ee9..6174d4a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -303,6 +303,38 @@ static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx) static void call_update_outputs(struct hda_codec *codec); static void alc_inv_dmic_sync(struct hda_codec *codec, bool force);
+/* for shared I/O, change the pin-control accordingly */ +static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) +{ + struct alc_spec *spec = codec->spec; + unsigned int val; + hda_nid_t pin = spec->autocfg.inputs[1].pin; + /* NOTE: this assumes that there are only two inputs, the + * first is the real internal mic and the second is HP/mic jack. + */ + + val = snd_hda_get_default_vref(codec, pin); + + /* This pin does not have vref caps - let's instead enable vref on pin 0x18 + instead, as suggested by Realtek */ + if (val == AC_PINCTL_VREF_HIZ) { + const hda_nid_t vref_pin = 0x18; + /* Sanity check pin 0x18 */ + if (get_wcaps_type(get_wcaps(codec, vref_pin)) == AC_WID_PIN && + get_defcfg_connect(snd_hda_codec_get_pincfg(codec, vref_pin)) == AC_JACK_PORT_NONE) { + unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); + if (vref_val != AC_PINCTL_VREF_HIZ) + snd_hda_set_pin_ctl(codec, vref_pin, PIN_IN | (set_as_mic ? vref_val : 0)); + } + } + + val = set_as_mic ? val | PIN_IN : PIN_HP; + snd_hda_set_pin_ctl(codec, pin, val); + + spec->automute_speaker = !set_as_mic; + call_update_outputs(codec); +} + /* select the given imux item; either unmute exclusively or select the route */ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, unsigned int idx, bool force) @@ -329,21 +361,8 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, return 0; spec->cur_mux[adc_idx] = idx;
- /* for shared I/O, change the pin-control accordingly */ - if (spec->shared_mic_hp) { - unsigned int val; - hda_nid_t pin = spec->autocfg.inputs[1].pin; - /* NOTE: this assumes that there are only two inputs, the - * first is the real internal mic and the second is HP jack. - */ - if (spec->cur_mux[adc_idx]) - val = snd_hda_get_default_vref(codec, pin) | PIN_IN; - else - val = PIN_HP; - snd_hda_set_pin_ctl(codec, pin, val); - spec->automute_speaker = !spec->cur_mux[adc_idx]; - call_update_outputs(codec); - } + if (spec->shared_mic_hp) + update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
if (spec->dyn_adc_switch) { alc_dyn_adc_pcm_resetup(codec, idx);
This 3-pin jack was labeled "Headphone Jack", but it could also be used as a mic jack just by switching "Input Source". Therefore we need to call the jack something else, to make sure PulseAudio can use the speaker together with the external mic. (PulseAudio might mute the speaker if it detects a headphone being plugged in.)
Signed-off-by: David Henningsson david.henningsson@canonical.com --- sound/pci/hda/patch_realtek.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6174d4a..7189e07 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2001,13 +2001,31 @@ static int __alc_build_controls(struct hda_codec *codec) return 0; }
-static int alc_build_controls(struct hda_codec *codec) +static int alc_build_jacks(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + + if (spec->shared_mic_hp) { + int err; + int nid = spec->autocfg.inputs[1].pin; + err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); + if (err < 0) + return err; + err = snd_hda_jack_detect_enable(codec, nid, 0); + if (err < 0) + return err; + } + + return snd_hda_jack_add_kctls(codec, &spec->autocfg); +} + +static int alc_build_controls(struct hda_codec *codec) +{ int err = __alc_build_controls(codec); if (err < 0) return err; - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); + + err = alc_build_jacks(codec); if (err < 0) return err; alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD);
At Wed, 27 Jun 2012 18:45:45 +0200, David Henningsson wrote:
This 3-pin jack was labeled "Headphone Jack", but it could also be used as a mic jack just by switching "Input Source". Therefore we need to call the jack something else, to make sure PulseAudio can use the speaker together with the external mic. (PulseAudio might mute the speaker if it detects a headphone being plugged in.)
Signed-off-by: David Henningsson david.henningsson@canonical.com
Applied. Thanks.
Takashi
sound/pci/hda/patch_realtek.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6174d4a..7189e07 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2001,13 +2001,31 @@ static int __alc_build_controls(struct hda_codec *codec) return 0; }
-static int alc_build_controls(struct hda_codec *codec) +static int alc_build_jacks(struct hda_codec *codec) { struct alc_spec *spec = codec->spec;
- if (spec->shared_mic_hp) {
int err;
int nid = spec->autocfg.inputs[1].pin;
err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0);
if (err < 0)
return err;
err = snd_hda_jack_detect_enable(codec, nid, 0);
if (err < 0)
return err;
- }
- return snd_hda_jack_add_kctls(codec, &spec->autocfg);
+}
+static int alc_build_controls(struct hda_codec *codec) +{ int err = __alc_build_controls(codec); if (err < 0) return err;
- err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
- err = alc_build_jacks(codec); if (err < 0) return err; alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD);
-- 1.7.9.5
At Wed, 27 Jun 2012 18:45:44 +0200, David Henningsson wrote:
Some ASUS device has a single 3-pin jack that can either be a mic or a headphone, but the pin does not have VREF capabilities. We've been told by Realtek to instead enable VREF on pin 0x18 in that case.
BugLink: https://bugs.launchpad.net/bugs/1018262 Tested-by: Chih-Hsyuan Ho chih.ho@canonical.com Signed-off-by: David Henningsson david.henningsson@canonical.com
Applied now (with a minor typo fix in the comment).
Thanks.
Takashi
sound/pci/hda/patch_realtek.c | 49 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-)
Alsa info: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1018262/+attachment/320...
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5c81ee9..6174d4a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -303,6 +303,38 @@ static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx) static void call_update_outputs(struct hda_codec *codec); static void alc_inv_dmic_sync(struct hda_codec *codec, bool force);
+/* for shared I/O, change the pin-control accordingly */ +static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) +{
- struct alc_spec *spec = codec->spec;
- unsigned int val;
- hda_nid_t pin = spec->autocfg.inputs[1].pin;
- /* NOTE: this assumes that there are only two inputs, the
* first is the real internal mic and the second is HP/mic jack.
*/
- val = snd_hda_get_default_vref(codec, pin);
- /* This pin does not have vref caps - let's instead enable vref on pin 0x18
instead, as suggested by Realtek */
- if (val == AC_PINCTL_VREF_HIZ) {
const hda_nid_t vref_pin = 0x18;
/* Sanity check pin 0x18 */
if (get_wcaps_type(get_wcaps(codec, vref_pin)) == AC_WID_PIN &&
get_defcfg_connect(snd_hda_codec_get_pincfg(codec, vref_pin)) == AC_JACK_PORT_NONE) {
unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
if (vref_val != AC_PINCTL_VREF_HIZ)
snd_hda_set_pin_ctl(codec, vref_pin, PIN_IN | (set_as_mic ? vref_val : 0));
}
- }
- val = set_as_mic ? val | PIN_IN : PIN_HP;
- snd_hda_set_pin_ctl(codec, pin, val);
- spec->automute_speaker = !set_as_mic;
- call_update_outputs(codec);
+}
/* select the given imux item; either unmute exclusively or select the route */ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, unsigned int idx, bool force) @@ -329,21 +361,8 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, return 0; spec->cur_mux[adc_idx] = idx;
- /* for shared I/O, change the pin-control accordingly */
- if (spec->shared_mic_hp) {
unsigned int val;
hda_nid_t pin = spec->autocfg.inputs[1].pin;
/* NOTE: this assumes that there are only two inputs, the
* first is the real internal mic and the second is HP jack.
*/
if (spec->cur_mux[adc_idx])
val = snd_hda_get_default_vref(codec, pin) | PIN_IN;
else
val = PIN_HP;
snd_hda_set_pin_ctl(codec, pin, val);
spec->automute_speaker = !spec->cur_mux[adc_idx];
call_update_outputs(codec);
- }
if (spec->shared_mic_hp)
update_shared_mic_hp(codec, spec->cur_mux[adc_idx]);
if (spec->dyn_adc_switch) { alc_dyn_adc_pcm_resetup(codec, idx);
-- 1.7.9.5
participants (2)
-
David Henningsson
-
Takashi Iwai