]> Pileus Git - ~andy/linux/blobdiff - sound/soc/soc-dapm.c
Merge branch 'topic/hda' into for-linus
[~andy/linux] / sound / soc / soc-dapm.c
index c39146d435e227217ce12cb68376332230863cc1..f42e8b9fb17db7baeabaf7152f81123773cdecd0 100644 (file)
@@ -124,7 +124,7 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
        return !list_empty(&w->dirty);
 }
 
-static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
+void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
 {
        if (!dapm_dirty_widget(w)) {
                dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
@@ -132,6 +132,7 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
                list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
        }
 }
+EXPORT_SYMBOL_GPL(dapm_mark_dirty);
 
 /* create a new dapm widget */
 static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
@@ -665,6 +666,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
        struct snd_soc_dapm_path *path;
        int con = 0;
 
+       if (widget->outputs >= 0)
+               return widget->outputs;
+
        DAPM_UPDATE_STAT(widget, path_checks);
 
        if (widget->id == snd_soc_dapm_supply)
@@ -673,21 +677,29 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
        switch (widget->id) {
        case snd_soc_dapm_adc:
        case snd_soc_dapm_aif_out:
-               if (widget->active)
-                       return snd_soc_dapm_suspend_check(widget);
+               if (widget->active) {
+                       widget->outputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->outputs;
+               }
        default:
                break;
        }
 
        if (widget->connected) {
                /* connected pin ? */
-               if (widget->id == snd_soc_dapm_output && !widget->ext)
-                       return snd_soc_dapm_suspend_check(widget);
+               if (widget->id == snd_soc_dapm_output && !widget->ext) {
+                       widget->outputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->outputs;
+               }
 
                /* connected jack or spk ? */
-               if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
-                   (widget->id == snd_soc_dapm_line && !list_empty(&widget->sources)))
-                       return snd_soc_dapm_suspend_check(widget);
+               if (widget->id == snd_soc_dapm_hp ||
+                   widget->id == snd_soc_dapm_spk ||
+                   (widget->id == snd_soc_dapm_line &&
+                    !list_empty(&widget->sources))) {
+                       widget->outputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->outputs;
+               }
        }
 
        list_for_each_entry(path, &widget->sinks, list_source) {
@@ -705,6 +717,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
                }
        }
 
+       widget->outputs = con;
+
        return con;
 }
 
@@ -717,6 +731,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
        struct snd_soc_dapm_path *path;
        int con = 0;
 
+       if (widget->inputs >= 0)
+               return widget->inputs;
+
        DAPM_UPDATE_STAT(widget, path_checks);
 
        if (widget->id == snd_soc_dapm_supply)
@@ -726,25 +743,35 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
        switch (widget->id) {
        case snd_soc_dapm_dac:
        case snd_soc_dapm_aif_in:
-               if (widget->active)
-                       return snd_soc_dapm_suspend_check(widget);
+               if (widget->active) {
+                       widget->inputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->inputs;
+               }
        default:
                break;
        }
 
        if (widget->connected) {
                /* connected pin ? */
-               if (widget->id == snd_soc_dapm_input && !widget->ext)
-                       return snd_soc_dapm_suspend_check(widget);
+               if (widget->id == snd_soc_dapm_input && !widget->ext) {
+                       widget->inputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->inputs;
+               }
 
                /* connected VMID/Bias for lower pops */
-               if (widget->id == snd_soc_dapm_vmid)
-                       return snd_soc_dapm_suspend_check(widget);
+               if (widget->id == snd_soc_dapm_vmid) {
+                       widget->inputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->inputs;
+               }
 
                /* connected jack ? */
                if (widget->id == snd_soc_dapm_mic ||
-                   (widget->id == snd_soc_dapm_line && !list_empty(&widget->sinks)))
-                       return snd_soc_dapm_suspend_check(widget);
+                   (widget->id == snd_soc_dapm_line &&
+                    !list_empty(&widget->sinks))) {
+                       widget->inputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->inputs;
+               }
+
        }
 
        list_for_each_entry(path, &widget->sources, list_sink) {
@@ -762,6 +789,8 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
                }
        }
 
+       widget->inputs = con;
+
        return con;
 }
 
@@ -851,7 +880,6 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
 static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
 {
        struct snd_soc_dapm_path *path;
-       int power = 0;
 
        DAPM_UPDATE_STAT(w, power_checks);
 
@@ -869,15 +897,13 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
                if (!path->sink)
                        continue;
 
-               if (dapm_widget_power_check(path->sink)) {
-                       power = 1;
-                       break;
-               }
+               if (dapm_widget_power_check(path->sink))
+                       return 1;
        }
 
        dapm_clear_walk(w->dapm);
 
-       return power;
+       return 0;
 }
 
 static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
@@ -1260,11 +1286,18 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
                                                   path->connect);
                }
        }
