Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17a52fd6 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: Begin to factor out register cache I/O functions



A lot of CODECs share the same register data formats and therefore
replicate the code to manage access to and caching of the register
map. In order to reduce code duplication centralised versions of
this code will be introduced with drivers able to configure the use
of the common code by calling the new snd_soc_codec_set_cache_io()
API call during startup.

As an initial user the 7 bit address/9 bit data format used by many
Wolfson devices is supported for write only CODECs and the drivers
with straightforward register cache implementations are converted to
use it.

Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent 5420f307
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -192,6 +192,8 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform);
int snd_soc_register_codec(struct snd_soc_codec *codec);
void snd_soc_unregister_codec(struct snd_soc_codec *codec);
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
			       int addr_bits, int data_bits);

#ifdef CONFIG_PM
int snd_soc_suspend_device(struct device *dev);
+1 −1
Original line number Diff line number Diff line
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o

obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
obj-$(CONFIG_SND_SOC)	+= codecs/
+49 −92
Original line number Diff line number Diff line
@@ -58,55 +58,7 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
#define WM8510_POWER1_BIASEN  0x08
#define WM8510_POWER1_BUFIOEN 0x10

/*
 * read wm8510 register cache
 */
static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec,
	unsigned int reg)
{
	u16 *cache = codec->reg_cache;
	if (reg == WM8510_RESET)
		return 0;
	if (reg >= WM8510_CACHEREGNUM)
		return -1;
	return cache[reg];
}

/*
 * write wm8510 register cache
 */
static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec,
	u16 reg, unsigned int value)
{
	u16 *cache = codec->reg_cache;
	if (reg >= WM8510_CACHEREGNUM)
		return;
	cache[reg] = value;
}

/*
 * write to the WM8510 register space
 */
static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg,
	unsigned int value)
{
	u8 data[2];

	/* data is
	 *   D15..D9 WM8510 register offset
	 *   D8...D0 register data
	 */
	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
	data[1] = value & 0x00ff;

	wm8510_write_reg_cache(codec, reg, value);
	if (codec->hw_write(codec->control_data, data, 2) == 2)
		return 0;
	else
		return -EIO;
}

#define wm8510_reset(c)	wm8510_write(c, WM8510_RESET, 0)
#define wm8510_reset(c)	snd_soc_write(c, WM8510_RESET, 0)

static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
@@ -327,27 +279,27 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,

	if (freq_in == 0 || freq_out == 0) {
		/* Clock CODEC directly from MCLK */
		reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
		wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff);
		reg = snd_soc_read(codec, WM8510_CLOCK);
		snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff);

		/* Turn off PLL */
		reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
		wm8510_write(codec, WM8510_POWER1, reg & 0x1df);
		reg = snd_soc_read(codec, WM8510_POWER1);
		snd_soc_write(codec, WM8510_POWER1, reg & 0x1df);
		return 0;
	}

	pll_factors(freq_out*4, freq_in);

	wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
	wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
	wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
	wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
	reg = wm8510_read_reg_cache(codec, WM8510_POWER1);
	wm8510_write(codec, WM8510_POWER1, reg | 0x020);
	snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
	snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18);
	snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
	snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
	reg = snd_soc_read(codec, WM8510_POWER1);
	snd_soc_write(codec, WM8510_POWER1, reg | 0x020);

	/* Run CODEC from PLL instead of MCLK */
	reg = wm8510_read_reg_cache(codec, WM8510_CLOCK);
	wm8510_write(codec, WM8510_CLOCK, reg | 0x100);
	reg = snd_soc_read(codec, WM8510_CLOCK);
	snd_soc_write(codec, WM8510_CLOCK, reg | 0x100);

	return 0;
}
@@ -363,24 +315,24 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,

	switch (div_id) {
	case WM8510_OPCLKDIV:
		reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf;
		wm8510_write(codec, WM8510_GPIO, reg | div);
		reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf;
		snd_soc_write(codec, WM8510_GPIO, reg | div);
		break;
	case WM8510_MCLKDIV:
		reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f;
		wm8510_write(codec, WM8510_CLOCK, reg | div);
		reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f;
		snd_soc_write(codec, WM8510_CLOCK, reg | div);
		break;
	case WM8510_ADCCLK:
		reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7;
		wm8510_write(codec, WM8510_ADC, reg | div);
		reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7;
		snd_soc_write(codec, WM8510_ADC, reg | div);
		break;
	case WM8510_DACCLK:
		reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7;
		wm8510_write(codec, WM8510_DAC, reg | div);
		reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7;
		snd_soc_write(codec, WM8510_DAC, reg | div);
		break;
	case WM8510_BCLKDIV:
		reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3;
		wm8510_write(codec, WM8510_CLOCK, reg | div);
		reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3;
		snd_soc_write(codec, WM8510_CLOCK, reg | div);
		break;
	default:
		return -EINVAL;
@@ -394,7 +346,7 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
{
	struct snd_soc_codec *codec = codec_dai->codec;
	u16 iface = 0;
	u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe;
	u16 clk = snd_soc_read(codec, WM8510_CLOCK) & 0x1fe;

	/* set master/slave audio interface */
	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -441,8 +393,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
		return -EINVAL;
	}

	wm8510_write(codec, WM8510_IFACE, iface);
	wm8510_write(codec, WM8510_CLOCK, clk);
	snd_soc_write(codec, WM8510_IFACE, iface);
	snd_soc_write(codec, WM8510_CLOCK, clk);
	return 0;
}

