Merge tag 'asoc-v3.13-4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[cascardo/linux.git] / sound / soc / soc-dapm.c
index b2949ae..dcade13 100644 (file)
@@ -59,31 +59,31 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 0,
-       [snd_soc_dapm_supply] = 1,
        [snd_soc_dapm_regulator_supply] = 1,
        [snd_soc_dapm_clock_supply] = 1,
-       [snd_soc_dapm_micbias] = 2,
+       [snd_soc_dapm_supply] = 2,
+       [snd_soc_dapm_micbias] = 3,
        [snd_soc_dapm_dai_link] = 2,
-       [snd_soc_dapm_dai_in] = 3,
-       [snd_soc_dapm_dai_out] = 3,
-       [snd_soc_dapm_aif_in] = 3,
-       [snd_soc_dapm_aif_out] = 3,
-       [snd_soc_dapm_mic] = 4,
-       [snd_soc_dapm_mux] = 5,
-       [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,
-       [snd_soc_dapm_adc] = 9,
-       [snd_soc_dapm_out_drv] = 10,
-       [snd_soc_dapm_hp] = 10,
-       [snd_soc_dapm_spk] = 10,
-       [snd_soc_dapm_line] = 10,
-       [snd_soc_dapm_kcontrol] = 11,
-       [snd_soc_dapm_post] = 12,
+       [snd_soc_dapm_dai_in] = 4,
+       [snd_soc_dapm_dai_out] = 4,
+       [snd_soc_dapm_aif_in] = 4,
+       [snd_soc_dapm_aif_out] = 4,
+       [snd_soc_dapm_mic] = 5,
+       [snd_soc_dapm_mux] = 6,
+       [snd_soc_dapm_virt_mux] = 6,
+       [snd_soc_dapm_value_mux] = 6,
+       [snd_soc_dapm_dac] = 7,
+       [snd_soc_dapm_switch] = 8,
+       [snd_soc_dapm_mixer] = 8,
+       [snd_soc_dapm_mixer_named_ctl] = 8,
+       [snd_soc_dapm_pga] = 9,
+       [snd_soc_dapm_adc] = 10,
+       [snd_soc_dapm_out_drv] = 11,
+       [snd_soc_dapm_hp] = 11,
+       [snd_soc_dapm_spk] = 11,
+       [snd_soc_dapm_line] = 11,
+       [snd_soc_dapm_kcontrol] = 12,
+       [snd_soc_dapm_post] = 13,
 };
 
 static int dapm_down_seq[] = {
@@ -109,10 +109,10 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_dai_in] = 10,
        [snd_soc_dapm_dai_out] = 10,
        [snd_soc_dapm_dai_link] = 11,
-       [snd_soc_dapm_clock_supply] = 12,
-       [snd_soc_dapm_regulator_supply] = 12,
        [snd_soc_dapm_supply] = 12,
-       [snd_soc_dapm_post] = 13,
+       [snd_soc_dapm_clock_supply] = 13,
+       [snd_soc_dapm_regulator_supply] = 13,
+       [snd_soc_dapm_post] = 14,
 };
 
 static void pop_wait(u32 pop_time)
@@ -409,6 +409,12 @@ static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
                mutex_unlock(&w->platform->mutex);
 }
 
