ALSA: Make snd_printd() and snd_printdd() inline
[firefly-linux-kernel-4.4.55.git] / sound / pci / hda / hda_generic.c
index 9c06749738b192381a698a4a00c3b531634ee5fb..c4ba3066a01344af9085c6219acd39a602e15082 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <linux/sort.h>
+#include <linux/delay.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
@@ -153,6 +154,9 @@ static void parse_user_hints(struct hda_codec *codec)
        val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
        if (val >= 0)
                spec->add_in_jack_modes = !!val;
+       val = snd_hda_get_bool_hint(codec, "power_down_unused");
+       if (val >= 0)
+               spec->power_down_unused = !!val;
 
        if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
                spec->mixer_nid = val;
@@ -261,6 +265,7 @@ int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
                return 0;
        return idx + 1;
 }
+EXPORT_SYMBOL_HDA(snd_hda_get_path_idx);
 
 /* get the path instance corresponding to the given index number */
 struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
@@ -271,6 +276,7 @@ struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
                return NULL;
        return snd_array_elem(&spec->paths, idx - 1);
 }
+EXPORT_SYMBOL_HDA(snd_hda_get_path_from_idx);
 
 /* check whether the given DAC is already found in any existing paths */
 static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
@@ -315,11 +321,10 @@ static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
 
 /* check whether a control with the given (nid, dir, idx) was assigned */
 static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
-                             int dir, int idx)
+                             int dir, int idx, int type)
 {
        unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
-       return is_ctl_used(codec, val, NID_PATH_VOL_CTL) ||
-               is_ctl_used(codec, val, NID_PATH_MUTE_CTL);
+       return is_ctl_used(codec, val, type);
 }
 
 static void print_nid_path(const char *pfx, struct nid_path *path)
@@ -568,7 +573,7 @@ static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
 
 /* check whether the given (nid,dir,idx) is active */
 static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
-                         unsigned int idx, unsigned int dir)
+                         unsigned int dir, unsigned int idx)
 {
        struct hda_gen_spec *spec = codec->spec;
        int i, n;
@@ -590,12 +595,10 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
 
 /* get the default amp value for the target state */
 static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
-                                  int dir, bool enable)
+                                  int dir, unsigned int caps, bool enable)
 {
-       unsigned int caps;
        unsigned int val = 0;
 
-       caps = query_amp_caps(codec, nid, dir);
        if (caps & AC_AMPCAP_NUM_STEPS) {
                /* set to 0dB */
                if (enable)
@@ -611,19 +614,49 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
 /* initialize the amp value (only at the first time) */
 static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
 {
-       int val = get_amp_val_to_activate(codec, nid, dir, false);
+       unsigned int caps = query_amp_caps(codec, nid, dir);
+       int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
        snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
 }
 
+/* calculate amp value mask we can modify;
+ * if the given amp is controlled by mixers, don't touch it
+ */
+static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
+                                          hda_nid_t nid, int dir, int idx,
+                                          unsigned int caps)
+{
+       unsigned int mask = 0xff;
+
+       if (caps & AC_AMPCAP_MUTE) {
+               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
+                       mask &= ~0x80;
+       }
+       if (caps & AC_AMPCAP_NUM_STEPS) {
+               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
+                   is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
+                       mask &= ~0x7f;
+       }
+       return mask;
+}
+
 static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
-                        int idx, bool enable)
+                        int idx, int idx_to_check, bool enable)
 {
-       int val;
-       if (is_ctl_associated(codec, nid, dir, idx) ||
-           (!enable && is_active_nid(codec, nid, dir, idx)))
+       unsigned int caps;
+       unsigned int mask, val;
+
+       if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
                return;
-       val = get_amp_val_to_activate(codec, nid, dir, enable);
-       snd_hda_codec_amp_stereo(codec, nid, dir, idx, 0xff, val);
+
+       caps = query_amp_caps(codec, nid, dir);
+       val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
+       mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
+       if (!mask)
+               return;
+
+       val &= mask;
+       snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val);
 }
 
 static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
@@ -631,7 +664,7 @@ static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
 {
        hda_nid_t nid = path->path[i];
        init_amp(codec, nid, HDA_OUTPUT, 0);
-       activate_amp(codec, nid, HDA_OUTPUT, 0, enable);
+       activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
 }
 
 static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
@@ -655,16 +688,13 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
        for (n = 0; n < nums; n++)
                init_amp(codec, nid, HDA_INPUT, n);
 
-       if (is_ctl_associated(codec, nid, HDA_INPUT, idx))
-               return;
-
        /* here is a little bit tricky in comparison with activate_amp_out();
         * when aa-mixer is available, we need to enable the path as well
         */
        for (n = 0; n < nums; n++) {
-               if (n != idx && (!add_aamix || conn[n] != spec->mixer_nid))
+               if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid))
                        continue;
-               activate_amp(codec, nid, HDA_INPUT, n, enable);
+               activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
        }
 }
 
@@ -674,14 +704,23 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
 void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
                           bool enable, bool add_aamix)
 {
+       struct hda_gen_spec *spec = codec->spec;
        int i;
 
        if (!enable)
                path->active = false;
 
        for (i = path->depth - 1; i >= 0; i--) {
+               hda_nid_t nid = path->path[i];
+               if (enable && spec->power_down_unused) {
+                       /* make sure the widget is powered up */
+                       if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0))
+                               snd_hda_codec_write(codec, nid, 0,
+                                                   AC_VERB_SET_POWER_STATE,
+                                                   AC_PWRST_D0);
+               }
                if (enable && path->multi[i])
