Commit a96ca338 authored by Mark Brown's avatar Mark Brown

ASoC: Support turning off bias when the CODEC is idle

Currently ASoC always maintains the bias of the CODEC while the system
is active.  With older mobile CODECs this is required since the outputs
are referenced to a non-zero voltage and enabling or disabling this
voltage without audible pops or clicks in the output takes too long to
do when starting or stopping audio.

As a result of features such as ground referenced outputs and class D
speaker drivers current generation devices are able to power on and off
much more quickly without these system level issues so provide a new
flag idle_bias_off in snd_soc_codec which will cause the core to turn
off the CODEC bias.  The distinction between STANDBY and OFF is still
maintained.  This is partly for consistency but also allows for
potential future extensions such as per-machine overrides or deferring
the bias removal.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: default avatarLiam Girdwood <lrg@slimlogic.co.uk>
parent b91b8fa0
...@@ -405,6 +405,8 @@ struct snd_soc_codec { ...@@ -405,6 +405,8 @@ struct snd_soc_codec {
short reg_cache_size; short reg_cache_size;
short reg_cache_step; short reg_cache_step;
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
/* dapm */ /* dapm */
u32 pop_time; u32 pop_time;
struct list_head dapm_widgets; struct list_head dapm_widgets;
......
...@@ -1012,13 +1012,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) ...@@ -1012,13 +1012,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
sys_power = 0; sys_power = 0;
break; break;
case SND_SOC_DAPM_STREAM_NOP: case SND_SOC_DAPM_STREAM_NOP:
sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; switch (codec->bias_level) {
case SND_SOC_BIAS_STANDBY:
case SND_SOC_BIAS_OFF:
sys_power = 0;
break;
default:
sys_power = 1;
break;
}
break; break;
default: default:
break; break;
} }
} }
if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
ret = snd_soc_dapm_set_bias_level(socdev,
SND_SOC_BIAS_STANDBY);
if (ret != 0)
pr_err("Failed to turn on bias: %d\n", ret);
}
/* If we're changing to all on or all off then prepare */ /* If we're changing to all on or all off then prepare */
if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
(!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
...@@ -1042,6 +1057,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) ...@@ -1042,6 +1057,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
pr_err("Failed to apply standby bias: %d\n", ret); pr_err("Failed to apply standby bias: %d\n", ret);
} }
/* If we're in standby and can support bias off then do that */
if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
codec->idle_bias_off) {
ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
if (ret != 0)
pr_err("Failed to turn off bias: %d\n", ret);
}
/* If we just powered up then move to active bias */ /* If we just powered up then move to active bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
ret = snd_soc_dapm_set_bias_level(socdev, ret = snd_soc_dapm_set_bias_level(socdev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment