aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/sta32x.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/sta32x.c')
-rw-r--r--sound/soc/codecs/sta32x.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 97091e3b9a0b..3b0deafd766b 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -27,6 +27,7 @@
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/regulator/consumer.h> 28#include <linux/regulator/consumer.h>
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/workqueue.h>
30#include <sound/core.h> 31#include <sound/core.h>
31#include <sound/pcm.h> 32#include <sound/pcm.h>
32#include <sound/pcm_params.h> 33#include <sound/pcm_params.h>
@@ -80,6 +81,8 @@ struct sta32x_priv {
80 unsigned int format; 81 unsigned int format;
81 82
82 u32 coef_shadow[STA32X_COEF_COUNT]; 83 u32 coef_shadow[STA32X_COEF_COUNT];
84 struct delayed_work watchdog_work;
85 int shutdown;
83}; 86};
84 87
85static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); 88static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
@@ -304,6 +307,46 @@ int sta32x_cache_sync(struct snd_soc_codec *codec)
304 return rc; 307 return rc;
305} 308}
306 309
310/* work around ESD issue where sta32x resets and loses all configuration */
311static void sta32x_watchdog(struct work_struct *work)
312{
313 struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
314 watchdog_work.work);
315 struct snd_soc_codec *codec = sta32x->codec;
316 unsigned int confa, confa_cached;
317
318 /* check if sta32x has reset itself */
319 confa_cached = snd_soc_read(codec, STA32X_CONFA);
320 codec->cache_bypass = 1;
321 confa = snd_soc_read(codec, STA32X_CONFA);
322 codec->cache_bypass = 0;
323 if (confa != confa_cached) {
324 codec->cache_sync = 1;
325 sta32x_cache_sync(codec);
326 }
327
328 if (!sta32x->shutdown)
329 schedule_delayed_work(&sta32x->watchdog_work,
330 round_jiffies_relative(HZ));
331}
332
333static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
334{
335 if (sta32x->pdata->needs_esd_watchdog) {
336 sta32x->shutdown = 0;
337 schedule_delayed_work(&sta32x->watchdog_work,
338 round_jiffies_relative(HZ));
339 }
340}
341
342static void sta32x_watchdog_stop(struct sta32x_priv *sta32x)
343{
344 if (sta32x->pdata->needs_esd_watchdog) {
345 sta32x->shutdown = 1;
346 cancel_delayed_work_sync(&sta32x->watchdog_work);
347 }
348}
349
307#define SINGLE_COEF(xname, index) \ 350#define SINGLE_COEF(xname, index) \
308{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 351{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
309 .info = sta32x_coefficient_info, \ 352 .info = sta32x_coefficient_info, \
@@ -714,6 +757,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
714 } 757 }
715 758
716 sta32x_cache_sync(codec); 759 sta32x_cache_sync(codec);
760 sta32x_watchdog_start(sta32x);
717 } 761 }
718 762
719 /* Power up to mute */ 763 /* Power up to mute */
@@ -730,7 +774,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
730 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 774 STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
731 STA32X_CONFF_PWDN); 775 STA32X_CONFF_PWDN);
732 msleep(300); 776 msleep(300);
733 777 sta32x_watchdog_stop(sta32x);
734 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), 778 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
735 sta32x->supplies); 779 sta32x->supplies);
736 break; 780 break;
@@ -863,6 +907,9 @@ static int sta32x_probe(struct snd_soc_codec *codec)
863 sta32x->coef_shadow[60] = 0x400000; 907 sta32x->coef_shadow[60] = 0x400000;
864 sta32x->coef_shadow[61] = 0x400000; 908 sta32x->coef_shadow[61] = 0x400000;
865 909
910 if (sta32x->pdata->needs_esd_watchdog)
911 INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
912
866 sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 913 sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
867 /* Bias level configuration will have done an extra enable */ 914 /* Bias level configuration will have done an extra enable */
868 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); 915 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
@@ -879,6 +926,7 @@ static int sta32x_remove(struct snd_soc_codec *codec)
879{ 926{
880 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); 927 struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
881 928
929 sta32x_watchdog_stop(sta32x);
882 sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); 930 sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
883 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); 931 regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
884 regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); 932 regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);