Skip to contentSkip to conversation

Convert wm8xxx codec drivers to use snd_soc_write/snd_soc_cache_sync

PATCH Superseded Axel Lin 2 participants 16 messages Oct 6, 2011 – Oct 7, 2011

Subsystems (3)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Axel Lin

author
#0 lore raw

v2 cover Convert wm8xxx codec drivers to use snd_soc_write/snd_soc_cache_sync

This serial converts the wm8xxx codec drivers to use snd_soc_cache_sync. I don't have these hardware, but I assume Mark has all these hardware. These patches are UNTESTED. I'd appreciate if someone can test it. (Current code is broken anyway, thus we need convert to use new API. )

v2: For 7, 9 CODECs that are write only, convert to using cache_bypass + snd_soc_write
v2 also includes wm8990 that I had sent separately.

*** BLURB HERE ***

Axel Lin (11):
ASoC: wm8510: Convert to snd_soc_write
ASoC: wm8711: Convert to snd_soc_write
ASoC: wm8731: Convert to snd_soc_write
ASoC: wm8750: Convert to snd_soc_write
ASoC: wm8776: Convert to snd_soc_write
ASoC: wm8940: Convert to snd_soc_cache_sync
ASoC: wm8960: Convert to snd_soc_write
ASoC: wm8971: Convert to snd_soc_write
ASoC: wm8974: Convert to snd_soc_write
ASoC: wm8988: Convert to snd_soc_write
ASoC: wm8990: Convert to snd_soc_cache_sync

 sound/soc/codecs/wm8510.c |   33 +++++++++++++++++++++----------
 sound/soc/codecs/wm8711.c |   33 +++++++++++++++++++++----------
 sound/soc/codecs/wm8731.c |   35 +++++++++++++++++++++------------
 sound/soc/codecs/wm8750.c |   36 +++++++++++++++++++++-------------
 sound/soc/codecs/wm8776.c |   36 +++++++++++++++++++++-------------
 sound/soc/codecs/wm8940.c |   46 +++++++++++++++++++++-----------------------
 sound/soc/codecs/wm8960.c |   34 +++++++++++++++++++++++---------
 sound/soc/codecs/wm8971.c |   35 ++++++++++++++++++++++-----------
 sound/soc/codecs/wm8974.c |   33 +++++++++++++++++++++----------
 sound/soc/codecs/wm8988.c |   37 +++++++++++++++++++++--------------
 sound/soc/codecs/wm8990.c |   32 ++++++++++++++++++------------
 11 files changed, 242 insertions(+), 148 deletions(-)
Signature · 1 line
1.7.4.1
author
#1 lore raw

PATCH v2 1/11 ASoC: wm8510: Convert to snd_soc_write

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8510.c |   33 ++++++++++++++++++++++-----------
 1 files changed, 22 insertions(+), 11 deletions(-)
sound/soc/codecs/wm8510.c +22 -11
index 55a4c83..fc8bc9c 100644
@@ -463,6 +463,26 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
+static void wm8510_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 0;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8510_RESET || cache[i] == wm8510_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 1;
+	codec->cache_sync = 0;
+}
+
 /* liam need to make this lower power with dapm */
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
@@ -480,6 +500,8 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 		power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
 
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			wm8510_sync_cache(codec);
+
 			/* Initial cap charge at VMID 5k */
 			snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
 			mdelay(100);
@@ -541,18 +563,7 @@ static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8510_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) {
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
 	wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
Signature · 1 line
1.7.4.1
author
#5 lore raw

PATCH v2 2/11 ASoC: wm8711: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8711.c |   33 ++++++++++++++++++++++-----------
 1 files changed, 22 insertions(+), 11 deletions(-)
sound/soc/codecs/wm8711.c +22 -11
index 47c7fd5..f4c15ea 100644
@@ -287,6 +287,25 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
+static void wm8711_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8711_RESET || cache[i] == wm8711_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
 
 static int wm8711_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
@@ -300,6 +319,9 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+			wm8711_sync_cache(codec);
+
 		snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
 		break;
 	case SND_SOC_BIAS_OFF:
@@ -346,18 +368,7 @@ static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8711_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8711_reg); i++) {
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
 	wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
Signature · 1 line
1.7.4.1
author
#6 lore raw

PATCH v2 3/11 ASoC: wm8731: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8731.c |   35 ++++++++++++++++++++++-------------
 1 files changed, 22 insertions(+), 13 deletions(-)
sound/soc/codecs/wm8731.c +22 -13
index f76b6fc..853aed1 100644
@@ -423,13 +423,31 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	return 0;
 }
 
+static void wm8731_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8731_RESET || cache[i] == wm8731_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
 	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
-	int i, ret;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
+	int ret;
 	u16 reg;
 
 	switch (level) {
@@ -444,16 +462,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 			if (ret != 0)
 				return ret;
 
-			/* Sync reg_cache with the hardware */
-			for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
-				if (cache[i] == wm8731_reg[i])
-					continue;
-
-				data[0] = (i << 1) | ((cache[i] >> 8)
-						      & 0x0001);
-				data[1] = cache[i] & 0x00ff;
-				codec->hw_write(codec->control_data, data, 2);
-			}
+			wm8731_sync_cache(codec);
 		}
 
 		/* Clear PWROFF, gate CLKOUT, everything else as-is */
Signature · 1 line
1.7.4.1
author
#7 lore raw

PATCH v2 4/11 ASoC: wm8750: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8750.c |   36 ++++++++++++++++++++++--------------
 1 files changed, 22 insertions(+), 14 deletions(-)
sound/soc/codecs/wm8750.c +22 -14
index 862c520..8b5a41b 100644
@@ -602,6 +602,26 @@ static int wm8750_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
+static void wm8750_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8750_RESET || cache[i] == wm8750_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 static int wm8750_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
@@ -616,6 +636,8 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			wm8750_sync_cache(codec);
+
 			/* Set VMID to 5k */
 			snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
 
@@ -673,21 +695,7 @@ static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8750_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) {
-		if (i == WM8750_RESET)
-			continue;
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
-
 	wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
Signature · 1 line
1.7.4.1
author
#8 lore raw

PATCH v2 5/11 ASoC: wm8776: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8776.c |   36 ++++++++++++++++++++++--------------
 1 files changed, 22 insertions(+), 14 deletions(-)
sound/soc/codecs/wm8776.c +22 -14
index 00d8846..9d488e6 100644
@@ -298,6 +298,26 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
 	return 0;
 }
 
+static void wm8776_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8776_RESET || cache[i] == wm8776_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 static int wm8776_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
@@ -308,6 +328,8 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			wm8776_sync_cache(codec);
+
 			/* Disable the global powerdown; DAPM does the rest */
 			snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
 		}