-                       snd_hda_codec_write_cache(codec, path->path[i], 0,
+                       snd_hda_codec_write_cache(codec, nid, 0,
                                            AC_VERB_SET_CONNECT_SEL,
                                            path->idx[i]);
                if (has_amp_in(codec, path, i))
@@ -695,6 +734,33 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
 }
 EXPORT_SYMBOL_HDA(snd_hda_activate_path);
 
+/* if the given path is inactive, put widgets into D3 (only if suitable) */
+static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       bool changed;
+       int i;
+
+       if (!spec->power_down_unused || path->active)
+               return;
+
+       for (i = 0; i < path->depth; i++) {
+               hda_nid_t nid = path->path[i];
+               if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3)) {
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+                       changed = true;
+               }
+       }
+
+       if (changed) {
+               msleep(10);
+               snd_hda_codec_read(codec, path->path[0], 0,
+                                  AC_VERB_GET_POWER_STATE, 0);
+       }
+}
+
 /* turn on/off EAPD on the given pin */
 static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
 {
@@ -709,6 +775,14 @@ static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
                                   enable ? 0x02 : 0x00);
 }
 
+/* re-initialize the path specified by the given path index */
+static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
+{
+       struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
+       if (path)
+               snd_hda_activate_path(codec, path, path->active, false);
+}
+
 
 /*
  * Helper functions for creating mixer ctl elements
@@ -726,19 +800,20 @@ static const struct snd_kcontrol_new control_templates[] = {
 };
 
 /* add dynamic controls from template */
-static int add_control(struct hda_gen_spec *spec, int type, const char *name,
+static struct snd_kcontrol_new *
+add_control(struct hda_gen_spec *spec, int type, const char *name,
                       int cidx, unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
        knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
        if (!knew)
-               return -ENOMEM;
+               return NULL;
        knew->index = cidx;
        if (get_amp_nid_(val))
                knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
-       return 0;
+       return knew;
 }
 
 static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
@@ -747,7 +822,9 @@ static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
 {
        char name[32];
        snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
-       return add_control(spec, type, name, cidx, val);
+       if (!add_control(spec, type, name, cidx, val))
+               return -ENOMEM;
+       return 0;
 }
 
 #define add_pb_vol_ctrl(spec, type, pfx, val)                  \
@@ -825,19 +902,27 @@ static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
        return add_sw_ctl(codec, pfx, cidx, chs, path);
 }
 
+/* any ctl assigned to the path with the given index? */
+static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
+{
+       struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
+       return path && path->ctls[ctl_type];
+}
+
 static const char * const channel_name[4] = {
        "Front", "Surround", "CLFE", "Side"
 };
 
 /* give some appropriate ctl name prefix for the given line out channel */
-static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch,
-                                   bool can_be_master, int *index)
+static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
+                                   int *index, int ctl_type)
 {
+       struct hda_gen_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
 
        *index = 0;
        if (cfg->line_outs == 1 && !spec->multi_ios &&
-           !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
+           !cfg->hp_outs && !cfg->speaker_outs)
                return spec->vmaster_mute.hook ? "PCM" : "Master";
 
        /* if there is really a single DAC used in the whole output paths,
@@ -847,24 +932,41 @@ static const char *get_line_out_pfx(struct hda_gen_spec *spec, int ch,
            !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
                return spec->vmaster_mute.hook ? "PCM" : "Master";
 
+       /* multi-io channels */
+       if (ch >= cfg->line_outs)
+               return channel_name[ch];
+
        switch (cfg->line_out_type) {
        case AUTO_PIN_SPEAKER_OUT:
+               /* if the primary channel vol/mute is shared with HP volume,
+                * don't name it as Speaker
+                */
+               if (!ch && cfg->hp_outs &&
+                   !path_has_mixer(codec, spec->hp_paths[0], ctl_type))
+                       break;
                if (cfg->line_outs == 1)
                        return "Speaker";
                if (cfg->line_outs == 2)
                        return ch ? "Bass Speaker" : "Speaker";
                break;
        case AUTO_PIN_HP_OUT:
+               /* if the primary channel vol/mute is shared with spk volume,
+                * don't name it as Headphone
+                */
+               if (!ch && cfg->speaker_outs &&
+                   !path_has_mixer(codec, spec->speaker_paths[0], ctl_type))
+                       break;
                /* for multi-io case, only the primary out */
                if (ch && spec->multi_ios)
                        break;
                *index = ch;
                return "Headphone";
-       default:
-               if (cfg->line_outs == 1 && !spec->multi_ios)
-                       return "PCM";
-               break;
        }
+
+       /* for a single channel output, we don't have to name the channel */
+       if (cfg->line_outs == 1 && !spec->multi_ios)
+               return "PCM";
+
        if (ch >= ARRAY_SIZE(channel_name)) {
                snd_BUG();
                return "PCM";
@@ -1053,15 +1155,18 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs,
                        else
                                badness += bad->no_dac;
                }
+               if (!dac)
+                       continue;
                path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
                if (!path && !i && spec->mixer_nid) {
                        /* try with aamix */
                        path = snd_hda_add_new_path(codec, dac, pin, 0);
                }
-               if (!path)
+               if (!path) {
                        dac = dacs[i] = 0;
-               else {
-                       print_nid_path("output", path);
+                       badness += bad->no_dac;
+               } else {
+                       /* print_nid_path("output", path); */
                        path->active = true;
                        path_idx[i] = snd_hda_get_path_idx(codec, path);
                        badness += assign_out_path_ctls(codec, path);
@@ -1188,7 +1293,7 @@ static int fill_multi_ios(struct hda_codec *codec,
                                badness++;
                                continue;
                        }
-                       print_nid_path("multiio", path);
+                       /* print_nid_path("multiio", path); */
                        spec->multi_io[spec->multi_ios].pin = nid;
                        spec->multi_io[spec->multi_ios].dac = dac;
                        spec->out_paths[cfg->line_outs + spec->multi_ios] =
@@ -1245,7 +1350,7 @@ static bool map_singles(struct hda_codec *codec, int outs,
                if (path) {
                        dacs[i] = dac;
                        found = true;
-                       print_nid_path("output", path);
+                       /* print_nid_path("output", path); */
                        path->active = true;
                        path_idx[i] = snd_hda_get_path_idx(codec, path);
                }
@@ -1258,17 +1363,29 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct nid_path *path;
+       hda_nid_t dac, pin;
 
        path = snd_hda_get_path_from_idx(codec, path_idx);
        if (!path || !path->depth ||
            is_nid_contained(path, spec->mixer_nid))
                return 0;
-       path = snd_hda_add_new_path(codec, path->path[0],
-                                   path->path[path->depth - 1],
-                                   spec->mixer_nid);
+       dac = path->path[0];
+       pin = path->path[path->depth - 1];
+       path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
+       if (!path) {
+               if (dac != spec->multiout.dac_nids[0])
+                       dac = spec->multiout.dac_nids[0];
+               else if (spec->multiout.hp_out_nid[0])
+                       dac = spec->multiout.hp_out_nid[0];
+               else if (spec->multiout.extra_out_nid[0])
+                       dac = spec->multiout.extra_out_nid[0];
+               if (dac)
+                       path = snd_hda_add_new_path(codec, dac, pin,
+                                                   spec->mixer_nid);
+       }
        if (!path)
                return 0;
-       print_nid_path("output-aamix", path);
+       /* print_nid_path("output-aamix", path); */
        path->active = false; /* unused as default */
        return snd_hda_get_path_idx(codec, path);
 }
@@ -1300,7 +1417,6 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
        struct hda_gen_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        int i, err, badness;
-       unsigned int val;
 
        /* set num_dacs once to full for look_for_dac() */
        spec->multiout.num_dacs = cfg->line_outs;
@@ -1437,20 +1553,6 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
                                   spec->multiout.extra_out_nid,
                                   spec->speaker_paths);
 
-       /* set initial pinctl targets */
-       if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
-               val = PIN_HP;
-       else
-               val = PIN_OUT;
-       set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-               set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
-               set_pin_targets(codec, cfg->speaker_outs,
-                               cfg->speaker_pins, val);
-       }
-
        return badness;
 }
 
