Merge branch 'reg-cache' into for-2.6.32

This commit is contained in:
Mark Brown 2009-08-07 11:43:58 +01:00
commit 06cddefc1f
19 changed files with 1111 additions and 1782 deletions

View File

@ -209,11 +209,20 @@ typedef int (*hw_read_t)(void *,char* ,int);
extern struct snd_ac97_bus_ops soc_ac97_ops; extern struct snd_ac97_bus_ops soc_ac97_ops;
enum snd_soc_control_type {
SND_SOC_CUSTOM,
SND_SOC_I2C,
SND_SOC_SPI,
};
int snd_soc_register_platform(struct snd_soc_platform *platform); int snd_soc_register_platform(struct snd_soc_platform *platform);
void snd_soc_unregister_platform(struct snd_soc_platform *platform); void snd_soc_unregister_platform(struct snd_soc_platform *platform);
int snd_soc_register_codec(struct snd_soc_codec *codec); int snd_soc_register_codec(struct snd_soc_codec *codec);
void snd_soc_unregister_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_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,
enum snd_soc_control_type control);
#ifdef CONFIG_PM #ifdef CONFIG_PM
int snd_soc_suspend_device(struct device *dev); int snd_soc_suspend_device(struct device *dev);
@ -387,7 +396,7 @@ struct snd_soc_codec {
int (*volatile_register)(unsigned int); int (*volatile_register)(unsigned int);
int (*readable_register)(unsigned int); int (*readable_register)(unsigned int);
hw_write_t hw_write; hw_write_t hw_write;
hw_read_t hw_read; unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
void *reg_cache; void *reg_cache;
short reg_cache_size; short reg_cache_size;
short reg_cache_step; short reg_cache_step;

View File

@ -1,4 +1,4 @@
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) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += codecs/

View File

@ -145,8 +145,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
u8 *value) u8 *value)
{ {
*value = reg & 0xff; *value = reg & 0xff;
if (codec->hw_read(codec->control_data, value, 1) != 1)
return -EIO; value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]);
aic3x_write_reg_cache(codec, reg, *value); aic3x_write_reg_cache(codec, reg, *value);
return 0; return 0;
@ -1325,12 +1325,6 @@ static struct i2c_driver aic3x_i2c_driver = {
.id_table = aic3x_i2c_id, .id_table = aic3x_i2c_id,
}; };
static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len)
{
value[0] = i2c_smbus_read_byte_data(client, value[0]);
return (len == 1);
}
static int aic3x_add_i2c_device(struct platform_device *pdev, static int aic3x_add_i2c_device(struct platform_device *pdev,
const struct aic3x_setup_data *setup) const struct aic3x_setup_data *setup)
{ {
@ -1403,7 +1397,6 @@ static int aic3x_probe(struct platform_device *pdev)
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) { if (setup->i2c_address) {
codec->hw_write = (hw_write_t) i2c_master_send; codec->hw_write = (hw_write_t) i2c_master_send;
codec->hw_read = (hw_read_t) aic3x_i2c_read;
ret = aic3x_add_i2c_device(pdev, setup); ret = aic3x_add_i2c_device(pdev, setup);
} }
#else #else

View File

@ -58,55 +58,7 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
#define WM8510_POWER1_BIASEN 0x08 #define WM8510_POWER1_BIASEN 0x08
#define WM8510_POWER1_BUFIOEN 0x10 #define WM8510_POWER1_BUFIOEN 0x10
/* #define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0)
* 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)
static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; 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) { if (freq_in == 0 || freq_out == 0) {
/* Clock CODEC directly from MCLK */ /* Clock CODEC directly from MCLK */
reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); reg = snd_soc_read(codec, WM8510_CLOCK);
wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff);
/* Turn off PLL */ /* Turn off PLL */
reg = wm8510_read_reg_cache(codec, WM8510_POWER1); reg = snd_soc_read(codec, WM8510_POWER1);
wm8510_write(codec, WM8510_POWER1, reg & 0x1df); snd_soc_write(codec, WM8510_POWER1, reg & 0x1df);
return 0; return 0;
} }
pll_factors(freq_out*4, freq_in); pll_factors(freq_out*4, freq_in);
wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18);
wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff);
wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff);
reg = wm8510_read_reg_cache(codec, WM8510_POWER1); reg = snd_soc_read(codec, WM8510_POWER1);
wm8510_write(codec, WM8510_POWER1, reg | 0x020); snd_soc_write(codec, WM8510_POWER1, reg | 0x020);
/* Run CODEC from PLL instead of MCLK */ /* Run CODEC from PLL instead of MCLK */
reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); reg = snd_soc_read(codec, WM8510_CLOCK);
wm8510_write(codec, WM8510_CLOCK, reg | 0x100); snd_soc_write(codec, WM8510_CLOCK, reg | 0x100);
return 0; return 0;
} }
@ -363,24 +315,24 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) { switch (div_id) {
case WM8510_OPCLKDIV: case WM8510_OPCLKDIV:
reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf;
wm8510_write(codec, WM8510_GPIO, reg | div); snd_soc_write(codec, WM8510_GPIO, reg | div);
break; break;
case WM8510_MCLKDIV: case WM8510_MCLKDIV:
reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f; reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f;
wm8510_write(codec, WM8510_CLOCK, reg | div); snd_soc_write(codec, WM8510_CLOCK, reg | div);
break; break;
case WM8510_ADCCLK: case WM8510_ADCCLK:
reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7;
wm8510_write(codec, WM8510_ADC, reg | div); snd_soc_write(codec, WM8510_ADC, reg | div);
break; break;
case WM8510_DACCLK: case WM8510_DACCLK:
reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7;
wm8510_write(codec, WM8510_DAC, reg | div); snd_soc_write(codec, WM8510_DAC, reg | div);
break; break;
case WM8510_BCLKDIV: case WM8510_BCLKDIV:
reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3;
wm8510_write(codec, WM8510_CLOCK, reg | div); snd_soc_write(codec, WM8510_CLOCK, reg | div);
break; break;
default: default:
return -EINVAL; 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; struct snd_soc_codec *codec = codec_dai->codec;
u16 iface = 0; 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 */ /* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 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; return -EINVAL;
} }
wm8510_write(codec, WM8510_IFACE, iface); snd_soc_write(codec, WM8510_IFACE, iface);
wm8510_write(codec, WM8510_CLOCK, clk); snd_soc_write(codec, WM8510_CLOCK, clk);
return 0; 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_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
/* bit size */ /* bit size */
switch (params_format(params)) { switch (params_format(params)) {
@ -493,20 +445,20 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
break; break;
} }
wm8510_write(codec, WM8510_IFACE, iface); snd_soc_write(codec, WM8510_IFACE, iface);
wm8510_write(codec, WM8510_ADD, adn); snd_soc_write(codec, WM8510_ADD, adn);
return 0; return 0;
} }
static int wm8510_mute(struct snd_soc_dai *dai, int mute) static int wm8510_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; 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) if (mute)
wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40);
else else
wm8510_write(codec, WM8510_DAC, mute_reg); snd_soc_write(codec, WM8510_DAC, mute_reg);
return 0; 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, static int wm8510_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) 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) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
power1 |= 0x1; /* VMID 50k */ power1 |= 0x1; /* VMID 50k */
wm8510_write(codec, WM8510_POWER1, power1); snd_soc_write(codec, WM8510_POWER1, power1);
break; break;
case SND_SOC_BIAS_STANDBY: 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) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Initial cap charge at VMID 5k */ /* Initial cap charge at VMID 5k */
wm8510_write(codec, WM8510_POWER1, power1 | 0x3); snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
mdelay(100); mdelay(100);
} }
power1 |= 0x2; /* VMID 500k */ power1 |= 0x2; /* VMID 500k */
wm8510_write(codec, WM8510_POWER1, power1); snd_soc_write(codec, WM8510_POWER1, power1);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
wm8510_write(codec, WM8510_POWER1, 0); snd_soc_write(codec, WM8510_POWER1, 0);
wm8510_write(codec, WM8510_POWER2, 0); snd_soc_write(codec, WM8510_POWER2, 0);
wm8510_write(codec, WM8510_POWER3, 0); snd_soc_write(codec, WM8510_POWER3, 0);
break; break;
} }
@ -613,15 +565,14 @@ static int wm8510_resume(struct platform_device *pdev)
* initialise the WM8510 driver * initialise the WM8510 driver
* register the mixer and dsp interfaces with the kernel * register the mixer and dsp interfaces with the kernel
*/ */
static int wm8510_init(struct snd_soc_device *socdev) static int wm8510_init(struct snd_soc_device *socdev,
enum snd_soc_control_type control)
{ {
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0; int ret = 0;
codec->name = "WM8510"; codec->name = "WM8510";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8510_read_reg_cache;
codec->write = wm8510_write;
codec->set_bias_level = wm8510_set_bias_level; codec->set_bias_level = wm8510_set_bias_level;
codec->dai = &wm8510_dai; codec->dai = &wm8510_dai;
codec->num_dai = 1; codec->num_dai = 1;
@ -631,13 +582,20 @@ static int wm8510_init(struct snd_soc_device *socdev)
if (codec->reg_cache == NULL) if (codec->reg_cache == NULL)
return -ENOMEM; return -ENOMEM;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
ret);
goto err;
}
wm8510_reset(codec); wm8510_reset(codec);
/* register pcms */ /* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "wm8510: failed to create pcms\n"); printk(KERN_ERR "wm8510: failed to create pcms\n");
goto pcm_err; goto err;
} }
/* power on device */ /* power on device */
@ -656,7 +614,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
card_err: card_err:
snd_soc_free_pcms(socdev); snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev); snd_soc_dapm_free(socdev);
pcm_err: err:
kfree(codec->reg_cache); kfree(codec->reg_cache);
return ret; return ret;
} }
@ -679,7 +637,7 @@ static int wm8510_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, codec); i2c_set_clientdata(i2c, codec);
codec->control_data = i2c; codec->control_data = i2c;
ret = wm8510_init(socdev); ret = wm8510_init(socdev, SND_SOC_I2C);
if (ret < 0) if (ret < 0)
pr_err("failed to initialise WM8510\n"); pr_err("failed to initialise WM8510\n");
@ -759,7 +717,7 @@ static int __devinit wm8510_spi_probe(struct spi_device *spi)
codec->control_data = spi; codec->control_data = spi;
ret = wm8510_init(socdev); ret = wm8510_init(socdev, SND_SOC_SPI);
if (ret < 0) if (ret < 0)
dev_err(&spi->dev, "failed to initialise WM8510\n"); dev_err(&spi->dev, "failed to initialise WM8510\n");
@ -780,30 +738,6 @@ static struct spi_driver wm8510_spi_driver = {
.probe = wm8510_spi_probe, .probe = wm8510_spi_probe,
.remove = __devexit_p(wm8510_spi_remove), .remove = __devexit_p(wm8510_spi_remove),
}; };
static int wm8510_spi_write(struct spi_device *spi, const char *data, int len)
{
struct spi_transfer t;
struct spi_message m;
u8 msg[2];
if (len <= 0)
return 0;
msg[0] = data[0];
msg[1] = data[1];
spi_message_init(&m);
memset(&t, 0, (sizeof t));
t.tx_buf = &msg[0];
t.len = len;
spi_message_add_tail(&t, &m);
spi_sync(spi, &m);
return len;
}
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
static int wm8510_probe(struct platform_device *pdev) static int wm8510_probe(struct platform_device *pdev)
@ -828,13 +762,11 @@ static int wm8510_probe(struct platform_device *pdev)
wm8510_socdev = socdev; wm8510_socdev = socdev;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) { if (setup->i2c_address) {
codec->hw_write = (hw_write_t)i2c_master_send;
ret = wm8510_add_i2c_device(pdev, setup); ret = wm8510_add_i2c_device(pdev, setup);
} }
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
if (setup->spi) { if (setup->spi) {
codec->hw_write = (hw_write_t)wm8510_spi_write;
ret = spi_register_driver(&wm8510_spi_driver); ret = spi_register_driver(&wm8510_spi_driver);
if (ret != 0) if (ret != 0)
printk(KERN_ERR "can't add spi driver"); printk(KERN_ERR "can't add spi driver");

View File

@ -62,7 +62,7 @@ static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = {
0x0000, /* R8 - ZERO_DETECT */ 0x0000, /* R8 - ZERO_DETECT */
}; };
static int wm8523_volatile(unsigned int reg) static int wm8523_volatile_register(unsigned int reg)
{ {
switch (reg) { switch (reg) {
case WM8523_DEVICE_ID: case WM8523_DEVICE_ID:
@ -73,71 +73,9 @@ static int wm8523_volatile(unsigned int reg)
} }
} }
static int wm8523_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
struct wm8523_priv *wm8523 = codec->private_data;
u8 data[3];
BUG_ON(reg > WM8523_MAX_REGISTER);
data[0] = reg;
data[1] = (value >> 8) & 0x00ff;
data[2] = value & 0x00ff;
if (!wm8523_volatile(reg))
wm8523->reg_cache[reg] = value;
if (codec->hw_write(codec->control_data, data, 3) == 3)
return 0;
else
return -EIO;
}
static int wm8523_reset(struct snd_soc_codec *codec) static int wm8523_reset(struct snd_soc_codec *codec)
{ {
return wm8523_write(codec, WM8523_DEVICE_ID, 0); return snd_soc_write(codec, WM8523_DEVICE_ID, 0);
}
static unsigned int wm8523_read_hw(struct snd_soc_codec *codec, u8 reg)
{
struct i2c_msg xfer[2];
u16 data;
int ret;
struct i2c_client *i2c = codec->control_data;
/* Write register */
xfer[0].addr = i2c->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = i2c->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (u8 *)&data;
ret = i2c_transfer(i2c->adapter, xfer, 2);
if (ret != 2) {
dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret);
return 0;
}
return (data >> 8) | ((data & 0xff) << 8);
}
static unsigned int wm8523_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *reg_cache = codec->reg_cache;
BUG_ON(reg > WM8523_MAX_REGISTER);
if (wm8523_volatile(reg))
return wm8523_read_hw(codec, reg);
else
return reg_cache[reg];
} }
static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0); static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0);
@ -228,8 +166,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
struct wm8523_priv *wm8523 = codec->private_data; struct wm8523_priv *wm8523 = codec->private_data;
int i; int i;
u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
u16 aifctrl2 = wm8523_read(codec, WM8523_AIF_CTRL2); u16 aifctrl2 = snd_soc_read(codec, WM8523_AIF_CTRL2);
/* Find a supported LRCLK ratio */ /* Find a supported LRCLK ratio */
for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
@ -263,8 +201,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
break; break;
} }
wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1);
wm8523_write(codec, WM8523_AIF_CTRL2, aifctrl2); snd_soc_write(codec, WM8523_AIF_CTRL2, aifctrl2);
return 0; return 0;
} }
@ -322,7 +260,7 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt) unsigned int fmt)
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK | aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK |
WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK); WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK);
@ -372,7 +310,7 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1);
return 0; return 0;
} }
@ -411,7 +349,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
/* Sync back default/cached values */ /* Sync back default/cached values */
for (i = WM8523_AIF_CTRL1; for (i = WM8523_AIF_CTRL1;
i < WM8523_MAX_REGISTER; i++) i < WM8523_MAX_REGISTER; i++)
wm8523_write(codec, i, wm8523->reg_cache[i]); snd_soc_write(codec, i, wm8523->reg_cache[i]);
msleep(100); msleep(100);
@ -543,7 +481,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8523 = {
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523); EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
static int wm8523_register(struct wm8523_priv *wm8523) static int wm8523_register(struct wm8523_priv *wm8523,
enum snd_soc_control_type control)
{ {
int ret; int ret;
struct snd_soc_codec *codec = &wm8523->codec; struct snd_soc_codec *codec = &wm8523->codec;
@ -561,14 +500,13 @@ static int wm8523_register(struct wm8523_priv *wm8523)
codec->private_data = wm8523; codec->private_data = wm8523;
codec->name = "WM8523"; codec->name = "WM8523";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8523_read;
codec->write = wm8523_write;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm8523_set_bias_level; codec->set_bias_level = wm8523_set_bias_level;
codec->dai = &wm8523_dai; codec->dai = &wm8523_dai;
codec->num_dai = 1; codec->num_dai = 1;
codec->reg_cache_size = WM8523_REGISTER_COUNT; codec->reg_cache_size = WM8523_REGISTER_COUNT;
codec->reg_cache = &wm8523->reg_cache; codec->reg_cache = &wm8523->reg_cache;
codec->volatile_register = wm8523_volatile_register;
wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
wm8523->rate_constraint.count = wm8523->rate_constraint.count =
@ -576,6 +514,12 @@ static int wm8523_register(struct wm8523_priv *wm8523)
memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg));
ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
wm8523->supplies[i].supply = wm8523_supply_names[i]; wm8523->supplies[i].supply = wm8523_supply_names[i];
@ -593,7 +537,7 @@ static int wm8523_register(struct wm8523_priv *wm8523)
goto err_get; goto err_get;
} }
ret = wm8523_read(codec, WM8523_DEVICE_ID); ret = snd_soc_read(codec, WM8523_DEVICE_ID);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to read ID register\n"); dev_err(codec->dev, "Failed to read ID register\n");
goto err_enable; goto err_enable;
@ -604,7 +548,7 @@ static int wm8523_register(struct wm8523_priv *wm8523)
goto err_enable; goto err_enable;
} }
ret = wm8523_read(codec, WM8523_REVISION); ret = snd_soc_read(codec, WM8523_REVISION);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to read revision register\n"); dev_err(codec->dev, "Failed to read revision register\n");
goto err_enable; goto err_enable;
@ -684,7 +628,7 @@ static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
return wm8523_register(wm8523); return wm8523_register(wm8523, SND_SOC_I2C);
} }
static __devexit int wm8523_i2c_remove(struct i2c_client *client) static __devexit int wm8523_i2c_remove(struct i2c_client *client)

View File

