ALSA: HDA: Support single 3-pin jack without VREF on the actual pin
authorDavid Henningsson <david.henningsson@canonical.com>
Wed, 27 Jun 2012 16:45:44 +0000 (18:45 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 27 Jun 2012 18:20:40 +0000 (20:20 +0200)
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>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_realtek.c

index 5c81ee95d7f08abc3be0ec9c9650011bbae9f8d1..40dda2a8377429a131f35b3f2866a9ac506c000b 100644 (file)
@@ -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 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);