@@ -1462,35 +1564,68 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
 #define debug_badness(...)
 #endif
 
-static void debug_show_configs(struct hda_gen_spec *spec, struct auto_pin_cfg *cfg)
+#ifdef DEBUG_BADNESS
+static inline void print_nid_path_idx(struct hda_codec *codec,
+                                     const char *pfx, int idx)
+{
+       struct nid_path *path;
+
+       path = snd_hda_get_path_from_idx(codec, idx);
+       if (path)
+               print_nid_path(pfx, path);
+}
+
+static void debug_show_configs(struct hda_codec *codec,
+                              struct auto_pin_cfg *cfg)
 {
-       debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+       struct hda_gen_spec *spec = codec->spec;
+       static const char * const lo_type[3] = { "LO", "SP", "HP" };
+       int i;
+
+       debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n",
                      cfg->line_out_pins[0], cfg->line_out_pins[1],
                      cfg->line_out_pins[2], cfg->line_out_pins[3],
                      spec->multiout.dac_nids[0],
                      spec->multiout.dac_nids[1],
                      spec->multiout.dac_nids[2],
-                     spec->multiout.dac_nids[3]);
+                     spec->multiout.dac_nids[3],
+                     lo_type[cfg->line_out_type]);
+       for (i = 0; i < cfg->line_outs; i++)
+               print_nid_path_idx(codec, "  out", spec->out_paths[i]);
        if (spec->multi_ios > 0)
                debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
                              spec->multi_ios,
                              spec->multi_io[0].pin, spec->multi_io[1].pin,
                              spec->multi_io[0].dac, spec->multi_io[1].dac);
-       debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+       for (i = 0; i < spec->multi_ios; i++)
+               print_nid_path_idx(codec, "  mio",
+                                  spec->out_paths[cfg->line_outs + i]);
+       if (cfg->hp_outs)
+               debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
                      cfg->hp_pins[0], cfg->hp_pins[1],
                      cfg->hp_pins[2], cfg->hp_pins[3],
                      spec->multiout.hp_out_nid[0],
                      spec->multiout.hp_out_nid[1],
                      spec->multiout.hp_out_nid[2],
                      spec->multiout.hp_out_nid[3]);
-       debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+       for (i = 0; i < cfg->hp_outs; i++)
+               print_nid_path_idx(codec, "  hp ", spec->hp_paths[i]);
+       if (cfg->speaker_outs)
+               debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
                      cfg->speaker_pins[0], cfg->speaker_pins[1],
                      cfg->speaker_pins[2], cfg->speaker_pins[3],
                      spec->multiout.extra_out_nid[0],
                      spec->multiout.extra_out_nid[1],
                      spec->multiout.extra_out_nid[2],
                      spec->multiout.extra_out_nid[3]);
+       for (i = 0; i < cfg->speaker_outs; i++)
+               print_nid_path_idx(codec, "  spk", spec->speaker_paths[i]);
+       for (i = 0; i < 3; i++)
+               print_nid_path_idx(codec, "  mix", spec->aamix_out_paths[i]);
 }
+#else
+#define debug_show_configs(codec, cfg) /* NOP */
+#endif
 
 /* find all available DACs of the codec */
 static void fill_all_dac_nids(struct hda_codec *codec)
@@ -1517,6 +1652,7 @@ static int parse_output_paths(struct hda_codec *codec)
        struct hda_gen_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        struct auto_pin_cfg *best_cfg;
