};
 
 /* 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,
 {
        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)                  \
        return false;
 }
 
+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->capture_switch_hook) {
+               bool enable = (ucontrol->value.integer.value[0] ||
+                              ucontrol->value.integer.value[1]);
+               spec->capture_switch_hook(codec, enable);
+       }
+
+       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)
        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;
        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 && spec->capture_switch_hook)
+               knew->put = cap_single_sw_put;
+       if (!inv_dmic)
+               return 0;
 
        /* Make independent right kcontrol */
        if (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 && spec->capture_switch_hook)
+               knew->put = cap_single_sw_put;
+       return 0;
 }
 
 /* create single (and simple) capture volume and switch controls */
        struct hda_gen_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        struct hda_input_mux *imux = &spec->input_mux;
-       int i, err;
+       int i;
 
        if (!spec->num_adc_nids)
                return 0;
                /* create a boost control */
                snprintf(boost_label, sizeof(boost_label),
                         "%s Boost Volume", spec->input_labels[idx]);
-               err = add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
-                                 spec->input_label_idxs[idx], val);
-               if (err < 0)
-                       return err;
+               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;
        }