Merge branch 'for-2.6.38' into for-2.6.39
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 9 Mar 2011 12:37:42 +0000 (12:37 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 9 Mar 2011 12:37:42 +0000 (12:37 +0000)
Conflicts:
sound/soc/codecs/wm8978.c
sound/soc/soc-dapm.c

1  2 
sound/soc/soc-dapm.c

diff --combined sound/soc/soc-dapm.c
@@@ -32,7 -32,6 +32,7 @@@
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/init.h>
 +#include <linux/async.h>
  #include <linux/delay.h>
  #include <linux/pm.h>
  #include <linux/bitops.h>
@@@ -126,17 -125,17 +126,17 @@@ static inline struct snd_soc_dapm_widge
  
  /**
   * snd_soc_dapm_set_bias_level - set the bias level for the system
 - * @card: audio device
 + * @dapm: DAPM context
   * @level: level to configure
   *
   * Configure the bias (power) levels for the SoC audio device.
   *
   * Returns 0 for success else error.
   */
 -static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
 -                                     struct snd_soc_dapm_context *dapm,
 +static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
                                       enum snd_soc_bias_level level)
  {
 +      struct snd_soc_card *card = dapm->card;
        int ret = 0;
  
        switch (level) {
@@@ -366,20 -365,9 +366,20 @@@ static int dapm_new_mixer(struct snd_so
        struct snd_soc_dapm_widget *w)
  {
        int i, ret = 0;
 -      size_t name_len;
 +      size_t name_len, prefix_len;
        struct snd_soc_dapm_path *path;
 -      struct snd_card *card = dapm->codec->card->snd_card;
 +      struct snd_card *card = dapm->card->snd_card;
 +      const char *prefix;
 +
 +      if (dapm->codec)
 +              prefix = dapm->codec->name_prefix;
 +      else
 +              prefix = NULL;
 +
 +      if (prefix)
 +              prefix_len = strlen(prefix) + 1;
 +      else
 +              prefix_len = 0;
  
        /* add kcontrol */
        for (i = 0; i < w->num_kcontrols; i++) {
  
                        switch (w->id) {
                        default:
 +                              /* 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(path->long_name, name_len, "%s %s",
 -                                       w->name, w->kcontrols[i].name);
 +                                       w->name + prefix_len,
 +                                       w->kcontrols[i].name);
                                break;
                        case snd_soc_dapm_mixer_named_ctl:
                                snprintf(path->long_name, name_len, "%s",
                        path->long_name[name_len - 1] = '\0';
  
                        path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
 -                              path->long_name);
 +                                                    path->long_name, prefix);
                        ret = snd_ctl_add(card, path->kcontrol);
                        if (ret < 0) {
                                dev_err(dapm->dev,
@@@ -448,9 -429,7 +448,9 @@@ static int dapm_new_mux(struct snd_soc_
  {
        struct snd_soc_dapm_path *path = NULL;
        struct snd_kcontrol *kcontrol;
 -      struct snd_card *card = dapm->codec->card->snd_card;
 +      struct snd_card *card = dapm->card->snd_card;
 +      const char *prefix;
 +      size_t prefix_len;
        int ret = 0;
  
        if (!w->num_kcontrols) {
                return -EINVAL;
        }
  
 -      kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
 +      if (dapm->codec)
 +              prefix = dapm->codec->name_prefix;
 +      else
 +              prefix = NULL;
 +
 +      if (prefix)
 +              prefix_len = strlen(prefix) + 1;
 +      else
 +              prefix_len = 0;
 +
 +      /* 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.
 +       */
 +      kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len,
 +                              prefix);
        ret = snd_ctl_add(card, kcontrol);
  
        if (ret < 0)
@@@ -515,7 -479,7 +515,7 @@@ static inline void dapm_clear_walk(stru
   */
  static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
  {
 -      int level = snd_power_get_state(widget->dapm->codec->card->snd_card);
 +      int level = snd_power_get_state(widget->dapm->card->snd_card);
  
        switch (level) {
        case SNDRV_CTL_POWER_D3hot:
@@@ -770,23 -734,10 +770,23 @@@ static int dapm_supply_check_power(stru
  
  static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
                            struct snd_soc_dapm_widget *b,
 -                          int sort[])
 +                          bool power_up)
  {
 +      int *sort;
 +
 +      if (power_up)
 +              sort = dapm_up_seq;
 +      else
 +              sort = dapm_down_seq;
 +
        if (sort[a->id] != sort[b->id])
                return sort[a->id] - sort[b->id];
 +      if (a->subseq != b->subseq) {
 +              if (power_up)
 +                      return a->subseq - b->subseq;
 +              else
 +                      return b->subseq - a->subseq;
 +      }
        if (a->reg != b->reg)
                return a->reg - b->reg;
        if (a->dapm != b->dapm)
  /* Insert a widget in order into a DAPM power sequence. */
  static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
                            struct list_head *list,
 -                          int sort[])
 +                          bool power_up)
  {
        struct snd_soc_dapm_widget *w;
  
        list_for_each_entry(w, list, power_list)
 -              if (dapm_seq_compare(new_widget, w, sort) < 0) {
 +              if (dapm_seq_compare(new_widget, w, power_up) < 0) {
                        list_add_tail(&new_widget->power_list, &w->power_list);
                        return;
                }
@@@ -914,42 -865,26 +914,42 @@@ static void dapm_seq_run_coalesced(stru
   * handled.
   */
  static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
 -                       struct list_head *list, int event, int sort[])
 +                       struct list_head *list, int event, bool power_up)
  {
        struct snd_soc_dapm_widget *w, *n;
        LIST_HEAD(pending);
        int cur_sort = -1;
 +      int cur_subseq = -1;
        int cur_reg = SND_SOC_NOPM;
        struct snd_soc_dapm_context *cur_dapm = NULL;
 -      int ret;
 +      int ret, i;
 +      int *sort;
 +
 +      if (power_up)
 +              sort = dapm_up_seq;
 +      else
 +              sort = dapm_down_seq;
  
        list_for_each_entry_safe(w, n, list, power_list) {
                ret = 0;
  
                /* Do we need to apply any queued changes? */
                if (sort[w->id] != cur_sort || w->reg != cur_reg ||
 -                  w->dapm != cur_dapm) {
 +                  w->dapm != cur_dapm || w->subseq != cur_subseq) {
                        if (!list_empty(&pending))
                                dapm_seq_run_coalesced(cur_dapm, &pending);
  
 +                      if (cur_dapm && cur_dapm->seq_notifier) {
 +                              for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
 +                                      if (sort[i] == cur_sort)
 +                                              cur_dapm->seq_notifier(cur_dapm,
 +                                                                     i,
 +                                                                     cur_subseq);
 +                      }
 +
                        INIT_LIST_HEAD(&pending);
                        cur_sort = -1;
 +                      cur_subseq = -1;
                        cur_reg = SND_SOC_NOPM;
                        cur_dapm = NULL;
                }
                default:
                        /* Queue it up for application */
                        cur_sort = sort[w->id];
 +                      cur_subseq = w->subseq;
                        cur_reg = w->reg;
                        cur_dapm = w->dapm;
                        list_move(&w->power_list, &pending);
        }
  
        if (!list_empty(&pending))
-               dapm_seq_run_coalesced(dapm, &pending);
+               dapm_seq_run_coalesced(cur_dapm, &pending);
 +
 +      if (cur_dapm && cur_dapm->seq_notifier) {
 +              for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
 +                      if (sort[i] == cur_sort)
 +                              cur_dapm->seq_notifier(cur_dapm,
 +                                                     i, cur_subseq);
 +      }
  }
  
  static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
        }
  }
  
 +/* Async callback run prior to DAPM sequences - brings to _PREPARE if
 + * they're changing state.
 + */
 +static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
 +{
 +      struct snd_soc_dapm_context *d = data;
 +      int ret;
  
 +      if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
 +              ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
 +              if (ret != 0)
 +                      dev_err(d->dev,
 +                              "Failed to turn on bias: %d\n", ret);
 +      }
 +
 +      /* If we're changing to all on or all off then prepare */
 +      if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
 +          (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
 +              ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
 +              if (ret != 0)
 +                      dev_err(d->dev,
 +                              "Failed to prepare bias: %d\n", ret);
 +      }
 +}
 +
 +/* Async callback run prior to DAPM sequences - brings to their final
 + * state.
 + */
 +static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
 +{
 +      struct snd_soc_dapm_context *d = data;
 +      int ret;
 +
 +      /* If we just powered the last thing off drop to standby bias */
 +      if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
 +              ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
 +              if (ret != 0)
 +                      dev_err(d->dev, "Failed to apply standby bias: %d\n",
 +                              ret);
 +      }
 +
 +      /* If we're in standby and can support bias off then do that */
 +      if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) {
 +              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 we just powered up then move to active bias */
 +      if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
 +              ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
 +              if (ret != 0)
 +                      dev_err(d->dev, "Failed to apply active bias: %d\n",
 +                              ret);
 +      }
 +}
  
  /*
   * Scan each dapm widget for complete audio path.
   */
  static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
  {
 -      struct snd_soc_card *card = dapm->codec->card;
 +      struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
        struct snd_soc_dapm_context *d;
        LIST_HEAD(up_list);
        LIST_HEAD(down_list);
 -      int ret = 0;
 +      LIST_HEAD(async_domain);
        int power;
  
        trace_snd_soc_dapm_start(card);
        list_for_each_entry(w, &card->widgets, list) {
                switch (w->id) {
                case snd_soc_dapm_pre:
 -                      dapm_seq_insert(w, &down_list, dapm_down_seq);
 +                      dapm_seq_insert(w, &down_list, false);
                        break;
                case snd_soc_dapm_post:
 -                      dapm_seq_insert(w, &up_list, dapm_up_seq);
 +                      dapm_seq_insert(w, &up_list, true);
                        break;
  
                default:
                        trace_snd_soc_dapm_widget_power(w, power);
  
                        if (power)
 -                              dapm_seq_insert(w, &up_list, dapm_up_seq);
 +                              dapm_seq_insert(w, &up_list, true);
                        else
 -                              dapm_seq_insert(w, &down_list, dapm_down_seq);
 +                              dapm_seq_insert(w, &down_list, false);
  
                        w->power = power;
                        break;
                }
        }
  
 -      list_for_each_entry(d, &dapm->card->dapm_list, list) {
 -              if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
 -                      ret = snd_soc_dapm_set_bias_level(card, d,
 -                                                        SND_SOC_BIAS_STANDBY);
 -                      if (ret != 0)
 -                              dev_err(d->dev,
 -                                      "Failed to turn on bias: %d\n", ret);
 -              }
 -
 -              /* If we're changing to all on or all off then prepare */
 -              if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
 -                  (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
 -                      ret = snd_soc_dapm_set_bias_level(card, d,
 -                                                        SND_SOC_BIAS_PREPARE);
 -                      if (ret != 0)
 -                              dev_err(d->dev,
 -                                      "Failed to prepare bias: %d\n", ret);
 -              }
 -      }
 +      /* Run all the bias changes in parallel */
 +      list_for_each_entry(d, &dapm->card->dapm_list, list)
 +              async_schedule_domain(dapm_pre_sequence_async, d,
 +                                      &async_domain);
 +      async_synchronize_full_domain(&async_domain);
  
        /* Power down widgets first; try to avoid amplifying pops. */
 -      dapm_seq_run(dapm, &down_list, event, dapm_down_seq);
 +      dapm_seq_run(dapm, &down_list, event, false);
  
        dapm_widget_update(dapm);
  
        /* Now power up. */
 -      dapm_seq_run(dapm, &up_list, event, dapm_up_seq);
 -
 -      list_for_each_entry(d, &dapm->card->dapm_list, list) {
 -              /* If we just powered the last thing off drop to standby bias */
 -              if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
 -                      ret = snd_soc_dapm_set_bias_level(card, d,
 -                                                        SND_SOC_BIAS_STANDBY);
 -                      if (ret != 0)
 -                              dev_err(d->dev,
 -                                      "Failed to apply standby bias: %d\n",
 -                                      ret);
 -              }
 +      dapm_seq_run(dapm, &up_list, event, true);
  
 -              /* If we're in standby and can support bias off then do that */
 -              if (d->bias_level == SND_SOC_BIAS_STANDBY &&
 -                  d->idle_bias_off) {
 -                      ret = snd_soc_dapm_set_bias_level(card, d,
 -                                                        SND_SOC_BIAS_OFF);
 -                      if (ret != 0)
 -                              dev_err(d->dev,
 -                                      "Failed to turn off bias: %d\n", ret);
 -              }
 -
 -              /* If we just powered up then move to active bias */
 -              if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
 -                      ret = snd_soc_dapm_set_bias_level(card, d,
 -                                                        SND_SOC_BIAS_ON);
 -                      if (ret != 0)
 -                              dev_err(d->dev,
 -                                      "Failed to apply active bias: %d\n",
 -                                      ret);
 -              }
 -      }
 +      /* Run all the bias changes in parallel */
 +      list_for_each_entry(d, &dapm->card->dapm_list, list)
 +              async_schedule_domain(dapm_post_sequence_async, d,
 +                                      &async_domain);
 +      async_synchronize_full_domain(&async_domain);
  
        pop_dbg(dapm->dev, card->pop_time,
                "DAPM sequencing finished, waiting %dms\n", card->pop_time);