+       unsigned int val;
        int best_badness = INT_MAX;
        int badness;
        bool fill_hardwired = true, fill_mio_first = true;
@@ -1538,7 +1674,7 @@ static int parse_output_paths(struct hda_codec *codec)
                debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
                              cfg->line_out_type, fill_hardwired, fill_mio_first,
                              badness);
-               debug_show_configs(spec, cfg);
+               debug_show_configs(codec, cfg);
                if (badness < best_badness) {
                        best_badness = badness;
                        *best_cfg = *cfg;
@@ -1594,7 +1730,7 @@ static int parse_output_paths(struct hda_codec *codec)
        }
        debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
                      cfg->line_out_type, best_wired, best_mio);
-       debug_show_configs(spec, cfg);
+       debug_show_configs(codec, cfg);
 
        if (cfg->line_out_pins[0]) {
                struct nid_path *path;
@@ -1606,6 +1742,20 @@ static int parse_output_paths(struct hda_codec *codec)
                                                HDA_OUTPUT, spec->vmaster_tlv);
        }
 
+       /* set initial pinctl targets */
+       if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
+               val = PIN_HP;
+       else
+               val = PIN_OUT;
+       set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
+               set_pin_targets(codec, cfg->speaker_outs,
+                               cfg->speaker_pins, val);
+       }
+
        kfree(best_cfg);
        return 0;
 }
@@ -1626,16 +1776,11 @@ static int create_multi_out_ctls(struct hda_codec *codec,
                int index;
                struct nid_path *path;
 
-               if (i >= cfg->line_outs) {
-                       index = 0;
-                       name = channel_name[i];
-               } else {
-                       name = get_line_out_pfx(spec, i, true, &index);
-               }
-
                path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
                if (!path)
                        continue;
+
+               name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL);
                if (!name || !strcmp(name, "CLFE")) {
                        /* Center/LFE */
                        err = add_vol_ctl(codec, "Center", 0, 1, path);
@@ -1644,6 +1789,14 @@ static int create_multi_out_ctls(struct hda_codec *codec,
                        err = add_vol_ctl(codec, "LFE", 0, 2, path);
                        if (err < 0)
                                return err;
+               } else {
+                       err = add_stereo_vol(codec, name, index, path);
+                       if (err < 0)
+                               return err;
+               }
+
+               name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL);
+               if (!name || !strcmp(name, "CLFE")) {
                        err = add_sw_ctl(codec, "Center", 0, 1, path);
                        if (err < 0)
                                return err;
@@ -1651,9 +1804,6 @@ static int create_multi_out_ctls(struct hda_codec *codec,
                        if (err < 0)
                                return err;
                } else {
-                       err = add_stereo_vol(codec, name, index, path);
-                       if (err < 0)
-                               return err;
                        err = add_stereo_sw(codec, name, index, path);
                        if (err < 0)
                                return err;
@@ -1743,6 +1893,10 @@ static int indep_hp_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
+                              int nomix_path_idx, int mix_path_idx,
+                              int out_type);
+
 static int indep_hp_put(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
@@ -1758,11 +1912,38 @@ static int indep_hp_put(struct snd_kcontrol *kcontrol,
        }
 
        if (spec->indep_hp_enabled != select) {
+               hda_nid_t *dacp;
+               if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+                       dacp = &spec->private_dac_nids[0];
+               else
+                       dacp = &spec->multiout.hp_out_nid[0];
+
+               /* update HP aamix paths in case it conflicts with indep HP */
+               if (spec->have_aamix_ctl) {
+                       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+                               update_aamix_paths(codec, spec->aamix_mode,
+                                                  spec->out_paths[0],
+                                                  spec->aamix_out_paths[0],
+                                                  spec->autocfg.line_out_type);
+                       else
+                               update_aamix_paths(codec, spec->aamix_mode,
+                                                  spec->hp_paths[0],
+                                                  spec->aamix_out_paths[1],
+                                                  AUTO_PIN_HP_OUT);
+               }
+
                spec->indep_hp_enabled = select;
                if (spec->indep_hp_enabled)
-                       spec->multiout.hp_out_nid[0] = 0;
+                       *dacp = 0;
+               else
+                       *dacp = spec->alt_dac_nid;
+
+               /* update HP auto-mute state too */
+               if (spec->hp_automute_hook)
+                       spec->hp_automute_hook(codec, NULL);
                else
-                       spec->multiout.hp_out_nid[0] = spec->alt_dac_nid;
+                       snd_hda_gen_hp_automute(codec, NULL);
+
                ret = 1;
        }
  unlock:
@@ -1782,16 +1963,21 @@ static const struct snd_kcontrol_new indep_hp_ctl = {
 static int create_indep_hp_ctls(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t dac;
 
        if (!spec->indep_hp)
                return 0;
-       if (!spec->multiout.hp_out_nid[0]) {
+       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+               dac = spec->multiout.dac_nids[0];
+       else
+               dac = spec->multiout.hp_out_nid[0];
+       if (!dac) {
                spec->indep_hp = 0;
                return 0;
        }
 
        spec->indep_hp_enabled = false;
-       spec->alt_dac_nid = spec->multiout.hp_out_nid[0];
+       spec->alt_dac_nid = dac;
        if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
                return -ENOMEM;
        return 0;
@@ -1859,6 +2045,7 @@ static int set_multi_io(struct hda_codec *codec, int idx, bool output)
                set_pin_eapd(codec, nid, false);
                snd_hda_activate_path(codec, path, false, true);
                set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
+               path_power_down_sync(codec, path);
        }
 
        /* update jack retasking in case it modifies any of them */
@@ -1924,20 +2111,32 @@ static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
 }
 
 static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
-                              int nomix_path_idx, int mix_path_idx)
+                              int nomix_path_idx, int mix_path_idx,
+                              int out_type)
 {
+       struct hda_gen_spec *spec = codec->spec;
        struct nid_path *nomix_path, *mix_path;
 
        nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
        mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
        if (!nomix_path || !mix_path)
                return;
+
+       /* if HP aamix path is driven from a different DAC and the
+        * independent HP mode is ON, can't turn on aamix path
+        */
+       if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled &&
+           mix_path->path[0] != spec->alt_dac_nid)
+               do_mix = false;
+
        if (do_mix) {
                snd_hda_activate_path(codec, nomix_path, false, true);
                snd_hda_activate_path(codec, mix_path, true, true);
+               path_power_down_sync(codec, nomix_path);
        } else {
                snd_hda_activate_path(codec, mix_path, false, true);
                snd_hda_activate_path(codec, nomix_path, true, true);
+               path_power_down_sync(codec, mix_path);
        }
 }
 