@@ -453,8 +405,8 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_device *socdev = rtd->socdev;
	struct snd_soc_codec *codec = socdev->card->codec;
	u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f;
	u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1;
	u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
	u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;

	/* bit size */
	switch (params_format(params)) {
@@ -493,20 +445,20 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
		break;
	}

	wm8510_write(codec, WM8510_IFACE, iface);
	wm8510_write(codec, WM8510_ADD, adn);
	snd_soc_write(codec, WM8510_IFACE, iface);
	snd_soc_write(codec, WM8510_ADD, adn);
	return 0;
}

static int wm8510_mute(struct snd_soc_dai *dai, int mute)
{
	struct snd_soc_codec *codec = dai->codec;
	u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf;
	u16 mute_reg = snd_soc_read(codec, WM8510_DAC) & 0xffbf;

	if (mute)
		wm8510_write(codec, WM8510_DAC, mute_reg | 0x40);
		snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40);
	else
		wm8510_write(codec, WM8510_DAC, mute_reg);
		snd_soc_write(codec, WM8510_DAC, mute_reg);
	return 0;
}

@@ -514,13 +466,13 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
static int wm8510_set_bias_level(struct snd_soc_codec *codec,
	enum snd_soc_bias_level level)
{
	u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
	u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3;

	switch (level) {
	case SND_SOC_BIAS_ON:
	case SND_SOC_BIAS_PREPARE:
		power1 |= 0x1;  /* VMID 50k */
		wm8510_write(codec, WM8510_POWER1, power1);
		snd_soc_write(codec, WM8510_POWER1, power1);
		break;

	case SND_SOC_BIAS_STANDBY:
@@ -528,18 +480,18 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,

		if (codec->bias_level == SND_SOC_BIAS_OFF) {
			/* Initial cap charge at VMID 5k */
			wm8510_write(codec, WM8510_POWER1, power1 | 0x3);
			snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
			mdelay(100);
		}

		power1 |= 0x2;  /* VMID 500k */
		wm8510_write(codec, WM8510_POWER1, power1);
		snd_soc_write(codec, WM8510_POWER1, power1);
		break;

	case SND_SOC_BIAS_OFF:
		wm8510_write(codec, WM8510_POWER1, 0);
		wm8510_write(codec, WM8510_POWER2, 0);
		wm8510_write(codec, WM8510_POWER3, 0);
		snd_soc_write(codec, WM8510_POWER1, 0);
		snd_soc_write(codec, WM8510_POWER2, 0);
		snd_soc_write(codec, WM8510_POWER3, 0);
		break;
	}

@@ -619,8 +571,6 @@ static int wm8510_init(struct snd_soc_device *socdev)

	codec->name = "WM8510";
	codec->owner = THIS_MODULE;
	codec->read = wm8510_read_reg_cache;
	codec->write = wm8510_write;
	codec->set_bias_level = wm8510_set_bias_level;
	codec->dai = &wm8510_dai;
	codec->num_dai = 1;
@@ -630,13 +580,20 @@ static int wm8510_init(struct snd_soc_device *socdev)
	if (codec->reg_cache == NULL)
		return -ENOMEM;

	ret = snd_soc_codec_set_cache_io(codec, 7, 9);
	if (ret < 0) {
		printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
		       ret);
		goto err;
	}

	wm8510_reset(codec);

	/* register pcms */
	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
	if (ret < 0) {
		printk(KERN_ERR "wm8510: failed to create pcms\n");
		goto pcm_err;
		goto err;
	}

	/* power on device */
@@ -655,7 +612,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
card_err:
	snd_soc_free_pcms(socdev);
	snd_soc_dapm_free(socdev);
pcm_err:
err:
	kfree(codec->reg_cache);
	return ret;
}
+22 −56
Original line number Diff line number Diff line
@@ -43,45 +43,6 @@ static const u16 wm8728_reg_defaults[] = {
	0x100,
};

static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec,
	unsigned int reg)
{
	u16 *cache = codec->reg_cache;
	BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
	return cache[reg];
}

static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec,
	u16 reg, unsigned int value)
{
	u16 *cache = codec->reg_cache;
	BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
	cache[reg] = value;
}

/*
 * write to the WM8728 register space
 */
static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg,
	unsigned int value)
{
	u8 data[2];

	/* data is
	 *   D15..D9 WM8728 register offset
	 *   D8...D0 register data
	 */
	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
	data[1] = value & 0x00ff;

	wm8728_write_reg_cache(codec, reg, value);

	if (codec->hw_write(codec->control_data, data, 2) == 2)
		return 0;
	else
		return -EIO;
}

static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);

static const struct snd_kcontrol_new wm8728_snd_controls[] = {
@@ -121,12 +82,12 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec)
static int wm8728_mute(struct snd_soc_dai *dai, int mute)
{
	struct snd_soc_codec *codec = dai->codec;
	u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
	u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL);

	if (mute)
		wm8728_write(codec, WM8728_DACCTL, mute_reg | 1);
		snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1);
	else
		wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1);
		snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1);

	return 0;
}
@@ -138,7 +99,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_device *socdev = rtd->socdev;
	struct snd_soc_codec *codec = socdev->card->codec;
	u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL);
	u16 dac = snd_soc_read(codec, WM8728_DACCTL);

	dac &= ~0x18;

@@ -155,7 +116,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
		return -EINVAL;
	}

	wm8728_write(codec, WM8728_DACCTL, dac);
	snd_soc_write(codec, WM8728_DACCTL, dac);

	return 0;
}
@@ -164,7 +125,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
		unsigned int fmt)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL);
	u16 iface = snd_soc_read(codec, WM8728_IFCTL);

	/* Currently only I2S is supported by the driver, though the
	 * hardware is more flexible.
@@ -204,7 +165,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
		return -EINVAL;
	}

	wm8728_write(codec, WM8728_IFCTL, iface);
	snd_soc_write(codec, WM8728_IFCTL, iface);
	return 0;
}

@@ -220,19 +181,19 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
	case SND_SOC_BIAS_STANDBY:
		if (codec->bias_level == SND_SOC_BIAS_OFF) {
			/* Power everything up... */
			reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
			wm8728_write(codec, WM8728_DACCTL, reg & ~0x4);
			reg = snd_soc_read(codec, WM8728_DACCTL);
			snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);

			/* ..then sync in the register cache. */
			for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++)
				wm8728_write(codec, i,
					     wm8728_read_reg_cache(codec, i));
				snd_soc_write(codec, i,
					     snd_soc_read(codec, i));
		}
		break;

	case SND_SOC_BIAS_OFF:
		reg = wm8728_read_reg_cache(codec, WM8728_DACCTL);
		wm8728_write(codec, WM8728_DACCTL, reg | 0x4);
		reg = snd_soc_read(codec, WM8728_DACCTL);
		snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
		break;
	}
	codec->bias_level = level;
