aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorDmitry Lavnikevich <d.lavnikevich@sam-solutions.com>2014-10-03 09:18:56 -0400
committerMark Brown <broonie@kernel.org>2014-10-03 11:06:11 -0400
commit31d9f8faf9a54c851e835af489c82f45105a442f (patch)
tree384e3f64d35d650cababae4abfa2a46487bdfe12 /sound/soc
parent7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (diff)
ASoC: tlv320aic3x: fix PLL D configuration
Current caching implementation during regcache_sync() call bypasses all register writes of values that are already known as default (regmap reg_defaults). Same time in TLV320AIC3x codecs register 5 (AIC3X_PLL_PROGC_REG) write should be immediately followed by register 6 write (AIC3X_PLL_PROGD_REG) even if it was not changed. Otherwise both registers will not be written. This brings to issue that appears particulary in case of 44.1kHz playback with 19.2MHz master clock. In this case AIC3X_PLL_PROGC_REG is 0x6e while AIC3X_PLL_PROGD_REG is 0x0 (same as register default). Thus AIC3X_PLL_PROGC_REG also remains not written and we get wrong playback speed. In this patch snd_soc_read() is used to get cached pll values and snd_soc_write() (unlike regcache_sync() this function doesn't bypasses hardware default values) to write them to registers. Signed-off-by: Dmitry Lavnikevich <d.lavnikevich@sam-solutions.com> Signed-off-by: Mark Brown <broonie@kernel.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/codecs/tlv320aic3x.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 64f179ee9834..5e8626ae612b 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1121,6 +1121,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
1121static int aic3x_set_power(struct snd_soc_codec *codec, int power) 1121static int aic3x_set_power(struct snd_soc_codec *codec, int power)
1122{ 1122{
1123 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); 1123 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
1124 unsigned int pll_c, pll_d;
1124 int ret; 1125 int ret;
1125 1126
1126 if (power) { 1127 if (power) {
@@ -1138,6 +1139,18 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
1138 /* Sync reg_cache with the hardware */ 1139 /* Sync reg_cache with the hardware */
1139 regcache_cache_only(aic3x->regmap, false); 1140 regcache_cache_only(aic3x->regmap, false);
1140 regcache_sync(aic3x->regmap); 1141 regcache_sync(aic3x->regmap);
1142
1143 /* Rewrite paired PLL D registers in case cached sync skipped
1144 * writing one of them and thus caused other one also not
1145 * being written
1146 */
1147 pll_c = snd_soc_read(codec, AIC3X_PLL_PROGC_REG);
1148 pll_d = snd_soc_read(codec, AIC3X_PLL_PROGD_REG);
1149 if (pll_c == aic3x_reg[AIC3X_PLL_PROGC_REG].def ||
1150 pll_d == aic3x_reg[AIC3X_PLL_PROGD_REG].def) {
1151 snd_soc_write(codec, AIC3X_PLL_PROGC_REG, pll_c);
1152 snd_soc_write(codec, AIC3X_PLL_PROGD_REG, pll_d);
1153 }
1141 } else { 1154 } else {
1142 /* 1155 /*
1143 * Do soft reset to this codec instance in order to clear 1156 * Do soft reset to this codec instance in order to clear