@@ -1952,11 +2151,14 @@ static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
                return 0;
        spec->aamix_mode = val;
        update_aamix_paths(codec, val, spec->out_paths[0],
-                          spec->aamix_out_paths[0]);
+                          spec->aamix_out_paths[0],
+                          spec->autocfg.line_out_type);
        update_aamix_paths(codec, val, spec->hp_paths[0],
-                          spec->aamix_out_paths[1]);
+                          spec->aamix_out_paths[1],
+                          AUTO_PIN_HP_OUT);
        update_aamix_paths(codec, val, spec->speaker_paths[0],
-                          spec->aamix_out_paths[2]);
+                          spec->aamix_out_paths[2],
+                          AUTO_PIN_SPEAKER_OUT);
        return 1;
 }
 
@@ -1979,6 +2181,7 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec)
                return 0;
        if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
                return -ENOMEM;
+       spec->have_aamix_ctl = 1;
        return 0;
 }
 
@@ -2338,6 +2541,19 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
 
        path->active = true;
        add_loopback_list(spec, mix_nid, idx);
+
+       if (spec->mixer_nid != spec->mixer_merge_nid &&
+           !spec->loopback_merge_path) {
+               path = snd_hda_add_new_path(codec, spec->mixer_nid,
+                                           spec->mixer_merge_nid, 0);
+               if (path) {
+                       print_nid_path("loopback-merge", path);
+                       path->active = true;
+                       spec->loopback_merge_path =
+                               snd_hda_get_path_idx(codec, path);
+               }
+       }
+
        return 0;
 }
 
@@ -2368,6 +2584,11 @@ static int fill_adc_nids(struct hda_codec *codec)
                        break;
        }
        spec->num_adc_nids = nums;
+
+       /* copy the detected ADCs to all_adcs[] */
+       spec->num_all_adcs = nums;
+       memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t));
+
        return nums;
 }
 
@@ -2448,7 +2669,8 @@ static int check_dyn_adc_switch(struct hda_codec *codec)
 
 /* parse capture source paths from the given pin and create imux items */
 static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
-                               int num_adcs, const char *label, int anchor)
+                               int cfg_idx, int num_adcs,
+                               const char *label, int anchor)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->input_mux;
@@ -2471,8 +2693,7 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
 
                if (!imux_added) {
                        spec->imux_pins[imux->num_items] = pin;
-                       snd_hda_add_imux_item(imux, label,
-                                             imux->num_items, NULL);
+                       snd_hda_add_imux_item(imux, label, cfg_idx, NULL);
                        imux_added = true;
                }
        }
@@ -2483,35 +2704,65 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
 /*
  * create playback/capture controls for input pins
  */
+
+/* fill the label for each input at first */
+static int fill_input_pin_labels(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin = cfg->inputs[i].pin;
+               const char *label;
+               int j, idx;
+
+               if (!is_input_pin(codec, pin))
+                       continue;
+
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               idx = 0;
+               for (j = i - 1; j >= 0; j--) {
+                       if (spec->input_labels[j] &&
+                           !strcmp(spec->input_labels[j], label)) {
+                               idx = spec->input_label_idxs[j] + 1;
+                               break;
+                       }
+               }
+
+               spec->input_labels[i] = label;
+               spec->input_label_idxs[i] = idx;
+       }
+
+       return 0;
+}
+
+#define CFG_IDX_MIX    99      /* a dummy cfg->input idx for stereo mix */
+
 static int create_input_ctls(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec = codec->spec;
        const struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t mixer = spec->mixer_nid;
        int num_adcs;
-       int i, err, type_idx = 0;
-       const char *prev_label = NULL;
+       int i, err;
        unsigned int val;
 
        num_adcs = fill_adc_nids(codec);
        if (num_adcs < 0)
                return 0;
 
+       err = fill_input_pin_labels(codec);
+       if (err < 0)
+               return err;
+
        for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t pin;
-               const char *label;
 
                pin = cfg->inputs[i].pin;
                if (!is_input_pin(codec, pin))
                        continue;
 
-               label = hda_get_autocfg_input_label(codec, cfg, i);
-               if (prev_label && !strcmp(label, prev_label))
-                       type_idx++;
-               else
-                       type_idx = 0;
-               prev_label = label;
-
                val = PIN_IN;
                if (cfg->inputs[i].type == AUTO_PIN_MIC)
                        val |= snd_hda_get_default_vref(codec, pin);
@@ -2520,13 +2771,16 @@ static int create_input_ctls(struct hda_codec *codec)
                if (mixer) {
                        if (is_reachable_path(codec, pin, mixer)) {
                                err = new_analog_input(codec, i, pin,
-                                                      label, type_idx, mixer);
+                                                      spec->input_labels[i],
+                                                      spec->input_label_idxs[i],
+                                                      mixer);
                                if (err < 0)
                                        return err;
                        }
                }
 
