[alsa-devel] [PATCH 1/2] ASoC: Remove card from snd_soc_dapm_set_bias_level()
We can get the card from the DAPM context so don't bother passing it as an argument.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/soc-dapm.c | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3bee4b2..1a932bb 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -125,17 +125,17 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
/** * 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) { @@ -1112,7 +1112,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
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, + ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); if (ret != 0) dev_err(d->dev, @@ -1122,7 +1122,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) /* 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, + ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); if (ret != 0) dev_err(d->dev, @@ -1141,7 +1141,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) 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, + ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); if (ret != 0) dev_err(d->dev, @@ -1152,7 +1152,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) /* 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, + ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); if (ret != 0) dev_err(d->dev, @@ -1161,7 +1161,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
/* 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, + ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); if (ret != 0) dev_err(d->dev, @@ -2439,9 +2439,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) * standby. */ if (powerdown) { - snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_PREPARE); + 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(NULL, dapm, SND_SOC_BIAS_STANDBY); + snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); } }
@@ -2454,7 +2454,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card)
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); } }
As bias level changes can be quite time consuming and the bias changes for multiple devices aren't strongly tied to each other (if anything it can be advantageous to bring different devices up together) we can improve the state transition time for multi-component systems by running the bias level changes for all the devices in parallel. This is very simple to achieve using the kernel async functionality so use that to schedule the work.
This should have no practical effect for the overwhelming majority of systems which have a single DAPM context - we'll bounce into another thread to do the bias level change but otherwise everything will happen in exactly the same order as it did before.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com ---
I currently don't have access to a test system which can meaningfully test this so I'm pushing it out without any testing and it may therefore explode horribly. Testing from people working on systems with multiple CODECs would be especially useful.
sound/soc/soc-dapm.c | 118 ++++++++++++++++++++++++++++--------------------- 1 files changed, 67 insertions(+), 51 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1a932bb..200ae7c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -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> @@ -1014,7 +1015,62 @@ 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. @@ -1032,7 +1088,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) 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); @@ -1110,25 +1166,11 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) } }
- 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(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); - } - } + /* 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, false); @@ -1138,37 +1180,11 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) /* Now power up. */ dapm_seq_run(dapm, &up_list, event, true);
- 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(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); - } - } + /* 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);
On Fri, 2011-02-18 at 19:55 +0000, Mark Brown wrote:
We can get the card from the DAPM context so don't bother passing it as an argument.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
Both
Acked-by: Liam Girdwood lrg@slimlogic.co.uk
participants (2)
-
Liam Girdwood
-
Mark Brown