@@ -379,21 +401,7 @@ static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8776_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) {
-		if (cache[i] == wm8776_reg[i])
-			continue;
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
-
 	wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 #else
Signature · 1 line
1.7.4.1
author
#9 lore raw

PATCH v2 6/11 ASoC: wm8940: Convert to snd_soc_cache_sync

In reply to Axel Lin

Convert codec->hw_write to snd_soc_cache_sync

---
 sound/soc/codecs/wm8940.c |   46 +++++++++++++++++++++-----------------------
 1 files changed, 22 insertions(+), 24 deletions(-)
sound/soc/codecs/wm8940.c +22 -24
index 7e0f54c..a4abfdf 100644
@@ -45,6 +45,17 @@ struct wm8940_priv {
 	enum snd_soc_control_type control_type;
 };
 
+static int wm8940_volatile_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	switch (reg) {
+	case WM8940_SOFTRESET:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
 static u16 wm8940_reg_defaults[] = {
 	0x8940, /* Soft Reset */
 	0x0000, /* Power 1 */
@@ -459,6 +470,14 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
 		ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
 		break;
 	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			ret = snd_soc_cache_sync(codec);
+			if (ret < 0) {
+				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+
 		/* ensure bufioen and biasen */
 		pwr_reg |= (1 << 2) | (1 << 3);
 		/* set vmid to 300k for standby */
@@ -659,30 +678,8 @@ static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8940_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	int ret;
-	u8 data[3];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware
-	 * Could use auto incremented writes to speed this up
-	 */
-	for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) {
-		data[0] = i;
-		data[1] = (cache[i] & 0xFF00) >> 8;
-		data[2] = cache[i] & 0x00FF;
-		ret = codec->hw_write(codec->control_data, data, 3);
-		if (ret < 0)
-			goto error_ret;
-		else if (ret != 3) {
-			ret = -EIO;
-			goto error_ret;
-		}
-	}
-	ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-error_ret:
-	return ret;
+	wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
 }
 
 static int wm8940_probe(struct snd_soc_codec *codec)
@@ -742,6 +739,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
 	.reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8940_reg_defaults,
+	.volatile_register = wm8940_volatile_register,
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
Signature · 1 line
1.7.4.1
author
#10 lore raw

PATCH v2 7/11 ASoC: wm8960: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8960.c |   34 ++++++++++++++++++++++++----------
 1 files changed, 24 insertions(+), 10 deletions(-)
sound/soc/codecs/wm8960.c +24 -10
index 831c20f..c043722 100644
@@ -555,6 +555,26 @@ static int wm8960_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
+static void wm8960_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8960_RESET || cache[i] == wm8960_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 				      enum snd_soc_bias_level level)
 {
@@ -574,6 +594,8 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			wm8960_sync_cache(codec);
+
 			/* Enable anti-pop features */
 			snd_soc_write(codec, WM8960_APOP1,
 				      WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -629,6 +651,8 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		switch (codec->dapm.bias_level) {
 		case SND_SOC_BIAS_STANDBY:
+			wm8960_sync_cache(codec);
+
 			/* Enable anti pop mode */
 			snd_soc_update_bits(codec, WM8960_APOP1,
 					    WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -901,16 +925,6 @@ static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int wm8960_resume(struct snd_soc_codec *codec)
 {
 	struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8960_reg); i++) {
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
 
 	wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	return 0;
Signature · 1 line
1.7.4.1
author
#11 lore raw

PATCH v2 8/11 ASoC: wm8971: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8971.c |   35 +++++++++++++++++++++++------------
 1 files changed, 23 insertions(+), 12 deletions(-)
sound/soc/codecs/wm8971.c +23 -12
index 08ea6f8..2265e00 100644
@@ -533,6 +533,26 @@ static int wm8971_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
+static void wm8971_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8971_RESET || cache[i] == wm8971_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 static int wm8971_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
@@ -546,6 +566,9 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+			wm8971_sync_cache(codec);
+
 		/* mute dac and set vmid to 500k, enable VREF */
 		snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
 		break;
@@ -605,20 +628,8 @@ static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8971_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
 	u16 reg;
 
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) {
-		if (i == WM8971_RESET)
-			continue;
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
-
 	wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	/* charge wm8971 caps */
Signature · 1 line
1.7.4.1
author
#12 lore raw

PATCH v2 9/11 ASoC: wm8974: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8974.c |   33 ++++++++++++++++++++++-----------
 1 files changed, 22 insertions(+), 11 deletions(-)
sound/soc/codecs/wm8974.c +22 -11
index ca646a8..7db3808 100644
@@ -513,6 +513,26 @@ static int wm8974_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
+static void wm8974_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8974_RESET || cache[i] == wm8974_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 /* liam need to make this lower power with dapm */
 static int wm8974_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
@@ -530,6 +550,8 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
 		power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
 
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			wm8974_sync_cache(codec);
+
 			/* Initial cap charge at VMID 5k */
 			snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
 			mdelay(100);
@@ -589,18 +611,7 @@ static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8974_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8974_reg); i++) {
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
 	wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
Signature · 1 line
1.7.4.1
author
#13 lore raw

PATCH v2 10/11 ASoC: wm8988: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
 sound/soc/codecs/wm8988.c |   37 ++++++++++++++++++++++---------------
 1 files changed, 22 insertions(+), 15 deletions(-)
sound/soc/codecs/wm8988.c +22 -15
index 1c6f8bf..33584e0 100644
@@ -55,7 +55,6 @@ struct wm8988_priv {
 	struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
-
 #define wm8988_reset(c)	snd_soc_write(c, WM8988_RESET, 0)
 
 /*
@@ -660,6 +659,26 @@ static int wm8988_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
+static void wm8988_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8988_RESET || cache[i] == wm8988_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 static int wm8988_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 {
@@ -676,6 +695,8 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			wm8988_sync_cache(codec);
+
 			/* VREF, VMID=2x5k */
 			snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
 
@@ -736,21 +757,7 @@ static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8988_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < WM8988_NUM_REG; i++) {
-		if (i == WM8988_RESET)
-			continue;
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
-
 	wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
Signature · 1 line
1.7.4.1
author
#14 lore raw

PATCH v2 11/11 ASoC: wm8990: Convert to snd_soc_cache_sync

In reply to Axel Lin

Convert codec->hw_write to snd_soc_cache_sync

---
 sound/soc/codecs/wm8990.c |   32 +++++++++++++++++++-------------
 1 files changed, 19 insertions(+), 13 deletions(-)
sound/soc/codecs/wm8990.c +19 -13
index 100aeee..48e9dd9 100644
@@ -36,6 +36,17 @@ struct wm8990_priv {
 	unsigned int pcmclk;
 };
 
+static int wm8990_volatile_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	switch (reg) {
+	case WM8990_RESET:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
 /*
  * wm8990 register cache.  Note that register 0 is not included in the
  * cache.
@@ -1156,6 +1167,7 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
 static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
+	int ret;
 	u16 val;
 
 	switch (level) {
@@ -1171,6 +1183,12 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
 
 	case SND_SOC_BIAS_STANDBY:
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			ret = snd_soc_cache_sync(codec);
+			if (ret < 0) {
+				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+
 			/* Enable all output discharge bits */
 			snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
 				WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
@@ -1319,19 +1337,6 @@ static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8990_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) {
-		if (i + 1 == WM8990_RESET)
-			continue;
-		data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
-
 	wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	return 0;
 }
@@ -1392,6 +1397,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
 	.reg_cache_size = ARRAY_SIZE(wm8990_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8990_reg,
+	.volatile_register = wm8990_volatile_register,
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
Signature · 1 line
1.7.4.1
author
#2 lore raw

PATCH RESEND v2 1/11 ASoC: wm8510: Convert to snd_soc_write

In reply to Axel Lin

Convert codec->hw_write to snd_soc_write

---
This resend fixes a copy-paste bug.
cache_bypass flag should be set before snd_soc_write and be clear after the write.

Axel

 sound/soc/codecs/wm8510.c |   33 ++++++++++++++++++++++-----------
 1 files changed, 22 insertions(+), 11 deletions(-)
sound/soc/codecs/wm8510.c +22 -11
index 55a4c83..fc8bc9c 100644
@@ -463,6 +463,26 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 	return 0;
 }
 
+static void wm8510_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8510_RESET || cache[i] == wm8510_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;
+}
+
 /* liam need to make this lower power with dapm */
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
@@ -480,6 +500,8 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 		power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
 
 		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			wm8510_sync_cache(codec);
+
 			/* Initial cap charge at VMID 5k */
 			snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
 			mdelay(100);
@@ -541,18 +563,7 @@ static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8510_resume(struct snd_soc_codec *codec)
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) {
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
 	wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
 	return 0;
 }
 
Signature · 1 line
1.7.4.1
#3 lore raw

Re: [PATCH 01/11 RESEND] ASoC: wm8510: Convert to snd_soc_write

Quoted 8 lines · Axel Lin
sound/soc/codecs/wm8510.c +8 -0
+static void wm8510_sync_cache(struct snd_soc_codec *codec)
+{
+	short i;
+	u16 *cache;
+
+	if (!codec->cache_sync)
+		return;
+	codec->cache_only = 0;

sound/soc/codecs/wm8510.c static int wm8510_mute(struct snd_soc_dai *dai, int mute) · line 483

Quoted 10 lines
sound/soc/codecs/wm8510.c +10 -0
+	codec->cache_bypass = 1;
+	/* restore cache */
+	cache = codec->reg_cache;
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
+		if (i == WM8510_RESET || cache[i] == wm8510_reg[i])
+			continue;
+		snd_soc_write(codec, i, cache[i]);
+	}
+	codec->cache_bypass = 0;
+	codec->cache_sync = 0;

The usual trick for avoiding this is to provide a register default value for the reset register and then write that value when the chip is reset. This then means that the write to the reset register is suppressed by the cache restore code when it skips writes of default registers.

Thanks for doing this work.

#15 lore raw

Re: [PATCH 11/11] ASoC: wm8990: Convert to snd_soc_cache_sync

In reply to Axel Lin
Quoted 1 line · Axel Lin

Convert codec->hw_write to snd_soc_cache_sync

This doesn't apply against current code, mostly due to a version of the patch already having been applied and a conflict with your subsequent patch updating the comments.

author
#4 lore raw

Re: [PATCH 01/11 RESEND] ASoC: wm8510: Convert to snd_soc_write

In reply to Mark Brown

2011/10/7 Mark Brown <[email protected]>:

Quoted 17 lines · Axel Lin
Quoted 16 lines
sound/soc/codecs/wm8510.c +15 -0
+static void wm8510_sync_cache(struct snd_soc_codec *codec)
+{
+     short i;
+     u16 *cache;
+
+     if (!codec->cache_sync)
+             return;
+     codec->cache_only = 0;
+     codec->cache_bypass = 1;
+     /* restore cache */
+     cache = codec->reg_cache;
+     for (i = 0; i < codec->driver->reg_cache_size; i++) {
+             if (i == WM8510_RESET || cache[i] == wm8510_reg[i])
+                     continue;
+             snd_soc_write(codec, i, cache[i]);
Quoted 9 lines
Quoted 3 lines

+     }
+     codec->cache_bypass = 0;
+     codec->cache_sync = 0;

The usual trick for avoiding this is to provide a register default value for the reset register and then write that value when the chip is reset. This then means that the write to the reset register is suppressed by the cache restore code when it skips writes of default registers.

Nice trick. Then we can use snd_soc_cache_sync() to replace the customized xxxx_sync_cache() calls.

I'll send a v3 soon.

Quoted 1 line

Thanks for doing this work.

And thanks for your valuable review.

Regards,
Axel