-       list_for_each_entry(path, &w->sinks, list_source) {
-               if (path->sink) {
-                       dapm_widget_set_peer_power(path->sink, power,
-                                                  path->connect);
+       switch (w->id) {
+       case snd_soc_dapm_supply:
+               /* Supplies can't affect their outputs, only their inputs */
+               break;
+       default:
+               list_for_each_entry(path, &w->sinks, list_source) {
+                       if (path->sink) {
+                               dapm_widget_set_peer_power(path->sink, power,
+                                                          path->connect);
+                       }
                }
+               break;
        }
 
        if (power)
@@ -1331,6 +1364,8 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 
        list_for_each_entry(w, &card->widgets, list) {
                w->power_checked = false;
+               w->inputs = -1;
+               w->outputs = -1;
        }
 
        /* Check which widgets we need to power and store them in
@@ -1841,6 +1876,13 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
  */
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
 {
+       /*
+        * Suppress early reports (eg, jacks syncing their state) to avoid
+        * silly DAPM runs during card startup.
+        */
+       if (!dapm->card || !dapm->card->instantiated)
+               return 0;
+
        return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
@@ -2126,48 +2168,21 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                case snd_soc_dapm_switch:
                case snd_soc_dapm_mixer:
                case snd_soc_dapm_mixer_named_ctl:
-                       w->power_check = dapm_generic_check_power;
                        dapm_new_mixer(w);
                        break;
                case snd_soc_dapm_mux:
                case snd_soc_dapm_virt_mux:
                case snd_soc_dapm_value_mux:
-                       w->power_check = dapm_generic_check_power;
                        dapm_new_mux(w);
                        break;
-               case snd_soc_dapm_adc:
-               case snd_soc_dapm_aif_out:
-                       w->power_check = dapm_adc_check_power;
-                       break;
-               case snd_soc_dapm_dac:
-               case snd_soc_dapm_aif_in:
-                       w->power_check = dapm_dac_check_power;
-                       break;
                case snd_soc_dapm_pga:
                case snd_soc_dapm_out_drv:
-                       w->power_check = dapm_generic_check_power;
                        dapm_new_pga(w);
                        break;
-               case snd_soc_dapm_input:
-               case snd_soc_dapm_output:
-               case snd_soc_dapm_micbias:
-               case snd_soc_dapm_spk:
-               case snd_soc_dapm_hp:
-               case snd_soc_dapm_mic:
-               case snd_soc_dapm_line:
-                       w->power_check = dapm_generic_check_power;
-                       break;
-               case snd_soc_dapm_supply:
-                       w->power_check = dapm_supply_check_power;
-               case snd_soc_dapm_vmid:
-               case snd_soc_dapm_pre:
-               case snd_soc_dapm_post:
+               default:
                        break;
                }
 
-               if (!w->power_check)
-                       w->power_check = dapm_always_on_check_power;
-
                /* Read the initial power state from the device */
                if (w->reg >= 0) {
                        val = soc_widget_read(w, w->reg);
@@ -2181,7 +2196,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 
                w->new = 1;
 
-               list_add(&w->dirty, &(w->dapm->card->dapm_dirty));
+               dapm_mark_dirty(w, "new widget");
                dapm_debugfs_add_widget(w);
        }
 
@@ -2656,6 +2671,44 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        else
                snprintf(w->name, name_len, "%s", widget->name);
 
+       switch (w->id) {
+       case snd_soc_dapm_switch:
+       case snd_soc_dapm_mixer:
+       case snd_soc_dapm_mixer_named_ctl:
+               w->power_check = dapm_generic_check_power;
+               break;
+       case snd_soc_dapm_mux:
+       case snd_soc_dapm_virt_mux:
+       case snd_soc_dapm_value_mux:
+               w->power_check = dapm_generic_check_power;
+               break;
+       case snd_soc_dapm_adc:
+       case snd_soc_dapm_aif_out:
+               w->power_check = dapm_adc_check_power;
+               break;
+       case snd_soc_dapm_dac:
+       case snd_soc_dapm_aif_in:
+               w->power_check = dapm_dac_check_power;
+               break;
+       case snd_soc_dapm_pga:
+       case snd_soc_dapm_out_drv:
+       case snd_soc_dapm_input:
+       case snd_soc_dapm_output:
+       case snd_soc_dapm_micbias:
+       case snd_soc_dapm_spk:
+       case snd_soc_dapm_hp:
+       case snd_soc_dapm_mic:
+       case snd_soc_dapm_line:
+               w->power_check = dapm_generic_check_power;
+               break;
+       case snd_soc_dapm_supply:
+               w->power_check = dapm_supply_check_power;
+               break;
+       default:
+               w->power_check = dapm_always_on_check_power;
+               break;
+       }
+
        dapm->n_widgets++;
        w->dapm = dapm;
        w->codec = dapm->codec;