@ -205,73 +205,6 @@ struct wm8580_priv {
struct pll_state b; struct pll_state b;
}; };
/*
* read wm8580 register cache
*/
static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
return cache[reg];
}
/*
* write wm8580 register cache
*/
static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
cache[reg] = value;
}
/*
* write to the WM8580 register space
*/
static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
/* Registers are 9 bits wide */
value &= 0x1ff;
switch (reg) {
case WM8580_RESET:
/* Uncached */
break;
default:
if (value == wm8580_read_reg_cache(codec, reg))
return 0;
}
/* data is
* D15..D9 WM8580 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8580_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
static inline unsigned int wm8580_read(struct snd_soc_codec *codec,
unsigned int reg)
{
switch (reg) {
default:
return wm8580_read_reg_cache(codec, reg);
}
}
static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
static int wm8580_out_vu(struct snd_kcontrol *kcontrol, static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
@ -280,25 +213,22 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *mc = struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
u16 *reg_cache = codec->reg_cache;
unsigned int reg = mc->reg; unsigned int reg = mc->reg;
unsigned int reg2 = mc->rreg; unsigned int reg2 = mc->rreg;
int ret; int ret;
u16 val;
/* Clear the register cache so we write without VU set */ /* Clear the register cache so we write without VU set */
wm8580_write_reg_cache(codec, reg, 0); reg_cache[reg] = 0;
wm8580_write_reg_cache(codec, reg2, 0); reg_cache[reg2] = 0;
ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Now write again with the volume update bit set */ /* Now write again with the volume update bit set */
val = wm8580_read_reg_cache(codec, reg); snd_soc_update_bits(codec, reg, 0x100, 0x100);
wm8580_write(codec, reg, val | 0x0100); snd_soc_update_bits(codec, reg2, 0x100, 0x100);
val = wm8580_read_reg_cache(codec, reg2);
wm8580_write(codec, reg2, val | 0x0100);
return 0; return 0;
} }
@ -521,27 +451,27 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai,
/* Always disable the PLL - it is not safe to leave it running /* Always disable the PLL - it is not safe to leave it running
* while reprogramming it. * while reprogramming it.
*/ */
reg = wm8580_read(codec, WM8580_PWRDN2); reg = snd_soc_read(codec, WM8580_PWRDN2);
wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask); snd_soc_write(codec, WM8580_PWRDN2, reg | pwr_mask);
if (!freq_in || !freq_out) if (!freq_in || !freq_out)
return 0; return 0;
wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff);
wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff);
wm8580_write(codec, WM8580_PLLA3 + offset, snd_soc_write(codec, WM8580_PLLA3 + offset,
(pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); (pll_div.k >> 18 & 0xf) | (pll_div.n << 4));
reg = wm8580_read(codec, WM8580_PLLA4 + offset); reg = snd_soc_read(codec, WM8580_PLLA4 + offset);
reg &= ~0x3f; reg &= ~0x3f;
reg |= pll_div.prescale | pll_div.postscale << 1 | reg |= pll_div.prescale | pll_div.postscale << 1 |
pll_div.freqmode << 3; pll_div.freqmode << 3;
wm8580_write(codec, WM8580_PLLA4 + offset, reg); snd_soc_write(codec, WM8580_PLLA4 + offset, reg);
/* All done, turn it on */ /* All done, turn it on */
reg = wm8580_read(codec, WM8580_PWRDN2); reg = snd_soc_read(codec, WM8580_PWRDN2);
wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); snd_soc_write(codec, WM8580_PWRDN2, reg & ~pwr_mask);
return 0; return 0;
} }
@ -556,7 +486,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id);
paifb &= ~WM8580_AIF_LENGTH_MASK; paifb &= ~WM8580_AIF_LENGTH_MASK;
/* bit size */ /* bit size */
@ -576,7 +506,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb); snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb);
return 0; return 0;
} }
@ -588,8 +518,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int aifb; unsigned int aifb;
int can_invert_lrclk; int can_invert_lrclk;
aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id); aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id);
aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id); aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id);
aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
@ -655,8 +585,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
return 0; return 0;
} }
@ -669,7 +599,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) { switch (div_id) {
case WM8580_MCLK: case WM8580_MCLK:
reg = wm8580_read(codec, WM8580_PLLB4); reg = snd_soc_read(codec, WM8580_PLLB4);
reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK; reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK;
switch (div) { switch (div) {
@ -691,11 +621,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
default: default:
return -EINVAL; return -EINVAL;
} }
wm8580_write(codec, WM8580_PLLB4, reg); snd_soc_write(codec, WM8580_PLLB4, reg);
break; break;
case WM8580_DAC_CLKSEL: case WM8580_DAC_CLKSEL:
reg = wm8580_read(codec, WM8580_CLKSEL); reg = snd_soc_read(codec, WM8580_CLKSEL);
reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK; reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
switch (div) { switch (div) {
@ -713,11 +643,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
default: default:
return -EINVAL; return -EINVAL;
} }
wm8580_write(codec, WM8580_CLKSEL, reg); snd_soc_write(codec, WM8580_CLKSEL, reg);
break; break;
case WM8580_CLKOUTSRC: case WM8580_CLKOUTSRC:
reg = wm8580_read(codec, WM8580_PLLB4); reg = snd_soc_read(codec, WM8580_PLLB4);
reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
switch (div) { switch (div) {
@ -739,7 +669,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
default: default:
return -EINVAL; return -EINVAL;
} }
wm8580_write(codec, WM8580_PLLB4, reg); snd_soc_write(codec, WM8580_PLLB4, reg);
break; break;
default: default:
@ -754,14 +684,14 @@ static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
unsigned int reg; unsigned int reg;
reg = wm8580_read(codec, WM8580_DAC_CONTROL5); reg = snd_soc_read(codec, WM8580_DAC_CONTROL5);
if (mute) if (mute)
reg |= WM8580_DAC_CONTROL5_MUTEALL; reg |= WM8580_DAC_CONTROL5_MUTEALL;
else else
reg &= ~WM8580_DAC_CONTROL5_MUTEALL; reg &= ~WM8580_DAC_CONTROL5_MUTEALL;
wm8580_write(codec, WM8580_DAC_CONTROL5, reg); snd_soc_write(codec, WM8580_DAC_CONTROL5, reg);
return 0; return 0;
} }
@ -778,20 +708,20 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Power up and get individual control of the DACs */ /* Power up and get individual control of the DACs */
reg = wm8580_read(codec, WM8580_PWRDN1); reg = snd_soc_read(codec, WM8580_PWRDN1);
reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD);
wm8580_write(codec, WM8580_PWRDN1, reg); snd_soc_write(codec, WM8580_PWRDN1, reg);
/* Make VMID high impedence */ /* Make VMID high impedence */
reg = wm8580_read(codec, WM8580_ADC_CONTROL1); reg = snd_soc_read(codec, WM8580_ADC_CONTROL1);
reg &= ~0x100; reg &= ~0x100;
wm8580_write(codec, WM8580_ADC_CONTROL1, reg); snd_soc_write(codec, WM8580_ADC_CONTROL1, reg);
} }
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
reg = wm8580_read(codec, WM8580_PWRDN1); reg = snd_soc_read(codec, WM8580_PWRDN1);
wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
break; break;
} }
codec->bias_level = level; codec->bias_level = level;
@ -902,7 +832,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = {
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
static int wm8580_register(struct wm8580_priv *wm8580) static int wm8580_register(struct wm8580_priv *wm8580,
enum snd_soc_control_type control)
{ {
int ret, i; int ret, i;
struct snd_soc_codec *codec = &wm8580->codec; struct snd_soc_codec *codec = &wm8580->codec;
@ -920,8 +851,6 @@ static int wm8580_register(struct wm8580_priv *wm8580)
codec->private_data = wm8580; codec->private_data = wm8580;
codec->name = "WM8580"; codec->name = "WM8580";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8580_read_reg_cache;
codec->write = wm8580_write;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm8580_set_bias_level; codec->set_bias_level = wm8580_set_bias_level;
codec->dai = wm8580_dai; codec->dai = wm8580_dai;
@ -931,6 +860,12 @@ static int wm8580_register(struct wm8580_priv *wm8580)
memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
wm8580->supplies[i].supply = wm8580_supply_names[i]; wm8580->supplies[i].supply = wm8580_supply_names[i];
@ -949,7 +884,7 @@ static int wm8580_register(struct wm8580_priv *wm8580)
} }
/* Get the codec into a known state */ /* Get the codec into a known state */
ret = wm8580_write(codec, WM8580_RESET, 0); ret = snd_soc_write(codec, WM8580_RESET, 0);
if (ret != 0) { if (ret != 0) {
dev_err(codec->dev, "Failed to reset codec: %d\n", ret); dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
goto err_regulator_enable; goto err_regulator_enable;
@ -1010,14 +945,13 @@ static int wm8580_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
codec = &wm8580->codec; codec = &wm8580->codec;
codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, wm8580); i2c_set_clientdata(i2c, wm8580);
codec->control_data = i2c; codec->control_data = i2c;
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
return wm8580_register(wm8580); return wm8580_register(wm8580, SND_SOC_I2C);
} }
static int wm8580_i2c_remove(struct i2c_client *client) static int wm8580_i2c_remove(struct i2c_client *client)

View File

@ -43,45 +43,6 @@ static const u16 wm8728_reg_defaults[] = {
0x100, 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 DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
static const struct snd_kcontrol_new wm8728_snd_controls[] = { 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) static int wm8728_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; 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) if (mute)
wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1);
else else
wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1);
return 0; 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_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; 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; dac &= ~0x18;
@ -155,7 +116,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
wm8728_write(codec, WM8728_DACCTL, dac); snd_soc_write(codec, WM8728_DACCTL, dac);
return 0; return 0;
} }
@ -164,7 +125,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt) unsigned int fmt)
{ {
struct snd_soc_codec *codec = codec_dai->codec; 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 /* Currently only I2S is supported by the driver, though the
* hardware is more flexible. * hardware is more flexible.
@ -204,7 +165,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8728_write(codec, WM8728_IFCTL, iface); snd_soc_write(codec, WM8728_IFCTL, iface);
return 0; return 0;
} }
@ -220,19 +181,19 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Power everything up... */ /* Power everything up... */
reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); reg = snd_soc_read(codec, WM8728_DACCTL);
wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
/* ..then sync in the register cache. */ /* ..then sync in the register cache. */
for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++)
wm8728_write(codec, i, snd_soc_write(codec, i,
wm8728_read_reg_cache(codec, i)); snd_soc_read(codec, i));
} }
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); reg = snd_soc_read(codec, WM8728_DACCTL);
wm8728_write(codec, WM8728_DACCTL, reg | 0x4); snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
break; break;
} }
codec->bias_level = level; codec->bias_level = level;
@ -287,15 +248,14 @@ static int wm8728_resume(struct platform_device *pdev)
* initialise the WM8728 driver * initialise the WM8728 driver
* register the mixer and dsp interfaces with the kernel * register the mixer and dsp interfaces with the kernel
*/ */
static int wm8728_init(struct snd_soc_device *socdev) static int wm8728_init(struct snd_soc_device *socdev,
enum snd_soc_control_type control)
{ {
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0; int ret = 0;
codec->name = "WM8728"; codec->name = "WM8728";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8728_read_reg_cache;
codec->write = wm8728_write;
codec->set_bias_level = wm8728_set_bias_level; codec->set_bias_level = wm8728_set_bias_level;
codec->dai = &wm8728_dai; codec->dai = &wm8728_dai;
codec->num_dai = 1; codec->num_dai = 1;
@ -307,11 +267,18 @@ static int wm8728_init(struct snd_soc_device *socdev)
if (codec->reg_cache == NULL) if (codec->reg_cache == NULL)
return -ENOMEM; return -ENOMEM;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
ret);
goto err;
}
/* register pcms */ /* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "wm8728: failed to create pcms\n"); printk(KERN_ERR "wm8728: failed to create pcms\n");
goto pcm_err; goto err;
} }
/* power on device */ /* power on device */
@ -331,7 +298,7 @@ static int wm8728_init(struct snd_soc_device *socdev)
card_err: card_err:
snd_soc_free_pcms(socdev); snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev); snd_soc_dapm_free(socdev);
pcm_err: err:
kfree(codec->reg_cache); kfree(codec->reg_cache);
return ret; return ret;
} }
@ -357,7 +324,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, codec); i2c_set_clientdata(i2c, codec);
codec->control_data = i2c; codec->control_data = i2c;
ret = wm8728_init(socdev); ret = wm8728_init(socdev, SND_SOC_I2C);
if (ret < 0) if (ret < 0)
pr_err("failed to initialise WM8728\n"); pr_err("failed to initialise WM8728\n");
@ -437,7 +404,7 @@ static int __devinit wm8728_spi_probe(struct spi_device *spi)
codec->control_data = spi; codec->control_data = spi;
ret = wm8728_init(socdev); ret = wm8728_init(socdev, SND_SOC_SPI);
if (ret < 0) if (ret < 0)
dev_err(&spi->dev, "failed to initialise WM8728\n"); dev_err(&spi->dev, "failed to initialise WM8728\n");
@ -458,30 +425,6 @@ static struct spi_driver wm8728_spi_driver = {
.probe = wm8728_spi_probe, .probe = wm8728_spi_probe,
.remove = __devexit_p(wm8728_spi_remove), .remove = __devexit_p(wm8728_spi_remove),
}; };
static int wm8728_spi_write(struct spi_device *spi, const char *data, int len)
{
struct spi_transfer t;
struct spi_message m;
u8 msg[2];
if (len <= 0)
return 0;
msg[0] = data[0];
msg[1] = data[1];
spi_message_init(&m);
memset(&t, 0, (sizeof t));
t.tx_buf = &msg[0];
t.len = len;
spi_message_add_tail(&t, &m);
spi_sync(spi, &m);
return len;
}
#endif /* CONFIG_SPI_MASTER */ #endif /* CONFIG_SPI_MASTER */
static int wm8728_probe(struct platform_device *pdev) static int wm8728_probe(struct platform_device *pdev)
@ -506,13 +449,11 @@ static int wm8728_probe(struct platform_device *pdev)
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) { if (setup->i2c_address) {
codec->hw_write = (hw_write_t)i2c_master_send;
ret = wm8728_add_i2c_device(pdev, setup); ret = wm8728_add_i2c_device(pdev, setup);
} }
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
if (setup->spi) { if (setup->spi) {
codec->hw_write = (hw_write_t)wm8728_spi_write;
ret = spi_register_driver(&wm8728_spi_driver); ret = spi_register_driver(&wm8728_spi_driver);
if (ret != 0) if (ret != 0)
printk(KERN_ERR "can't add spi driver"); printk(KERN_ERR "can't add spi driver");

View File

@ -51,60 +51,12 @@ static int wm8731_spi_write(struct spi_device *spi, const char *data, int len);
* There is no point in caching the reset register * There is no point in caching the reset register
*/ */
static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
0x0097, 0x0097, 0x0079, 0x0079, 0x0097, 0x0097, 0x0079, 0x0079,
0x000a, 0x0008, 0x009f, 0x000a, 0x000a, 0x0008, 0x009f, 0x000a,
0x0000, 0x0000 0x0000, 0x0000
}; };
/* #define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0)
* 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)
static const char *wm8731_input_select[] = {"Line In", "Mic"}; static const char *wm8731_input_select[] = {"Line In", "Mic"};
static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
@ -267,12 +219,12 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
struct wm8731_priv *wm8731 = codec->private_data; 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)); int i = get_coeff(wm8731->sysclk, params_rate(params));
u16 srate = (coeff_div[i].sr << 2) | u16 srate = (coeff_div[i].sr << 2) |
(coeff_div[i].bosr << 1) | coeff_div[i].usb; (coeff_div[i].bosr << 1) | coeff_div[i].usb;
wm8731_write(codec, WM8731_SRATE, srate); snd_soc_write(codec, WM8731_SRATE, srate);
/* bit size */ /* bit size */
switch (params_format(params)) { switch (params_format(params)) {
@ -286,7 +238,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
break; break;
} }
wm8731_write(codec, WM8731_IFACE, iface); snd_soc_write(codec, WM8731_IFACE, iface);
return 0; return 0;
} }
@ -298,7 +250,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
/* set active */ /* set active */
wm8731_write(codec, WM8731_ACTIVE, 0x0001); snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
return 0; return 0;
} }
@ -313,19 +265,19 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream,
/* deactivate */ /* deactivate */
if (!codec->active) { if (!codec->active) {
udelay(50); 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) static int wm8731_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; 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) if (mute)
wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8);
else else
wm8731_write(codec, WM8731_APDIGI, mute_reg); snd_soc_write(codec, WM8731_APDIGI, mute_reg);
return 0; return 0;
} }
@ -403,7 +355,7 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
} }
/* set iface */ /* set iface */
wm8731_write(codec, WM8731_IFACE, iface); snd_soc_write(codec, WM8731_IFACE, iface);
return 0; return 0;
} }
@ -419,12 +371,12 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
/* Clear PWROFF, gate CLKOUT, everything else as-is */ /* Clear PWROFF, gate CLKOUT, everything else as-is */
reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f;
wm8731_write(codec, WM8731_PWR, reg | 0x0040); snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
wm8731_write(codec, WM8731_ACTIVE, 0x0); snd_soc_write(codec, WM8731_ACTIVE, 0x0);
wm8731_write(codec, WM8731_PWR, 0xffff); snd_soc_write(codec, WM8731_PWR, 0xffff);
break; break;
} }
codec->bias_level = level; codec->bias_level = level;
@ -474,7 +426,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_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec; 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); wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0; return 0;
} }
@ -560,11 +512,11 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = {
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
static int wm8731_register(struct wm8731_priv *wm8731) static int wm8731_register(struct wm8731_priv *wm8731,
enum snd_soc_control_type control)
{ {
int ret; int ret;
struct snd_soc_codec *codec = &wm8731->codec; struct snd_soc_codec *codec = &wm8731->codec;
u16 reg;
if (wm8731_codec) { if (wm8731_codec) {
dev_err(codec->dev, "Another WM8731 is registered\n"); dev_err(codec->dev, "Another WM8731 is registered\n");
@ -579,8 +531,6 @@ static int wm8731_register(struct wm8731_priv *wm8731)
codec->private_data = wm8731; codec->private_data = wm8731;
codec->name = "WM8731"; codec->name = "WM8731";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8731_read_reg_cache;
codec->write = wm8731_write;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm8731_set_bias_level; codec->set_bias_level = wm8731_set_bias_level;
codec->dai = &wm8731_dai; codec->dai = &wm8731_dai;
@ -590,6 +540,12 @@ static int wm8731_register(struct wm8731_priv *wm8731)
memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
ret = wm8731_reset(codec); ret = wm8731_reset(codec);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret); dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
@ -601,18 +557,13 @@ static int wm8731_register(struct wm8731_priv *wm8731)
wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */ /* Latch the update bits */
reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0);
wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0);
reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0);
wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0);
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);
/* Disable bypass path by default */ /* Disable bypass path by default */
reg = wm8731_read_reg_cache(codec, WM8731_APANA); snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);
wm8731_write(codec, WM8731_APANA, reg & ~0x4);
wm8731_codec = codec; wm8731_codec = codec;
@ -648,30 +599,6 @@ static void wm8731_unregister(struct wm8731_priv *wm8731)
} }
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
{
struct spi_transfer t;
struct spi_message m;
u8 msg[2];
if (len <= 0)
return 0;
msg[0] = data[0];
msg[1] = data[1];
spi_message_init(&m);
memset(&t, 0, (sizeof t));
t.tx_buf = &msg[0];
t.len = len;
spi_message_add_tail(&t, &m);
spi_sync(spi, &m);
return len;
}
static int __devinit wm8731_spi_probe(struct spi_device *spi) static int __devinit wm8731_spi_probe(struct spi_device *spi)
{ {
struct snd_soc_codec *codec; struct snd_soc_codec *codec;
@ -683,12 +610,11 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi)
codec = &wm8731->codec; codec = &wm8731->codec;
codec->control_data = spi; codec->control_data = spi;
codec->hw_write = (hw_write_t)wm8731_spi_write;
codec->dev = &spi->dev; codec->dev = &spi->dev;
dev_set_drvdata(&spi->dev, wm8731); dev_set_drvdata(&spi->dev, wm8731);
return wm8731_register(wm8731); return wm8731_register(wm8731, SND_SOC_SPI);
} }
static int __devexit wm8731_spi_remove(struct spi_device *spi) static int __devexit wm8731_spi_remove(struct spi_device *spi)
@ -740,14 +666,13 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
codec = &wm8731->codec; codec = &wm8731->codec;
codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, wm8731); i2c_set_clientdata(i2c, wm8731);
codec->control_data = i2c; codec->control_data = i2c;
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
return wm8731_register(wm8731); return wm8731_register(wm8731, SND_SOC_I2C);
} }
static __devexit int wm8731_i2c_remove(struct i2c_client *client) static __devexit int wm8731_i2c_remove(struct i2c_client *client)

View File

@ -55,50 +55,7 @@ static const u16 wm8750_reg[] = {
0x0079, 0x0079, 0x0079, /* 40 */ 0x0079, 0x0079, 0x0079, /* 40 */
}; };
/* #define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0)
* read wm8750 register cache
*/
static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg > WM8750_CACHE_REGNUM)
return -1;
return cache[reg];
}
/*
* write wm8750 register cache
*/
static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg > WM8750_CACHE_REGNUM)
return;
cache[reg] = value;
}
static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8753 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8750_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0)
/* /*
* WM8750 Controls * WM8750 Controls
@ -594,7 +551,7 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8750_write(codec, WM8750_IFACE, iface); snd_soc_write(codec, WM8750_IFACE, iface);
return 0; return 0;
} }
@ -606,8 +563,8 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
struct wm8750_priv *wm8750 = codec->private_data; struct wm8750_priv *wm8750 = codec->private_data;
u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
int coeff = get_coeff(wm8750->sysclk, params_rate(params)); int coeff = get_coeff(wm8750->sysclk, params_rate(params));
/* bit size */ /* bit size */
@ -626,9 +583,9 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
} }
/* set iface & srate */ /* set iface & srate */
wm8750_write(codec, WM8750_IFACE, iface); snd_soc_write(codec, WM8750_IFACE, iface);
if (coeff >= 0) if (coeff >= 0)
wm8750_write(codec, WM8750_SRATE, srate | snd_soc_write(codec, WM8750_SRATE, srate |
(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
return 0; return 0;
@ -637,35 +594,35 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
static int wm8750_mute(struct snd_soc_dai *dai, int mute) static int wm8750_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; u16 mute_reg = snd_soc_read(codec, WM8750_ADCDAC) & 0xfff7;
if (mute) if (mute)
wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); snd_soc_write(codec, WM8750_ADCDAC, mute_reg | 0x8);
else else
wm8750_write(codec, WM8750_ADCDAC, mute_reg); snd_soc_write(codec, WM8750_ADCDAC, mute_reg);
return 0; return 0;
} }
static int wm8750_set_bias_level(struct snd_soc_codec *codec, static int wm8750_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; u16 pwr_reg = snd_soc_read(codec, WM8750_PWR1) & 0xfe3e;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/* set vmid to 50k and unmute dac */ /* set vmid to 50k and unmute dac */
wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* set vmid to 5k for quick power up */ /* set vmid to 5k for quick power up */
wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
/* mute dac and set vmid to 500k, enable VREF */ /* mute dac and set vmid to 500k, enable VREF */
wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
wm8750_write(codec, WM8750_PWR1, 0x0001); snd_soc_write(codec, WM8750_PWR1, 0x0001);
break; break;
} }
codec->bias_level = level; codec->bias_level = level;
@ -754,15 +711,14 @@ static int wm8750_resume(struct platform_device *pdev)
* initialise the WM8750 driver * initialise the WM8750 driver
* register the mixer and dsp interfaces with the kernel * register the mixer and dsp interfaces with the kernel
*/ */
static int wm8750_init(struct snd_soc_device *socdev) static int wm8750_init(struct snd_soc_device *socdev,
enum snd_soc_control_type control)
{ {
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
int reg, ret = 0; int reg, ret = 0;
codec->name = "WM8750"; codec->name = "WM8750";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8750_read_reg_cache;
codec->write = wm8750_write;
codec->set_bias_level = wm8750_set_bias_level; codec->set_bias_level = wm8750_set_bias_level;
codec->dai = &wm8750_dai; codec->dai = &wm8750_dai;
codec->num_dai = 1; codec->num_dai = 1;
@ -771,13 +727,23 @@ static int wm8750_init(struct snd_soc_device *socdev)
if (codec->reg_cache == NULL) if (codec->reg_cache == NULL)
return -ENOMEM; return -ENOMEM;
wm8750_reset(codec); ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
goto err;
}
ret = wm8750_reset(codec);
if (ret < 0) {
printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
goto err;
}
/* register pcms */ /* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "wm8750: failed to create pcms\n"); printk(KERN_ERR "wm8750: failed to create pcms\n");
goto pcm_err; goto err;
} }
/* charge output caps */ /* charge output caps */
@ -786,22 +752,22 @@ static int wm8750_init(struct snd_soc_device *socdev)
schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
/* set the update bits */ /* set the update bits */
reg = wm8750_read_reg_cache(codec, WM8750_LDAC); reg = snd_soc_read(codec, WM8750_LDAC);
wm8750_write(codec, WM8750_LDAC, reg | 0x0100); snd_soc_write(codec, WM8750_LDAC, reg | 0x0100);
reg = wm8750_read_reg_cache(codec, WM8750_RDAC); reg = snd_soc_read(codec, WM8750_RDAC);
wm8750_write(codec, WM8750_RDAC, reg | 0x0100); snd_soc_write(codec, WM8750_RDAC, reg | 0x0100);
reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); reg = snd_soc_read(codec, WM8750_LOUT1V);
wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); snd_soc_write(codec, WM8750_LOUT1V, reg | 0x0100);
reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); reg = snd_soc_read(codec, WM8750_ROUT1V);
wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); snd_soc_write(codec, WM8750_ROUT1V, reg | 0x0100);
reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); reg = snd_soc_read(codec, WM8750_LOUT2V);
wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); snd_soc_write(codec, WM8750_LOUT2V, reg | 0x0100);
reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); reg = snd_soc_read(codec, WM8750_ROUT2V);
wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); snd_soc_write(codec, WM8750_ROUT2V, reg | 0x0100);
reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); reg = snd_soc_read(codec, WM8750_LINVOL);
wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); snd_soc_write(codec, WM8750_LINVOL, reg | 0x0100);
reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); reg = snd_soc_read(codec, WM8750_RINVOL);
wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
snd_soc_add_controls(codec, wm8750_snd_controls, snd_soc_add_controls(codec, wm8750_snd_controls,
ARRAY_SIZE(wm8750_snd_controls)); ARRAY_SIZE(wm8750_snd_controls));
@ -816,7 +782,7 @@ static int wm8750_init(struct snd_soc_device *socdev)
card_err: card_err:
snd_soc_free_pcms(socdev); snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev); snd_soc_dapm_free(socdev);
pcm_err: err:
kfree(codec->reg_cache); kfree(codec->reg_cache);
return ret; return ret;
} }
@ -844,7 +810,7 @@ static int wm8750_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, codec); i2c_set_clientdata(i2c, codec);
codec->control_data = i2c; codec->control_data = i2c;
ret = wm8750_init(socdev); ret = wm8750_init(socdev, SND_SOC_I2C);
if (ret < 0) if (ret < 0)
pr_err("failed to initialise WM8750\n"); pr_err("failed to initialise WM8750\n");
@ -924,7 +890,7 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi)
codec->control_data = spi; codec->control_data = spi;
ret = wm8750_init(socdev); ret = wm8750_init(socdev, SND_SOC_SPI);
if (ret < 0) if (ret < 0)
dev_err(&spi->dev, "failed to initialise WM8750\n"); dev_err(&spi->dev, "failed to initialise WM8750\n");
@ -945,30 +911,6 @@ static struct spi_driver wm8750_spi_driver = {
.probe = wm8750_spi_probe, .probe = wm8750_spi_probe,
.remove = __devexit_p(wm8750_spi_remove), .remove = __devexit_p(wm8750_spi_remove),
}; };
static int wm8750_spi_write(struct spi_device *spi, const char *data, int len)
{
struct spi_transfer t;
struct spi_message m;
u8 msg[2];
if (len <= 0)
return 0;
msg[0] = data[0];
msg[1] = data[1];
spi_message_init(&m);
memset(&t, 0, (sizeof t));
t.tx_buf = &msg[0];
t.len = len;
spi_message_add_tail(&t, &m);
spi_sync(spi, &m);
return len;
}
#endif #endif
static int wm8750_probe(struct platform_device *pdev) static int wm8750_probe(struct platform_device *pdev)
@ -1002,13 +944,11 @@ static int wm8750_probe(struct platform_device *pdev)
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) { if (setup->i2c_address) {
codec->hw_write = (hw_write_t)i2c_master_send;
ret = wm8750_add_i2c_device(pdev, setup); ret = wm8750_add_i2c_device(pdev, setup);
} }
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
if (setup->spi) { if (setup->spi) {
codec->hw_write = (hw_write_t)wm8750_spi_write;
ret = spi_register_driver(&wm8750_spi_driver); ret = spi_register_driver(&wm8750_spi_driver);
if (ret != 0) if (ret != 0)
printk(KERN_ERR "can't add spi driver"); printk(KERN_ERR "can't add spi driver");

View File

@ -183,111 +183,20 @@ static const u16 wm8900_reg_defaults[WM8900_MAXREG] = {
/* Remaining registers all zero */ /* Remaining registers all zero */
}; };
/* static int wm8900_volatile_register(unsigned int reg)
* read wm8900 register cache
*/
static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg >= WM8900_MAXREG);
if (reg == WM8900_REG_ID)
return 0;
return cache[reg];
}
/*
* write wm8900 register cache
*/
static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg >= WM8900_MAXREG);
cache[reg] = value;
}
/*
* write to the WM8900 register space
*/
static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[3];
if (value == wm8900_read_reg_cache(codec, reg))
return 0;
/* data is
* D15..D9 WM8900 register offset
* D8...D0 register data
*/
data[0] = reg;
data[1] = value >> 8;
data[2] = value & 0x00ff;
wm8900_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 3) == 3)
return 0;
else
return -EIO;
}
/*
* Read from the wm8900.
*/
static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg)
{
struct i2c_msg xfer[2];
u16 data;
int ret;
struct i2c_client *client = codec->control_data;
BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1);
/* Write register */
xfer[0].addr = client->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (u8 *)&data;
ret = i2c_transfer(client->adapter, xfer, 2);
if (ret != 2) {
printk(KERN_CRIT "i2c_transfer returned %d\n", ret);
return 0;
}
return (data >> 8) | ((data & 0xff) << 8);
}
/*
* Read from the WM8900 register space. Most registers can't be read
* and are therefore supplied from cache.
*/
static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg)
{ {
switch (reg) { switch (reg) {
case WM8900_REG_ID: case WM8900_REG_ID:
return wm8900_chip_read(codec, reg); case WM8900_REG_POWER1:
return 1;
default: default:
return wm8900_read_reg_cache(codec, reg); return 0;
} }
} }
static void wm8900_reset(struct snd_soc_codec *codec) static void wm8900_reset(struct snd_soc_codec *codec)
{ {
wm8900_write(codec, WM8900_REG_RESET, 0); snd_soc_write(codec, WM8900_REG_RESET, 0);
memcpy(codec->reg_cache, wm8900_reg_defaults, memcpy(codec->reg_cache, wm8900_reg_defaults,
sizeof(codec->reg_cache)); sizeof(codec->reg_cache));
@ -297,14 +206,14 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1); u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1);
switch (event) { switch (event) {
case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_PRE_PMU:
/* Clamp headphone outputs */ /* Clamp headphone outputs */
hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP |
WM8900_REG_HPCTL1_HP_CLAMP_OP; WM8900_REG_HPCTL1_HP_CLAMP_OP;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
break; break;
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
@ -313,41 +222,41 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT |
WM8900_REG_HPCTL1_HP_SHORT2 | WM8900_REG_HPCTL1_HP_SHORT2 |
WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
msleep(400); msleep(400);
/* Enable the output stage */ /* Enable the output stage */
hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP;
hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
/* Remove the shorts */ /* Remove the shorts */
hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
break; break;
case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_PRE_PMD:
/* Short the output */ /* Short the output */
hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
/* Disable the output stage */ /* Disable the output stage */
hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
/* Clamp the outputs and power down input */ /* Clamp the outputs and power down input */
hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP |
WM8900_REG_HPCTL1_HP_CLAMP_OP; WM8900_REG_HPCTL1_HP_CLAMP_OP;
hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA;
wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1);
break; break;
case SND_SOC_DAPM_POST_PMD: case SND_SOC_DAPM_POST_PMD:
/* Disable everything */ /* Disable everything */
wm8900_write(codec, WM8900_REG_HPCTL1, 0); snd_soc_write(codec, WM8900_REG_HPCTL1, 0);
break; break;
default: default:
@ -723,7 +632,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
u16 reg; u16 reg;
reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
switch (params_format(params)) { switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
@ -741,17 +650,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
wm8900_write(codec, WM8900_REG_AUDIO1, reg); snd_soc_write(codec, WM8900_REG_AUDIO1, reg);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg = wm8900_read(codec, WM8900_REG_DACCTRL); reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
if (params_rate(params) <= 24000) if (params_rate(params) <= 24000)
reg |= WM8900_REG_DACCTRL_DAC_SB_FILT; reg |= WM8900_REG_DACCTRL_DAC_SB_FILT;
else else
reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT; reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT;
wm8900_write(codec, WM8900_REG_DACCTRL, reg); snd_soc_write(codec, WM8900_REG_DACCTRL, reg);
} }
return 0; return 0;
@ -845,18 +754,18 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
return 0; return 0;
/* The digital side should be disabled during any change. */ /* The digital side should be disabled during any change. */
reg = wm8900_read(codec, WM8900_REG_POWER1); reg = snd_soc_read(codec, WM8900_REG_POWER1);
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
reg & (~WM8900_REG_POWER1_FLL_ENA)); reg & (~WM8900_REG_POWER1_FLL_ENA));
/* Disable the FLL? */ /* Disable the FLL? */
if (!freq_in || !freq_out) { if (!freq_in || !freq_out) {
reg = wm8900_read(codec, WM8900_REG_CLOCKING1); reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
wm8900_write(codec, WM8900_REG_CLOCKING1, snd_soc_write(codec, WM8900_REG_CLOCKING1,
reg & (~WM8900_REG_CLOCKING1_MCLK_SRC)); reg & (~WM8900_REG_CLOCKING1_MCLK_SRC));
reg = wm8900_read(codec, WM8900_REG_FLLCTL1); reg = snd_soc_read(codec, WM8900_REG_FLLCTL1);
wm8900_write(codec, WM8900_REG_FLLCTL1, snd_soc_write(codec, WM8900_REG_FLLCTL1,
reg & (~WM8900_REG_FLLCTL1_OSC_ENA)); reg & (~WM8900_REG_FLLCTL1_OSC_ENA));
wm8900->fll_in = freq_in; wm8900->fll_in = freq_in;
@ -873,33 +782,33 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
/* The osclilator *MUST* be enabled before we enable the /* The osclilator *MUST* be enabled before we enable the
* digital circuit. */ * digital circuit. */
wm8900_write(codec, WM8900_REG_FLLCTL1, snd_soc_write(codec, WM8900_REG_FLLCTL1,
fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA); fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA);
wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); snd_soc_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5);
wm8900_write(codec, WM8900_REG_FLLCTL5, snd_soc_write(codec, WM8900_REG_FLLCTL5,
(fll_div.fllclk_div << 6) | (fll_div.n & 0x1f)); (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f));
if (fll_div.k) { if (fll_div.k) {
wm8900_write(codec, WM8900_REG_FLLCTL2, snd_soc_write(codec, WM8900_REG_FLLCTL2,
(fll_div.k >> 8) | 0x100); (fll_div.k >> 8) | 0x100);
wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); snd_soc_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff);
} else } else
wm8900_write(codec, WM8900_REG_FLLCTL2, 0); snd_soc_write(codec, WM8900_REG_FLLCTL2, 0);
if (fll_div.fll_slow_lock_ref) if (fll_div.fll_slow_lock_ref)
wm8900_write(codec, WM8900_REG_FLLCTL6, snd_soc_write(codec, WM8900_REG_FLLCTL6,
WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF); WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF);
else else
wm8900_write(codec, WM8900_REG_FLLCTL6, 0); snd_soc_write(codec, WM8900_REG_FLLCTL6, 0);
reg = wm8900_read(codec, WM8900_REG_POWER1); reg = snd_soc_read(codec, WM8900_REG_POWER1);
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
reg | WM8900_REG_POWER1_FLL_ENA); reg | WM8900_REG_POWER1_FLL_ENA);
reenable: reenable:
reg = wm8900_read(codec, WM8900_REG_CLOCKING1); reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
wm8900_write(codec, WM8900_REG_CLOCKING1, snd_soc_write(codec, WM8900_REG_CLOCKING1,
reg | WM8900_REG_CLOCKING1_MCLK_SRC); reg | WM8900_REG_CLOCKING1_MCLK_SRC);
return 0; return 0;
@ -919,38 +828,38 @@ static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) { switch (div_id) {
case WM8900_BCLK_DIV: case WM8900_BCLK_DIV:
reg = wm8900_read(codec, WM8900_REG_CLOCKING1); reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
wm8900_write(codec, WM8900_REG_CLOCKING1, snd_soc_write(codec, WM8900_REG_CLOCKING1,
div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK)); div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK));
break; break;
case WM8900_OPCLK_DIV: case WM8900_OPCLK_DIV:
reg = wm8900_read(codec, WM8900_REG_CLOCKING1); reg = snd_soc_read(codec, WM8900_REG_CLOCKING1);
wm8900_write(codec, WM8900_REG_CLOCKING1, snd_soc_write(codec, WM8900_REG_CLOCKING1,
div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK)); div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK));
break; break;
case WM8900_DAC_LRCLK: case WM8900_DAC_LRCLK:
reg = wm8900_read(codec, WM8900_REG_AUDIO4); reg = snd_soc_read(codec, WM8900_REG_AUDIO4);
wm8900_write(codec, WM8900_REG_AUDIO4, snd_soc_write(codec, WM8900_REG_AUDIO4,
div | (reg & WM8900_LRC_MASK)); div | (reg & WM8900_LRC_MASK));
break; break;
case WM8900_ADC_LRCLK: case WM8900_ADC_LRCLK:
reg = wm8900_read(codec, WM8900_REG_AUDIO3); reg = snd_soc_read(codec, WM8900_REG_AUDIO3);
wm8900_write(codec, WM8900_REG_AUDIO3, snd_soc_write(codec, WM8900_REG_AUDIO3,
div | (reg & WM8900_LRC_MASK)); div | (reg & WM8900_LRC_MASK));
break; break;
case WM8900_DAC_CLKDIV: case WM8900_DAC_CLKDIV:
reg = wm8900_read(codec, WM8900_REG_CLOCKING2); reg = snd_soc_read(codec, WM8900_REG_CLOCKING2);
wm8900_write(codec, WM8900_REG_CLOCKING2, snd_soc_write(codec, WM8900_REG_CLOCKING2,
div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV)); div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV));
break; break;
case WM8900_ADC_CLKDIV: case WM8900_ADC_CLKDIV:
reg = wm8900_read(codec, WM8900_REG_CLOCKING2); reg = snd_soc_read(codec, WM8900_REG_CLOCKING2);
wm8900_write(codec, WM8900_REG_CLOCKING2, snd_soc_write(codec, WM8900_REG_CLOCKING2,
div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV)); div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV));
break; break;
case WM8900_LRCLK_MODE: case WM8900_LRCLK_MODE:
reg = wm8900_read(codec, WM8900_REG_DACCTRL); reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
wm8900_write(codec, WM8900_REG_DACCTRL, snd_soc_write(codec, WM8900_REG_DACCTRL,
div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE)); div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE));
break; break;
default: default:
@ -967,10 +876,10 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
unsigned int clocking1, aif1, aif3, aif4; unsigned int clocking1, aif1, aif3, aif4;
clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1); clocking1 = snd_soc_read(codec, WM8900_REG_CLOCKING1);
aif1 = wm8900_read(codec, WM8900_REG_AUDIO1); aif1 = snd_soc_read(codec, WM8900_REG_AUDIO1);
aif3 = wm8900_read(codec, WM8900_REG_AUDIO3); aif3 = snd_soc_read(codec, WM8900_REG_AUDIO3);
aif4 = wm8900_read(codec, WM8900_REG_AUDIO4); aif4 = snd_soc_read(codec, WM8900_REG_AUDIO4);
/* set master/slave audio interface */ /* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@ -1066,10 +975,10 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1); snd_soc_write(codec, WM8900_REG_CLOCKING1, clocking1);
wm8900_write(codec, WM8900_REG_AUDIO1, aif1); snd_soc_write(codec, WM8900_REG_AUDIO1, aif1);
wm8900_write(codec, WM8900_REG_AUDIO3, aif3); snd_soc_write(codec, WM8900_REG_AUDIO3, aif3);
wm8900_write(codec, WM8900_REG_AUDIO4, aif4); snd_soc_write(codec, WM8900_REG_AUDIO4, aif4);
return 0; return 0;
} }
@ -1079,14 +988,14 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 reg; u16 reg;
reg = wm8900_read(codec, WM8900_REG_DACCTRL); reg = snd_soc_read(codec, WM8900_REG_DACCTRL);
if (mute) if (mute)
reg |= WM8900_REG_DACCTRL_MUTE; reg |= WM8900_REG_DACCTRL_MUTE;
else else
reg &= ~WM8900_REG_DACCTRL_MUTE; reg &= ~WM8900_REG_DACCTRL_MUTE;
wm8900_write(codec, WM8900_REG_DACCTRL, reg); snd_soc_write(codec, WM8900_REG_DACCTRL, reg);
return 0; return 0;
} }
@ -1135,11 +1044,11 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/* Enable thermal shutdown */ /* Enable thermal shutdown */
reg = wm8900_read(codec, WM8900_REG_GPIO); reg = snd_soc_read(codec, WM8900_REG_GPIO);
wm8900_write(codec, WM8900_REG_GPIO, snd_soc_write(codec, WM8900_REG_GPIO,
reg | WM8900_REG_GPIO_TEMP_ENA); reg | WM8900_REG_GPIO_TEMP_ENA);
reg = wm8900_read(codec, WM8900_REG_ADDCTL); reg = snd_soc_read(codec, WM8900_REG_ADDCTL);
wm8900_write(codec, WM8900_REG_ADDCTL, snd_soc_write(codec, WM8900_REG_ADDCTL,
reg | WM8900_REG_ADDCTL_TEMP_SD); reg | WM8900_REG_ADDCTL_TEMP_SD);
break; break;
@ -1150,69 +1059,69 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
/* Charge capacitors if initial power up */ /* Charge capacitors if initial power up */
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* STARTUP_BIAS_ENA on */ /* STARTUP_BIAS_ENA on */
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
WM8900_REG_POWER1_STARTUP_BIAS_ENA); WM8900_REG_POWER1_STARTUP_BIAS_ENA);
/* Startup bias mode */ /* Startup bias mode */
wm8900_write(codec, WM8900_REG_ADDCTL, snd_soc_write(codec, WM8900_REG_ADDCTL,
WM8900_REG_ADDCTL_BIAS_SRC | WM8900_REG_ADDCTL_BIAS_SRC |
WM8900_REG_ADDCTL_VMID_SOFTST); WM8900_REG_ADDCTL_VMID_SOFTST);
/* VMID 2x50k */ /* VMID 2x50k */
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1); WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1);
/* Allow capacitors to charge */ /* Allow capacitors to charge */
schedule_timeout_interruptible(msecs_to_jiffies(400)); schedule_timeout_interruptible(msecs_to_jiffies(400));
/* Enable bias */ /* Enable bias */
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
WM8900_REG_POWER1_STARTUP_BIAS_ENA | WM8900_REG_POWER1_STARTUP_BIAS_ENA |
WM8900_REG_POWER1_BIAS_ENA | 0x1); WM8900_REG_POWER1_BIAS_ENA | 0x1);
wm8900_write(codec, WM8900_REG_ADDCTL, 0); snd_soc_write(codec, WM8900_REG_ADDCTL, 0);
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
WM8900_REG_POWER1_BIAS_ENA | 0x1); WM8900_REG_POWER1_BIAS_ENA | 0x1);
} }
reg = wm8900_read(codec, WM8900_REG_POWER1); reg = snd_soc_read(codec, WM8900_REG_POWER1);
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
(reg & WM8900_REG_POWER1_FLL_ENA) | (reg & WM8900_REG_POWER1_FLL_ENA) |
WM8900_REG_POWER1_BIAS_ENA | 0x1); WM8900_REG_POWER1_BIAS_ENA | 0x1);
wm8900_write(codec, WM8900_REG_POWER2, snd_soc_write(codec, WM8900_REG_POWER2,
WM8900_REG_POWER2_SYSCLK_ENA); WM8900_REG_POWER2_SYSCLK_ENA);
wm8900_write(codec, WM8900_REG_POWER3, 0); snd_soc_write(codec, WM8900_REG_POWER3, 0);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* Startup bias enable */ /* Startup bias enable */
reg = wm8900_read(codec, WM8900_REG_POWER1); reg = snd_soc_read(codec, WM8900_REG_POWER1);
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA); reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA);
wm8900_write(codec, WM8900_REG_ADDCTL, snd_soc_write(codec, WM8900_REG_ADDCTL,
WM8900_REG_ADDCTL_BIAS_SRC | WM8900_REG_ADDCTL_BIAS_SRC |
WM8900_REG_ADDCTL_VMID_SOFTST); WM8900_REG_ADDCTL_VMID_SOFTST);
/* Discharge caps */ /* Discharge caps */
wm8900_write(codec, WM8900_REG_POWER1, snd_soc_write(codec, WM8900_REG_POWER1,
WM8900_REG_POWER1_STARTUP_BIAS_ENA); WM8900_REG_POWER1_STARTUP_BIAS_ENA);
schedule_timeout_interruptible(msecs_to_jiffies(500)); schedule_timeout_interruptible(msecs_to_jiffies(500));
/* Remove clamp */ /* Remove clamp */
wm8900_write(codec, WM8900_REG_HPCTL1, 0); snd_soc_write(codec, WM8900_REG_HPCTL1, 0);
/* Power down */ /* Power down */
wm8900_write(codec, WM8900_REG_ADDCTL, 0); snd_soc_write(codec, WM8900_REG_ADDCTL, 0);
wm8900_write(codec, WM8900_REG_POWER1, 0); snd_soc_write(codec, WM8900_REG_POWER1, 0);
wm8900_write(codec, WM8900_REG_POWER2, 0); snd_soc_write(codec, WM8900_REG_POWER2, 0);
wm8900_write(codec, WM8900_REG_POWER3, 0); snd_soc_write(codec, WM8900_REG_POWER3, 0);
/* Need to let things settle before stopping the clock /* Need to let things settle before stopping the clock
* to ensure that restart works, see "Stopping the * to ensure that restart works, see "Stopping the
* master clock" in the datasheet. */ * master clock" in the datasheet. */
schedule_timeout_interruptible(msecs_to_jiffies(1)); schedule_timeout_interruptible(msecs_to_jiffies(1));
wm8900_write(codec, WM8900_REG_POWER2, snd_soc_write(codec, WM8900_REG_POWER2,
WM8900_REG_POWER2_SYSCLK_ENA); WM8900_REG_POWER2_SYSCLK_ENA);
break; break;
} }
@ -1275,7 +1184,7 @@ static int wm8900_resume(struct platform_device *pdev)
if (cache) { if (cache) {
for (i = 0; i < WM8900_MAXREG; i++) for (i = 0; i < WM8900_MAXREG; i++)
wm8900_write(codec, i, cache[i]); snd_soc_write(codec, i, cache[i]);
kfree(cache); kfree(cache);
} else } else
dev_err(&pdev->dev, "Unable to allocate register cache\n"); dev_err(&pdev->dev, "Unable to allocate register cache\n");
@ -1308,16 +1217,20 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
codec->name = "WM8900"; codec->name = "WM8900";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8900_read;
codec->write = wm8900_write;
codec->dai = &wm8900_dai; codec->dai = &wm8900_dai;
codec->num_dai = 1; codec->num_dai = 1;
codec->hw_write = (hw_write_t)i2c_master_send;
codec->control_data = i2c; codec->control_data = i2c;
codec->set_bias_level = wm8900_set_bias_level; codec->set_bias_level = wm8900_set_bias_level;
codec->volatile_register = wm8900_volatile_register;
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
reg = wm8900_read(codec, WM8900_REG_ID); ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
reg = snd_soc_read(codec, WM8900_REG_ID);
if (reg != 0x8900) { if (reg != 0x8900) {
dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg);
ret = -ENODEV; ret = -ENODEV;
@ -1325,7 +1238,7 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
} }
/* Read back from the chip */ /* Read back from the chip */
reg = wm8900_chip_read(codec, WM8900_REG_POWER1); reg = snd_soc_read(codec, WM8900_REG_POWER1);
reg = (reg >> 12) & 0xf; reg = (reg >> 12) & 0xf;
dev_info(&i2c->dev, "WM8900 revision %d\n", reg); dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
@ -1335,29 +1248,29 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the volume update bits */ /* Latch the volume update bits */
wm8900_write(codec, WM8900_REG_LINVOL, snd_soc_write(codec, WM8900_REG_LINVOL,
wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); snd_soc_read(codec, WM8900_REG_LINVOL) | 0x100);
wm8900_write(codec, WM8900_REG_RINVOL, snd_soc_write(codec, WM8900_REG_RINVOL,
wm8900_read(codec, WM8900_REG_RINVOL) | 0x100); snd_soc_read(codec, WM8900_REG_RINVOL) | 0x100);
wm8900_write(codec, WM8900_REG_LOUT1CTL, snd_soc_write(codec, WM8900_REG_LOUT1CTL,
wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100); snd_soc_read(codec, WM8900_REG_LOUT1CTL) | 0x100);
wm8900_write(codec, WM8900_REG_ROUT1CTL, snd_soc_write(codec, WM8900_REG_ROUT1CTL,
wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100); snd_soc_read(codec, WM8900_REG_ROUT1CTL) | 0x100);
wm8900_write(codec, WM8900_REG_LOUT2CTL, snd_soc_write(codec, WM8900_REG_LOUT2CTL,
wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100); snd_soc_read(codec, WM8900_REG_LOUT2CTL) | 0x100);
wm8900_write(codec, WM8900_REG_ROUT2CTL, snd_soc_write(codec, WM8900_REG_ROUT2CTL,
wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100); snd_soc_read(codec, WM8900_REG_ROUT2CTL) | 0x100);
wm8900_write(codec, WM8900_REG_LDAC_DV, snd_soc_write(codec, WM8900_REG_LDAC_DV,
wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100); snd_soc_read(codec, WM8900_REG_LDAC_DV) | 0x100);
wm8900_write(codec, WM8900_REG_RDAC_DV, snd_soc_write(codec, WM8900_REG_RDAC_DV,
wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100); snd_soc_read(codec, WM8900_REG_RDAC_DV) | 0x100);
wm8900_write(codec, WM8900_REG_LADC_DV, snd_soc_write(codec, WM8900_REG_LADC_DV,
wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100); snd_soc_read(codec, WM8900_REG_LADC_DV) | 0x100);
wm8900_write(codec, WM8900_REG_RADC_DV, snd_soc_write(codec, WM8900_REG_RADC_DV,
wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100); snd_soc_read(codec, WM8900_REG_RADC_DV) | 0x100);
/* Set the DAC and mixer output bias */ /* Set the DAC and mixer output bias */
wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
wm8900_dai.dev = &i2c->dev; wm8900_dai.dev = &i2c->dev;

View File

@ -225,94 +225,18 @@ struct wm8903_priv {
struct snd_pcm_substream *slave_substream; struct snd_pcm_substream *slave_substream;
}; };
static int wm8903_volatile_register(unsigned int reg)
static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
return cache[reg];
}
static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg)
{
struct i2c_msg xfer[2];
u16 data;
int ret;
struct i2c_client *client = codec->control_data;
/* Write register */
xfer[0].addr = client->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (u8 *)&data;
ret = i2c_transfer(client->adapter, xfer, 2);
if (ret != 2) {
pr_err("i2c_transfer returned %d\n", ret);
return 0;
}
return (data >> 8) | ((data & 0xff) << 8);
}
static unsigned int wm8903_read(struct snd_soc_codec *codec,
unsigned int reg)
{ {
switch (reg) { switch (reg) {
case WM8903_SW_RESET_AND_ID: case WM8903_SW_RESET_AND_ID:
case WM8903_REVISION_NUMBER: case WM8903_REVISION_NUMBER:
case WM8903_INTERRUPT_STATUS_1: case WM8903_INTERRUPT_STATUS_1:
case WM8903_WRITE_SEQUENCER_4: case WM8903_WRITE_SEQUENCER_4:
return wm8903_hw_read(codec, reg); return 1;
default: default:
return wm8903_read_reg_cache(codec, reg);
}
}
static void wm8903_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults));
switch (reg) {
case WM8903_SW_RESET_AND_ID:
case WM8903_REVISION_NUMBER:
break;
default:
cache[reg] = value;
break;
}
}
static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[3];
wm8903_write_reg_cache(codec, reg, value);
/* Data format is 1 byte of address followed by 2 bytes of data */
data[0] = reg;
data[1] = (value >> 8) & 0xff;
data[2] = value & 0xff;
if (codec->hw_write(codec->control_data, data, 3) == 2)
return 0; return 0;
else }
return -EIO;
} }
static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
@ -323,13 +247,13 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
BUG_ON(start > 48); BUG_ON(start > 48);
/* Enable the sequencer */ /* Enable the sequencer */
reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0); reg[0] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_0);
reg[0] |= WM8903_WSEQ_ENA; reg[0] |= WM8903_WSEQ_ENA;
wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
dev_dbg(&i2c->dev, "Starting sequence at %d\n", start); dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
wm8903_write(codec, WM8903_WRITE_SEQUENCER_3, snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3,
start | WM8903_WSEQ_START); start | WM8903_WSEQ_START);
/* Wait for it to complete. If we have the interrupt wired up then /* Wait for it to complete. If we have the interrupt wired up then
@ -339,13 +263,13 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
do { do {
msleep(10); msleep(10);
reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4); reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
} while (reg[4] & WM8903_WSEQ_BUSY); } while (reg[4] & WM8903_WSEQ_BUSY);
dev_dbg(&i2c->dev, "Sequence complete\n"); dev_dbg(&i2c->dev, "Sequence complete\n");
/* Disable the sequencer again */ /* Disable the sequencer again */
wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
reg[0] & ~WM8903_WSEQ_ENA); reg[0] & ~WM8903_WSEQ_ENA);
return 0; return 0;
@ -357,12 +281,12 @@ static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache)
/* There really ought to be something better we can do here :/ */ /* There really ought to be something better we can do here :/ */
for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++) for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
cache[i] = wm8903_hw_read(codec, i); cache[i] = codec->hw_read(codec, i);
} }
static void wm8903_reset(struct snd_soc_codec *codec) static void wm8903_reset(struct snd_soc_codec *codec)
{ {
wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0);
memcpy(codec->reg_cache, wm8903_reg_defaults, memcpy(codec->reg_cache, wm8903_reg_defaults,
sizeof(wm8903_reg_defaults)); sizeof(wm8903_reg_defaults));
} }
@ -423,52 +347,52 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
} }
if (event & SND_SOC_DAPM_PRE_PMU) { if (event & SND_SOC_DAPM_PRE_PMU) {
val = wm8903_read(codec, reg); val = snd_soc_read(codec, reg);
/* Short the output */ /* Short the output */
val &= ~(WM8903_OUTPUT_SHORT << shift); val &= ~(WM8903_OUTPUT_SHORT << shift);
wm8903_write(codec, reg, val); snd_soc_write(codec, reg, val);
} }
if (event & SND_SOC_DAPM_POST_PMU) { if (event & SND_SOC_DAPM_POST_PMU) {
val = wm8903_read(codec, reg); val = snd_soc_read(codec, reg);
val |= (WM8903_OUTPUT_IN << shift); val |= (WM8903_OUTPUT_IN << shift);
wm8903_write(codec, reg, val); snd_soc_write(codec, reg, val);
val |= (WM8903_OUTPUT_INT << shift); val |= (WM8903_OUTPUT_INT << shift);
wm8903_write(codec, reg, val); snd_soc_write(codec, reg, val);
/* Turn on the output ENA_OUTP */ /* Turn on the output ENA_OUTP */
val |= (WM8903_OUTPUT_OUT << shift); val |= (WM8903_OUTPUT_OUT << shift);
wm8903_write(codec, reg, val); snd_soc_write(codec, reg, val);
/* Enable the DC servo */ /* Enable the DC servo */
dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0);
dcs_reg |= dcs_bit; dcs_reg |= dcs_bit;
wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg);
/* Remove the short */ /* Remove the short */
val |= (WM8903_OUTPUT_SHORT << shift); val |= (WM8903_OUTPUT_SHORT << shift);
wm8903_write(codec, reg, val); snd_soc_write(codec, reg, val);
} }
if (event & SND_SOC_DAPM_PRE_PMD) { if (event & SND_SOC_DAPM_PRE_PMD) {
val = wm8903_read(codec, reg); val = snd_soc_read(codec, reg);
/* Short the output */ /* Short the output */
val &= ~(WM8903_OUTPUT_SHORT << shift); val &= ~(WM8903_OUTPUT_SHORT << shift);
wm8903_write(codec, reg, val); snd_soc_write(codec, reg, val);
/* Disable the DC servo */ /* Disable the DC servo */
dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0);
dcs_reg &= ~dcs_bit; dcs_reg &= ~dcs_bit;
wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg);
/* Then disable the intermediate and output stages */ /* Then disable the intermediate and output stages */
val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
WM8903_OUTPUT_IN) << shift); WM8903_OUTPUT_IN) << shift);
wm8903_write(codec, reg, val); snd_soc_write(codec, reg, val);
} }
return 0; return 0;
@ -492,13 +416,13 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
u16 reg; u16 reg;
int ret; int ret;
reg = wm8903_read(codec, WM8903_CLASS_W_0); reg = snd_soc_read(codec, WM8903_CLASS_W_0);
/* Turn it off if we're about to enable bypass */ /* Turn it off if we're about to enable bypass */
if (ucontrol->value.integer.value[0]) { if (ucontrol->value.integer.value[0]) {
if (wm8903->class_w_users == 0) { if (wm8903->class_w_users == 0) {
dev_dbg(&i2c->dev, "Disabling Class W\n"); dev_dbg(&i2c->dev, "Disabling Class W\n");
wm8903_write(codec, WM8903_CLASS_W_0, reg & snd_soc_write(codec, WM8903_CLASS_W_0, reg &
~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V)); ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
} }
wm8903->class_w_users++; wm8903->class_w_users++;
@ -511,7 +435,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
if (!ucontrol->value.integer.value[0]) { if (!ucontrol->value.integer.value[0]) {
if (wm8903->class_w_users == 1) { if (wm8903->class_w_users == 1) {
dev_dbg(&i2c->dev, "Enabling Class W\n"); dev_dbg(&i2c->dev, "Enabling Class W\n");
wm8903_write(codec, WM8903_CLASS_W_0, reg | snd_soc_write(codec, WM8903_CLASS_W_0, reg |
WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
} }
wm8903->class_w_users--; wm8903->class_w_users--;
@ -1009,55 +933,55 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0);
reg &= ~(WM8903_VMID_RES_MASK); reg &= ~(WM8903_VMID_RES_MASK);
reg |= WM8903_VMID_RES_50K; reg |= WM8903_VMID_RES_50K;
wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
wm8903_write(codec, WM8903_CLOCK_RATES_2, snd_soc_write(codec, WM8903_CLOCK_RATES_2,
WM8903_CLK_SYS_ENA); WM8903_CLK_SYS_ENA);
/* Change DC servo dither level in startup sequence */ /* Change DC servo dither level in startup sequence */
wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11);
wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); snd_soc_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257);
wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); snd_soc_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2);
wm8903_run_sequence(codec, 0); wm8903_run_sequence(codec, 0);
wm8903_sync_reg_cache(codec, codec->reg_cache); wm8903_sync_reg_cache(codec, codec->reg_cache);
/* Enable low impedence charge pump output */ /* Enable low impedence charge pump output */
reg = wm8903_read(codec, reg = snd_soc_read(codec,
WM8903_CONTROL_INTERFACE_TEST_1); WM8903_CONTROL_INTERFACE_TEST_1);
wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
reg | WM8903_TEST_KEY); reg | WM8903_TEST_KEY);
reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1); reg2 = snd_soc_read(codec, WM8903_CHARGE_PUMP_TEST_1);
wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1, snd_soc_write(codec, WM8903_CHARGE_PUMP_TEST_1,
reg2 | WM8903_CP_SW_KELVIN_MODE_MASK); reg2 | WM8903_CP_SW_KELVIN_MODE_MASK);
wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
reg); reg);
/* By default no bypass paths are enabled so /* By default no bypass paths are enabled so
* enable Class W support. * enable Class W support.
*/ */
dev_dbg(&i2c->dev, "Enabling Class W\n"); dev_dbg(&i2c->dev, "Enabling Class W\n");
wm8903_write(codec, WM8903_CLASS_W_0, reg | snd_soc_write(codec, WM8903_CLASS_W_0, reg |
WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
} }
reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0);
reg &= ~(WM8903_VMID_RES_MASK); reg &= ~(WM8903_VMID_RES_MASK);
reg |= WM8903_VMID_RES_250K; reg |= WM8903_VMID_RES_250K;
wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
wm8903_run_sequence(codec, 32); wm8903_run_sequence(codec, 32);
reg = wm8903_read(codec, WM8903_CLOCK_RATES_2); reg = snd_soc_read(codec, WM8903_CLOCK_RATES_2);
reg &= ~WM8903_CLK_SYS_ENA; reg &= ~WM8903_CLK_SYS_ENA;
wm8903_write(codec, WM8903_CLOCK_RATES_2, reg); snd_soc_write(codec, WM8903_CLOCK_RATES_2, reg);
break; break;
} }
@ -1081,7 +1005,7 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt) unsigned int fmt)
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1);
aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK | aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK |
WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV); WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
@ -1159,7 +1083,7 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
return 0; return 0;
} }
@ -1169,14 +1093,14 @@ static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute)
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 reg; u16 reg;
reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1); reg = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
if (mute) if (mute)
reg |= WM8903_DAC_MUTE; reg |= WM8903_DAC_MUTE;
else else
reg &= ~WM8903_DAC_MUTE; reg &= ~WM8903_DAC_MUTE;
wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg); snd_soc_write(codec, WM8903_DAC_DIGITAL_1, reg);
return 0; return 0;
} }
@ -1366,12 +1290,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
int cur_val; int cur_val;
int clk_sys; int clk_sys;
u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1);
u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2); u16 aif2 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_2);
u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); u16 aif3 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_3);
u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); u16 clock0 = snd_soc_read(codec, WM8903_CLOCK_RATES_0);
u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); u16 clock1 = snd_soc_read(codec, WM8903_CLOCK_RATES_1);
u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1); u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
if (substream == wm8903->slave_substream) { if (substream == wm8903->slave_substream) {
dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
@ -1503,12 +1427,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
aif2 |= bclk_divs[bclk_div].div; aif2 |= bclk_divs[bclk_div].div;
aif3 |= bclk / fs; aif3 |= bclk / fs;
wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0); snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0);
wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1); snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1);
wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); snd_soc_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); snd_soc_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1); snd_soc_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1);
return 0; return 0;
} }
@ -1593,7 +1517,7 @@ static int wm8903_resume(struct platform_device *pdev)
if (tmp_cache) { if (tmp_cache) {
for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
if (tmp_cache[i] != reg_cache[i]) if (tmp_cache[i] != reg_cache[i])
wm8903_write(codec, i, tmp_cache[i]); snd_soc_write(codec, i, tmp_cache[i]);
} else { } else {
dev_err(&i2c->dev, "Failed to allocate temporary cache\n"); dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
} }
@ -1624,9 +1548,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
codec->name = "WM8903"; codec->name = "WM8903";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8903_read;
codec->write = wm8903_write;
codec->hw_write = (hw_write_t)i2c_master_send;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm8903_set_bias_level; codec->set_bias_level = wm8903_set_bias_level;
codec->dai = &wm8903_dai; codec->dai = &wm8903_dai;
@ -1634,18 +1555,25 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache); codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
codec->reg_cache = &wm8903->reg_cache[0]; codec->reg_cache = &wm8903->reg_cache[0];
codec->private_data = wm8903; codec->private_data = wm8903;
codec->volatile_register = wm8903_volatile_register;
i2c_set_clientdata(i2c, codec); i2c_set_clientdata(i2c, codec);
codec->control_data = i2c; codec->control_data = i2c;
val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
dev_err(&i2c->dev, dev_err(&i2c->dev,
"Device with ID register %x is not a WM8903\n", val); "Device with ID register %x is not a WM8903\n", val);
return -ENODEV; return -ENODEV;
} }
val = wm8903_read(codec, WM8903_REVISION_NUMBER); val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
dev_info(&i2c->dev, "WM8903 revision %d\n", dev_info(&i2c->dev, "WM8903 revision %d\n",
val & WM8903_CHIP_REV_MASK); val & WM8903_CHIP_REV_MASK);
@ -1655,35 +1583,35 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch volume update bits */ /* Latch volume update bits */
val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT);
val |= WM8903_ADCVU; val |= WM8903_ADCVU;
wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val);
wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val);
val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT);
val |= WM8903_DACVU; val |= WM8903_DACVU;
wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val);
wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val);
val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT); val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT);
val |= WM8903_HPOUTVU; val |= WM8903_HPOUTVU;
wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val);
wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val);
val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT); val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT);
val |= WM8903_LINEOUTVU; val |= WM8903_LINEOUTVU;
wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val);
wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val);
val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT); val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT);
val |= WM8903_SPKVU; val |= WM8903_SPKVU;
wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val);
wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
/* Enable DAC soft mute by default */ /* Enable DAC soft mute by default */
val = wm8903_read(codec, WM8903_DAC_DIGITAL_1); val = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
val |= WM8903_DAC_MUTEMODE; val |= WM8903_DAC_MUTEMODE;
wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val);
wm8903_dai.dev = &i2c->dev; wm8903_dai.dev = &i2c->dev;
wm8903_codec = codec; wm8903_codec = codec;

View File

@ -106,50 +106,6 @@ static u16 wm8940_reg_defaults[] = {
0x0000, /* Mono Mixer Control */ 0x0000, /* Mono Mixer Control */
}; };
static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
return -1;
return cache[reg];
}
static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg >= ARRAY_SIZE(wm8940_reg_defaults))
return -1;
cache[reg] = value;
return 0;
}
static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
int ret;
u8 data[3] = { reg,
(value & 0xff00) >> 8,
(value & 0x00ff)
};
wm8940_write_reg_cache(codec, reg, value);
ret = codec->hw_write(codec->control_data, data, 3);
if (ret < 0)
return ret;
else if (ret != 3)
return -EIO;
return 0;
}
static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
static const struct soc_enum wm8940_adc_companding_enum static const struct soc_enum wm8940_adc_companding_enum
= SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); = SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding);
@ -348,14 +304,14 @@ error_ret:
return ret; return ret;
} }
#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0); #define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt) unsigned int fmt)
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67; u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67;
u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe; u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_CBM_CFM:
@ -366,7 +322,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
default: default:
return -EINVAL; return -EINVAL;
} }
wm8940_write(codec, WM8940_CLOCK, clk); snd_soc_write(codec, WM8940_CLOCK, clk);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
@ -399,7 +355,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
break; break;
} }
wm8940_write(codec, WM8940_IFACE, iface); snd_soc_write(codec, WM8940_IFACE, iface);
return 0; return 0;
} }
@ -411,9 +367,9 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F; u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1; u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
u16 companding = wm8940_read_reg_cache(codec, u16 companding = snd_soc_read(codec,
WM8940_COMPANDINGCTL) & 0xFFDF; WM8940_COMPANDINGCTL) & 0xFFDF;
int ret; int ret;
@ -442,7 +398,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_RATE_48000: case SNDRV_PCM_RATE_48000:
break; break;
} }
ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl); ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl);
if (ret) if (ret)
goto error_ret; goto error_ret;
@ -462,10 +418,10 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
iface |= (3 << 5); iface |= (3 << 5);
break; break;
} }
ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding); ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding);
if (ret) if (ret)
goto error_ret; goto error_ret;
ret = wm8940_write(codec, WM8940_IFACE, iface); ret = snd_soc_write(codec, WM8940_IFACE, iface);
error_ret: error_ret:
return ret; return ret;
@ -474,19 +430,19 @@ error_ret:
static int wm8940_mute(struct snd_soc_dai *dai, int mute) static int wm8940_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf; u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf;
if (mute) if (mute)
mute_reg |= 0x40; mute_reg |= 0x40;
return wm8940_write(codec, WM8940_DAC, mute_reg); return snd_soc_write(codec, WM8940_DAC, mute_reg);
} }
static int wm8940_set_bias_level(struct snd_soc_codec *codec, static int wm8940_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 val; u16 val;
u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0; u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
int ret = 0; int ret = 0;
switch (level) { switch (level) {
@ -494,26 +450,26 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
/* ensure bufioen and biasen */ /* ensure bufioen and biasen */
pwr_reg |= (1 << 2) | (1 << 3); pwr_reg |= (1 << 2) | (1 << 3);
/* Enable thermal shutdown */ /* Enable thermal shutdown */
val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); val = snd_soc_read(codec, WM8940_OUTPUTCTL);
ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2); ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2);
if (ret) if (ret)
break; break;
/* set vmid to 75k */ /* set vmid to 75k */
ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* ensure bufioen and biasen */ /* ensure bufioen and biasen */
pwr_reg |= (1 << 2) | (1 << 3); pwr_reg |= (1 << 2) | (1 << 3);
ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
/* ensure bufioen and biasen */ /* ensure bufioen and biasen */
pwr_reg |= (1 << 2) | (1 << 3); pwr_reg |= (1 << 2) | (1 << 3);
/* set vmid to 300k for standby */ /* set vmid to 300k for standby */
ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2); ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
ret = wm8940_write(codec, WM8940_POWER1, pwr_reg); ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg);
break; break;
} }
@ -587,36 +543,36 @@ static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai,
u16 reg; u16 reg;
/* Turn off PLL */ /* Turn off PLL */
reg = wm8940_read_reg_cache(codec, WM8940_POWER1); reg = snd_soc_read(codec, WM8940_POWER1);
wm8940_write(codec, WM8940_POWER1, reg & 0x1df); snd_soc_write(codec, WM8940_POWER1, reg & 0x1df);
if (freq_in == 0 || freq_out == 0) { if (freq_in == 0 || freq_out == 0) {
/* Clock CODEC directly from MCLK */ /* Clock CODEC directly from MCLK */
reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); reg = snd_soc_read(codec, WM8940_CLOCK);
wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff); snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff);
/* Pll power down */ /* Pll power down */
wm8940_write(codec, WM8940_PLLN, (1 << 7)); snd_soc_write(codec, WM8940_PLLN, (1 << 7));
return 0; return 0;
} }
/* Pll is followed by a frequency divide by 4 */ /* Pll is followed by a frequency divide by 4 */
pll_factors(freq_out*4, freq_in); pll_factors(freq_out*4, freq_in);
if (pll_div.k) if (pll_div.k)
wm8940_write(codec, WM8940_PLLN, snd_soc_write(codec, WM8940_PLLN,
(pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); (pll_div.pre_scale << 4) | pll_div.n | (1 << 6));
else /* No factional component */ else /* No factional component */
wm8940_write(codec, WM8940_PLLN, snd_soc_write(codec, WM8940_PLLN,
(pll_div.pre_scale << 4) | pll_div.n); (pll_div.pre_scale << 4) | pll_div.n);
wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18); snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18);
wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff);
wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff);
/* Enable the PLL */ /* Enable the PLL */
reg = wm8940_read_reg_cache(codec, WM8940_POWER1); reg = snd_soc_read(codec, WM8940_POWER1);
wm8940_write(codec, WM8940_POWER1, reg | 0x020); snd_soc_write(codec, WM8940_POWER1, reg | 0x020);
/* Run CODEC from PLL instead of MCLK */ /* Run CODEC from PLL instead of MCLK */
reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); reg = snd_soc_read(codec, WM8940_CLOCK);
wm8940_write(codec, WM8940_CLOCK, reg | 0x100); snd_soc_write(codec, WM8940_CLOCK, reg | 0x100);
return 0; return 0;
} }
@ -648,16 +604,16 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) { switch (div_id) {
case WM8940_BCLKDIV: case WM8940_BCLKDIV:
reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3; reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3;
ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2)); ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2));
break; break;
case WM8940_MCLKDIV: case WM8940_MCLKDIV:
reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F; reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F;
ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5)); ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5));
break; break;
case WM8940_OPCLKDIV: case WM8940_OPCLKDIV:
reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF; reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF;
ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
break; break;
} }
return ret; return ret;
@ -808,7 +764,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8940 = {
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940); EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
static int wm8940_register(struct wm8940_priv *wm8940) static int wm8940_register(struct wm8940_priv *wm8940,
enum snd_soc_control_type control)
{ {
struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data; struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
struct snd_soc_codec *codec = &wm8940->codec; struct snd_soc_codec *codec = &wm8940->codec;
@ -825,8 +782,6 @@ static int wm8940_register(struct wm8940_priv *wm8940)
codec->private_data = wm8940; codec->private_data = wm8940;
codec->name = "WM8940"; codec->name = "WM8940";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8940_read_reg_cache;
codec->write = wm8940_write;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm8940_set_bias_level; codec->set_bias_level = wm8940_set_bias_level;
codec->dai = &wm8940_dai; codec->dai = &wm8940_dai;
@ -834,6 +789,12 @@ static int wm8940_register(struct wm8940_priv *wm8940)
codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults); codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
codec->reg_cache = &wm8940->reg_cache; codec->reg_cache = &wm8940->reg_cache;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
if (ret == 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
memcpy(codec->reg_cache, wm8940_reg_defaults, memcpy(codec->reg_cache, wm8940_reg_defaults,
sizeof(wm8940_reg_defaults)); sizeof(wm8940_reg_defaults));
@ -847,15 +808,15 @@ static int wm8940_register(struct wm8940_priv *wm8940)
wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ret = wm8940_write(codec, WM8940_POWER1, 0x180); ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!pdata) if (!pdata)
dev_warn(codec->dev, "No platform data supplied\n"); dev_warn(codec->dev, "No platform data supplied\n");
else { else {
reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); reg = snd_soc_read(codec, WM8940_OUTPUTCTL);
ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
@ -904,7 +865,7 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
codec->control_data = i2c; codec->control_data = i2c;
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
return wm8940_register(wm8940); return wm8940_register(wm8940, SND_SOC_I2C);
} }
static int __devexit wm8940_i2c_remove(struct i2c_client *client) static int __devexit wm8940_i2c_remove(struct i2c_client *client)

View File

@ -69,61 +69,7 @@ struct wm8960_priv {
struct snd_soc_codec codec; struct snd_soc_codec codec;
}; };
/* #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0)
* read wm8960 register cache
*/
static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg == WM8960_RESET)
return 0;
if (reg >= WM8960_CACHEREGNUM)
return -1;
return cache[reg];
}
/*
* write wm8960 register cache
*/
static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg >= WM8960_CACHEREGNUM)
return;
cache[reg] = value;
}
static inline unsigned int wm8960_read(struct snd_soc_codec *codec,
unsigned int reg)
{
return wm8960_read_reg_cache(codec, reg);
}
/*
* write to the WM8960 register space
*/
static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8960 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8960_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8960_reset(c) wm8960_write(c, WM8960_RESET, 0)
/* enumerated controls */ /* enumerated controls */
static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
@ -420,7 +366,7 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
} }
/* set iface */ /* set iface */
wm8960_write(codec, WM8960_IFACE1, iface); snd_soc_write(codec, WM8960_IFACE1, iface);
return 0; return 0;
} }
@ -431,7 +377,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3; u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
/* bit size */ /* bit size */
switch (params_format(params)) { switch (params_format(params)) {
@ -446,19 +392,19 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
} }
/* set iface */ /* set iface */
wm8960_write(codec, WM8960_IFACE1, iface); snd_soc_write(codec, WM8960_IFACE1, iface);
return 0; return 0;
} }
static int wm8960_mute(struct snd_soc_dai *dai, int mute) static int wm8960_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7; u16 mute_reg = snd_soc_read(codec, WM8960_DACCTL1) & 0xfff7;
if (mute) if (mute)
wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8); snd_soc_write(codec, WM8960_DACCTL1, mute_reg | 0x8);
else else
wm8960_write(codec, WM8960_DACCTL1, mute_reg); snd_soc_write(codec, WM8960_DACCTL1, mute_reg);
return 0; return 0;
} }
@ -474,16 +420,16 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* Set VMID to 2x50k */ /* Set VMID to 2x50k */
reg = wm8960_read(codec, WM8960_POWER1); reg = snd_soc_read(codec, WM8960_POWER1);
reg &= ~0x180; reg &= ~0x180;
reg |= 0x80; reg |= 0x80;
wm8960_write(codec, WM8960_POWER1, reg); snd_soc_write(codec, WM8960_POWER1, reg);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Enable anti-pop features */ /* Enable anti-pop features */
wm8960_write(codec, WM8960_APOP1, snd_soc_write(codec, WM8960_APOP1,
WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_POBCTRL | WM8960_SOFT_ST |
WM8960_BUFDCOPEN | WM8960_BUFIOEN); WM8960_BUFDCOPEN | WM8960_BUFIOEN);
@ -491,43 +437,43 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec,
reg = WM8960_DISOP; reg = WM8960_DISOP;
if (pdata) if (pdata)
reg |= pdata->dres << 4; reg |= pdata->dres << 4;
wm8960_write(codec, WM8960_APOP2, reg); snd_soc_write(codec, WM8960_APOP2, reg);
msleep(400); msleep(400);
wm8960_write(codec, WM8960_APOP2, 0); snd_soc_write(codec, WM8960_APOP2, 0);
/* Enable & ramp VMID at 2x50k */ /* Enable & ramp VMID at 2x50k */
reg = wm8960_read(codec, WM8960_POWER1); reg = snd_soc_read(codec, WM8960_POWER1);
reg |= 0x80; reg |= 0x80;
wm8960_write(codec, WM8960_POWER1, reg); snd_soc_write(codec, WM8960_POWER1, reg);
msleep(100); msleep(100);
/* Enable VREF */ /* Enable VREF */
wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF); snd_soc_write(codec, WM8960_POWER1, reg | WM8960_VREF);
/* Disable anti-pop features */ /* Disable anti-pop features */
wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN); snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
} }
/* Set VMID to 2x250k */ /* Set VMID to 2x250k */
reg = wm8960_read(codec, WM8960_POWER1); reg = snd_soc_read(codec, WM8960_POWER1);
reg &= ~0x180; reg &= ~0x180;
reg |= 0x100; reg |= 0x100;
wm8960_write(codec, WM8960_POWER1, reg); snd_soc_write(codec, WM8960_POWER1, reg);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* Enable anti-pop features */ /* Enable anti-pop features */
wm8960_write(codec, WM8960_APOP1, snd_soc_write(codec, WM8960_APOP1,
WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_POBCTRL | WM8960_SOFT_ST |
WM8960_BUFDCOPEN | WM8960_BUFIOEN); WM8960_BUFDCOPEN | WM8960_BUFIOEN);
/* Disable VMID and VREF, let them discharge */ /* Disable VMID and VREF, let them discharge */
wm8960_write(codec, WM8960_POWER1, 0); snd_soc_write(codec, WM8960_POWER1, 0);
msleep(600); msleep(600);
wm8960_write(codec, WM8960_APOP1, 0); snd_soc_write(codec, WM8960_APOP1, 0);
break; break;
} }
@ -610,33 +556,33 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai,
/* Disable the PLL: even if we are changing the frequency the /* Disable the PLL: even if we are changing the frequency the
* PLL needs to be disabled while we do so. */ * PLL needs to be disabled while we do so. */
wm8960_write(codec, WM8960_CLOCK1, snd_soc_write(codec, WM8960_CLOCK1,
wm8960_read(codec, WM8960_CLOCK1) & ~1); snd_soc_read(codec, WM8960_CLOCK1) & ~1);
wm8960_write(codec, WM8960_POWER2, snd_soc_write(codec, WM8960_POWER2,
wm8960_read(codec, WM8960_POWER2) & ~1); snd_soc_read(codec, WM8960_POWER2) & ~1);
if (!freq_in || !freq_out) if (!freq_in || !freq_out)
return 0; return 0;
reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f; reg = snd_soc_read(codec, WM8960_PLL1) & ~0x3f;
reg |= pll_div.pre_div << 4; reg |= pll_div.pre_div << 4;
reg |= pll_div.n; reg |= pll_div.n;
if (pll_div.k) { if (pll_div.k) {
reg |= 0x20; reg |= 0x20;
wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f);
wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff);
wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff);
} }
wm8960_write(codec, WM8960_PLL1, reg); snd_soc_write(codec, WM8960_PLL1, reg);
/* Turn it on */ /* Turn it on */
wm8960_write(codec, WM8960_POWER2, snd_soc_write(codec, WM8960_POWER2,
wm8960_read(codec, WM8960_POWER2) | 1); snd_soc_read(codec, WM8960_POWER2) | 1);
msleep(250); msleep(250);
wm8960_write(codec, WM8960_CLOCK1, snd_soc_write(codec, WM8960_CLOCK1,
wm8960_read(codec, WM8960_CLOCK1) | 1); snd_soc_read(codec, WM8960_CLOCK1) | 1);
return 0; return 0;
} }
@ -649,28 +595,28 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) { switch (div_id) {
case WM8960_SYSCLKSEL: case WM8960_SYSCLKSEL:
reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe; reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1fe;
wm8960_write(codec, WM8960_CLOCK1, reg | div); snd_soc_write(codec, WM8960_CLOCK1, reg | div);
break; break;
case WM8960_SYSCLKDIV: case WM8960_SYSCLKDIV:
reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9; reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9;
wm8960_write(codec, WM8960_CLOCK1, reg | div); snd_soc_write(codec, WM8960_CLOCK1, reg | div);
break; break;
case WM8960_DACDIV: case WM8960_DACDIV:
reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7; reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1c7;
wm8960_write(codec, WM8960_CLOCK1, reg | div); snd_soc_write(codec, WM8960_CLOCK1, reg | div);
break; break;
case WM8960_OPCLKDIV: case WM8960_OPCLKDIV:
reg = wm8960_read(codec, WM8960_PLL1) & 0x03f; reg = snd_soc_read(codec, WM8960_PLL1) & 0x03f;
wm8960_write(codec, WM8960_PLL1, reg | div); snd_soc_write(codec, WM8960_PLL1, reg | div);
break; break;
case WM8960_DCLKDIV: case WM8960_DCLKDIV:
reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f; reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f;
wm8960_write(codec, WM8960_CLOCK2, reg | div); snd_soc_write(codec, WM8960_CLOCK2, reg | div);
break; break;
case WM8960_TOCLKSEL: case WM8960_TOCLKSEL:
reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd; reg = snd_soc_read(codec, WM8960_ADDCTL1) & 0x1fd;
wm8960_write(codec, WM8960_ADDCTL1, reg | div); snd_soc_write(codec, WM8960_ADDCTL1, reg | div);
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -801,7 +747,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8960 = {
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960); EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
static int wm8960_register(struct wm8960_priv *wm8960) static int wm8960_register(struct wm8960_priv *wm8960,
enum snd_soc_control_type control)
{ {
struct wm8960_data *pdata = wm8960->codec.dev->platform_data; struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
struct snd_soc_codec *codec = &wm8960->codec; struct snd_soc_codec *codec = &wm8960->codec;
@ -830,8 +777,6 @@ static int wm8960_register(struct wm8960_priv *wm8960)
codec->private_data = wm8960; codec->private_data = wm8960;
codec->name = "WM8960"; codec->name = "WM8960";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8960_read_reg_cache;
codec->write = wm8960_write;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm8960_set_bias_level; codec->set_bias_level = wm8960_set_bias_level;
codec->dai = &wm8960_dai; codec->dai = &wm8960_dai;
@ -841,6 +786,12 @@ static int wm8960_register(struct wm8960_priv *wm8960)
memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
ret = wm8960_reset(codec); ret = wm8960_reset(codec);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n"); dev_err(codec->dev, "Failed to issue reset\n");
@ -852,26 +803,26 @@ static int wm8960_register(struct wm8960_priv *wm8960)
wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */ /* Latch the update bits */
reg = wm8960_read(codec, WM8960_LINVOL); reg = snd_soc_read(codec, WM8960_LINVOL);
wm8960_write(codec, WM8960_LINVOL, reg | 0x100); snd_soc_write(codec, WM8960_LINVOL, reg | 0x100);
reg = wm8960_read(codec, WM8960_RINVOL); reg = snd_soc_read(codec, WM8960_RINVOL);
wm8960_write(codec, WM8960_RINVOL, reg | 0x100); snd_soc_write(codec, WM8960_RINVOL, reg | 0x100);
reg = wm8960_read(codec, WM8960_LADC); reg = snd_soc_read(codec, WM8960_LADC);
wm8960_write(codec, WM8960_LADC, reg | 0x100); snd_soc_write(codec, WM8960_LADC, reg | 0x100);
reg = wm8960_read(codec, WM8960_RADC); reg = snd_soc_read(codec, WM8960_RADC);
wm8960_write(codec, WM8960_RADC, reg | 0x100); snd_soc_write(codec, WM8960_RADC, reg | 0x100);
reg = wm8960_read(codec, WM8960_LDAC); reg = snd_soc_read(codec, WM8960_LDAC);
wm8960_write(codec, WM8960_LDAC, reg | 0x100); snd_soc_write(codec, WM8960_LDAC, reg | 0x100);
reg = wm8960_read(codec, WM8960_RDAC); reg = snd_soc_read(codec, WM8960_RDAC);
wm8960_write(codec, WM8960_RDAC, reg | 0x100); snd_soc_write(codec, WM8960_RDAC, reg | 0x100);
reg = wm8960_read(codec, WM8960_LOUT1); reg = snd_soc_read(codec, WM8960_LOUT1);
wm8960_write(codec, WM8960_LOUT1, reg | 0x100); snd_soc_write(codec, WM8960_LOUT1, reg | 0x100);
reg = wm8960_read(codec, WM8960_ROUT1); reg = snd_soc_read(codec, WM8960_ROUT1);
wm8960_write(codec, WM8960_ROUT1, reg | 0x100); snd_soc_write(codec, WM8960_ROUT1, reg | 0x100);
reg = wm8960_read(codec, WM8960_LOUT2); reg = snd_soc_read(codec, WM8960_LOUT2);
wm8960_write(codec, WM8960_LOUT2, reg | 0x100); snd_soc_write(codec, WM8960_LOUT2, reg | 0x100);
reg = wm8960_read(codec, WM8960_ROUT2); reg = snd_soc_read(codec, WM8960_ROUT2);
wm8960_write(codec, WM8960_ROUT2, reg | 0x100); snd_soc_write(codec, WM8960_ROUT2, reg | 0x100);
wm8960_codec = codec; wm8960_codec = codec;
@ -916,14 +867,13 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
codec = &wm8960->codec; codec = &wm8960->codec;
codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, wm8960); i2c_set_clientdata(i2c, wm8960);
codec->control_data = i2c; codec->control_data = i2c;
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
return wm8960_register(wm8960); return wm8960_register(wm8960, SND_SOC_I2C);
} }
static __devexit int wm8960_i2c_remove(struct i2c_client *client) static __devexit int wm8960_i2c_remove(struct i2c_client *client)

View File

@ -292,9 +292,10 @@ struct wm8961_priv {
u16 reg_cache[WM8961_MAX_REGISTER]; u16 reg_cache[WM8961_MAX_REGISTER];
}; };
static int wm8961_reg_is_volatile(int reg) static int wm8961_volatile_register(unsigned int reg)
{ {
switch (reg) { switch (reg) {
case WM8961_SOFTWARE_RESET:
case WM8961_WRITE_SEQUENCER_7: case WM8961_WRITE_SEQUENCER_7:
case WM8961_DC_SERVO_1: case WM8961_DC_SERVO_1:
return 1; return 1;
@ -304,76 +305,9 @@ static int wm8961_reg_is_volatile(int reg)
} }
} }
static unsigned int wm8961_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg > WM8961_MAX_REGISTER);
return cache[reg];
}
static unsigned int wm8961_read_hw(struct snd_soc_codec *codec, u8 reg)
{
struct i2c_msg xfer[2];
u16 data;
int ret;
struct i2c_client *client = codec->control_data;
BUG_ON(reg > WM8961_MAX_REGISTER);
/* Write register */
xfer[0].addr = client->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (u8 *)&data;
ret = i2c_transfer(client->adapter, xfer, 2);
if (ret != 2) {
dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
return 0;
}
return (data >> 8) | ((data & 0xff) << 8);
}
static unsigned int wm8961_read(struct snd_soc_codec *codec, unsigned int reg)
{
if (wm8961_reg_is_volatile(reg))
return wm8961_read_hw(codec, reg);
else
return wm8961_read_reg_cache(codec, reg);
}
static int wm8961_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u16 *cache = codec->reg_cache;
u8 data[3];
BUG_ON(reg > WM8961_MAX_REGISTER);
if (!wm8961_reg_is_volatile(reg))
cache[reg] = value;
data[0] = reg;
data[1] = value >> 8;
data[2] = value & 0x00ff;
if (codec->hw_write(codec->control_data, data, 3) == 3)
return 0;
else
return -EIO;
}
static int wm8961_reset(struct snd_soc_codec *codec) static int wm8961_reset(struct snd_soc_codec *codec)
{ {
return wm8961_write(codec, WM8961_SOFTWARE_RESET, 0); return snd_soc_write(codec, WM8961_SOFTWARE_RESET, 0);
} }
/* /*
@ -384,33 +318,33 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
u16 hp_reg = wm8961_read(codec, WM8961_ANALOGUE_HP_0); u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0);
u16 cp_reg = wm8961_read(codec, WM8961_CHARGE_PUMP_1); u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1);
u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
u16 dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); u16 dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
int timeout = 500; int timeout = 500;
if (event & SND_SOC_DAPM_POST_PMU) { if (event & SND_SOC_DAPM_POST_PMU) {
/* Make sure the output is shorted */ /* Make sure the output is shorted */
hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
/* Enable the charge pump */ /* Enable the charge pump */
cp_reg |= WM8961_CP_ENA; cp_reg |= WM8961_CP_ENA;
wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg); snd_soc_write(codec, WM8961_CHARGE_PUMP_1, cp_reg);
mdelay(5); mdelay(5);
/* Enable the PGA */ /* Enable the PGA */
pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA; pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA;
wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
/* Enable the amplifier */ /* Enable the amplifier */
hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA; hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA;
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
/* Second stage enable */ /* Second stage enable */
hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY; hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY;
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
/* Enable the DC servo & trigger startup */ /* Enable the DC servo & trigger startup */
dcs_reg |= dcs_reg |=
@ -418,10 +352,10 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL; WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL;
dev_dbg(codec->dev, "Enabling DC servo\n"); dev_dbg(codec->dev, "Enabling DC servo\n");
wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);
do { do {
msleep(1); msleep(1);
dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1);
} while (--timeout && } while (--timeout &&
dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR | dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR |
WM8961_DCS_TRIG_STARTUP_HPL)); WM8961_DCS_TRIG_STARTUP_HPL));
@ -433,39 +367,39 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
/* Enable the output stage */ /* Enable the output stage */
hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP; hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP;
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
/* Remove the short on the output stage */ /* Remove the short on the output stage */
hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT; hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT;
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
} }
if (event & SND_SOC_DAPM_PRE_PMD) { if (event & SND_SOC_DAPM_PRE_PMD) {
/* Short the output */ /* Short the output */
hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT);
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
/* Disable the output stage */ /* Disable the output stage */
hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP); hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP);
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
/* Disable DC offset cancellation */ /* Disable DC offset cancellation */
dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR | dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR |
WM8961_DCS_ENA_CHAN_HPL); WM8961_DCS_ENA_CHAN_HPL);
wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg);
/* Finish up */ /* Finish up */
hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA | hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA |
WM8961_HPL_ENA_DLY | WM8961_HPL_ENA); WM8961_HPL_ENA_DLY | WM8961_HPL_ENA);
wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg);
/* Disable the PGA */ /* Disable the PGA */
pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA); pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA);
wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
/* Disable the charge pump */ /* Disable the charge pump */
dev_dbg(codec->dev, "Disabling charge pump\n"); dev_dbg(codec->dev, "Disabling charge pump\n");
wm8961_write(codec, WM8961_CHARGE_PUMP_1, snd_soc_write(codec, WM8961_CHARGE_PUMP_1,
cp_reg & ~WM8961_CP_ENA); cp_reg & ~WM8961_CP_ENA);
} }
@ -476,27 +410,27 @@ static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
u16 spk_reg = wm8961_read(codec, WM8961_CLASS_D_CONTROL_1); u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1);
if (event & SND_SOC_DAPM_POST_PMU) { if (event & SND_SOC_DAPM_POST_PMU) {
/* Enable the PGA */ /* Enable the PGA */
pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA; pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA;
wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
/* Enable the amplifier */ /* Enable the amplifier */
spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA; spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA;
wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
} }
if (event & SND_SOC_DAPM_PRE_PMD) { if (event & SND_SOC_DAPM_PRE_PMD) {
/* Enable the amplifier */ /* Enable the amplifier */
spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA); spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA);
wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
/* Enable the PGA */ /* Enable the PGA */
pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA); pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA);
wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
} }
return 0; return 0;
@ -714,10 +648,10 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
abs(wm8961_srate[best].rate - fs)) abs(wm8961_srate[best].rate - fs))
best = i; best = i;
} }
reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_3); reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_3);
reg &= ~WM8961_SAMPLE_RATE_MASK; reg &= ~WM8961_SAMPLE_RATE_MASK;
reg |= wm8961_srate[best].val; reg |= wm8961_srate[best].val;
wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg);
dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n", dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n",
wm8961_srate[best].rate, fs); wm8961_srate[best].rate, fs);
@ -747,12 +681,12 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs, wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs,
wm8961->sysclk / fs); wm8961->sysclk / fs);
reg = wm8961_read(codec, WM8961_CLOCKING_4); reg = snd_soc_read(codec, WM8961_CLOCKING_4);
reg &= ~WM8961_CLK_SYS_RATE_MASK; reg &= ~WM8961_CLK_SYS_RATE_MASK;
reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT; reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT;
wm8961_write(codec, WM8961_CLOCKING_4, reg); snd_soc_write(codec, WM8961_CLOCKING_4, reg);
reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);
reg &= ~WM8961_WL_MASK; reg &= ~WM8961_WL_MASK;
switch (params_format(params)) { switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
@ -769,15 +703,15 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
default: default:
return -EINVAL; return -EINVAL;
} }
wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, reg); snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, reg);
/* Sloping stop-band filter is recommended for <= 24kHz */ /* Sloping stop-band filter is recommended for <= 24kHz */
reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2);
if (fs <= 24000) if (fs <= 24000)
reg |= WM8961_DACSLOPE; reg |= WM8961_DACSLOPE;
else else
reg &= WM8961_DACSLOPE; reg &= WM8961_DACSLOPE;
wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
return 0; return 0;
} }
@ -788,7 +722,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct wm8961_priv *wm8961 = codec->private_data; struct wm8961_priv *wm8961 = codec->private_data;
u16 reg = wm8961_read(codec, WM8961_CLOCKING1); u16 reg = snd_soc_read(codec, WM8961_CLOCKING1);
if (freq > 33000000) { if (freq > 33000000) {
dev_err(codec->dev, "MCLK must be <33MHz\n"); dev_err(codec->dev, "MCLK must be <33MHz\n");
@ -804,7 +738,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
reg &= WM8961_MCLKDIV; reg &= WM8961_MCLKDIV;
} }
wm8961_write(codec, WM8961_CLOCKING1, reg); snd_soc_write(codec, WM8961_CLOCKING1, reg);
wm8961->sysclk = freq; wm8961->sysclk = freq;
@ -814,7 +748,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 aif = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); u16 aif = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0);
aif &= ~(WM8961_BCLKINV | WM8961_LRP | aif &= ~(WM8961_BCLKINV | WM8961_LRP |
WM8961_MS | WM8961_FORMAT_MASK); WM8961_MS | WM8961_FORMAT_MASK);
@ -874,26 +808,26 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL; return -EINVAL;
} }
return wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, aif); return snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, aif);
} }
static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate) static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_2); u16 reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_2);
if (tristate) if (tristate)
reg |= WM8961_TRIS; reg |= WM8961_TRIS;
else else
reg &= ~WM8961_TRIS; reg &= ~WM8961_TRIS;
return wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg); return snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg);
} }
static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute) static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_1); u16 reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_1);
if (mute) if (mute)
reg |= WM8961_DACMU; reg |= WM8961_DACMU;
@ -902,7 +836,7 @@ static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute)
msleep(17); msleep(17);
return wm8961_write(codec, WM8961_ADC_DAC_CONTROL_1, reg); return snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_1, reg);
} }
static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
@ -912,17 +846,17 @@ static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
switch (div_id) { switch (div_id) {
case WM8961_BCLK: case WM8961_BCLK:
reg = wm8961_read(codec, WM8961_CLOCKING2); reg = snd_soc_read(codec, WM8961_CLOCKING2);
reg &= ~WM8961_BCLKDIV_MASK; reg &= ~WM8961_BCLKDIV_MASK;
reg |= div; reg |= div;
wm8961_write(codec, WM8961_CLOCKING2, reg); snd_soc_write(codec, WM8961_CLOCKING2, reg);
break; break;
case WM8961_LRCLK: case WM8961_LRCLK:
reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_2); reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_2);
reg &= ~WM8961_LRCLK_RATE_MASK; reg &= ~WM8961_LRCLK_RATE_MASK;
reg |= div; reg |= div;
wm8961_write(codec, WM8961_AUDIO_INTERFACE_2, reg); snd_soc_write(codec, WM8961_AUDIO_INTERFACE_2, reg);
break; break;
default: default:
@ -949,34 +883,34 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
if (codec->bias_level == SND_SOC_BIAS_STANDBY) { if (codec->bias_level == SND_SOC_BIAS_STANDBY) {
/* Enable bias generation */ /* Enable bias generation */
reg = wm8961_read(codec, WM8961_ANTI_POP); reg = snd_soc_read(codec, WM8961_ANTI_POP);
reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
wm8961_write(codec, WM8961_ANTI_POP, reg); snd_soc_write(codec, WM8961_ANTI_POP, reg);
/* VMID=2*50k, VREF */ /* VMID=2*50k, VREF */
reg = wm8961_read(codec, WM8961_PWR_MGMT_1); reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
reg &= ~WM8961_VMIDSEL_MASK; reg &= ~WM8961_VMIDSEL_MASK;
reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF; reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF;
wm8961_write(codec, WM8961_PWR_MGMT_1, reg); snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
} }
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_PREPARE) { if (codec->bias_level == SND_SOC_BIAS_PREPARE) {
/* VREF off */ /* VREF off */
reg = wm8961_read(codec, WM8961_PWR_MGMT_1); reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
reg &= ~WM8961_VREF; reg &= ~WM8961_VREF;
wm8961_write(codec, WM8961_PWR_MGMT_1, reg); snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
/* Bias generation off */ /* Bias generation off */
reg = wm8961_read(codec, WM8961_ANTI_POP); reg = snd_soc_read(codec, WM8961_ANTI_POP);
reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN); reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN);
wm8961_write(codec, WM8961_ANTI_POP, reg); snd_soc_write(codec, WM8961_ANTI_POP, reg);
/* VMID off */ /* VMID off */
reg = wm8961_read(codec, WM8961_PWR_MGMT_1); reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
reg &= ~WM8961_VMIDSEL_MASK; reg &= ~WM8961_VMIDSEL_MASK;
wm8961_write(codec, WM8961_PWR_MGMT_1, reg); snd_soc_write(codec, WM8961_PWR_MGMT_1, reg);
} }
break; break;
@ -1101,7 +1035,7 @@ static int wm8961_resume(struct platform_device *pdev)
if (i == WM8961_SOFTWARE_RESET) if (i == WM8961_SOFTWARE_RESET)
continue; continue;
wm8961_write(codec, i, reg_cache[i]); snd_soc_write(codec, i, reg_cache[i]);
} }
wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@ -1140,26 +1074,32 @@ static int wm8961_register(struct wm8961_priv *wm8961)
codec->private_data = wm8961; codec->private_data = wm8961;
codec->name = "WM8961"; codec->name = "WM8961";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8961_read;
codec->write = wm8961_write;
codec->dai = &wm8961_dai; codec->dai = &wm8961_dai;
codec->num_dai = 1; codec->num_dai = 1;
codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache); codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache);
codec->reg_cache = &wm8961->reg_cache; codec->reg_cache = &wm8961->reg_cache;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm8961_set_bias_level; codec->set_bias_level = wm8961_set_bias_level;
codec->volatile_register = wm8961_volatile_register;
memcpy(codec->reg_cache, wm8961_reg_defaults, memcpy(codec->reg_cache, wm8961_reg_defaults,
sizeof(wm8961_reg_defaults)); sizeof(wm8961_reg_defaults));
reg = wm8961_read_hw(codec, WM8961_SOFTWARE_RESET); ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET);
if (reg != 0x1801) { if (reg != 0x1801) {
dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg); dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }
reg = wm8961_read_hw(codec, WM8961_RIGHT_INPUT_VOLUME); /* This isn't volatile - readback doesn't correspond to write */
reg = codec->hw_read(codec, WM8961_RIGHT_INPUT_VOLUME);
dev_info(codec->dev, "WM8961 family %d revision %c\n", dev_info(codec->dev, "WM8961 family %d revision %c\n",
(reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)
@ -1172,37 +1112,37 @@ static int wm8961_register(struct wm8961_priv *wm8961)
} }
/* Enable class W */ /* Enable class W */
reg = wm8961_read(codec, WM8961_CHARGE_PUMP_B); reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);
reg |= WM8961_CP_DYN_PWR_MASK; reg |= WM8961_CP_DYN_PWR_MASK;
wm8961_write(codec, WM8961_CHARGE_PUMP_B, reg); snd_soc_write(codec, WM8961_CHARGE_PUMP_B, reg);
/* Latch volume update bits (right channel only, we always /* Latch volume update bits (right channel only, we always
* write both out) and default ZC on. */ * write both out) and default ZC on. */
reg = wm8961_read(codec, WM8961_ROUT1_VOLUME); reg = snd_soc_read(codec, WM8961_ROUT1_VOLUME);
wm8961_write(codec, WM8961_ROUT1_VOLUME, snd_soc_write(codec, WM8961_ROUT1_VOLUME,
reg | WM8961_LO1ZC | WM8961_OUT1VU); reg | WM8961_LO1ZC | WM8961_OUT1VU);
wm8961_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC); snd_soc_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC);
reg = wm8961_read(codec, WM8961_ROUT2_VOLUME); reg = snd_soc_read(codec, WM8961_ROUT2_VOLUME);
wm8961_write(codec, WM8961_ROUT2_VOLUME, snd_soc_write(codec, WM8961_ROUT2_VOLUME,
reg | WM8961_SPKRZC | WM8961_SPKVU); reg | WM8961_SPKRZC | WM8961_SPKVU);
wm8961_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC); snd_soc_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC);
reg = wm8961_read(codec, WM8961_RIGHT_ADC_VOLUME); reg = snd_soc_read(codec, WM8961_RIGHT_ADC_VOLUME);
wm8961_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU); snd_soc_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU);
reg = wm8961_read(codec, WM8961_RIGHT_INPUT_VOLUME); reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME);
wm8961_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU); snd_soc_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU);
/* Use soft mute by default */ /* Use soft mute by default */
reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2);
reg |= WM8961_DACSMM; reg |= WM8961_DACSMM;
wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg);
/* Use automatic clocking mode by default; for now this is all /* Use automatic clocking mode by default; for now this is all
* we support. * we support.
*/ */
reg = wm8961_read(codec, WM8961_CLOCKING_3); reg = snd_soc_read(codec, WM8961_CLOCKING_3);
reg &= ~WM8961_MANUAL_MODE; reg &= ~WM8961_MANUAL_MODE;
wm8961_write(codec, WM8961_CLOCKING_3, reg); snd_soc_write(codec, WM8961_CLOCKING_3, reg);
wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@ -1250,7 +1190,6 @@ static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
codec = &wm8961->codec; codec = &wm8961->codec;
codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, wm8961); i2c_set_clientdata(i2c, wm8961);
codec->control_data = i2c; codec->control_data = i2c;

View File

@ -59,44 +59,7 @@ static const u16 wm8971_reg[] = {
0x0079, 0x0079, 0x0079, /* 40 */ 0x0079, 0x0079, 0x0079, /* 40 */
}; };
static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec, #define wm8971_reset(c) snd_soc_write(c, WM8971_RESET, 0)
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg < WM8971_REG_COUNT)
return cache[reg];
return -1;
}
static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg < WM8971_REG_COUNT)
cache[reg] = value;
}
static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8753 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8971_write_reg_cache (codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8971_reset(c) wm8971_write(c, WM8971_RESET, 0)
/* WM8971 Controls */ /* WM8971 Controls */
static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" }; static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" };
@ -521,7 +484,7 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8971_write(codec, WM8971_IFACE, iface); snd_soc_write(codec, WM8971_IFACE, iface);
return 0; return 0;
} }
@ -533,8 +496,8 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
struct wm8971_priv *wm8971 = codec->private_data; struct wm8971_priv *wm8971 = codec->private_data;
u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
int coeff = get_coeff(wm8971->sysclk, params_rate(params)); int coeff = get_coeff(wm8971->sysclk, params_rate(params));
/* bit size */ /* bit size */
@ -553,9 +516,9 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
} }
/* set iface & srate */ /* set iface & srate */
wm8971_write(codec, WM8971_IFACE, iface); snd_soc_write(codec, WM8971_IFACE, iface);
if (coeff >= 0) if (coeff >= 0)
wm8971_write(codec, WM8971_SRATE, srate | snd_soc_write(codec, WM8971_SRATE, srate |
(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
return 0; return 0;
@ -564,33 +527,33 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
static int wm8971_mute(struct snd_soc_dai *dai, int mute) static int wm8971_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7; u16 mute_reg = snd_soc_read(codec, WM8971_ADCDAC) & 0xfff7;
if (mute) if (mute)
wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8); snd_soc_write(codec, WM8971_ADCDAC, mute_reg | 0x8);
else else
wm8971_write(codec, WM8971_ADCDAC, mute_reg); snd_soc_write(codec, WM8971_ADCDAC, mute_reg);
return 0; return 0;
} }
static int wm8971_set_bias_level(struct snd_soc_codec *codec, static int wm8971_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/* set vmid to 50k and unmute dac */ /* set vmid to 50k and unmute dac */
wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
/* mute dac and set vmid to 500k, enable VREF */ /* mute dac and set vmid to 500k, enable VREF */
wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140); snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
wm8971_write(codec, WM8971_PWR1, 0x0001); snd_soc_write(codec, WM8971_PWR1, 0x0001);
break; break;
} }
codec->bias_level = level; codec->bias_level = level;
@ -667,8 +630,8 @@ static int wm8971_resume(struct platform_device *pdev)
/* charge wm8971 caps */ /* charge wm8971 caps */
if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
codec->bias_level = SND_SOC_BIAS_ON; codec->bias_level = SND_SOC_BIAS_ON;
queue_delayed_work(wm8971_workq, &codec->delayed_work, queue_delayed_work(wm8971_workq, &codec->delayed_work,
msecs_to_jiffies(1000)); msecs_to_jiffies(1000));
@ -677,15 +640,14 @@ static int wm8971_resume(struct platform_device *pdev)
return 0; return 0;
} }
static int wm8971_init(struct snd_soc_device *socdev) static int wm8971_init(struct snd_soc_device *socdev,
enum snd_soc_control_type control)
{ {
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
int reg, ret = 0; int reg, ret = 0;
codec->name = "WM8971"; codec->name = "WM8971";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8971_read_reg_cache;
codec->write = wm8971_write;
codec->set_bias_level = wm8971_set_bias_level; codec->set_bias_level = wm8971_set_bias_level;
codec->dai = &wm8971_dai; codec->dai = &wm8971_dai;
codec->reg_cache_size = ARRAY_SIZE(wm8971_reg); codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
@ -695,42 +657,48 @@ static int wm8971_init(struct snd_soc_device *socdev)
if (codec->reg_cache == NULL) if (codec->reg_cache == NULL)
return -ENOMEM; return -ENOMEM;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
goto err;
}
wm8971_reset(codec); wm8971_reset(codec);
/* register pcms */ /* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "wm8971: failed to create pcms\n"); printk(KERN_ERR "wm8971: failed to create pcms\n");
goto pcm_err; goto err;
} }
/* charge output caps - set vmid to 5k for quick power up */ /* charge output caps - set vmid to 5k for quick power up */
reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
codec->bias_level = SND_SOC_BIAS_STANDBY; codec->bias_level = SND_SOC_BIAS_STANDBY;
queue_delayed_work(wm8971_workq, &codec->delayed_work, queue_delayed_work(wm8971_workq, &codec->delayed_work,
msecs_to_jiffies(1000)); msecs_to_jiffies(1000));
/* set the update bits */ /* set the update bits */
reg = wm8971_read_reg_cache(codec, WM8971_LDAC); reg = snd_soc_read(codec, WM8971_LDAC);
wm8971_write(codec, WM8971_LDAC, reg | 0x0100); snd_soc_write(codec, WM8971_LDAC, reg | 0x0100);
reg = wm8971_read_reg_cache(codec, WM8971_RDAC); reg = snd_soc_read(codec, WM8971_RDAC);
wm8971_write(codec, WM8971_RDAC, reg | 0x0100); snd_soc_write(codec, WM8971_RDAC, reg | 0x0100);
reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V); reg = snd_soc_read(codec, WM8971_LOUT1V);
wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100); snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100);
reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V); reg = snd_soc_read(codec, WM8971_ROUT1V);
wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100); snd_soc_write(codec, WM8971_ROUT1V, reg | 0x0100);
reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V); reg = snd_soc_read(codec, WM8971_LOUT2V);
wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100); snd_soc_write(codec, WM8971_LOUT2V, reg | 0x0100);
reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V); reg = snd_soc_read(codec, WM8971_ROUT2V);
wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100); snd_soc_write(codec, WM8971_ROUT2V, reg | 0x0100);
reg = wm8971_read_reg_cache(codec, WM8971_LINVOL); reg = snd_soc_read(codec, WM8971_LINVOL);
wm8971_write(codec, WM8971_LINVOL, reg | 0x0100); snd_soc_write(codec, WM8971_LINVOL, reg | 0x0100);
reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); reg = snd_soc_read(codec, WM8971_RINVOL);
wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); snd_soc_write(codec, WM8971_RINVOL, reg | 0x0100);
snd_soc_add_controls(codec, wm8971_snd_controls, snd_soc_add_controls(codec, wm8971_snd_controls,
ARRAY_SIZE(wm8971_snd_controls)); ARRAY_SIZE(wm8971_snd_controls));
@ -745,7 +713,7 @@ static int wm8971_init(struct snd_soc_device *socdev)
card_err: card_err:
snd_soc_free_pcms(socdev); snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev); snd_soc_dapm_free(socdev);
pcm_err: err:
kfree(codec->reg_cache); kfree(codec->reg_cache);
return ret; return ret;
} }
@ -767,7 +735,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
codec->control_data = i2c; codec->control_data = i2c;
ret = wm8971_init(socdev); ret = wm8971_init(socdev, SND_SOC_I2C);
if (ret < 0) if (ret < 0)
pr_err("failed to initialise WM8971\n"); pr_err("failed to initialise WM8971\n");
@ -877,7 +845,6 @@ static int wm8971_probe(struct platform_device *pdev)
#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
if (setup->i2c_address) { if (setup->i2c_address) {
codec->hw_write = (hw_write_t)i2c_master_send;
ret = wm8971_add_i2c_device(pdev, setup); ret = wm8971_add_i2c_device(pdev, setup);
} }
#endif #endif

View File

@ -57,50 +57,7 @@ struct wm8988_priv {
}; };
/* #define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0)
* read wm8988 register cache
*/
static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg > WM8988_NUM_REG)
return -1;
return cache[reg];
}
/*
* write wm8988 register cache
*/
static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg > WM8988_NUM_REG)
return;
cache[reg] = value;
}
static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D9 WM8753 register offset
* D8...D0 register data
*/
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
wm8988_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
#define wm8988_reset(c) wm8988_write(c, WM8988_RESET, 0)
/* /*
* WM8988 Controls * WM8988 Controls
@ -226,15 +183,15 @@ static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2); u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2);
/* Use the DAC to gate LRC if active, otherwise use ADC */ /* Use the DAC to gate LRC if active, otherwise use ADC */
if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180) if (snd_soc_read(codec, WM8988_PWR2) & 0x180)
adctl2 &= ~0x4; adctl2 &= ~0x4;
else else
adctl2 |= 0x4; adctl2 |= 0x4;
return wm8988_write(codec, WM8988_ADCTL2, adctl2); return snd_soc_write(codec, WM8988_ADCTL2, adctl2);
} }
static const char *wm8988_line_texts[] = { static const char *wm8988_line_texts[] = {
@ -619,7 +576,7 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8988_write(codec, WM8988_IFACE, iface); snd_soc_write(codec, WM8988_IFACE, iface);
return 0; return 0;
} }
@ -653,8 +610,8 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
struct wm8988_priv *wm8988 = codec->private_data; struct wm8988_priv *wm8988 = codec->private_data;
u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3; u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180; u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
int coeff; int coeff;
coeff = get_coeff(wm8988->sysclk, params_rate(params)); coeff = get_coeff(wm8988->sysclk, params_rate(params));
@ -685,9 +642,9 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
} }
/* set iface & srate */ /* set iface & srate */
wm8988_write(codec, WM8988_IFACE, iface); snd_soc_write(codec, WM8988_IFACE, iface);
if (coeff >= 0) if (coeff >= 0)
wm8988_write(codec, WM8988_SRATE, srate | snd_soc_write(codec, WM8988_SRATE, srate |
(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);
return 0; return 0;
@ -696,19 +653,19 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
static int wm8988_mute(struct snd_soc_dai *dai, int mute) static int wm8988_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7; u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7;
if (mute) if (mute)
wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8); snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
else else
wm8988_write(codec, WM8988_ADCDAC, mute_reg); snd_soc_write(codec, WM8988_ADCDAC, mute_reg);
return 0; return 0;
} }
static int wm8988_set_bias_level(struct snd_soc_codec *codec, static int wm8988_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1; u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
@ -716,24 +673,24 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* VREF, VMID=2x50k, digital enabled */ /* VREF, VMID=2x50k, digital enabled */
wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* VREF, VMID=2x5k */ /* VREF, VMID=2x5k */
wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
/* Charge caps */ /* Charge caps */
msleep(100); msleep(100);
} }
/* VREF, VMID=2*500k, digital stopped */ /* VREF, VMID=2*500k, digital stopped */
wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141); snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x0141);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
wm8988_write(codec, WM8988_PWR1, 0x0000); snd_soc_write(codec, WM8988_PWR1, 0x0000);
break; break;
} }
codec->bias_level = level; codec->bias_level = level;
@ -868,7 +825,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8988 = {
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988); EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
static int wm8988_register(struct wm8988_priv *wm8988) static int wm8988_register(struct wm8988_priv *wm8988,
enum snd_soc_control_type control)
{ {
struct snd_soc_codec *codec = &wm8988->codec; struct snd_soc_codec *codec = &wm8988->codec;
int ret; int ret;
@ -887,8 +845,6 @@ static int wm8988_register(struct wm8988_priv *wm8988)
codec->private_data = wm8988; codec->private_data = wm8988;
codec->name = "WM8988"; codec->name = "WM8988";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8988_read_reg_cache;
codec->write = wm8988_write;
codec->dai = &wm8988_dai; codec->dai = &wm8988_dai;
codec->num_dai = 1; codec->num_dai = 1;
codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
@ -899,6 +855,12 @@ static int wm8988_register(struct wm8988_priv *wm8988)
memcpy(codec->reg_cache, wm8988_reg, memcpy(codec->reg_cache, wm8988_reg,
sizeof(wm8988_reg)); sizeof(wm8988_reg));
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
goto err;
}
ret = wm8988_reset(codec); ret = wm8988_reset(codec);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n"); dev_err(codec->dev, "Failed to issue reset\n");
@ -906,16 +868,16 @@ static int wm8988_register(struct wm8988_priv *wm8988)
} }
/* set the update bits (we always update left then right) */ /* set the update bits (we always update left then right) */
reg = wm8988_read_reg_cache(codec, WM8988_RADC); reg = snd_soc_read(codec, WM8988_RADC);
wm8988_write(codec, WM8988_RADC, reg | 0x100); snd_soc_write(codec, WM8988_RADC, reg | 0x100);
reg = wm8988_read_reg_cache(codec, WM8988_RDAC); reg = snd_soc_read(codec, WM8988_RDAC);
wm8988_write(codec, WM8988_RDAC, reg | 0x0100); snd_soc_write(codec, WM8988_RDAC, reg | 0x0100);
reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V); reg = snd_soc_read(codec, WM8988_ROUT1V);
wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100); snd_soc_write(codec, WM8988_ROUT1V, reg | 0x0100);
reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V); reg = snd_soc_read(codec, WM8988_ROUT2V);
wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100); snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100);
reg = wm8988_read_reg_cache(codec, WM8988_RINVOL); reg = snd_soc_read(codec, WM8988_RINVOL);
wm8988_write(codec, WM8988_RINVOL, reg | 0x0100); snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
@ -966,14 +928,13 @@ static int wm8988_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
codec = &wm8988->codec; codec = &wm8988->codec;
codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, wm8988); i2c_set_clientdata(i2c, wm8988);
codec->control_data = i2c; codec->control_data = i2c;
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
return wm8988_register(wm8988); return wm8988_register(wm8988, SND_SOC_I2C);
} }
static int wm8988_i2c_remove(struct i2c_client *client) static int wm8988_i2c_remove(struct i2c_client *client)
@ -1018,30 +979,6 @@ static struct i2c_driver wm8988_i2c_driver = {
#endif #endif
#if defined(CONFIG_SPI_MASTER) #if defined(CONFIG_SPI_MASTER)
static int wm8988_spi_write(struct spi_device *spi, const char *data, int len)
{
struct spi_transfer t;
struct spi_message m;
u8 msg[2];
if (len <= 0)
return 0;
msg[0] = data[0];
msg[1] = data[1];
spi_message_init(&m);
memset(&t, 0, (sizeof t));
t.tx_buf = &msg[0];
t.len = len;
spi_message_add_tail(&t, &m);
spi_sync(spi, &m);
return len;
}
static int __devinit wm8988_spi_probe(struct spi_device *spi) static int __devinit wm8988_spi_probe(struct spi_device *spi)
{ {
struct wm8988_priv *wm8988; struct wm8988_priv *wm8988;
@ -1052,13 +989,12 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
codec = &wm8988->codec; codec = &wm8988->codec;
codec->hw_write = (hw_write_t)wm8988_spi_write;
codec->control_data = spi; codec->control_data = spi;
codec->dev = &spi->dev; codec->dev = &spi->dev;
spi->dev.driver_data = wm8988; spi->dev.driver_data = wm8988;
return wm8988_register(wm8988); return wm8988_register(wm8988, SND_SOC_SPI);
} }
static int __devexit wm8988_spi_remove(struct spi_device *spi) static int __devexit wm8988_spi_remove(struct spi_device *spi)

View File

@ -108,53 +108,7 @@ static const u16 wm8990_reg[] = {
0x0000, /* R63 - Driver internal */ 0x0000, /* R63 - Driver internal */
}; };
/* #define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
* read wm8990 register cache
*/
static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg >= ARRAY_SIZE(wm8990_reg));
return cache[reg];
}
/*
* write wm8990 register cache
*/
static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
/* Reset register and reserved registers are uncached */
if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg))
return;
cache[reg] = value;
}
/*
* write to the wm8990 register space
*/
static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[3];
data[0] = reg & 0xFF;
data[1] = (value >> 8) & 0xFF;
data[2] = value & 0xFF;
wm8990_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 3) == 2)
return 0;
else
return -EIO;
}
#define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0)
static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
@ -187,8 +141,8 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
return ret; return ret;
/* now hit the volume update bits (always bit 8) */ /* now hit the volume update bits (always bit 8) */
val = wm8990_read_reg_cache(codec, reg); val = snd_soc_read(codec, reg);
return wm8990_write(codec, reg, val | 0x0100); return snd_soc_write(codec, reg, val | 0x0100);
} }
#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
@ -427,8 +381,8 @@ static int inmixer_event(struct snd_soc_dapm_widget *w,
{ {
u16 reg, fakepower; u16 reg, fakepower;
reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2);
fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS);
if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) |
(1 << WM8990_AINLMUX_PWR_BIT))) { (1 << WM8990_AINLMUX_PWR_BIT))) {
@ -443,7 +397,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w,
} else { } else {
reg &= ~WM8990_AINL_ENA; reg &= ~WM8990_AINL_ENA;
} }
wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
return 0; return 0;
} }
@ -457,7 +411,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
switch (reg_shift) { switch (reg_shift) {
case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1);
if (reg & WM8990_LDLO) { if (reg & WM8990_LDLO) {
printk(KERN_WARNING printk(KERN_WARNING
"Cannot set as Output Mixer 1 LDLO Set\n"); "Cannot set as Output Mixer 1 LDLO Set\n");
@ -465,7 +419,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
} }
break; break;
case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2);
if (reg & WM8990_RDRO) { if (reg & WM8990_RDRO) {
printk(KERN_WARNING printk(KERN_WARNING
"Cannot set as Output Mixer 2 RDRO Set\n"); "Cannot set as Output Mixer 2 RDRO Set\n");
@ -473,7 +427,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
} }
break; break;
case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
if (reg & WM8990_LDSPK) { if (reg & WM8990_LDSPK) {
printk(KERN_WARNING printk(KERN_WARNING
"Cannot set as Speaker Mixer LDSPK Set\n"); "Cannot set as Speaker Mixer LDSPK Set\n");
@ -481,7 +435,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
} }
break; break;
case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
if (reg & WM8990_RDSPK) { if (reg & WM8990_RDSPK) {
printk(KERN_WARNING printk(KERN_WARNING
"Cannot set as Speaker Mixer RDSPK Set\n"); "Cannot set as Speaker Mixer RDSPK Set\n");
@ -1029,24 +983,24 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai,
pll_factors(&pll_div, freq_out * 4, freq_in); pll_factors(&pll_div, freq_out * 4, freq_in);
/* Turn on PLL */ /* Turn on PLL */
reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
reg |= WM8990_PLL_ENA; reg |= WM8990_PLL_ENA;
wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
/* sysclk comes from PLL */ /* sysclk comes from PLL */
reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); reg = snd_soc_read(codec, WM8990_CLOCKING_2);
wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC);
/* set up N , fractional mode and pre-divisor if neccessary */ /* set up N , fractional mode and pre-divisor if neccessary */
wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM |
(pll_div.div2?WM8990_PRESCALE:0)); (pll_div.div2?WM8990_PRESCALE:0));
wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
} else { } else {
/* Turn on PLL */ /* Turn on PLL */
reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
reg &= ~WM8990_PLL_ENA; reg &= ~WM8990_PLL_ENA;
wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
} }
return 0; return 0;
} }
@ -1073,8 +1027,8 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 audio1, audio3; u16 audio1, audio3;
audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); audio3 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_3);
/* set master/slave audio interface */ /* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@ -1115,8 +1069,8 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL; return -EINVAL;
} }
wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); snd_soc_write(codec, WM8990_AUDIO_INTERFACE_3, audio3);
return 0; return 0;
} }
@ -1128,24 +1082,24 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) { switch (div_id) {
case WM8990_MCLK_DIV: case WM8990_MCLK_DIV:
reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
~WM8990_MCLK_DIV_MASK; ~WM8990_MCLK_DIV_MASK;
wm8990_write(codec, WM8990_CLOCKING_2, reg | div); snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break; break;
case WM8990_DACCLK_DIV: case WM8990_DACCLK_DIV:
reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
~WM8990_DAC_CLKDIV_MASK; ~WM8990_DAC_CLKDIV_MASK;
wm8990_write(codec, WM8990_CLOCKING_2, reg | div); snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break; break;
case WM8990_ADCCLK_DIV: case WM8990_ADCCLK_DIV:
reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & reg = snd_soc_read(codec, WM8990_CLOCKING_2) &
~WM8990_ADC_CLKDIV_MASK; ~WM8990_ADC_CLKDIV_MASK;
wm8990_write(codec, WM8990_CLOCKING_2, reg | div); snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break; break;
case WM8990_BCLK_DIV: case WM8990_BCLK_DIV:
reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & reg = snd_soc_read(codec, WM8990_CLOCKING_1) &
~WM8990_BCLK_DIV_MASK; ~WM8990_BCLK_DIV_MASK;
wm8990_write(codec, WM8990_CLOCKING_1, reg | div); snd_soc_write(codec, WM8990_CLOCKING_1, reg | div);
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -1164,7 +1118,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec; struct snd_soc_codec *codec = socdev->card->codec;
u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
audio1 &= ~WM8990_AIF_WL_MASK; audio1 &= ~WM8990_AIF_WL_MASK;
/* bit size */ /* bit size */
@ -1182,7 +1136,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
break; break;
} }
wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
return 0; return 0;
} }
@ -1191,12 +1145,12 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 val; u16 val;
val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; val = snd_soc_read(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE;
if (mute) if (mute)
wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
else else
wm8990_write(codec, WM8990_DAC_CTRL, val); snd_soc_write(codec, WM8990_DAC_CTRL, val);
return 0; return 0;
} }
@ -1212,21 +1166,21 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* VMID=2*50k */ /* VMID=2*50k */
val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) &
~WM8990_VMID_MODE_MASK; ~WM8990_VMID_MODE_MASK;
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Enable all output discharge bits */ /* Enable all output discharge bits */
wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
WM8990_DIS_OUT4 | WM8990_DIS_LOUT | WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
WM8990_DIS_ROUT); WM8990_DIS_ROUT);
/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFDCOPEN | WM8990_POBCTRL |
WM8990_VMIDTOG); WM8990_VMIDTOG);
@ -1234,83 +1188,83 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
msleep(msecs_to_jiffies(300)); msleep(msecs_to_jiffies(300));
/* Disable VMIDTOG */ /* Disable VMIDTOG */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_BUFDCOPEN | WM8990_POBCTRL); WM8990_BUFDCOPEN | WM8990_POBCTRL);
/* disable all output discharge bits */ /* disable all output discharge bits */
wm8990_write(codec, WM8990_ANTIPOP1, 0); snd_soc_write(codec, WM8990_ANTIPOP1, 0);
/* Enable outputs */ /* Enable outputs */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
msleep(msecs_to_jiffies(50)); msleep(msecs_to_jiffies(50));
/* Enable VMID at 2x50k */ /* Enable VMID at 2x50k */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02);
msleep(msecs_to_jiffies(100)); msleep(msecs_to_jiffies(100));
/* Enable VREF */ /* Enable VREF */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
msleep(msecs_to_jiffies(600)); msleep(msecs_to_jiffies(600));
/* Enable BUFIOEN */ /* Enable BUFIOEN */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFDCOPEN | WM8990_POBCTRL |
WM8990_BUFIOEN); WM8990_BUFIOEN);
/* Disable outputs */ /* Disable outputs */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3);
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
/* Enable workaround for ADC clocking issue. */ /* Enable workaround for ADC clocking issue. */
wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); snd_soc_write(codec, WM8990_EXT_CTL1, 0xa003);
wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0);
} }
/* VMID=2*250k */ /* VMID=2*250k */
val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) &
~WM8990_VMID_MODE_MASK; ~WM8990_VMID_MODE_MASK;
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* Enable POBCTRL and SOFT_ST */ /* Enable POBCTRL and SOFT_ST */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_POBCTRL | WM8990_BUFIOEN); WM8990_POBCTRL | WM8990_BUFIOEN);
/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFDCOPEN | WM8990_POBCTRL |
WM8990_BUFIOEN); WM8990_BUFIOEN);
/* mute DAC */ /* mute DAC */
val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); val = snd_soc_read(codec, WM8990_DAC_CTRL);
wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
/* Enable any disabled outputs */ /* Enable any disabled outputs */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
/* Disable VMID */ /* Disable VMID */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
msleep(msecs_to_jiffies(300)); msleep(msecs_to_jiffies(300));
/* Enable all output discharge bits */ /* Enable all output discharge bits */
wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
WM8990_DIS_OUT4 | WM8990_DIS_LOUT | WM8990_DIS_OUT4 | WM8990_DIS_LOUT |
WM8990_DIS_ROUT); WM8990_DIS_ROUT);
/* Disable VREF */ /* Disable VREF */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0);
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
wm8990_write(codec, WM8990_ANTIPOP2, 0x0); snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
break; break;
} }
@ -1411,8 +1365,6 @@ static int wm8990_init(struct snd_soc_device *socdev)
codec->name = "WM8990"; codec->name = "WM8990";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm8990_read_reg_cache;
codec->write = wm8990_write;
codec->set_bias_level = wm8990_set_bias_level; codec->set_bias_level = wm8990_set_bias_level;
codec->dai = &wm8990_dai; codec->dai = &wm8990_dai;
codec->num_dai = 2; codec->num_dai = 2;
@ -1422,6 +1374,12 @@ static int wm8990_init(struct snd_soc_device *socdev)
if (codec->reg_cache == NULL) if (codec->reg_cache == NULL)
return -ENOMEM; return -ENOMEM;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret < 0) {
printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
goto pcm_err;
}
wm8990_reset(codec); wm8990_reset(codec);
/* register pcms */ /* register pcms */
@ -1435,18 +1393,18 @@ static int wm8990_init(struct snd_soc_device *socdev)
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); snd_soc_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1);
reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & reg = snd_soc_read(codec, WM8990_GPIO1_GPIO2) &
~WM8990_GPIO1_SEL_MASK; ~WM8990_GPIO1_SEL_MASK;
wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); snd_soc_write(codec, WM8990_GPIO1_GPIO2, reg | 1);
reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA);
wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_add_controls(codec, wm8990_snd_controls, snd_soc_add_controls(codec, wm8990_snd_controls,
ARRAY_SIZE(wm8990_snd_controls)); ARRAY_SIZE(wm8990_snd_controls));

View File

@ -168,84 +168,19 @@ struct wm9081_priv {
struct wm9081_retune_mobile_config *retune; struct wm9081_retune_mobile_config *retune;
}; };
static int wm9081_reg_is_volatile(int reg) static int wm9081_volatile_register(unsigned int reg)
{ {
switch (reg) { switch (reg) {
case WM9081_SOFTWARE_RESET:
return 1;
default: default:
return 0; return 0;
} }
} }
static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
BUG_ON(reg > WM9081_MAX_REGISTER);
return cache[reg];
}
static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg)
{
struct i2c_msg xfer[2];
u16 data;
int ret;
struct i2c_client *client = codec->control_data;
BUG_ON(reg > WM9081_MAX_REGISTER);
/* Write register */
xfer[0].addr = client->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (u8 *)&data;
ret = i2c_transfer(client->adapter, xfer, 2);
if (ret != 2) {
dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
return 0;
}
return (data >> 8) | ((data & 0xff) << 8);
}
static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg)
{
if (wm9081_reg_is_volatile(reg))
return wm9081_read_hw(codec, reg);
else
return wm9081_read_reg_cache(codec, reg);
}
static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u16 *cache = codec->reg_cache;
u8 data[3];
BUG_ON(reg > WM9081_MAX_REGISTER);
if (!wm9081_reg_is_volatile(reg))
cache[reg] = value;
data[0] = reg;
data[1] = value >> 8;
data[2] = value & 0x00ff;
if (codec->hw_write(codec->control_data, data, 3) == 3)
return 0;
else
return -EIO;
}
static int wm9081_reset(struct snd_soc_codec *codec) static int wm9081_reset(struct snd_soc_codec *codec)
{ {
return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0); return snd_soc_write(codec, WM9081_SOFTWARE_RESET, 0);
} }
static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0); static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
@ -356,7 +291,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg; unsigned int reg;
reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
if (reg & WM9081_SPK_MODE) if (reg & WM9081_SPK_MODE)
ucontrol->value.integer.value[0] = 1; ucontrol->value.integer.value[0] = 1;
else else
@ -375,8 +310,8 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT); unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2);
/* Are we changing anything? */ /* Are we changing anything? */
if (ucontrol->value.integer.value[0] == if (ucontrol->value.integer.value[0] ==
@ -397,7 +332,7 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol,
reg2 &= ~WM9081_SPK_MODE; reg2 &= ~WM9081_SPK_MODE;
} }
wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2); snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2);
return 0; return 0;
} }
@ -456,7 +391,7 @@ static int speaker_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT); unsigned int reg = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
switch (event) { switch (event) {
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
@ -468,7 +403,7 @@ static int speaker_event(struct snd_soc_dapm_widget *w,
break; break;
} }
wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg); snd_soc_write(codec, WM9081_POWER_MANAGEMENT, reg);
return 0; return 0;
} }
@ -607,7 +542,7 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
if (ret != 0) if (ret != 0)
return ret; return ret;
reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5); reg5 = snd_soc_read(codec, WM9081_FLL_CONTROL_5);
reg5 &= ~WM9081_FLL_CLK_SRC_MASK; reg5 &= ~WM9081_FLL_CLK_SRC_MASK;
switch (fll_id) { switch (fll_id) {
@ -621,44 +556,44 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
} }
/* Disable CLK_SYS while we reconfigure */ /* Disable CLK_SYS while we reconfigure */
clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); clk_sys_reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
if (clk_sys_reg & WM9081_CLK_SYS_ENA) if (clk_sys_reg & WM9081_CLK_SYS_ENA)
wm9081_write(codec, WM9081_CLOCK_CONTROL_3, snd_soc_write(codec, WM9081_CLOCK_CONTROL_3,
clk_sys_reg & ~WM9081_CLK_SYS_ENA); clk_sys_reg & ~WM9081_CLK_SYS_ENA);
/* Any FLL configuration change requires that the FLL be /* Any FLL configuration change requires that the FLL be
* disabled first. */ * disabled first. */
reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1); reg1 = snd_soc_read(codec, WM9081_FLL_CONTROL_1);
reg1 &= ~WM9081_FLL_ENA; reg1 &= ~WM9081_FLL_ENA;
wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);
/* Apply the configuration */ /* Apply the configuration */
if (fll_div.k) if (fll_div.k)
reg1 |= WM9081_FLL_FRAC_MASK; reg1 |= WM9081_FLL_FRAC_MASK;
else else
reg1 &= ~WM9081_FLL_FRAC_MASK; reg1 &= ~WM9081_FLL_FRAC_MASK;
wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1);
wm9081_write(codec, WM9081_FLL_CONTROL_2, snd_soc_write(codec, WM9081_FLL_CONTROL_2,
(fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) | (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
(fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT)); (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k); snd_soc_write(codec, WM9081_FLL_CONTROL_3, fll_div.k);
reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4); reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4);
reg4 &= ~WM9081_FLL_N_MASK; reg4 &= ~WM9081_FLL_N_MASK;
reg4 |= fll_div.n << WM9081_FLL_N_SHIFT; reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4); snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4);
reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK; reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT; reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5); snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5);
/* Enable the FLL */ /* Enable the FLL */
wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
/* Then bring CLK_SYS up again if it was disabled */ /* Then bring CLK_SYS up again if it was disabled */
if (clk_sys_reg & WM9081_CLK_SYS_ENA) if (clk_sys_reg & WM9081_CLK_SYS_ENA)
wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
@ -742,19 +677,19 @@ static int configure_clock(struct snd_soc_codec *codec)
return -EINVAL; return -EINVAL;
} }
reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1); reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_1);
if (mclkdiv) if (mclkdiv)
reg |= WM9081_MCLKDIV2; reg |= WM9081_MCLKDIV2;
else else
reg &= ~WM9081_MCLKDIV2; reg &= ~WM9081_MCLKDIV2;
wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg); snd_soc_write(codec, WM9081_CLOCK_CONTROL_1, reg);
reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3);
if (fll) if (fll)
reg |= WM9081_CLK_SRC_SEL; reg |= WM9081_CLK_SRC_SEL;
else else
reg &= ~WM9081_CLK_SRC_SEL; reg &= ~WM9081_CLK_SRC_SEL;
wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg); snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, reg);
dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate); dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
@ -854,76 +789,76 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* VMID=2*40k */ /* VMID=2*40k */
reg = wm9081_read(codec, WM9081_VMID_CONTROL); reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
reg &= ~WM9081_VMID_SEL_MASK; reg &= ~WM9081_VMID_SEL_MASK;
reg |= 0x2; reg |= 0x2;
wm9081_write(codec, WM9081_VMID_CONTROL, reg); snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
/* Normal bias current */ /* Normal bias current */
reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
reg &= ~WM9081_STBY_BIAS_ENA; reg &= ~WM9081_STBY_BIAS_ENA;
wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
/* Initial cold start */ /* Initial cold start */
if (codec->bias_level == SND_SOC_BIAS_OFF) { if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* Disable LINEOUT discharge */ /* Disable LINEOUT discharge */
reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL);
reg &= ~WM9081_LINEOUT_DISCH; reg &= ~WM9081_LINEOUT_DISCH;
wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg);
/* Select startup bias source */ /* Select startup bias source */
reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA; reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA;
wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
/* VMID 2*4k; Soft VMID ramp enable */ /* VMID 2*4k; Soft VMID ramp enable */
reg = wm9081_read(codec, WM9081_VMID_CONTROL); reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
reg |= WM9081_VMID_RAMP | 0x6; reg |= WM9081_VMID_RAMP | 0x6;
wm9081_write(codec, WM9081_VMID_CONTROL, reg); snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
mdelay(100); mdelay(100);
/* Normal bias enable & soft start off */ /* Normal bias enable & soft start off */
reg |= WM9081_BIAS_ENA; reg |= WM9081_BIAS_ENA;
reg &= ~WM9081_VMID_RAMP; reg &= ~WM9081_VMID_RAMP;
wm9081_write(codec, WM9081_VMID_CONTROL, reg); snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
/* Standard bias source */ /* Standard bias source */
reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
reg &= ~WM9081_BIAS_SRC; reg &= ~WM9081_BIAS_SRC;
wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
} }
/* VMID 2*240k */ /* VMID 2*240k */
reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
reg &= ~WM9081_VMID_SEL_MASK; reg &= ~WM9081_VMID_SEL_MASK;
reg |= 0x40; reg |= 0x40;
wm9081_write(codec, WM9081_VMID_CONTROL, reg); snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
/* Standby bias current on */ /* Standby bias current on */
reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
reg |= WM9081_STBY_BIAS_ENA; reg |= WM9081_STBY_BIAS_ENA;
wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* Startup bias source */ /* Startup bias source */
reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
reg |= WM9081_BIAS_SRC; reg |= WM9081_BIAS_SRC;
wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
/* Disable VMID and biases with soft ramping */ /* Disable VMID and biases with soft ramping */
reg = wm9081_read(codec, WM9081_VMID_CONTROL); reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA); reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA);
reg |= WM9081_VMID_RAMP; reg |= WM9081_VMID_RAMP;
wm9081_write(codec, WM9081_VMID_CONTROL, reg); snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
/* Actively discharge LINEOUT */ /* Actively discharge LINEOUT */
reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL);
reg |= WM9081_LINEOUT_DISCH; reg |= WM9081_LINEOUT_DISCH;
wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg);
break; break;
} }
@ -937,7 +872,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct wm9081_priv *wm9081 = codec->private_data; struct wm9081_priv *wm9081 = codec->private_data;
unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);
aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV | aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK); WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
@ -1018,7 +953,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
return -EINVAL; return -EINVAL;
} }
wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
return 0; return 0;
} }
@ -1032,18 +967,18 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
int ret, i, best, best_val, cur_val; int ret, i, best, best_val, cur_val;
unsigned int clk_ctrl2, aif1, aif2, aif3, aif4; unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2); clk_ctrl2 = snd_soc_read(codec, WM9081_CLOCK_CONTROL_2);
clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK); clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK);
aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1);
aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);
aif2 &= ~WM9081_AIF_WL_MASK; aif2 &= ~WM9081_AIF_WL_MASK;
aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3); aif3 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_3);
aif3 &= ~WM9081_BCLK_DIV_MASK; aif3 &= ~WM9081_BCLK_DIV_MASK;
aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4); aif4 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_4);
aif4 &= ~WM9081_LRCLK_RATE_MASK; aif4 &= ~WM9081_LRCLK_RATE_MASK;
/* What BCLK do we need? */ /* What BCLK do we need? */
@ -1157,22 +1092,22 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
s->name, s->rate); s->name, s->rate);
/* If the EQ is enabled then disable it while we write out */ /* If the EQ is enabled then disable it while we write out */
eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA; eq1 = snd_soc_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA;
if (eq1 & WM9081_EQ_ENA) if (eq1 & WM9081_EQ_ENA)
wm9081_write(codec, WM9081_EQ_1, 0); snd_soc_write(codec, WM9081_EQ_1, 0);
/* Write out the other values */ /* Write out the other values */
for (i = 1; i < ARRAY_SIZE(s->config); i++) for (i = 1; i < ARRAY_SIZE(s->config); i++)
wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]); snd_soc_write(codec, WM9081_EQ_1 + i, s->config[i]);
eq1 |= (s->config[0] & ~WM9081_EQ_ENA); eq1 |= (s->config[0] & ~WM9081_EQ_ENA);
wm9081_write(codec, WM9081_EQ_1, eq1); snd_soc_write(codec, WM9081_EQ_1, eq1);
} }
wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2); snd_soc_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2);
wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3); snd_soc_write(codec, WM9081_AUDIO_INTERFACE_3, aif3);
wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4); snd_soc_write(codec, WM9081_AUDIO_INTERFACE_4, aif4);
return 0; return 0;
} }
@ -1182,14 +1117,14 @@ static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
unsigned int reg; unsigned int reg;
reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2); reg = snd_soc_read(codec, WM9081_DAC_DIGITAL_2);
if (mute) if (mute)
reg |= WM9081_DAC_MUTE; reg |= WM9081_DAC_MUTE;
else else
reg &= ~WM9081_DAC_MUTE; reg &= ~WM9081_DAC_MUTE;
wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg); snd_soc_write(codec, WM9081_DAC_DIGITAL_2, reg);
return 0; return 0;
} }
@ -1218,7 +1153,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int mask, int slots) unsigned int mask, int slots)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); unsigned int aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1);
aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK); aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
@ -1243,7 +1178,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL; return -EINVAL;
} }
wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1); snd_soc_write(codec, WM9081_AUDIO_INTERFACE_1, aif1);
return 0; return 0;
} }
@ -1365,7 +1300,7 @@ static int wm9081_resume(struct platform_device *pdev)
if (i == WM9081_SOFTWARE_RESET) if (i == WM9081_SOFTWARE_RESET)
continue; continue;
wm9081_write(codec, i, reg_cache[i]); snd_soc_write(codec, i, reg_cache[i]);
} }
wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@ -1385,7 +1320,8 @@ struct snd_soc_codec_device soc_codec_dev_wm9081 = {
}; };
EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081); EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
static int wm9081_register(struct wm9081_priv *wm9081) static int wm9081_register(struct wm9081_priv *wm9081,
enum snd_soc_control_type control)
{ {
struct snd_soc_codec *codec = &wm9081->codec; struct snd_soc_codec *codec = &wm9081->codec;
int ret; int ret;
@ -1404,19 +1340,24 @@ static int wm9081_register(struct wm9081_priv *wm9081)
codec->private_data = wm9081; codec->private_data = wm9081;
codec->name = "WM9081"; codec->name = "WM9081";
codec->owner = THIS_MODULE; codec->owner = THIS_MODULE;
codec->read = wm9081_read;
codec->write = wm9081_write;
codec->dai = &wm9081_dai; codec->dai = &wm9081_dai;
codec->num_dai = 1; codec->num_dai = 1;
codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache); codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
codec->reg_cache = &wm9081->reg_cache; codec->reg_cache = &wm9081->reg_cache;
codec->bias_level = SND_SOC_BIAS_OFF; codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = wm9081_set_bias_level; codec->set_bias_level = wm9081_set_bias_level;
codec->volatile_register = wm9081_volatile_register;
memcpy(codec->reg_cache, wm9081_reg_defaults, memcpy(codec->reg_cache, wm9081_reg_defaults,
sizeof(wm9081_reg_defaults)); sizeof(wm9081_reg_defaults));
reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET); ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
if (reg != 0x9081) { if (reg != 0x9081) {
dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg); dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
ret = -EINVAL; ret = -EINVAL;
@ -1432,10 +1373,10 @@ static int wm9081_register(struct wm9081_priv *wm9081)
wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Enable zero cross by default */ /* Enable zero cross by default */
reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT); reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
reg | WM9081_SPKPGAZC); reg | WM9081_SPKPGAZC);
wm9081_dai.dev = codec->dev; wm9081_dai.dev = codec->dev;
@ -1490,7 +1431,7 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
codec->dev = &i2c->dev; codec->dev = &i2c->dev;
return wm9081_register(wm9081); return wm9081_register(wm9081, SND_SOC_I2C);
} }
static __devexit int wm9081_i2c_remove(struct i2c_client *client) static __devexit int wm9081_i2c_remove(struct i2c_client *client)

218
sound/soc/soc-cache.c Normal file
View File

@ -0,0 +1,218 @@
/*
* soc-cache.c -- ASoC register cache helpers
*
* Copyright 2009 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <sound/soc.h>
static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= codec->reg_cache_size)
return -1;
return cache[reg];
}
static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u16 *cache = codec->reg_cache;
u8 data[2];
int ret;
BUG_ON(codec->volatile_register);
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
if (reg < codec->reg_cache_size)
cache[reg] = value;
ret = codec->hw_write(codec->control_data, data, 2);
if (ret == 2)
return 0;
if (ret < 0)
return ret;
else
return -EIO;
}
#if defined(CONFIG_SPI_MASTER)
static int snd_soc_7_9_spi_write(void *control_data, const char *data,
int len)
{
struct spi_device *spi = control_data;
struct spi_transfer t;
struct spi_message m;
u8 msg[2];
if (len <= 0)
return 0;
msg[0] = data[0];
msg[1] = data[1];
spi_message_init(&m);
memset(&t, 0, (sizeof t));
t.tx_buf = &msg[0];
t.len = len;
spi_message_add_tail(&t, &m);
spi_sync(spi, &m);
return len;
}
#else
#define snd_soc_7_9_spi_write NULL
#endif
static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u16 *reg_cache = codec->reg_cache;
u8 data[3];
data[0] = reg;
data[1] = (value >> 8) & 0xff;
data[2] = value & 0xff;
if (!snd_soc_codec_volatile_register(codec, reg))
reg_cache[reg] = value;
if (codec->hw_write(codec->control_data, data, 3) == 3)
return 0;
else
return -EIO;
}
static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= codec->reg_cache_size ||
snd_soc_codec_volatile_register(codec, reg))
return codec->hw_read(codec, reg);
else
return cache[reg];
}
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
unsigned int r)
{
struct i2c_msg xfer[2];
u8 reg = r;
u16 data;
int ret;
struct i2c_client *client = codec->control_data;
/* Write register */
xfer[0].addr = client->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (u8 *)&data;
ret = i2c_transfer(client->adapter, xfer, 2);
if (ret != 2) {
dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
return 0;
}
return (data >> 8) | ((data & 0xff) << 8);
}
#else
#define snd_soc_8_16_read_i2c NULL
#endif
static struct {
int addr_bits;
int data_bits;
int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
int (*spi_write)(void *, const char *, int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
} io_types[] = {
{ 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read },
{ 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read,
snd_soc_8_16_read_i2c },
};
/**
* snd_soc_codec_set_cache_io: Set up standard I/O functions.
*
* @codec: CODEC to configure.
* @type: Type of cache.
* @addr_bits: Number of bits of register address data.
* @data_bits: Number of bits of data per register.
* @control: Control bus used.
*
* Register formats are frequently shared between many I2C and SPI
* devices. In order to promote code reuse the ASoC core provides
* some standard implementations of CODEC read and write operations
* which can be set up using this function.
*
* The caller is responsible for allocating and initialising the
* actual cache.
*
* Note that at present this code cannot be used by CODECs with
* volatile registers.
*/
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control)
{
int i;
for (i = 0; i < ARRAY_SIZE(io_types); i++)
if (io_types[i].addr_bits == addr_bits &&
io_types[i].data_bits == data_bits)
break;
if (i == ARRAY_SIZE(io_types)) {
printk(KERN_ERR
"No I/O functions for %d bit address %d bit data\n",
addr_bits, data_bits);
return -EINVAL;
}
codec->write = io_types[i].write;
codec->read = io_types[i].read;
switch (control) {
case SND_SOC_CUSTOM:
break;
case SND_SOC_I2C:
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
codec->hw_write = (hw_write_t)i2c_master_send;
#endif
if (io_types[i].i2c_read)
codec->hw_read = io_types[i].i2c_read;
break;
case SND_SOC_SPI:
if (io_types[i].spi_write)
codec->hw_write = io_types[i].spi_write;
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);