diff options
Diffstat (limited to 'sound/soc/codecs/sta32x.c')
-rw-r--r-- | sound/soc/codecs/sta32x.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index bb82408ab8e1..d2f37152f940 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c | |||
@@ -76,6 +76,8 @@ struct sta32x_priv { | |||
76 | 76 | ||
77 | unsigned int mclk; | 77 | unsigned int mclk; |
78 | unsigned int format; | 78 | unsigned int format; |
79 | |||
80 | u32 coef_shadow[STA32X_COEF_COUNT]; | ||
79 | }; | 81 | }; |
80 | 82 | ||
81 | static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); | 83 | 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 | struct snd_ctl_elem_value *ucontrol) | 229 | struct snd_ctl_elem_value *ucontrol) |
228 | { | 230 | { |
229 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 231 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
232 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
230 | int numcoef = kcontrol->private_value >> 16; | 233 | int numcoef = kcontrol->private_value >> 16; |
231 | int index = kcontrol->private_value & 0xffff; | 234 | int index = kcontrol->private_value & 0xffff; |
232 | unsigned int cfud; | 235 | unsigned int cfud; |
@@ -239,6 +242,11 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, | |||
239 | snd_soc_write(codec, STA32X_CFUD, cfud); | 242 | snd_soc_write(codec, STA32X_CFUD, cfud); |
240 | 243 | ||
241 | snd_soc_write(codec, STA32X_CFADDR2, index); | 244 | snd_soc_write(codec, STA32X_CFADDR2, index); |
245 | for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++) | ||
246 | sta32x->coef_shadow[index + i] = | ||
247 | (ucontrol->value.bytes.data[3 * i] << 16) | ||
248 | | (ucontrol->value.bytes.data[3 * i + 1] << 8) | ||
249 | | (ucontrol->value.bytes.data[3 * i + 2]); | ||
242 | for (i = 0; i < 3 * numcoef; i++) | 250 | for (i = 0; i < 3 * numcoef; i++) |
243 | snd_soc_write(codec, STA32X_B1CF1 + i, | 251 | snd_soc_write(codec, STA32X_B1CF1 + i, |
244 | ucontrol->value.bytes.data[i]); | 252 | ucontrol->value.bytes.data[i]); |
@@ -252,6 +260,48 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, | |||
252 | return 0; | 260 | return 0; |
253 | } | 261 | } |
254 | 262 | ||
263 | int sta32x_sync_coef_shadow(struct snd_soc_codec *codec) | ||
264 | { | ||
265 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
266 | unsigned int cfud; | ||
267 | int i; | ||
268 | |||
269 | /* preserve reserved bits in STA32X_CFUD */ | ||
270 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
271 | |||
272 | for (i = 0; i < STA32X_COEF_COUNT; i++) { | ||
273 | snd_soc_write(codec, STA32X_CFADDR2, i); | ||
274 | snd_soc_write(codec, STA32X_B1CF1, | ||
275 | (sta32x->coef_shadow[i] >> 16) & 0xff); | ||
276 | snd_soc_write(codec, STA32X_B1CF2, | ||
277 | (sta32x->coef_shadow[i] >> 8) & 0xff); | ||
278 | snd_soc_write(codec, STA32X_B1CF3, | ||
279 | (sta32x->coef_shadow[i]) & 0xff); | ||
280 | /* chip documentation does not say if the bits are | ||
281 | * self-clearing, so do it explicitly */ | ||
282 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
283 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); | ||
284 | } | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | int sta32x_cache_sync(struct snd_soc_codec *codec) | ||
289 | { | ||
290 | unsigned int mute; | ||
291 | int rc; | ||
292 | |||
293 | if (!codec->cache_sync) | ||
294 | return 0; | ||
295 | |||
296 | /* mute during register sync */ | ||
297 | mute = snd_soc_read(codec, STA32X_MMUTE); | ||
298 | snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE); | ||
299 | sta32x_sync_coef_shadow(codec); | ||
300 | rc = snd_soc_cache_sync(codec); | ||
301 | snd_soc_write(codec, STA32X_MMUTE, mute); | ||
302 | return rc; | ||
303 | } | ||
304 | |||
255 | #define SINGLE_COEF(xname, index) \ | 305 | #define SINGLE_COEF(xname, index) \ |
256 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 306 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
257 | .info = sta32x_coefficient_info, \ | 307 | .info = sta32x_coefficient_info, \ |
@@ -661,7 +711,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec, | |||
661 | return ret; | 711 | return ret; |
662 | } | 712 | } |
663 | 713 | ||
664 | snd_soc_cache_sync(codec); | 714 | sta32x_cache_sync(codec); |
665 | } | 715 | } |
666 | 716 | ||
667 | /* Power up to mute */ | 717 | /* Power up to mute */ |
@@ -790,6 +840,17 @@ static int sta32x_probe(struct snd_soc_codec *codec) | |||
790 | STA32X_CxCFG_OM_MASK, | 840 | STA32X_CxCFG_OM_MASK, |
791 | 2 << STA32X_CxCFG_OM_SHIFT); | 841 | 2 << STA32X_CxCFG_OM_SHIFT); |
792 | 842 | ||
843 | /* initialize coefficient shadow RAM with reset values */ | ||
844 | for (i = 4; i <= 49; i += 5) | ||
845 | sta32x->coef_shadow[i] = 0x400000; | ||
846 | for (i = 50; i <= 54; i++) | ||
847 | sta32x->coef_shadow[i] = 0x7fffff; | ||
848 | sta32x->coef_shadow[55] = 0x5a9df7; | ||
849 | sta32x->coef_shadow[56] = 0x7fffff; | ||
850 | sta32x->coef_shadow[59] = 0x7fffff; | ||
851 | sta32x->coef_shadow[60] = 0x400000; | ||
852 | sta32x->coef_shadow[61] = 0x400000; | ||
853 | |||
793 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 854 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
794 | /* Bias level configuration will have done an extra enable */ | 855 | /* Bias level configuration will have done an extra enable */ |
795 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | 856 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); |