-               err = parse_capture_source(codec, pin, num_adcs, label, -mixer);
+               err = parse_capture_source(codec, pin, i, num_adcs,
+                                          spec->input_labels[i], -mixer);
                if (err < 0)
                        return err;
 
@@ -2538,7 +2792,7 @@ static int create_input_ctls(struct hda_codec *codec)
        }
 
        if (mixer && spec->add_stereo_mix_input) {
-               err = parse_capture_source(codec, mixer, num_adcs,
+               err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
                                           "Stereo Mix", 0);
                if (err < 0)
                        return err;
@@ -2562,7 +2816,7 @@ static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int
        }
        if (spec->dyn_adc_switch)
                adc_idx = spec->dyn_adc_idx[imux_idx];
-       if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_OUTS) {
+       if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) {
                snd_BUG();
                return NULL;
        }
@@ -2585,7 +2839,8 @@ static int mux_enum_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct hda_gen_spec *spec = codec->spec;
-       unsigned int adc_idx = kcontrol->id.index;
+       /* the ctls are created at once with multiple counts */
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
        ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
        return 0;
@@ -2595,7 +2850,7 @@ static int mux_enum_put(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int adc_idx = kcontrol->id.index;
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        return mux_select(codec, adc_idx,
                          ucontrol->value.enumerated.item[0]);
 }
@@ -2646,9 +2901,9 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol,
  error:
        codec->cached_write = 0;
        mutex_unlock(&codec->control_mutex);
-       snd_hda_codec_flush_amp_cache(codec); /* flush the updates */
+       snd_hda_codec_flush_cache(codec); /* flush the updates */
        if (err >= 0 && spec->cap_sync_hook)
-               spec->cap_sync_hook(codec);
+               spec->cap_sync_hook(codec, ucontrol);
        return err;
 }
 
@@ -2684,23 +2939,9 @@ static const struct snd_kcontrol_new cap_vol_temp = {
 static int cap_sw_put(struct snd_kcontrol *kcontrol,
                      struct snd_ctl_elem_value *ucontrol)
 {
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       int ret;
-
-       ret = cap_put_caller(kcontrol, ucontrol,
+       return cap_put_caller(kcontrol, ucontrol,
                              snd_hda_mixer_amp_switch_put,
                              NID_PATH_MUTE_CTL);
-       if (ret < 0)
-               return ret;
-
-       if (spec->capture_switch_hook) {
-               bool enable = (ucontrol->value.integer.value[0] ||
-                              ucontrol->value.integer.value[1]);
-               spec->capture_switch_hook(codec, enable);
-       }
-
-       return ret;
 }
 
 static const struct snd_kcontrol_new cap_sw_temp = {
@@ -2770,6 +3011,24 @@ static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
        return false;
 }
 
+/* capture switch put callback for a single control with hook call */
+static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       int ret;
+
+       ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       if (ret < 0)
+               return ret;
+
+       if (spec->cap_sync_hook)
+               spec->cap_sync_hook(codec, ucontrol);
+
+       return ret;
+}
+
 static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
                              int idx, bool is_switch, unsigned int ctl,
                              bool inv_dmic)
@@ -2779,7 +3038,7 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
        int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
        const char *sfx = is_switch ? "Switch" : "Volume";
        unsigned int chs = inv_dmic ? 1 : 3;
-       int err;
+       struct snd_kcontrol_new *knew;
 
        if (!ctl)
                return 0;
@@ -2790,10 +3049,14 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
        else
                snprintf(tmpname, sizeof(tmpname),
                         "Capture %s", sfx);
-       err = add_control(spec, type, tmpname, idx,
-                         amp_val_replace_channels(ctl, chs));
-       if (err < 0 || !inv_dmic)
-               return err;
+       knew = add_control(spec, type, tmpname, idx,
+                          amp_val_replace_channels(ctl, chs));
+       if (!knew)
+               return -ENOMEM;
+       if (is_switch)
+               knew->put = cap_single_sw_put;
+       if (!inv_dmic)
+               return 0;
 
        /* Make independent right kcontrol */
        if (label)
@@ -2802,8 +3065,13 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
        else
                snprintf(tmpname, sizeof(tmpname),
                         "Inverted Capture %s", sfx);
-       return add_control(spec, type, tmpname, idx,
+       knew = add_control(spec, type, tmpname, idx,
                           amp_val_replace_channels(ctl, 2));
+       if (!knew)
+               return -ENOMEM;
+       if (is_switch)
+               knew->put = cap_single_sw_put;
+       return 0;
 }
 
 /* create single (and simple) capture volume and switch controls */
