[alsa-devel] [PATCH] ASoC: WM8985: Register notifier for the regulator being disabled
Dimitris Papastamos
dp at opensource.wolfsonmicro.com
Wed Sep 29 12:38:37 CEST 2010
Make sure we get an event when the regulator is disabled so we know
we have to sync the cache afterwards.
Minor stylistic changes.
Signed-off-by: Dimitris Papastamos <dp at opensource.wolfsonmicro.com>
---
sound/soc/codecs/wm8985.c | 51 +++++++++++++++++++++++++++++++++++++++++---
1 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 6116b42..bd109c4 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -126,11 +126,35 @@ static const int volume_update_regs[] = {
struct wm8985_priv {
enum snd_soc_control_type control_type;
+ struct snd_soc_codec *codec;
struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
+ struct notifier_block disable_nb[WM8985_NUM_SUPPLIES];
unsigned int sysclk;
unsigned int bclk;
};
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8985_REGULATOR_EVENT(n) \
+static int wm8985_regulator_event_##n(struct notifier_block *nb, \
+ unsigned long event, void *data) \
+{ \
+ struct wm8985_priv *wm8985 = container_of(nb, struct wm8985_priv, \
+ disable_nb[n]); \
+ if (event & REGULATOR_EVENT_DISABLE) { \
+ wm8985->codec->cache_sync = 1; \
+ } \
+ return 0; \
+}
+
+WM8985_REGULATOR_EVENT(0)
+WM8985_REGULATOR_EVENT(1)
+WM8985_REGULATOR_EVENT(2)
+WM8985_REGULATOR_EVENT(3)
+
static const struct {
int div;
int ratio;
@@ -782,7 +806,7 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
{
int ret;
struct snd_soc_codec *codec;
- struct pll_div pll_div;
+ struct pll_div pll_div = { 0 };
codec = dai->codec;
if (freq_in && freq_out) {
@@ -794,7 +818,7 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
/* disable the PLL before reprogramming it */
snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
WM8985_PLLEN_MASK, 0);
-
+
if (!freq_in || !freq_out)
return 0;
@@ -932,8 +956,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0);
snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0);
- codec->cache_sync = 1;
-
regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies),
wm8985->supplies);
break;
@@ -963,9 +985,13 @@ static int wm8985_resume(struct snd_soc_codec *codec)
static int wm8985_remove(struct snd_soc_codec *codec)
{
struct wm8985_priv *wm8985;
+ int i;
wm8985 = snd_soc_codec_get_drvdata(codec);
wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++)
+ regulator_unregister_notifier(wm8985->supplies[i].consumer,
+ &wm8985->disable_nb[i]);
regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
return 0;
}
@@ -978,6 +1004,7 @@ static int wm8985_probe(struct snd_soc_codec *codec)
u16 *cache;
wm8985 = snd_soc_codec_get_drvdata(codec);
+ wm8985->codec = codec;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8985->control_type);
if (ret < 0) {
@@ -995,6 +1022,22 @@ static int wm8985_probe(struct snd_soc_codec *codec)
return ret;
}
+ wm8985->disable_nb[0].notifier_call = wm8985_regulator_event_0;
+ wm8985->disable_nb[1].notifier_call = wm8985_regulator_event_1;
+ wm8985->disable_nb[2].notifier_call = wm8985_regulator_event_2;
+ wm8985->disable_nb[3].notifier_call = wm8985_regulator_event_3;
+
+ /* This should really be moved into the regulator core */
+ for (i = 0; i < ARRAY_SIZE(wm8985->supplies); i++) {
+ ret = regulator_register_notifier(wm8985->supplies[i].consumer,
+ &wm8985->disable_nb[i]);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to register regulator notifier: %d\n",
+ ret);
+ }
+ }
+
ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
wm8985->supplies);
if (ret) {
--
1.7.3
More information about the Alsa-devel
mailing list