Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+62 −1
Original line number Original line Diff line number Diff line
@@ -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,
				  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,
	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,
	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,
				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)
			    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);
+1 −0
Original line number Original line Diff line number Diff line
@@ -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