ASoC: Factor out I/O for Wolfson 8 bit data 16 bit register CODECs

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
Mark Brown
2009-07-10 23:12:01 +01:00
parent afa2f1066e
commit 8d50e447d1
7 ha cambiato i file con 521 aggiunte e 937 eliminazioni

Vedi File

@@ -108,53 +108,7 @@ static const u16 wm8990_reg[] = {
0x0000, /* R63 - Driver internal */
};
/*
* 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)
#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
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;
/* now hit the volume update bits (always bit 8) */
val = wm8990_read_reg_cache(codec, reg);
return wm8990_write(codec, reg, val | 0x0100);
val = snd_soc_read(codec, reg);
return snd_soc_write(codec, reg, val | 0x0100);
}
#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;
reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2);
fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS);
reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2);
fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS);
if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) |
(1 << WM8990_AINLMUX_PWR_BIT))) {
@@ -443,7 +397,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w,
} else {
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;
}
@@ -457,7 +411,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
switch (reg_shift) {
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) {
printk(KERN_WARNING
"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -465,7 +419,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
}
break;
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) {
printk(KERN_WARNING
"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -473,7 +427,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
}
break;
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) {
printk(KERN_WARNING
"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -481,7 +435,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
}
break;
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) {
printk(KERN_WARNING
"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);
/* 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;
wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
/* sysclk comes from PLL */
reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2);
wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC);
reg = snd_soc_read(codec, WM8990_CLOCKING_2);
snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC);
/* 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));
wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
} else {
/* 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;
wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
}
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;
u16 audio1, audio3;
audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1);
audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3);
audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
audio3 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_3);
/* set master/slave audio interface */
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;
}
wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3);
snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
snd_soc_write(codec, WM8990_AUDIO_INTERFACE_3, audio3);
return 0;
}
@@ -1128,24 +1082,24 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) {
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_write(codec, WM8990_CLOCKING_2, reg | div);
snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break;
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_write(codec, WM8990_CLOCKING_2, reg | div);
snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break;
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_write(codec, WM8990_CLOCKING_2, reg | div);
snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break;
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_write(codec, WM8990_CLOCKING_1, reg | div);
snd_soc_write(codec, WM8990_CLOCKING_1, reg | div);
break;
default:
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_device *socdev = rtd->socdev;
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;
/* bit size */
@@ -1182,7 +1136,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
break;
}
wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1);
return 0;
}
@@ -1191,12 +1145,12 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
struct snd_soc_codec *codec = dai->codec;
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)
wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
else
wm8990_write(codec, WM8990_DAC_CTRL, val);
snd_soc_write(codec, WM8990_DAC_CTRL, val);
return 0;
}
@@ -1212,21 +1166,21 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
/* 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_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
/* 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_OUT4 | WM8990_DIS_LOUT |
WM8990_DIS_ROUT);
/* 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_VMIDTOG);
@@ -1234,83 +1188,83 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
msleep(msecs_to_jiffies(300));
/* Disable VMIDTOG */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_BUFDCOPEN | WM8990_POBCTRL);
/* disable all output discharge bits */
wm8990_write(codec, WM8990_ANTIPOP1, 0);
snd_soc_write(codec, WM8990_ANTIPOP1, 0);
/* Enable outputs */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
msleep(msecs_to_jiffies(50));
/* 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));
/* Enable VREF */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
msleep(msecs_to_jiffies(600));
/* Enable BUFIOEN */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_BUFDCOPEN | WM8990_POBCTRL |
WM8990_BUFIOEN);
/* 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 */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN);
/* Enable workaround for ADC clocking issue. */
wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
wm8990_write(codec, WM8990_EXT_CTL1, 0xa003);
wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0);
snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0x2);
snd_soc_write(codec, WM8990_EXT_CTL1, 0xa003);
snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0);
}
/* 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_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
break;
case SND_SOC_BIAS_OFF:
/* Enable POBCTRL and SOFT_ST */
wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
WM8990_POBCTRL | WM8990_BUFIOEN);
/* 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_BUFIOEN);
/* mute DAC */
val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL);
wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
val = snd_soc_read(codec, WM8990_DAC_CTRL);
snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE);
/* Enable any disabled outputs */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
/* Disable VMID */
wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
msleep(msecs_to_jiffies(300));
/* 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_OUT4 | WM8990_DIS_LOUT |
WM8990_DIS_ROUT);
/* 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 */
wm8990_write(codec, WM8990_ANTIPOP2, 0x0);
snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
break;
}
@@ -1411,8 +1365,6 @@ static int wm8990_init(struct snd_soc_device *socdev)
codec->name = "WM8990";
codec->owner = THIS_MODULE;
codec->read = wm8990_read_reg_cache;
codec->write = wm8990_write;
codec->set_bias_level = wm8990_set_bias_level;
codec->dai = &wm8990_dai;
codec->num_dai = 2;
@@ -1422,6 +1374,12 @@ static int wm8990_init(struct snd_soc_device *socdev)
if (codec->reg_cache == NULL)
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);
/* register pcms */
@@ -1435,18 +1393,18 @@ static int wm8990_init(struct snd_soc_device *socdev)
codec->bias_level = SND_SOC_BIAS_OFF;
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4);
wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1);
reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
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_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);
wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA);
reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA);
wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_add_controls(codec, wm8990_snd_controls,
ARRAY_SIZE(wm8990_snd_controls));