From 2440f4d7c16af00fee0e7b0723b4b66ff6f721c3 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Tue, 10 May 2011 11:36:39 +0200 Subject: Ux500 ASoC: Turn off AB8500 when inactive Using reference counter to be able to turn of AB8500 when none of playback, capture or vibra is active. Change-Id: If295d40a31e0f7529c2cd9573052ce798fdbe465 Signed-off-by: Ola Lilja Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21661 Reviewed-by: Roger NILSSON1 Conflicts: sound/soc/codecs/ab8500_audio.c --- sound/soc/codecs/ab8500_audio.c | 91 +++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ab8500_audio.c b/sound/soc/codecs/ab8500_audio.c index 9070e2dcd6d..10b61b7c479 100644 --- a/sound/soc/codecs/ab8500_audio.c +++ b/sound/soc/codecs/ab8500_audio.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -57,7 +58,7 @@ * AB8500 register cache & default register settings */ static const u8 ab8500_reg_cache[AB8500_CACHEREGNUM] = { - 0x88, /* REG_POWERUP (0x00) */ + 0x00, /* REG_POWERUP (0x00) */ 0x00, /* REG_AUDSWRESET (0x01) */ 0x00, /* REG_ADPATHENA (0x02) */ 0x00, /* REG_DAPATHENA (0x03) */ @@ -174,7 +175,9 @@ static const u8 ab8500_reg_cache[AB8500_CACHEREGNUM] = { static struct snd_soc_codec *ab8500_codec; static struct clk *clk_ptr_audioclk; static struct clk *clk_ptr_sysclk; -static int sysclk_on; +static DEFINE_MUTEX(power_lock); +static int ab8500_power_count; +static bool ab8500_vibra_on; /* Reads an arbitrary register from the ab8500 chip. */ @@ -1619,6 +1622,61 @@ static int ab8500_codec_set_bit_delay_if1(struct snd_soc_codec *codec, unsigned return 0; } +static int ab8500_codec_power_control_inc(struct snd_soc_codec *codec) +{ + int ret; + unsigned int set_mask; + + mutex_lock(&power_lock); + + ab8500_power_count++; + pr_debug("ab8500_power_count changed from %d to %d", + ab8500_power_count-1, + ab8500_power_count); + + if (ab8500_power_count == 1) { + pr_debug("Enabling AB8500."); + set_mask = BMASK(REG_POWERUP_POWERUP) | BMASK(REG_POWERUP_ENANA); + ab8500_codec_update_reg_audio(codec, REG_POWERUP, 0x00, set_mask); + + pr_debug("Enabling sysclk."); + ret = clk_enable(clk_ptr_audioclk); + if (ret) { + pr_err("ERROR: clk_enable failed (ret = %d)!", ret); + ab8500_power_count = 0; + return ret; + } + } + + mutex_unlock(&power_lock); + + return 0; +} + +static void ab8500_codec_power_control_dec(struct snd_soc_codec *codec) +{ + unsigned int clear_mask; + + mutex_lock(&power_lock); + + ab8500_power_count--; + + pr_debug("ab8500_power_count changed from %d to %d", + ab8500_power_count+1, + ab8500_power_count); + + if (ab8500_power_count == 0) { + pr_debug("Disabling sysclk."); + clk_disable(clk_ptr_audioclk); + + pr_debug("Disabling AB8500."); + clear_mask = BMASK(REG_POWERUP_POWERUP) | BMASK(REG_POWERUP_ENANA); + ab8500_codec_update_reg_audio(codec, REG_POWERUP, clear_mask, 0x00); + } + + mutex_unlock(&power_lock); +} + /* Extended interface for codec-driver */ int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl) @@ -1744,29 +1802,13 @@ static int ab8500_codec_pcm_startup(struct snd_pcm_substream *substream, static int ab8500_codec_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - int ret = 0; - pr_debug("%s Enter.\n", __func__); /* Clear interrupt status registers by reading them. */ ab8500_codec_read_reg_audio(dai->codec, REG_AUDINTSOURCE1); ab8500_codec_read_reg_audio(dai->codec, REG_AUDINTSOURCE2); - sysclk_on++; - pr_debug("sysclk_on changed from %d to %d", sysclk_on-1, sysclk_on); - - if (sysclk_on > 1) - return 0; - - ret = clk_enable(clk_ptr_audioclk); - if (ret) { - pr_err("ERROR: clk_enable failed (ret = %d)!", ret); - sysclk_on = 0; - return ret; - } - pr_debug("sysclk enabled."); - - return ret; + return ab8500_codec_power_control_inc(dai->codec); } static void ab8500_codec_pcm_shutdown(struct snd_pcm_substream *substream, @@ -1774,13 +1816,7 @@ static void ab8500_codec_pcm_shutdown(struct snd_pcm_substream *substream, { pr_debug("%s Enter.\n", __func__); - sysclk_on--; - pr_debug("sysclk_on changed from %d to %d", sysclk_on+1, sysclk_on); - - if (sysclk_on == 0) { - clk_disable(clk_ptr_audioclk); - pr_debug("sysclk disabled."); - } + ab8500_codec_power_control_dec(dai->codec); ab8500_codec_dump_all_reg(dai->codec); } @@ -2141,8 +2177,9 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) } ab8500_codec = codec; + ab8500_vibra_on = false; - sysclk_on = 0; + ab8500_power_count = 0; clk_ptr_sysclk = clk_get(codec->dev, "sysclk"); if (IS_ERR(clk_ptr_sysclk)) { pr_err("ERROR: clk_get failed (ret = %d)!", -EFAULT); -- cgit v1.2.3