/** * sta32x_set_bias_level - DAPM callback * @codec: the codec device * @level: DAPM power level * * This is called by ALSA to put the codec into low power mode * or to wake it up. If the codec is powered off completely * all registers must be restored after power on. */ static int sta32x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { int ret; struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "level = %d\n", level); switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: /* Full power on */ regmap_update_bits(sta32x->regmap, STA32X_CONFF, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); break; case SND_SOC_BIAS_STANDBY: if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); if (ret != 0) { dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); return ret; } sta32x_startup_sequence(sta32x); sta32x_cache_sync(codec); sta32x_watchdog_start(sta32x); } /* Power down */ regmap_update_bits(sta32x->regmap, STA32X_CONFF, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0); break; case SND_SOC_BIAS_OFF: /* The chip runs through the power down sequence for us. */ regmap_update_bits(sta32x->regmap, STA32X_CONFF, STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0); msleep(300); sta32x_watchdog_stop(sta32x); if (sta32x->gpiod_nreset) gpiod_set_value(sta32x->gpiod_nreset, 0); regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); break; } codec->dapm.bias_level = level; return 0; }
/* work around ESD issue where sta32x resets and loses all configuration */ static void sta32x_watchdog(struct work_struct *work) { struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv, watchdog_work.work); struct snd_soc_codec *codec = sta32x->codec; unsigned int confa, confa_cached; /* check if sta32x has reset itself */ confa_cached = snd_soc_read(codec, STA32X_CONFA); codec->cache_bypass = 1; confa = snd_soc_read(codec, STA32X_CONFA); codec->cache_bypass = 0; if (confa != confa_cached) { codec->cache_sync = 1; sta32x_cache_sync(codec); } if (!sta32x->shutdown) schedule_delayed_work(&sta32x->watchdog_work, round_jiffies_relative(HZ)); }
/* work around ESD issue where sta32x resets and loses all configuration */ static void sta32x_watchdog(struct work_struct *work) { struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv, watchdog_work.work); struct snd_soc_codec *codec = sta32x->codec; unsigned int confa, confa_cached; /* check if sta32x has reset itself */ confa_cached = snd_soc_read(codec, STA32X_CONFA); regcache_cache_bypass(sta32x->regmap, true); confa = snd_soc_read(codec, STA32X_CONFA); regcache_cache_bypass(sta32x->regmap, false); if (confa != confa_cached) { regcache_mark_dirty(sta32x->regmap); sta32x_cache_sync(codec); } if (!sta32x->shutdown) queue_delayed_work(system_power_efficient_wq, &sta32x->watchdog_work, round_jiffies_relative(HZ)); }