+static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
+{
+       if (dapm->codec && dapm->codec->using_regmap)
+               regmap_async_complete(dapm->codec->control_data);
+}
+
 static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
        unsigned short reg, unsigned int mask, unsigned int value)
 {
@@ -417,8 +423,9 @@ static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
        int ret;
 
        if (w->codec && w->codec->using_regmap) {
-               ret = regmap_update_bits_check(w->codec->control_data,
-                                              reg, mask, value, &change);
+               ret = regmap_update_bits_check_async(w->codec->control_data,
+                                                    reg, mask, value,
+                                                    &change);
                if (ret != 0)
                        return ret;
        } else {
@@ -499,18 +506,22 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                int val;
                struct soc_mixer_control *mc = (struct soc_mixer_control *)
                        w->kcontrol_news[i].private_value;
-               unsigned int reg = mc->reg;
+               int reg = mc->reg;
                unsigned int shift = mc->shift;
                int max = mc->max;
                unsigned int mask = (1 << fls(max)) - 1;
                unsigned int invert = mc->invert;
 
-               val = soc_widget_read(w, reg);
-               val = (val >> shift) & mask;
-               if (invert)
-                       val = max - val;
+               if (reg != SND_SOC_NOPM) {
+                       val = soc_widget_read(w, reg);
+                       val = (val >> shift) & mask;
+                       if (invert)
+                               val = max - val;
+                       p->connect = !!val;
+               } else {
+                       p->connect = 0;
+               }
 
-               p->connect = !!val;
        }
        break;
        case snd_soc_dapm_mux: {
@@ -1197,6 +1208,8 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 {
        int ret;
 
+       soc_dapm_async_complete(w->dapm);
+
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
                        ret = regulator_allow_bypass(w->regulator, false);
@@ -1230,6 +1243,8 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w,
        if (!w->clk)
                return -EIO;
 
+       soc_dapm_async_complete(w->dapm);
+
 #ifdef CONFIG_HAVE_CLK
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                return clk_prepare_enable(w->clk);
@@ -1412,7 +1427,7 @@ static void dapm_seq_check_event(struct snd_soc_card *card,
                power = 0;
                break;
        default:
-               BUG();
+               WARN(1, "Unknown event %d\n", event);
                return;
        }
 
@@ -1422,6 +1437,7 @@ static void dapm_seq_check_event(struct snd_soc_card *card,
        if (w->event && (w->event_flags & event)) {
                pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
                        w->name, ev_name);
+               soc_dapm_async_complete(w->dapm);
                trace_snd_soc_dapm_widget_event_start(w, event);
                ret = w->event(w, NULL, event);
                trace_snd_soc_dapm_widget_event_done(w, event);
@@ -1444,7 +1460,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
                               power_list)->reg;
 
        list_for_each_entry(w, pending, power_list) {
-               BUG_ON(reg != w->reg);
+               WARN_ON(reg != w->reg);
                w->power = w->new_power;
 
                mask |= w->mask << w->shift;
@@ -1494,6 +1510,7 @@ static void dapm_seq_run(struct snd_soc_card *card,
        struct list_head *list, int event, bool power_up)
 {
        struct snd_soc_dapm_widget *w, *n;
+       struct snd_soc_dapm_context *d;
        LIST_HEAD(pending);
        int cur_sort = -1;
        int cur_subseq = -1;
@@ -1524,6 +1541,9 @@ static void dapm_seq_run(struct snd_soc_card *card,
                                                                       cur_subseq);
                        }
 
+                       if (cur_dapm && w->dapm != cur_dapm)
+                               soc_dapm_async_complete(cur_dapm);
+
                        INIT_LIST_HEAD(&pending);
                        cur_sort = -1;
                        cur_subseq = INT_MIN;
@@ -1582,6 +1602,10 @@ static void dapm_seq_run(struct snd_soc_card *card,
                                cur_dapm->seq_notifier(cur_dapm,
                                                       i, cur_subseq);
        }
+
+       list_for_each_entry(d, &card->dapm_list, list) {
+               soc_dapm_async_complete(d);
+       }
 }
 
 static void dapm_widget_update(struct snd_soc_card *card)
@@ -1840,6 +1864,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
                         */
                        switch (w->id) {
                        case snd_soc_dapm_siggen:
+                       case snd_soc_dapm_vmid:
                                break;
                        case snd_soc_dapm_supply:
                        case snd_soc_dapm_regulator_supply:
@@ -2001,7 +2026,7 @@ static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
                level = "Off\n";
                break;
        default:
-               BUG();
+               WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
                level = "Unknown\n";
                break;
        }
@@ -2791,7 +2816,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = codec->card;
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       unsigned int reg = mc->reg;
+       int reg = mc->reg;
        unsigned int shift = mc->shift;
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
@@ -2804,7 +2829,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
                         kcontrol->id.name);
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       if (dapm_kcontrol_is_powered(kcontrol))
+       if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM)
                val = (snd_soc_read(codec, reg) >> shift) & mask;
        else
                val = dapm_kcontrol_get_value(kcontrol);
@@ -2835,7 +2860,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = codec->card;
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
-       unsigned int reg = mc->reg;
+       int reg = mc->reg;
        unsigned int shift = mc->shift;
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
@@ -2857,19 +2882,24 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       dapm_kcontrol_set_value(kcontrol, val);
+       change = dapm_kcontrol_set_value(kcontrol, val);
 
-       mask = mask << shift;
-       val = val << shift;
+       if (reg != SND_SOC_NOPM) {
+               mask = mask << shift;
+               val = val << shift;
+
+               change = snd_soc_test_bits(codec, reg, mask, val);
+       }
 
-       change = snd_soc_test_bits(codec, reg, mask, val);
        if (change) {
-               update.kcontrol = kcontrol;
-               update.reg = reg;
-               update.mask = mask;
-               update.val = val;
+               if (reg != SND_SOC_NOPM) {
+                       update.kcontrol = kcontrol;
+                       update.reg = reg;
+                       update.mask = mask;
+                       update.val = val;
 
-               card->update = &update;
+                       card->update = &update;
+               }
 
                soc_dapm_mixer_update_power(card, kcontrol, connect);
 
@@ -3329,8 +3359,9 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
        u64 fmt;
        int ret;
 
-       BUG_ON(!config);
-       BUG_ON(list_empty(&w->sources) || list_empty(&w->sinks));
+       if (WARN_ON(!config) ||
+           WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
+               return -EINVAL;
 
        /* We only support a single source and sink, pick the first */
        source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
@@ -3338,9 +3369,10 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
        sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
                                  list_source);
 
-       BUG_ON(!source_p || !sink_p);
-       BUG_ON(!sink_p->source || !source_p->sink);
-       BUG_ON(!source_p->source || !sink_p->sink);
+       if (WARN_ON(!source_p || !sink_p) ||
+           WARN_ON(!sink_p->source || !source_p->sink) ||
+           WARN_ON(!source_p->source || !sink_p->sink))
+               return -EINVAL;
 
        source = source_p->source->priv;
        sink = sink_p->sink->priv;
@@ -3416,7 +3448,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
                break;
 
        default:
-               BUG();
+               WARN(1, "Unknown event %d\n", event);
                return -EINVAL;
        }