From 2aba76f014a7b56ab4fe75845c5fd57b5590acc2 Mon Sep 17 00:00:00 2001
From: Michael Williamson <michael.williamson@criticallink.com>
Date: Fri, 20 May 2011 10:26:06 -0400
Subject: [PATCH 1/3] audio: tlv320aic26: fix PLL register configuration

The current PLL configuration code for the tlc320aic26 codec appears to assume a
hardcoded system clock of 12 MHz.  Use the clock value provided by the DAI_OPS
API for the calculation.

Tested using a MityDSP-L138 platform providing a 24.576 MHz clock.

Signed-off-by: Michael Williamson <michael.williamson@criticallink.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@ti.com>
---
 sound/soc/codecs/tlv320aic26.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index e2a7608d3944..7859bdcc93db 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -161,10 +161,18 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
 		dev_dbg(&aic26->spi->dev, "bad format\n"); return -EINVAL;
 	}
 
-	/* Configure PLL */
+	/**
+	 * Configure PLL
+	 * fsref = (mclk * PLLM) / 2048
+	 * where PLLM = J.DDDD (DDDD register ranges from 0 to 9999, decimal)
+	 */
 	pval = 1;
-	jval = (fsref == 44100) ? 7 : 8;
-	dval = (fsref == 44100) ? 5264 : 1920;
+	/* compute J portion of multiplier */
+	jval = fsref / (aic26->mclk / 2048);
+	/* compute fractional DDDD component of multiplier */
+	dval = fsref - (jval * (aic26->mclk / 2048));
+	dval = (10000 * dval) / (aic26->mclk / 2048);
+	dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval);
 	qval = 0;
 	reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
 	aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);

From 508b76864c18f34f8d6ba08d192f5817f8dc8ead Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jhnikula@gmail.com>
Date: Fri, 20 May 2011 16:52:37 +0300
Subject: [PATCH 2/3] ASoC: tlv320aic3x: Don't sync first two registers from
 register cache

There is no need to sync first two registers from cache to hw after a reset.
First one is used to select page for register access and this driver is
normally accessing page 0 only. Second one does a software reset which is
obviously unneeded after hardware or previous software reset command.

Signed-off-by: Jarkko Nikula <jhnikula@gmail.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@ti.com>
---
 sound/soc/codecs/tlv320aic3x.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index c3d96fc8c267..9047bb173c6b 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1114,7 +1114,7 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
 
 		/* Sync reg_cache with the hardware */
 		codec->cache_only = 0;
-		for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++)
+		for (i = AIC3X_SAMPLE_RATE_SEL_REG; i < ARRAY_SIZE(aic3x_reg); i++)
 			snd_soc_write(codec, i, cache[i]);
 		if (aic3x->model == AIC3X_MODEL_3007)
 			aic3x_init_3007(codec);

From 9fb352b18b11124ed1ddebc0d74ebbd7ba8defd7 Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jhnikula@gmail.com>
Date: Fri, 20 May 2011 16:52:38 +0300
Subject: [PATCH 3/3] ASoC: tlv320aic3x: Do soft reset to codec when going to
 bias off state

TLV320AIC33, TLV320AIC34 and I believe others too in this family have some
hw bugs that cause that analogue and digital VDD supplies remain leaking
up to a few mA of current after certain use cases even the hw blocks inside
codec are driven to off.

Highest leakages occur after using the bypass paths inside codec but it
is possible to get smaller leakages just by toggling mute switches in
unused audio paths (i.e. no DAPM changes) while codec is on due another
active audio path.

While some cases are able to workaroud by making sure that e.g. output mixer
switches are muted before powering down the output stage this doesn't help
all the cases.

Therefore use the software reset command to clear possible leakage currents
since that works in every cases and affects only this codec instance. Only
drawback is that now cache sync is required everytime when codec bias comes
out from bias off state, not only when supply regulators were off.

Signed-off-by: Jarkko Nikula <jhnikula@gmail.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@ti.com>
---
 sound/soc/codecs/tlv320aic3x.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 9047bb173c6b..789453d44ec5 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1120,6 +1120,13 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
 			aic3x_init_3007(codec);
 		codec->cache_sync = 0;
 	} else {
+		/*
+		 * Do soft reset to this codec instance in order to clear
+		 * possible VDD leakage currents in case the supply regulators
+		 * remain on
+		 */
+		snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
+		codec->cache_sync = 1;
 		aic3x->power = 0;
 		/* HW writes are needless when bias is off */
 		codec->cache_only = 1;