@@@ -1277,7 -1189,7 +1277,7 @@@ static ssize_t dapm_widget_power_read_f
  
                if (p->connect)
                        ret += snprintf(buf + ret, PAGE_SIZE - ret,
 -                                      " in  %s %s\n",
 +                                      " in  \"%s\" \"%s\"\n",
                                        p->name ? p->name : "static",
                                        p->source->name);
        }
  
                if (p->connect)
                        ret += snprintf(buf + ret, PAGE_SIZE - ret,
 -                                      " out %s %s\n",
 +                                      " out \"%s\" \"%s\"\n",
                                        p->name ? p->name : "static",
                                        p->sink->name);
        }
@@@ -1552,7 -1464,7 +1552,7 @@@ static int snd_soc_dapm_add_route(struc
        char prefixed_source[80];
        int ret = 0;
  
 -      if (dapm->codec->name_prefix) {
 +      if (dapm->codec && dapm->codec->name_prefix) {
                snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
                         dapm->codec->name_prefix, route->sink);
                sink = prefixed_sink;
@@@ -2202,14 -2114,14 +2202,14 @@@ int snd_soc_dapm_new_control(struct snd
                return -ENOMEM;
  
        name_len = strlen(widget->name) + 1;
 -      if (dapm->codec->name_prefix)
 +      if (dapm->codec && dapm->codec->name_prefix)
                name_len += 1 + strlen(dapm->codec->name_prefix);
        w->name = kmalloc(name_len, GFP_KERNEL);
        if (w->name == NULL) {
                kfree(w);
                return -ENOMEM;
        }
 -      if (dapm->codec->name_prefix)
 +      if (dapm->codec && dapm->codec->name_prefix)
                snprintf(w->name, name_len, "%s %s",
                        dapm->codec->name_prefix, widget->name);
        else
@@@ -2314,6 -2226,7 +2314,6 @@@ int snd_soc_dapm_stream_event(struct sn
        mutex_unlock(&codec->mutex);
        return 0;
  }
 -EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
  
  /**
   * snd_soc_dapm_enable_pin - enable pin.
@@@ -2480,7 -2393,7 +2480,7 @@@ static void soc_dapm_shutdown_codec(str
                if (w->dapm != dapm)
                        continue;
                if (w->power) {
 -                      dapm_seq_insert(w, &down_list, dapm_down_seq);
 +                      dapm_seq_insert(w, &down_list, false);
                        w->power = 0;
                        powerdown = 1;
                }
         * standby.
         */
        if (powerdown) {
 -              snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_PREPARE);
 -              dapm_seq_run(dapm, &down_list, 0, dapm_down_seq);
 -              snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_STANDBY);
 +              snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE);
 +              dapm_seq_run(dapm, &down_list, 0, false);
 +              snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
        }
  }
  
@@@ -2505,7 -2418,7 +2505,7 @@@ void snd_soc_dapm_shutdown(struct snd_s
  
        list_for_each_entry(codec, &card->codec_dev_list, list) {
                soc_dapm_shutdown_codec(&codec->dapm);
 -              snd_soc_dapm_set_bias_level(card, &codec->dapm, SND_SOC_BIAS_OFF);
 +              snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF);
        }
  }