From: Viorel Suman <viorel.suman@xxxxxxx> On BIAS STANDBY->OFF transition the current implementation sleeps 600ms on suspend in order to discharge the chip. The suspend is propagated from "snd_soc_suspend" call for all audio cards in a serial fashion, thus in case of boards like i.MX8DXL EVK which has 3 distinct WM8960 codecs the total cumulated sleep on suspend is 1.8 seconds. On the other hand the BIAS OFF->STANDBY transition happens asynchronously with regard to "snd_soc_resume" - the call is propagated from "soc_resume_deferred" which is just scheduled from "snd_soc_resume", each card having its own work scheduled to execute "soc_resume_deferred" call. The patch performs discharge completion on BIAS OFF->STANDBY transition so that the cumulated effect on suspend described above is avoided and discharge is completed in paralel in case of multiple WM8960 codecs on the board. Signed-off-by: Viorel Suman <viorel.suman@xxxxxxx> --- sound/soc/codecs/wm8960.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 75de6a81465df..b7a2246184e08 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -45,6 +45,8 @@ #define WM8960_DISOP 0x40 #define WM8960_DRES_MASK 0x30 +#define WM8960_DSCH_TOUT 600 /* discharge timeout, ms */ + static bool is_pll_freq_available(unsigned int source, unsigned int target); static int wm8960_set_pll(struct snd_soc_component *component, unsigned int freq_in, unsigned int freq_out); @@ -133,6 +135,7 @@ struct wm8960_priv { int freq_in; bool is_stream_in_use[2]; struct wm8960_data pdata; + ktime_t dsch_start; }; #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) @@ -898,6 +901,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component, struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); u16 pm2 = snd_soc_component_read(component, WM8960_POWER2); int ret; + ktime_t tout; switch (level) { case SND_SOC_BIAS_ON: @@ -944,6 +948,11 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component, case SND_SOC_BIAS_STANDBY: if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { + /* ensure discharge is complete */ + tout = WM8960_DSCH_TOUT - ktime_ms_delta(ktime_get(), wm8960->dsch_start); + if (tout > 0) + msleep(tout); + regcache_sync(wm8960->regmap); /* Enable anti-pop features */ @@ -973,9 +982,9 @@ static int wm8960_set_bias_level_out3(struct snd_soc_component *component, WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_BUFDCOPEN | WM8960_BUFIOEN); - /* Disable VMID and VREF, let them discharge */ + /* Disable VMID and VREF, mark discharge */ snd_soc_component_write(component, WM8960_POWER1, 0); - msleep(600); + wm8960->dsch_start = ktime_get(); break; } -- 2.26.3