.mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
 #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
        SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xitems, xtexts, xvalues)
+#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
+{      .reg = xreg, .shift_l = xshift, .shift_r = xshift, \
+       .mask = xmask, .items = xitems, .texts = xtexts, \
+       .values = xvalues, .autodisable = 1}
 #define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
        SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
 #define SOC_ENUM(xname, xenum) \
                                                        ARRAY_SIZE(xtexts), xtexts, xvalues)
 #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
        SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+
+#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
+       const struct soc_enum name = SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, \
+               xshift, xmask, ARRAY_SIZE(xtexts), xtexts, xvalues)
+
 #define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
        const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
 
        unsigned int mask;
        const char * const *texts;
        const unsigned int *values;
+       unsigned int autodisable:1;
 };
 
 /**
 
 {
        struct dapm_kcontrol_data *data;
        struct soc_mixer_control *mc;
+       struct soc_enum *e;
        const char *name;
        int ret;
 
                        }
                }
                break;
+       case snd_soc_dapm_mux:
+               e = (struct soc_enum *)kcontrol->private_value;
+
+               if (e->autodisable) {
+                       struct snd_soc_dapm_widget template;
+
+                       name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+                                        "Autodisable");
+                       if (!name) {
+                               ret = -ENOMEM;
+                               goto err_data;
+                       }
+
+                       memset(&template, 0, sizeof(template));
+                       template.reg = e->reg;
+                       template.mask = e->mask << e->shift_l;
+                       template.shift = e->shift_l;
+                       template.off_val = snd_soc_enum_item_to_val(e, 0);
+                       template.on_val = template.off_val;
+                       template.id = snd_soc_dapm_kcontrol;
+                       template.name = name;
+
+                       data->value = template.on_val;
+
+                       data->widget = snd_soc_dapm_new_control(widget->dapm,
+                                       &template);
+                       if (!data->widget) {
+                               ret = -ENOMEM;
+                               goto err_name;
+                       }
+
+                       snd_soc_dapm_add_path(widget->dapm, data->widget,
+                                             widget, NULL, NULL);
+               }
+               break;
        default:
                break;
        }
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
 
        list_add_tail(&path->list_kcontrol, &data->paths);
-
-       if (data->widget) {
-               snd_soc_dapm_add_path(data->widget->dapm, data->widget,
-                   path->source, NULL, NULL);
-       }
 }
 
 static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
 {
        int i, ret;
        struct snd_soc_dapm_path *path;
+       struct dapm_kcontrol_data *data;
 
        /* add kcontrol */
        for (i = 0; i < w->num_kcontrols; i++) {
                        if (path->name != (char *)w->kcontrol_news[i].name)
                                continue;
 
-                       if (w->kcontrols[i]) {
-                               dapm_kcontrol_add_path(w->kcontrols[i], path);
-                               continue;
+                       if (!w->kcontrols[i]) {
+                               ret = dapm_create_or_share_mixmux_kcontrol(w, i);
+                               if (ret < 0)
+                                       return ret;
                        }
 
-                       ret = dapm_create_or_share_mixmux_kcontrol(w, i);
-                       if (ret < 0)
-                               return ret;
-
                        dapm_kcontrol_add_path(w->kcontrols[i], path);
+
+                       data = snd_kcontrol_chip(w->kcontrols[i]);
+                       if (data->widget)
+                               snd_soc_dapm_add_path(data->widget->dapm,
+                                                     data->widget,
+                                                     path->source,
+                                                     NULL, NULL);
                }
        }
 
        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct snd_soc_card *card = dapm->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val;
 
-       if (e->reg != SND_SOC_NOPM) {
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
                int ret = soc_dapm_read(dapm, e->reg, ®_val);
                if (ret)
                        return ret;
        } else {
                reg_val = dapm_kcontrol_get_value(kcontrol);
        }
+       mutex_unlock(&card->dapm_mutex);
 
        val = (reg_val >> e->shift_l) & e->mask;
        ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
        struct snd_soc_card *card = dapm->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int *item = ucontrol->value.enumerated.item;
-       unsigned int val, change;
+       unsigned int val, change, reg_change = 0;
        unsigned int mask;
        struct snd_soc_dapm_update update;
        int ret = 0;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
+       change = dapm_kcontrol_set_value(kcontrol, val);
+
        if (e->reg != SND_SOC_NOPM)
-               change = soc_dapm_test_bits(dapm, e->reg, mask, val);
-       else
-               change = dapm_kcontrol_set_value(kcontrol, val);
+               reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
 
-       if (change) {
-               if (e->reg != SND_SOC_NOPM) {
+       if (change || reg_change) {
+               if (reg_change) {
                        update.kcontrol = kcontrol;
                        update.reg = e->reg;
                        update.mask = mask;
                        update.val = val;
                        card->update = &update;
                }
+               change |= reg_change;
 
                ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);