@@ -2873,22 +3141,22 @@ static int create_multi_cap_vol_ctl(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->input_mux;
-       int i, err, type, type_idx = 0;
-       const char *prev_label = NULL;
+       int i, err, type;
 
        for (i = 0; i < imux->num_items; i++) {
-               const char *label;
                bool inv_dmic;
-               label = hda_get_autocfg_input_label(codec, &spec->autocfg, i);
-               if (prev_label && !strcmp(label, prev_label))
-                       type_idx++;
-               else
-                       type_idx = 0;
-               prev_label = label;
+               int idx;
+
+               idx = imux->items[i].index;
+               if (idx >= spec->autocfg.num_inputs)
+                       continue;
                inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
 
                for (type = 0; type < 2; type++) {
-                       err = add_single_cap_ctl(codec, label, type_idx, type,
+                       err = add_single_cap_ctl(codec,
+                                                spec->input_labels[idx],
+                                                spec->input_label_idxs[idx],
+                                                type,
                                                 get_first_cap_ctl(codec, i, type),
                                                 inv_dmic);
                        if (err < 0)
@@ -2969,47 +3237,91 @@ static int create_capture_mixers(struct hda_codec *codec)
 /*
  * add mic boosts if needed
  */
+
+/* check whether the given amp is feasible as a boost volume */
+static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid,
+                           int dir, int idx)
+{
+       unsigned int step;
+
+       if (!nid_has_volume(codec, nid, dir) ||
+           is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
+           is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
+               return false;
+
+       step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE)
+               >> AC_AMPCAP_STEP_SIZE_SHIFT;
+       if (step < 0x20)
+               return false;
+       return true;
+}
+
+/* look for a boost amp in a widget close to the pin */
+static unsigned int look_for_boost_amp(struct hda_codec *codec,
+                                      struct nid_path *path)
+{
+       unsigned int val = 0;
+       hda_nid_t nid;
+       int depth;
+
+       for (depth = 0; depth < 3; depth++) {
+               if (depth >= path->depth - 1)
+                       break;
+               nid = path->path[depth];
+               if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) {
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+                       break;
+               } else if (check_boost_vol(codec, nid, HDA_INPUT,
+                                          path->idx[depth])) {
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth],
+                                                 HDA_INPUT);
+                       break;
+               }
+       }
+
+       return val;
+}
+
 static int parse_mic_boost(struct hda_codec *codec)
 {
        struct hda_gen_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i, err;
-       int type_idx = 0;
-       hda_nid_t nid;
-       const char *prev_label = NULL;
+       struct hda_input_mux *imux = &spec->input_mux;
+       int i;
 
-       for (i = 0; i < cfg->num_inputs; i++) {
-               if (cfg->inputs[i].type > AUTO_PIN_MIC)
-                       break;
-               nid = cfg->inputs[i].pin;
-               if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
-                       const char *label;
-                       char boost_label[44];
-                       struct nid_path *path;
-                       unsigned int val;
+       if (!spec->num_adc_nids)
+               return 0;
 
-                       if (!nid_has_volume(codec, nid, HDA_INPUT))
-                               continue;
+       for (i = 0; i < imux->num_items; i++) {
+               struct nid_path *path;
+               unsigned int val;
+               int idx;
+               char boost_label[44];
 
-                       label = hda_get_autocfg_input_label(codec, cfg, i);
-                       if (prev_label && !strcmp(label, prev_label))
-                               type_idx++;
-                       else
-                               type_idx = 0;
-                       prev_label = label;
+               idx = imux->items[i].index;
+               if (idx >= imux->num_items)
+                       continue;
 
-                       snprintf(boost_label, sizeof(boost_label),
-                                "%s Boost Volume", label);
-                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
-                       err = add_control(spec, HDA_CTL_WIDGET_VOL,
-                                         boost_label, type_idx, val);
-                       if (err < 0)
-                               return err;
+               /* check only line-in and mic pins */
+               if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
+                       continue;
 
-                       path = snd_hda_get_nid_path(codec, nid, 0);
-                       if (path)
-                               path->ctls[NID_PATH_BOOST_CTL] = val;
-               }
+               path = get_input_path(codec, 0, i);
+               if (!path)
+                       continue;
+
+               val = look_for_boost_amp(codec, path);
+               if (!val)
+                       continue;
+
+               /* create a boost control */
+               snprintf(boost_label, sizeof(boost_label),
+                        "%s Boost Volume", spec->input_labels[idx]);
+               if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
+                                spec->input_label_idxs[idx], val))
+                       return -ENOMEM;
+
+               path->ctls[NID_PATH_BOOST_CTL] = val;
        }
        return 0;
 }
@@ -3085,7 +3397,7 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
 {
        struct hda_gen_spec *spec = codec->spec;
        const struct hda_input_mux *imux;
-       struct nid_path *path;
+       struct nid_path *old_path, *path;
 
        imux = &spec->input_mux;
        if (!imux->num_items)
@@ -3096,11 +3408,11 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
        if (spec->cur_mux[adc_idx] == idx)
                return 0;
 
-       path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
-       if (!path)
+       old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
+       if (!old_path)
                return 0;
-       if (path->active)
-               snd_hda_activate_path(codec, path, false, false);
+       if (old_path->active)
+               snd_hda_activate_path(codec, old_path, false, false);
 
        spec->cur_mux[adc_idx] = idx;
 
@@ -3117,7 +3429,8 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
                return 0;
        snd_hda_activate_path(codec, path, true, false);
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec);
+               spec->cap_sync_hook(codec, NULL);
+       path_power_down_sync(codec, old_path);
        return 1;
 }
 
@@ -3226,10 +3539,16 @@ static void call_update_outputs(struct hda_codec *codec)
 void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t *pins = spec->autocfg.hp_pins;
+       int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins);
 
-       spec->hp_jack_present =
-               detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
-                            spec->autocfg.hp_pins);
+       /* No detection for the first HP jack during indep-HP mode */
+       if (spec->indep_hp_enabled) {
+               pins++;
+               num_pins--;
+       }
+
+       spec->hp_jack_present = detect_jacks(codec, num_pins, pins);
        if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
                return;
        call_update_outputs(codec);
@@ -3576,6 +3895,20 @@ static int check_auto_mic_availability(struct hda_codec *codec)
        return 0;
 }
 
+/* power_filter hook; make inactive widgets into power down */
+static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
+                                                 hda_nid_t nid,
+                                                 unsigned int power_state)
+{
+       if (power_state != AC_PWRST_D0)
+               return power_state;
+       if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
+               return power_state;
+       if (is_active_nid(codec, nid, HDA_OUTPUT, 0))
+               return power_state;
+       return AC_PWRST_D3;
+}
+
 
 /*
  * Parse the given BIOS configuration and set up the hda_gen_spec
@@ -3591,6 +3924,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
 
        parse_user_hints(codec);
 
+       if (spec->mixer_nid && !spec->mixer_merge_nid)
+               spec->mixer_merge_nid = spec->mixer_nid;
+
        if (cfg != &spec->autocfg) {
                spec->autocfg = *cfg;
                cfg = &spec->autocfg;
@@ -3700,6 +4036,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
  dig_only:
        parse_digital(codec);
 
+       if (spec->power_down_unused)
+               codec->power_filter = snd_hda_gen_path_power_filter;
+
        return 1;
 }
 EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
@@ -3810,6 +4149,16 @@ static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
                spec->pcm_playback_hook(hinfo, codec, substream, action);
 }
 
+static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream,
+                                 int action)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->pcm_capture_hook)
+               spec->pcm_capture_hook(hinfo, codec, substream, action);
+}
+
 /*
  * Analog playback callbacks
  */
