aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h5
-rw-r--r--include/sound/soc.h1
-rw-r--r--sound/soc/soc-core.c2
-rw-r--r--sound/soc/soc-dapm.c109
4 files changed, 71 insertions, 46 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c0e7c47469fc..98783510d2f1 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -471,6 +471,11 @@ struct snd_soc_dapm_context {
struct device *dev; /* from parent - for debug */
struct snd_soc_codec *codec; /* parent codec */
struct snd_soc_card *card; /* parent card */
+
+ /* used during DAPM updates */
+ int dev_power;
+ struct list_head list;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dapm;
#endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index d5fb8618fdba..74921f20a1d8 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -663,6 +663,7 @@ struct snd_soc_card {
struct list_head widgets;
struct list_head paths;
+ struct list_head dapm_list;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_card_root;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index bd183a7ed696..a233607a73c6 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1427,6 +1427,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
/* mark codec as probed and add to card codec list */
codec->probed = 1;
list_add(&codec->card_list, &card->codec_dev_list);
+ list_add(&codec->dapm.list, &card->dapm_list);
return ret;
}
@@ -1881,6 +1882,7 @@ static int soc_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&card->platform_dev_list);
INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths);
+ INIT_LIST_HEAD(&card->dapm_list);
soc_init_card_debugfs(card);
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);