Commit 54dc6cab authored by Johannes Stezenbach's avatar Johannes Stezenbach Committed by Mark Brown

ASoC: sta32x: preserve coefficient RAM

The coefficient RAM must be saved in a shadow so it can
be restored when the codec is powered on using
regulator_bulk_enable().
Signed-off-by: default avatarJohannes Stezenbach <js@sig21.net>
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Cc: stable@vger.kernel.org
parent 98d97019
...@@ -76,6 +76,8 @@ struct sta32x_priv { ...@@ -76,6 +76,8 @@ struct sta32x_priv {
unsigned int mclk; unsigned int mclk;
unsigned int format; unsigned int format;
u32 coef_shadow[STA32X_COEF_COUNT];
}; };
static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
...@@ -227,6 +229,7 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, ...@@ -227,6 +229,7 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
int numcoef = kcontrol->private_value >> 16; int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff; int index = kcontrol->private_value & 0xffff;
unsigned int cfud; unsigned int cfud;
...@@ -239,6 +242,11 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, ...@@ -239,6 +242,11 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
snd_soc_write(codec, STA32X_CFUD, cfud); snd_soc_write(codec, STA32X_CFUD, cfud);
snd_soc_write(codec, STA32X_CFADDR2, index); snd_soc_write(codec, STA32X_CFADDR2, index);
for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
sta32x->coef_shadow[index + i] =
(ucontrol->value.bytes.data[3 * i] << 16)
| (ucontrol->value.bytes.data[3 * i + 1] << 8)
| (ucontrol->value.bytes.data[3 * i + 2]);
for (i = 0; i < 3 * numcoef; i++) for (i = 0; i < 3 * numcoef; i++)
snd_soc_write(codec, STA32X_B1CF1 + i, snd_soc_write(codec, STA32X_B1CF1 + i,
ucontrol->value.bytes.data[i]); ucontrol->value.bytes.data[i]);
...@@ -252,6 +260,48 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, ...@@ -252,6 +260,48 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
{
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
unsigned int cfud;
int i;
/* preserve reserved bits in STA32X_CFUD */
cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
for (i = 0; i < STA32X_COEF_COUNT; i++) {
snd_soc_write(codec, STA32X_CFADDR2, i);
snd_soc_write(codec, STA32X_B1CF1,
(sta32x->coef_shadow[i] >> 16) & 0xff);
snd_soc_write(codec, STA32X_B1CF2,
(sta32x->coef_shadow[i] >> 8) & 0xff);
snd_soc_write(codec, STA32X_B1CF3,
(sta32x->coef_shadow[i]) & 0xff);
/* chip documentation does not say if the bits are
* self-clearing, so do it explicitly */
snd_soc_write(codec, STA32X_CFUD, cfud);
snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
}
return 0;
}
int sta32x_cache_sync(struct snd_soc_codec *codec)
{
unsigned int mute;
int rc;
if (!codec->cache_sync)
return 0;
/* mute during register sync */
mute = snd_soc_read(codec, STA32X_MMUTE);
snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
sta32x_sync_coef_shadow(codec);
rc = snd_soc_cache_sync(codec);
snd_soc_write(codec, STA32X_MMUTE, mute);
return rc;
}
#define SINGLE_COEF(xname, index) \ #define SINGLE_COEF(xname, index) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = sta32x_coefficient_info, \ .info = sta32x_coefficient_info, \
...@@ -661,7 +711,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, ...@@ -661,7 +711,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
return ret; return ret;
} }
snd_soc_cache_sync(codec); sta32x_cache_sync(codec);
} }
/* Power up to mute */ /* Power up to mute */
...@@ -790,6 +840,17 @@ static int sta32x_probe(struct snd_soc_codec *codec) ...@@ -790,6 +840,17 @@ static int sta32x_probe(struct snd_soc_codec *codec)
STA32X_CxCFG_OM_MASK, STA32X_CxCFG_OM_MASK,
2 << STA32X_CxCFG_OM_SHIFT); 2 << STA32X_CxCFG_OM_SHIFT);
/* initialize coefficient shadow RAM with reset values */
for (i = 4; i <= 49; i += 5)
sta32x->coef_shadow[i] = 0x400000;
for (i = 50; i <= 54; i++)
sta32x->coef_shadow[i] = 0x7fffff;
sta32x->coef_shadow[55] = 0x5a9df7;
sta32x->coef_shadow[56] = 0x7fffff;
sta32x->coef_shadow[59] = 0x7fffff;
sta32x->coef_shadow[60] = 0x400000;
sta32x->coef_shadow[61] = 0x400000;
sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */ /* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
/* STA326 register addresses */ /* STA326 register addresses */
#define STA32X_REGISTER_COUNT 0x2d #define STA32X_REGISTER_COUNT 0x2d
#define STA32X_COEF_COUNT 62
#define STA32X_CONFA 0x00 #define STA32X_CONFA 0x00
#define STA32X_CONFB 0x01 #define STA32X_CONFB 0x01
......
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