]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/soc/soc-dapm.c
Merge branch 'samsung-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene...
[karo-tx-linux.git] / sound / soc / soc-dapm.c
index f42e8b9fb17db7baeabaf7152f81123773cdecd0..3ad1f59b80281cfc7c9ace89ae8a30d34317fe7a 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
 #include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -339,6 +340,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_output:
        case snd_soc_dapm_adc:
        case snd_soc_dapm_input:
+       case snd_soc_dapm_siggen:
        case snd_soc_dapm_dac:
        case snd_soc_dapm_micbias:
        case snd_soc_dapm_vmid:
@@ -772,6 +774,11 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
                        return widget->inputs;
                }
 
+               /* signal generator */
+               if (widget->id == snd_soc_dapm_siggen) {
+                       widget->inputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->inputs;
+               }
        }
 
        list_for_each_entry(path, &widget->sources, list_sink) {
@@ -1200,6 +1207,9 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
        /* If we're off and we're not supposed to be go into STANDBY */
        if (d->bias_level == SND_SOC_BIAS_OFF &&
            d->target_bias_level != SND_SOC_BIAS_OFF) {
+               if (d->dev)
+                       pm_runtime_get_sync(d->dev);
+
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        dev_err(d->dev,
@@ -1239,6 +1249,9 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
                if (ret != 0)
                        dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
+
+               if (d->dev)
+                       pm_runtime_put_sync(d->dev);
        }
 
        /* If we just powered up then move to active bias */
@@ -1725,8 +1738,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 static ssize_t dapm_widget_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_pcm_runtime *rtd =
-                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
        struct snd_soc_codec *codec =rtd->codec;
        struct snd_soc_dapm_widget *w;
        int count = 0;
@@ -1982,6 +1994,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_out_drv:
        case snd_soc_dapm_input:
        case snd_soc_dapm_output:
+       case snd_soc_dapm_siggen:
        case snd_soc_dapm_micbias:
        case snd_soc_dapm_vmid:
        case snd_soc_dapm_pre:
@@ -2947,6 +2960,79 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
+static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
+                                             struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_path *p;
+
+       list_for_each_entry(p, &card->paths, list) {
+               if ((p->source == w) || (p->sink == w)) {
+                       dev_dbg(card->dev,
+                           "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
+                           p->source->name, p->source->id, p->source->dapm,
+                           p->sink->name, p->sink->id, p->sink->dapm);
+
+                       /* Connected to something other than the codec */
+                       if (p->source->dapm != p->sink->dapm)
+                               return true;
+                       /*
+                        * Loopback connection from codec external pin to
+                        * codec external pin
+                        */
+                       if (p->sink->id == snd_soc_dapm_input) {
+                               switch (p->source->id) {
+                               case snd_soc_dapm_output:
+                               case snd_soc_dapm_micbias:
+                                       return true;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return false;
+}
+
+/**
+ * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins
+ * @codec: The codec whose pins should be processed
+ *
+ * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec
+ * which are unused. Pins are used if they are connected externally to the
+ * codec, whether that be to some other device, or a loop-back connection to
+ * the codec itself.
+ */
+void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec)
+{
+       struct snd_soc_card *card = codec->card;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_widget *w;
+
+       dev_dbg(codec->dev, "Auto NC: DAPMs: card:%p codec:%p\n",
+               &card->dapm, &codec->dapm);
+
+       list_for_each_entry(w, &card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
+               switch (w->id) {
+               case snd_soc_dapm_input:
+               case snd_soc_dapm_output:
+               case snd_soc_dapm_micbias:
+                       dev_dbg(codec->dev, "Auto NC: Checking widget %s\n",
+                               w->name);
+                       if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
+                               dev_dbg(codec->dev,
+                                       "... Not in map; disabling\n");
+                               snd_soc_dapm_nc_pin(dapm, w->name);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
 /**
  * snd_soc_dapm_free - free dapm resources
  * @dapm: DAPM context