{      .id = snd_soc_dapm_mux, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
+#define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
+{      .id = snd_soc_dapm_demux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
        snd_soc_dapm_input = 0,         /* input pin */
        snd_soc_dapm_output,            /* output pin */
        snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
+       snd_soc_dapm_demux,                     /* connects the input to one of multiple outputs */
        snd_soc_dapm_mixer,                     /* mixes several analog signals together */
        snd_soc_dapm_mixer_named_ctl,           /* mixer with named controls */
        snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
 
        [snd_soc_dapm_aif_out] = 4,
        [snd_soc_dapm_mic] = 5,
        [snd_soc_dapm_mux] = 6,
+       [snd_soc_dapm_demux] = 6,
        [snd_soc_dapm_dac] = 7,
        [snd_soc_dapm_switch] = 8,
        [snd_soc_dapm_mixer] = 8,
        [snd_soc_dapm_mic] = 7,
        [snd_soc_dapm_micbias] = 8,
        [snd_soc_dapm_mux] = 9,
+       [snd_soc_dapm_demux] = 9,
        [snd_soc_dapm_aif_in] = 10,
        [snd_soc_dapm_aif_out] = 10,
        [snd_soc_dapm_dai_in] = 10,
                        }
                }
                break;
+       case snd_soc_dapm_demux:
        case snd_soc_dapm_mux:
                e = (struct soc_enum *)kcontrol->private_value;
 
 
 /* connect mux widget to its interconnecting audio paths */
 static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
-       struct snd_soc_dapm_path *path, const char *control_name)
+       struct snd_soc_dapm_path *path, const char *control_name,
+       struct snd_soc_dapm_widget *w)
 {
-       const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0];
+       const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, item;
        int i;
                                wname_in_long_name = false;
                                kcname_in_long_name = true;
                                break;
+                       case snd_soc_dapm_demux:
                        case snd_soc_dapm_mux:
                                wname_in_long_name = true;
                                kcname_in_long_name = false;
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_dapm_path *path;
+       struct list_head *paths;
+       const char *type;
        int ret;
 
+       switch (w->id) {
+       case snd_soc_dapm_mux:
+               paths = &w->sources;
+               type = "mux";
+               break;
+       case snd_soc_dapm_demux:
+               paths = &w->sinks;
+               type = "demux";
+               break;
+       default:
+               return -EINVAL;
+       }
+
        if (w->num_kcontrols != 1) {
                dev_err(dapm->dev,
-                       "ASoC: mux %s has incorrect number of controls\n",
+                       "ASoC: %s %s has incorrect number of controls\n", type,
                        w->name);
                return -EINVAL;
        }
 
-       if (list_empty(&w->sources)) {
-               dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
+       if (list_empty(paths)) {
+               dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
                return -EINVAL;
        }
 
        if (ret < 0)
                return ret;
 
-       list_for_each_entry(path, &w->sources, list_sink) {
-               if (path->name)
-                       dapm_kcontrol_add_path(w->kcontrols[0], path);
+       if (w->id == snd_soc_dapm_mux) {
+               list_for_each_entry(path, &w->sources, list_sink) {
+                       if (path->name)
+                               dapm_kcontrol_add_path(w->kcontrols[0], path);
+               }
+       } else {
+               list_for_each_entry(path, &w->sinks, list_source) {
+                       if (path->name)
+                               dapm_kcontrol_add_path(w->kcontrols[0], path);
+               }
        }
 
        return 0;
        }
 }
 
+static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
+       const char *control)
+{
+       bool dynamic_source = false;
+       bool dynamic_sink = false;
+
+       if (!control)
+               return 0;
+
+       switch (source->id) {
+       case snd_soc_dapm_demux:
+               dynamic_source = true;
+               break;
+       default:
+               break;
+       }
+
+       switch (sink->id) {
+       case snd_soc_dapm_mux:
+       case snd_soc_dapm_switch:
+       case snd_soc_dapm_mixer:
+       case snd_soc_dapm_mixer_named_ctl:
+               dynamic_sink = true;
+               break;
+       default:
+               break;
+       }
+
+       if (dynamic_source && dynamic_sink) {
+               dev_err(dapm->dev,
+                       "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
+                       source->name, control, sink->name);
+               return -EINVAL;
+       } else if (!dynamic_source && !dynamic_sink) {
+               dev_err(dapm->dev,
+                       "Control not supported for path %s -> [%s] -> %s\n",
+                       source->name, control, sink->name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
        const char *control,
                return -EINVAL;
        }
 
+       ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
+       if (ret)
+               return ret;
+
        path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
        if (!path)
                return -ENOMEM;
        if (control == NULL) {
                path->connect = 1;
        } else {
-               /* connect dynamic paths */
+               switch (wsource->id) {
+               case snd_soc_dapm_demux:
+                       ret = dapm_connect_mux(dapm, path, control, wsource);
+                       if (ret)
+                               goto err;
+                       break;
+               default:
+                       break;
+               }
+
                switch (wsink->id) {
                case snd_soc_dapm_mux:
-                       ret = dapm_connect_mux(dapm, path, control);
+                       ret = dapm_connect_mux(dapm, path, control, wsink);
                        if (ret != 0)
                                goto err;
                        break;
                                goto err;
                        break;
                default:
-                       dev_err(dapm->dev,
-                               "Control not supported for path %s -> [%s] -> %s\n",
-                               wsource->name, control, wsink->name);
-                       ret = -EINVAL;
-                       goto err;
+                       break;
                }
        }
 
                        dapm_new_mixer(w);
                        break;
                case snd_soc_dapm_mux:
+               case snd_soc_dapm_demux:
                        dapm_new_mux(w);
                        break;
                case snd_soc_dapm_pga:
                w->power_check = dapm_always_on_check_power;
                break;
        case snd_soc_dapm_mux:
+       case snd_soc_dapm_demux:
        case snd_soc_dapm_switch:
        case snd_soc_dapm_mixer:
        case snd_soc_dapm_mixer_named_ctl: