Merge remote-tracking branch 'asoc/fix/fsl' into asoc-linus
[firefly-linux-kernel-4.4.55.git] / sound / soc / soc-dapm.c
index c7051c457b75c0f09acdd9cd1e39ef62eda22f0f..b94190820e8cfa1b6c24e925f176196cc5efff98 100644 (file)
@@ -64,6 +64,7 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_virt_mux] = 5,
        [snd_soc_dapm_value_mux] = 5,
        [snd_soc_dapm_dac] = 6,
+       [snd_soc_dapm_switch] = 7,
        [snd_soc_dapm_mixer] = 7,
        [snd_soc_dapm_mixer_named_ctl] = 7,
        [snd_soc_dapm_pga] = 8,
@@ -83,6 +84,7 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_line] = 2,
        [snd_soc_dapm_out_drv] = 2,
        [snd_soc_dapm_pga] = 4,
+       [snd_soc_dapm_switch] = 5,
        [snd_soc_dapm_mixer_named_ctl] = 5,
        [snd_soc_dapm_mixer] = 5,
        [snd_soc_dapm_dac] = 6,
@@ -365,11 +367,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                val = soc_widget_read(w, e->reg);
                item = (val >> e->shift_l) & e->mask;
 
-               p->connect = 0;
-               for (i = 0; i < e->max; i++) {
-                       if (!(strcmp(p->name, e->texts[i])) && item == i)
-                               p->connect = 1;
-               }
+               if (item < e->max && !strcmp(p->name, e->texts[item]))
+                       p->connect = 1;
+               else
+                       p->connect = 0;
        }
        break;
        case snd_soc_dapm_virt_mux: {
@@ -399,11 +400,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                                break;
                }
 
-               p->connect = 0;
-               for (i = 0; i < e->max; i++) {
-                       if (!(strcmp(p->name, e->texts[i])) && item == i)
-                               p->connect = 1;
-               }
+               if (item < e->max && !strcmp(p->name, e->texts[item]))
+                       p->connect = 1;
+               else
+                       p->connect = 0;
        }
        break;
        /* does not affect routing - always connected */
@@ -507,6 +507,11 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        return 0;
 }
 
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
+{
+       kfree(kctl->private_data);
+}
+
 /*
  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
  * create it. Either way, add the widget into the control's widget list
@@ -524,7 +529,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        int wlistentries;
        size_t wlistsize;
        bool wname_in_long_name, kcname_in_long_name;
-       size_t name_len;
        char *long_name;
        const char *name;
        int ret;
@@ -589,25 +593,19 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                }
 
                if (wname_in_long_name && kcname_in_long_name) {
-                       name_len = strlen(w->name) - prefix_len + 1 +
-                                  strlen(w->kcontrol_news[kci].name) + 1;
-
-                       long_name = kmalloc(name_len, GFP_KERNEL);
-                       if (long_name == NULL) {
-                               kfree(wlist);
-                               return -ENOMEM;
-                       }
-
                        /*
                         * The control will get a prefix from the control
                         * creation process but we're also using the same
                         * prefix for widgets so cut the prefix off the
                         * front of the widget name.
                         */
-                       snprintf(long_name, name_len, "%s %s",
+                       long_name = kasprintf(GFP_KERNEL, "%s %s",
                                 w->name + prefix_len,
                                 w->kcontrol_news[kci].name);
-                       long_name[name_len - 1] = '\0';
+                       if (long_name == NULL) {
+                               kfree(wlist);
+                               return -ENOMEM;
+                       }
 
                        name = long_name;
                } else if (wname_in_long_name) {
@@ -620,17 +618,16 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
 
                kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
                                        prefix);
+               kcontrol->private_free = dapm_kcontrol_free;
+               kfree(long_name);
                ret = snd_ctl_add(card, kcontrol);
                if (ret < 0) {
                        dev_err(dapm->dev,
                                "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
                                w->name, name, ret);
                        kfree(wlist);
-                       kfree(long_name);
                        return ret;
                }
-
-               path->long_name = long_name;
        }
 
        kcontrol->private_data = wlist;
@@ -1270,6 +1267,14 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
                ev_name = "POST_PMD";
                power = 0;
                break;
+       case SND_SOC_DAPM_WILL_PMU:
+               ev_name = "WILL_PMU";
+               power = 1;
+               break;
+       case SND_SOC_DAPM_WILL_PMD:
+               ev_name = "WILL_PMD";
+               power = 0;
+               break;
        default:
                BUG();
                return;
@@ -1730,6 +1735,14 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
 
+       list_for_each_entry(w, &down_list, power_list) {
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
+       }
+
+       list_for_each_entry(w, &up_list, power_list) {
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
+       }
+
        /* Power down widgets first; try to avoid amplifying pops. */
        dapm_seq_run(dapm, &down_list, event, false);
 
@@ -2094,6 +2107,14 @@ static void snd_soc_dapm_sys_remove(struct device *dev)
        device_remove_file(dev, &dev_attr_dapm_widget);
 }
 
+static void dapm_free_path(struct snd_soc_dapm_path *path)
+{
+       list_del(&path->list_sink);
+       list_del(&path->list_source);
+       list_del(&path->list);
+       kfree(path);
+}
+
 /* free all dapm widgets and resources */
 static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
 {
@@ -2109,20 +2130,12 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
                 * While removing the path, remove reference to it from both
                 * source and sink widgets so that path is removed only once.
                 */
-               list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p->long_name);
-                       kfree(p);
-               }
-               list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
-                       list_del(&p->list_sink);
-                       list_del(&p->list_source);
-                       list_del(&p->list);
-                       kfree(p->long_name);
-                       kfree(p);
-               }
+               list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
+                       dapm_free_path(p);
+
+               list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
+                       dapm_free_path(p);
+
                kfree(w->kcontrols);
                kfree(w->name);
                kfree(w);
@@ -2398,10 +2411,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
                dapm_mark_dirty(path->source, "Route removed");
                dapm_mark_dirty(path->sink, "Route removed");
 
-               list_del(&path->list);
-               list_del(&path->list_sink);
-               list_del(&path->list_source);
-               kfree(path);
+               dapm_free_path(path);
        } else {
                dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
                         source, sink);
@@ -3055,7 +3065,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget)
 {
        struct snd_soc_dapm_widget *w;
-       size_t name_len;
        int ret;
 
        if ((w = dapm_cnew_widget(widget)) == NULL)
@@ -3096,19 +3105,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                break;
        }
 
-       name_len = strlen(widget->name) + 1;
        if (dapm->codec && dapm->codec->name_prefix)
-               name_len += 1 + strlen(dapm->codec->name_prefix);
-       w->name = kmalloc(name_len, GFP_KERNEL);
+               w->name = kasprintf(GFP_KERNEL, "%s %s",
+                       dapm->codec->name_prefix, widget->name);
+       else
+               w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
+
        if (w->name == NULL) {
                kfree(w);
                return NULL;
        }
-       if (dapm->codec && dapm->codec->name_prefix)
-               snprintf((char *)w->name, name_len, "%s %s",
-                       dapm->codec->name_prefix, widget->name);
-       else
-               snprintf((char *)w->name, name_len, "%s", widget->name);
 
        switch (w->id) {
        case snd_soc_dapm_switch: