Skip to content

Commit

Permalink
ASoC: Begin to factor out register cache I/O functions
Browse files Browse the repository at this point in the history
A lot of CODECs share the same register data formats and therefore
replicate the code to manage access to and caching of the register
map. In order to reduce code duplication centralised versions of
this code will be introduced with drivers able to configure the use
of the common code by calling the new snd_soc_codec_set_cache_io()
API call during startup.

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

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
  • Loading branch information
Mark Brown committed Jul 5, 2009
1 parent 5420f30 commit 17a52fd
Show file tree
Hide file tree
Showing 10 changed files with 400 additions and 577 deletions.
2 changes: 2 additions & 0 deletions include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform);
int snd_soc_register_codec(struct snd_soc_codec *codec);
void snd_soc_unregister_codec(struct snd_soc_codec *codec);
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits);

#ifdef CONFIG_PM
int snd_soc_suspend_device(struct device *dev);
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/Makefile
Original file line number Diff line number Diff line change
@@ -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) += codecs/
Expand Down
141 changes: 49 additions & 92 deletions sound/soc/codecs/wm8510.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,55 +58,7 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
#define WM8510_POWER1_BIASEN 0x08
#define WM8510_POWER1_BUFIOEN 0x10

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

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

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

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

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

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

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

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

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

pll_factors(freq_out*4, freq_in);

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

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

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

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

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

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

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

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

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

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

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

/* liam need to make this lower power with dapm */
static int wm8510_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3;
u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3;

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

case SND_SOC_BIAS_STANDBY:
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;

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

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

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

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

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

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

wm8510_reset(codec);

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

/* power on device */
Expand All @@ -655,7 +612,7 @@ static int wm8510_init(struct snd_soc_device *socdev)
card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
err:
kfree(codec->reg_cache);
return ret;
}
Expand Down
Loading

0 comments on commit 17a52fd

Please sign in to comment.