Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-drm-fsl-dcu.git] / sound / pci / hda / hda_generic.c
index b7c89dff7066758e950feec6842dab58f2de29ed..c4671d00babd6772193f955237c48412a3239a5a 100644 (file)
@@ -549,11 +549,15 @@ static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
 static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
                                      struct nid_path *path)
 {
+       struct hda_gen_spec *spec = codec->spec;
        int i;
 
        for (i = path->depth - 1; i >= 0; i--) {
-               if (nid_has_volume(codec, path->path[i], HDA_OUTPUT))
-                       return path->path[i];
+               hda_nid_t nid = path->path[i];
+               if ((spec->out_vol_mask >> nid) & 1)
+                       continue;
+               if (nid_has_volume(codec, nid, HDA_OUTPUT))
+                       return nid;
        }
        return 0;
 }
@@ -792,10 +796,10 @@ static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
        if (spec->own_eapd_ctl ||
            !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
                return;
-       if (codec->inv_eapd)
-               enable = !enable;
        if (spec->keep_eapd_on && !enable)
                return;
+       if (codec->inv_eapd)
+               enable = !enable;
        snd_hda_codec_update_cache(codec, pin, 0,
                                   AC_VERB_SET_EAPD_BTLENABLE,
                                   enable ? 0x02 : 0x00);
@@ -2502,12 +2506,8 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
 
        for (i = 0; i < num_pins; i++) {
                hda_nid_t pin = pins[i];
-               if (pin == spec->hp_mic_pin) {
-                       int ret = create_hp_mic_jack_mode(codec, pin);
-                       if (ret < 0)
-                               return ret;
+               if (pin == spec->hp_mic_pin)
                        continue;
-               }
                if (get_out_jack_num_items(codec, pin) > 1) {
                        struct snd_kcontrol_new *knew;
                        char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
@@ -2760,7 +2760,7 @@ static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
                        val &= ~(AC_PINCTL_VREFEN | PIN_HP);
                        val |= get_vref_idx(vref_caps, idx) | PIN_IN;
                } else
-                       val = snd_hda_get_default_vref(codec, nid);
+                       val = snd_hda_get_default_vref(codec, nid) | PIN_IN;
        }
        snd_hda_set_pin_ctl_cache(codec, nid, val);
        call_hp_automute(codec, NULL);
@@ -2780,9 +2780,6 @@ static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
        struct hda_gen_spec *spec = codec->spec;
        struct snd_kcontrol_new *knew;
 
-       if (get_out_jack_num_items(codec, pin) <= 1 &&
-           get_in_jack_num_items(codec, pin) <= 1)
-               return 0; /* no need */
        knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
                                    &hp_mic_jack_mode_enum);
        if (!knew)
@@ -2811,6 +2808,42 @@ static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
        return 0;
 }
 
+/* return true if either a volume or a mute amp is found for the given
+ * aamix path; the amp has to be either in the mixer node or its direct leaf
+ */
+static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
+                                  hda_nid_t pin, unsigned int *mix_val,
+                                  unsigned int *mute_val)
+{
+       int idx, num_conns;
+       const hda_nid_t *list;
+       hda_nid_t nid;
+
+       idx = snd_hda_get_conn_index(codec, mix_nid, pin, true);
+       if (idx < 0)
+               return false;
+
+       *mix_val = *mute_val = 0;
+       if (nid_has_volume(codec, mix_nid, HDA_INPUT))
+               *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
+       if (nid_has_mute(codec, mix_nid, HDA_INPUT))
+               *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
+       if (*mix_val && *mute_val)
+               return true;
+
+       /* check leaf node */
+       num_conns = snd_hda_get_conn_list(codec, mix_nid, &list);
+       if (num_conns < idx)
+               return false;
+       nid = list[idx];
+       if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT))
+               *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+       if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT))
+               *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+
+       return *mix_val || *mute_val;
+}
+
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct hda_codec *codec, int input_idx,
                            hda_nid_t pin, const char *ctlname, int ctlidx,
@@ -2818,12 +2851,11 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
 {
        struct hda_gen_spec *spec = codec->spec;
        struct nid_path *path;
-       unsigned int val;
+       unsigned int mix_val, mute_val;
        int err, idx;
 
-       if (!nid_has_volume(codec, mix_nid, HDA_INPUT) &&
-           !nid_has_mute(codec, mix_nid, HDA_INPUT))
-               return 0; /* no need for analog loopback */
+       if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val))
+               return 0;
 
        path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
        if (!path)
@@ -2832,20 +2864,18 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
        spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
 
        idx = path->idx[path->depth - 1];
-       if (nid_has_volume(codec, mix_nid, HDA_INPUT)) {
-               val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
-               err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val);
+       if (mix_val) {
+               err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val);
                if (err < 0)
                        return err;
-               path->ctls[NID_PATH_VOL_CTL] = val;
+               path->ctls[NID_PATH_VOL_CTL] = mix_val;
        }
 
-       if (nid_has_mute(codec, mix_nid, HDA_INPUT)) {
-               val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
-               err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val);
+       if (mute_val) {
+               err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val);
                if (err < 0)
                        return err;
-               path->ctls[NID_PATH_MUTE_CTL] = val;
+               path->ctls[NID_PATH_MUTE_CTL] = mute_val;
        }
 
        path->active = true;
@@ -4379,6 +4409,17 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
        if (err < 0)
                return err;
 
+       /* create "Headphone Mic Jack Mode" if no input selection is
+        * available (or user specifies add_jack_modes hint)
+        */
+       if (spec->hp_mic_pin &&
+           (spec->auto_mic || spec->input_mux.num_items == 1 ||
+            spec->add_jack_modes)) {
+               err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin);
+               if (err < 0)
+                       return err;
+       }
+
        if (spec->add_jack_modes) {
                if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
                        err = create_out_jack_modes(codec, cfg->line_outs,