@@ -3877,6 +4226,44 @@ static int playback_pcm_close(struct hda_pcm_stream *hinfo,
        return 0;
 }
 
+static int capture_pcm_open(struct hda_pcm_stream *hinfo,
+                           struct hda_codec *codec,
+                           struct snd_pcm_substream *substream)
+{
+       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN);
+       return 0;
+}
+
+static int capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+                              struct hda_codec *codec,
+                              unsigned int stream_tag,
+                              unsigned int format,
+                              struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_PREPARE);
+       return 0;
+}
+
+static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                              struct hda_codec *codec,
+                              struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_CLEANUP);
+       return 0;
+}
+
+static int capture_pcm_close(struct hda_pcm_stream *hinfo,
+                            struct hda_codec *codec,
+                            struct snd_pcm_substream *substream)
+{
+       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE);
+       return 0;
+}
+
 static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
                                 struct hda_codec *codec,
                                 struct snd_pcm_substream *substream)
@@ -3971,6 +4358,9 @@ static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
 /*
  * Analog capture
  */
+#define alt_capture_pcm_open   capture_pcm_open
+#define alt_capture_pcm_close  capture_pcm_close
+
 static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                   struct hda_codec *codec,
                                   unsigned int stream_tag,
@@ -3981,6 +4371,8 @@ static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
 
        snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
                                   stream_tag, 0, format);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_PREPARE);
        return 0;
 }
 
@@ -3992,6 +4384,8 @@ static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
 
        snd_hda_codec_cleanup_stream(codec,
                                     spec->adc_nids[substream->number + 1]);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_CLEANUP);
        return 0;
 }
 
@@ -4015,6 +4409,12 @@ static const struct hda_pcm_stream pcm_analog_capture = {
        .channels_min = 2,
        .channels_max = 2,
        /* NID is set in build_pcms */
+       .ops = {
+               .open = capture_pcm_open,
+               .close = capture_pcm_close,
+               .prepare = capture_pcm_prepare,
+               .cleanup = capture_pcm_cleanup
+       },
 };
 
 static const struct hda_pcm_stream pcm_analog_alt_playback = {
@@ -4036,6 +4436,8 @@ static const struct hda_pcm_stream pcm_analog_alt_capture = {
        .channels_max = 2,
        /* NID is set in build_pcms */
        .ops = {
+               .open = alt_capture_pcm_open,
+               .close = alt_capture_pcm_close,
                .prepare = alt_capture_pcm_prepare,
                .cleanup = alt_capture_pcm_cleanup
        },
@@ -4227,9 +4629,12 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
                !spec->dyn_adc_switch && !spec->auto_mic;
        /* Additional Analaog capture for index #2 */
        if (spec->alt_dac_nid || have_multi_adcs) {
+               fill_pcm_stream_name(spec->stream_name_alt_analog,
+                                    sizeof(spec->stream_name_alt_analog),
+                            " Alt Analog", codec->chip_name);
                codec->num_pcms = 3;
                info = spec->pcm_rec + 2;
-               info->name = spec->stream_name_analog;
+               info->name = spec->stream_name_alt_analog;
                if (spec->alt_dac_nid) {
                        p = spec->stream_analog_alt_playback;
                        if (!p)
@@ -4346,11 +4751,8 @@ static void init_analog_input(struct hda_codec *codec)
 
                /* init loopback inputs */
                if (spec->mixer_nid) {
-                       struct nid_path *path;
-                       path = snd_hda_get_path_from_idx(codec, spec->loopback_paths[i]);
-                       if (path)
-                               snd_hda_activate_path(codec, path,
-                                                     path->active, false);
+                       resume_path_from_idx(codec, spec->loopback_paths[i]);
+                       resume_path_from_idx(codec, spec->loopback_merge_path);
                }
        }
 }
@@ -4384,7 +4786,7 @@ static void init_input_src(struct hda_codec *codec)
                update_shared_mic_hp(codec, spec->cur_mux[0]);
 
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec);
+               spec->cap_sync_hook(codec, NULL);
 }
 
 /* set right pin controls for digital I/O */
@@ -4398,11 +4800,8 @@ static void init_digital(struct hda_codec *codec)
                set_output_and_unmute(codec, spec->digout_paths[i]);
        pin = spec->autocfg.dig_in_pin;
        if (pin) {
-               struct nid_path *path;
                restore_pin_ctl(codec, pin);
-               path = snd_hda_get_path_from_idx(codec, spec->digin_path);
-               if (path)
-                       snd_hda_activate_path(codec, path, path->active, false);
+               resume_path_from_idx(codec, spec->digin_path);
        }
 }
 
@@ -4450,8 +4849,7 @@ int snd_hda_gen_init(struct hda_codec *codec)
        /* call init functions of standard auto-mute helpers */
        update_automute_all(codec);
 
-       snd_hda_codec_flush_amp_cache(codec);
-       snd_hda_codec_flush_cmd_cache(codec);
+       snd_hda_codec_flush_cache(codec);
 
        if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
                snd_hda_sync_vmaster_hook(&spec->vmaster_mute);