@@ -294,8 +255,6 @@ static int wm8728_init(struct snd_soc_device *socdev)

	codec->name = "WM8728";
	codec->owner = THIS_MODULE;
	codec->read = wm8728_read_reg_cache;
	codec->write = wm8728_write;
	codec->set_bias_level = wm8728_set_bias_level;
	codec->dai = &wm8728_dai;
	codec->num_dai = 1;
@@ -307,11 +266,18 @@ static int wm8728_init(struct snd_soc_device *socdev)
	if (codec->reg_cache == NULL)
		return -ENOMEM;

	ret = snd_soc_codec_set_cache_io(codec, 7, 9);
	if (ret < 0) {
		printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
		       ret);
		goto err;
	}

	/* register pcms */
	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
	if (ret < 0) {
		printk(KERN_ERR "wm8728: failed to create pcms\n");
		goto pcm_err;
		goto err;
	}

	/* power on device */
@@ -331,7 +297,7 @@ static int wm8728_init(struct snd_soc_device *socdev)
card_err:
	snd_soc_free_pcms(socdev);
	snd_soc_dapm_free(socdev);
pcm_err:
err:
	kfree(codec->reg_cache);
	return ret;
}
+29 −79
Original line number Diff line number Diff line
@@ -55,55 +55,7 @@ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
	0x0000, 0x0000
};

/*
 * read wm8731 register cache
 */
static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec,
	unsigned int reg)
{
	u16 *cache = codec->reg_cache;
	if (reg == WM8731_RESET)
		return 0;
	if (reg >= WM8731_CACHEREGNUM)
		return -1;
	return cache[reg];
}

/*
 * write wm8731 register cache
 */
static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec,
	u16 reg, unsigned int value)
{
	u16 *cache = codec->reg_cache;
	if (reg >= WM8731_CACHEREGNUM)
		return;
	cache[reg] = value;
}

/*
 * write to the WM8731 register space
 */
static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg,
	unsigned int value)
{
	u8 data[2];

	/* data is
	 *   D15..D9 WM8731 register offset
	 *   D8...D0 register data
	 */
	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
	data[1] = value & 0x00ff;

	wm8731_write_reg_cache(codec, reg, value);
	if (codec->hw_write(codec->control_data, data, 2) == 2)
		return 0;
	else
		return -EIO;
}

#define wm8731_reset(c)	wm8731_write(c, WM8731_RESET, 0)
#define wm8731_reset(c)	snd_soc_write(c, WM8731_RESET, 0)

static const char *wm8731_input_select[] = {"Line In", "Mic"};
static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
@@ -260,12 +212,12 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
	struct snd_soc_device *socdev = rtd->socdev;
	struct snd_soc_codec *codec = socdev->card->codec;
	struct wm8731_priv *wm8731 = codec->private_data;
	u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
	u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
	int i = get_coeff(wm8731->sysclk, params_rate(params));
	u16 srate = (coeff_div[i].sr << 2) |
		(coeff_div[i].bosr << 1) | coeff_div[i].usb;

	wm8731_write(codec, WM8731_SRATE, srate);
	snd_soc_write(codec, WM8731_SRATE, srate);

	/* bit size */
	switch (params_format(params)) {
@@ -279,7 +231,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
		break;
	}

	wm8731_write(codec, WM8731_IFACE, iface);
	snd_soc_write(codec, WM8731_IFACE, iface);
	return 0;
}

