Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 157500
b: refs/heads/master
c: b22ead2
h: refs/heads/master
v: v3
  • Loading branch information
Mark Brown committed Jun 8, 2009
1 parent 25cecd9 commit 24cfeeb
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 33 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 163cac061c97394d4ef9c89efe5921dac937ddb8
refs/heads/master: b22ead2a510fdb30440753f90237e86fdac70fae
136 changes: 104 additions & 32 deletions trunk/sound/soc/soc-dapm.c
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
{
if (sort[a->id] != sort[b->id])
return sort[a->id] - sort[b->id];
if (a->reg != b->reg)
return a->reg - b->reg;

return 0;
}
Expand All @@ -733,63 +735,133 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
list_add_tail(&new_widget->power_list, list);
}

/* Apply a DAPM power sequence */
static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
int event)
/* Apply the coalesced changes from a DAPM sequence */
static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
struct list_head *pending)
{
struct snd_soc_dapm_widget *w;
int reg, power;
unsigned int value = 0;
unsigned int mask = 0;
unsigned int cur_mask;

reg = list_first_entry(pending, struct snd_soc_dapm_widget,
power_list)->reg;

list_for_each_entry(w, pending, power_list) {
cur_mask = 1 << w->shift;
BUG_ON(reg != w->reg);

if (w->invert)
power = !w->power;
else
power = w->power;

mask |= cur_mask;
if (power)
value |= cur_mask;

pop_dbg(codec->pop_time,
"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
w->name, reg, value, mask);
}

pop_dbg(codec->pop_time,
"pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, codec->pop_time);
pop_wait(codec->pop_time);
snd_soc_update_bits(codec, reg, mask, value);
}

/* Apply a DAPM power sequence.
*
* We walk over a pre-sorted list of widgets to apply power to. In
* order to minimise the number of writes to the device required
* multiple widgets will be updated in a single write where possible.
* Currently anything that requires more than a single write is not
* handled.
*/
static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
int event, int sort[])
{
struct snd_soc_dapm_widget *w, *n;
LIST_HEAD(pending);
int cur_sort = -1;
int cur_reg = SND_SOC_NOPM;
int ret;

list_for_each_entry(w, list, power_list) {
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 (!list_empty(&pending))
dapm_seq_run_coalesced(codec, &pending);

INIT_LIST_HEAD(&pending);
cur_sort = -1;
cur_reg = SND_SOC_NOPM;
}

switch (w->id) {
case snd_soc_dapm_pre:
if (!w->event)
list_for_each_entry_continue(w, list,
power_list);
list_for_each_entry_safe_continue(w, n, list,
power_list);

if (event == SND_SOC_DAPM_STREAM_START) {
if (event == SND_SOC_DAPM_STREAM_START)
ret = w->event(w,
NULL, SND_SOC_DAPM_PRE_PMU);
if (ret < 0)
pr_err("PRE widget failed: %d\n",
ret);
} else if (event == SND_SOC_DAPM_STREAM_STOP) {
else if (event == SND_SOC_DAPM_STREAM_STOP)
ret = w->event(w,
NULL, SND_SOC_DAPM_PRE_PMD);
if (ret < 0)
pr_err("PRE widget failed: %d\n",
ret);
}
break;

case snd_soc_dapm_post:
if (!w->event)
list_for_each_entry_continue(w, list,
power_list);
list_for_each_entry_safe_continue(w, n, list,
power_list);

if (event == SND_SOC_DAPM_STREAM_START) {
if (event == SND_SOC_DAPM_STREAM_START)
ret = w->event(w,
NULL, SND_SOC_DAPM_POST_PMU);
if (ret < 0)
pr_err("POST widget failed: %d\n",
ret);
} else if (event == SND_SOC_DAPM_STREAM_STOP) {
else if (event == SND_SOC_DAPM_STREAM_STOP)
ret = w->event(w,
NULL, SND_SOC_DAPM_POST_PMD);
if (ret < 0)
pr_err("POST widget failed: %d\n",
ret);
}
break;

default:
case snd_soc_dapm_input:
case snd_soc_dapm_output:
case snd_soc_dapm_hp:
case snd_soc_dapm_mic:
case snd_soc_dapm_line:
case snd_soc_dapm_spk:
/* No register support currently */
case snd_soc_dapm_pga:
/* Don't coalsece these yet due to gain ramping */
ret = dapm_generic_apply_power(w);
if (ret < 0)
pr_err("Failed to apply widget power: %d\n",
ret);
break;

default:
/* If there's an event or an invalid register
* then run immediately, otherwise store the
* updates so that we can coalesce. */
if (w->reg >= 0 && !w->event) {
cur_sort = sort[w->id];
cur_reg = w->reg;
list_move(&w->power_list, &pending);
} else {
ret = dapm_generic_apply_power(w);
}
}

if (ret < 0)
pr_err("Failed to apply widget power: %d\n",
ret);
}

if (!list_empty(&pending))
dapm_seq_run_coalesced(codec, &pending);
}

/*
Expand Down Expand Up @@ -857,10 +929,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
}

/* Power down widgets first; try to avoid amplifying pops. */
dapm_seq_run(codec, &codec->down_list, event);
dapm_seq_run(codec, &codec->down_list, event, dapm_down_seq);

/* Now power up. */
dapm_seq_run(codec, &codec->up_list, event);
dapm_seq_run(codec, &codec->up_list, event, dapm_up_seq);

/* If we just powered the last thing off drop to standby bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
Expand Down

0 comments on commit 24cfeeb

Please sign in to comment.