summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c109
1 files changed, 63 insertions, 46 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8731e89646ae..f362d1de78f3 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -847,19 +847,22 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
LIST_HEAD(pending);
int cur_sort = -1;
int cur_reg = SND_SOC_NOPM;
+ struct snd_soc_dapm_context *cur_dapm = NULL;
int ret;
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) {
+ if (sort[w->id] != cur_sort || w->reg != cur_reg ||
+ w->dapm != cur_dapm) {
if (!list_empty(&pending))
- dapm_seq_run_coalesced(dapm, &pending);
+ dapm_seq_run_coalesced(cur_dapm, &pending);
INIT_LIST_HEAD(&pending);
cur_sort = -1;
cur_reg = SND_SOC_NOPM;
+ cur_dapm = NULL;
}
switch (w->id) {
@@ -903,6 +906,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
/* Queue it up for application */
cur_sort = sort[w->id];
cur_reg = w->reg;
+ cur_dapm = w->dapm;
list_move(&w->power_list, &pending);
break;
}
@@ -929,20 +933,22 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
{
struct snd_soc_card *card = dapm->codec->card;
struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_context *d;
LIST_HEAD(up_list);
LIST_HEAD(down_list);
int ret = 0;
int power;
- int sys_power = 0;
trace_snd_soc_dapm_start(card);
+ list_for_each_entry(d, &card->dapm_list, list)
+ if (d->n_widgets)
+ d->dev_power = 0;
+
/* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down.
*/
list_for_each_entry(w, &card->widgets, list) {
- if (w->dapm != dapm)
- continue;
switch (w->id) {
case snd_soc_dapm_pre:
dapm_seq_insert(w, &down_list, dapm_down_seq);
@@ -960,7 +966,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
else
power = 1;
if (power)
- sys_power = 1;
+ w->dapm->dev_power = 1;
if (w->power == power)
continue;
@@ -984,22 +990,22 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
switch (event) {
case SND_SOC_DAPM_STREAM_START:
case SND_SOC_DAPM_STREAM_RESUME:
- sys_power = 1;
+ dapm->dev_power = 1;
break;
case SND_SOC_DAPM_STREAM_STOP:
- sys_power = !!dapm->codec->active;
+ dapm->dev_power = !!dapm->codec->active;
break;
case SND_SOC_DAPM_STREAM_SUSPEND:
- sys_power = 0;
+ dapm->dev_power = 0;
break;
case SND_SOC_DAPM_STREAM_NOP:
switch (dapm->bias_level) {
case SND_SOC_BIAS_STANDBY:
case SND_SOC_BIAS_OFF:
- sys_power = 0;
+ dapm->dev_power = 0;
break;
default:
- sys_power = 1;
+ dapm->dev_power = 1;
break;
}
break;
@@ -1008,21 +1014,24 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
}
}
- if (sys_power && dapm->bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_dapm_set_bias_level(card, dapm,
- SND_SOC_BIAS_STANDBY);
- if (ret != 0)
- dev_err(dapm->dev,
- "Failed to turn on bias: %d\n", ret);
- }
+ 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 ((sys_power && dapm->bias_level == SND_SOC_BIAS_STANDBY) ||
- (!sys_power && dapm->bias_level == SND_SOC_BIAS_ON)) {
- ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_PREPARE);
- if (ret != 0)
- dev_err(dapm->dev,
- "Failed to prepare 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);
+ }
}
/* Power down widgets first; try to avoid amplifying pops. */
@@ -1031,29 +1040,36 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
/* Now power up. */
dapm_seq_run(dapm, &up_list, event, dapm_up_seq);
- /* If we just powered the last thing off drop to standby bias */
- if (dapm->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
- ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
- if (ret != 0)
- dev_err(dapm->dev,
- "Failed to apply standby bias: %d\n", ret);
- }
+ 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);
+ }
- /* If we're in standby and can support bias off then do that */
- if (dapm->bias_level == SND_SOC_BIAS_STANDBY &&
- dapm->idle_bias_off) {
- ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_OFF);
- if (ret != 0)
- dev_err(dapm->dev,
- "Failed to turn off 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(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 (dapm->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
- ret = snd_soc_dapm_set_bias_level(card, dapm, SND_SOC_BIAS_ON);
- if (ret != 0)
- dev_err(dapm->dev,
- "Failed to apply active 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);
+ }
}
pop_dbg(dapm->dev, card->pop_time,
@@ -2309,6 +2325,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
{
snd_soc_dapm_sys_remove(dapm->dev);
dapm_free_widgets(dapm);
+ list_del(&dapm->list);
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);