@@ -291,7 +243,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
	struct snd_soc_codec *codec = socdev->card->codec;

	/* set active */
	wm8731_write(codec, WM8731_ACTIVE, 0x0001);
	snd_soc_write(codec, WM8731_ACTIVE, 0x0001);

	return 0;
}
@@ -306,19 +258,19 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream,
	/* deactivate */
	if (!codec->active) {
		udelay(50);
		wm8731_write(codec, WM8731_ACTIVE, 0x0);
		snd_soc_write(codec, WM8731_ACTIVE, 0x0);
	}
}

static int wm8731_mute(struct snd_soc_dai *dai, int mute)
{
	struct snd_soc_codec *codec = dai->codec;
	u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7;
	u16 mute_reg = snd_soc_read(codec, WM8731_APDIGI) & 0xfff7;

	if (mute)
		wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8);
		snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8);
	else
		wm8731_write(codec, WM8731_APDIGI, mute_reg);
		snd_soc_write(codec, WM8731_APDIGI, mute_reg);
	return 0;
}

@@ -396,7 +348,7 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
	}

	/* set iface */
	wm8731_write(codec, WM8731_IFACE, iface);
	snd_soc_write(codec, WM8731_IFACE, iface);
	return 0;
}

@@ -412,12 +364,12 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
		break;
	case SND_SOC_BIAS_STANDBY:
		/* Clear PWROFF, gate CLKOUT, everything else as-is */
		reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
		wm8731_write(codec, WM8731_PWR, reg | 0x0040);
		reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f;
		snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
		break;
	case SND_SOC_BIAS_OFF:
		wm8731_write(codec, WM8731_ACTIVE, 0x0);
		wm8731_write(codec, WM8731_PWR, 0xffff);
		snd_soc_write(codec, WM8731_ACTIVE, 0x0);
		snd_soc_write(codec, WM8731_PWR, 0xffff);
		break;
	}
	codec->bias_level = level;
@@ -466,7 +418,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
	struct snd_soc_codec *codec = socdev->card->codec;

	wm8731_write(codec, WM8731_ACTIVE, 0x0);
	snd_soc_write(codec, WM8731_ACTIVE, 0x0);
	wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
	return 0;
}
@@ -556,7 +508,6 @@ static int wm8731_register(struct wm8731_priv *wm8731)
{
	int ret;
	struct snd_soc_codec *codec = &wm8731->codec;
	u16 reg;

	if (wm8731_codec) {
		dev_err(codec->dev, "Another WM8731 is registered\n");
@@ -571,8 +522,6 @@ static int wm8731_register(struct wm8731_priv *wm8731)
	codec->private_data = wm8731;
	codec->name = "WM8731";
	codec->owner = THIS_MODULE;
	codec->read = wm8731_read_reg_cache;
	codec->write = wm8731_write;
	codec->bias_level = SND_SOC_BIAS_OFF;
	codec->set_bias_level = wm8731_set_bias_level;
	codec->dai = &wm8731_dai;
@@ -582,6 +531,12 @@ static int wm8731_register(struct wm8731_priv *wm8731)

	memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));

	ret = snd_soc_codec_set_cache_io(codec, 7, 9);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
		goto err;
	}

	ret = wm8731_reset(codec);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
@@ -593,18 +548,13 @@ static int wm8731_register(struct wm8731_priv *wm8731)
	wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

	/* Latch the update bits */
	reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
	wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
	reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
	wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
	reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
	wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
	reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
	wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
	snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0);
	snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0);
	snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0);
	snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0);

	/* Disable bypass path by default */
	reg = wm8731_read_reg_cache(codec, WM8731_APANA);
	wm8731_write(codec, WM8731_APANA, reg & ~0x4);
	snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);

	wm8731_codec = codec;

Loading