diff options
Diffstat (limited to 'sound/soc/codecs/wm8400.c')
-rw-r--r-- | sound/soc/codecs/wm8400.c | 95 |
1 files changed, 75 insertions, 20 deletions
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 48dc7d2..d2a0928 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -32,6 +32,13 @@ #include "wm8400.h" +/* Fake register for internal state */ +#define WM8400_INTDRIVBITS (WM8400_REGISTER_COUNT + 1) +#define WM8400_INMIXL_PWR 0 +#define WM8400_AINLMUX_PWR 1 +#define WM8400_INMIXR_PWR 2 +#define WM8400_AINRMUX_PWR 3 + static struct regulator_bulk_data power[] = { { .supply = "I2S1VDD", @@ -67,6 +74,32 @@ struct wm8400_priv { int fll_in, fll_out; }; +static inline unsigned int wm8400_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); + + if (reg == WM8400_INTDRIVBITS) + return wm8400->fake_register; + else + return wm8400_reg_read(wm8400->wm8400, reg); +} + +/* + * write to the wm8400 register space + */ +static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); + + if (reg == WM8400_INTDRIVBITS) { + wm8400->fake_register = value; + return 0; + } else + return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value); +} + static void wm8400_codec_reset(struct snd_soc_codec *codec) { struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec); @@ -319,6 +352,32 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME, * _DAPM_ Controls */ +static int inmixer_event (struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + u16 reg, fakepower; + + reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2); + fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS); + + if (fakepower & ((1 << WM8400_INMIXL_PWR) | + (1 << WM8400_AINLMUX_PWR))) { + reg |= WM8400_AINL_ENA; + } else { + reg &= ~WM8400_AINL_ENA; + } + + if (fakepower & ((1 << WM8400_INMIXR_PWR) | + (1 << WM8400_AINRMUX_PWR))) { + reg |= WM8400_AINR_ENA; + } else { + reg &= ~WM8400_AINR_ENA; + } + snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg); + + return 0; +} + static int outmixer_event (struct snd_soc_dapm_widget *w, struct snd_kcontrol * kcontrol, int event) { @@ -599,26 +658,27 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2, 0, &wm8400_dapm_rin34_pga_controls[0], ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)), -SND_SOC_DAPM_SUPPLY("INL", WM8400_POWER_MANAGEMENT_2, WM8400_AINL_ENA_SHIFT, - 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("INR", WM8400_POWER_MANAGEMENT_2, WM8400_AINR_ENA_SHIFT, - 0, NULL, 0), - /* INMIXL */ -SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0, +SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0, &wm8400_dapm_inmixl_controls[0], - ARRAY_SIZE(wm8400_dapm_inmixl_controls)), + ARRAY_SIZE(wm8400_dapm_inmixl_controls), + inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* AINLMUX */ -SND_SOC_DAPM_MUX("AILNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainlmux_controls), +SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0, + &wm8400_dapm_ainlmux_controls, inmixer_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* INMIXR */ -SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0, +SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0, &wm8400_dapm_inmixr_controls[0], - ARRAY_SIZE(wm8400_dapm_inmixr_controls)), + ARRAY_SIZE(wm8400_dapm_inmixr_controls), + inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* AINRMUX */ -SND_SOC_DAPM_MUX("AIRNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainrmux_controls), +SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0, + &wm8400_dapm_ainrmux_controls, inmixer_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* Output Side */ /* DACs */ @@ -729,13 +789,11 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = { {"LIN34 PGA", "LIN3 Switch", "LIN3"}, {"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"}, /* INMIXL */ - {"INMIXL", NULL, "INL"}, {"INMIXL", "Record Left Volume", "LOMIX"}, {"INMIXL", "LIN2 Volume", "LIN2"}, {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, /* AILNMUX */ - {"AILNMUX", NULL, "INL"}, {"AILNMUX", "INMIXL Mix", "INMIXL"}, {"AILNMUX", "DIFFINL Mix", "LIN12 PGA"}, {"AILNMUX", "DIFFINL Mix", "LIN34 PGA"}, @@ -750,14 +808,12 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = { /* RIN34 PGA */ {"RIN34 PGA", "RIN3 Switch", "RIN3"}, {"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"}, - /* INMIXR */ - {"INMIXR", NULL, "INR"}, + /* INMIXL */ {"INMIXR", "Record Right Volume", "ROMIX"}, {"INMIXR", "RIN2 Volume", "RIN2"}, {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, /* AIRNMUX */ - {"AIRNMUX", NULL, "INR"}, {"AIRNMUX", "INMIXR Mix", "INMIXR"}, {"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"}, {"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"}, @@ -1309,12 +1365,9 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) return -ENOMEM; snd_soc_codec_set_drvdata(codec, priv); - priv->wm8400 = wm8400; - codec->control_data = wm8400->regmap; + codec->control_data = priv->wm8400 = wm8400; priv->codec = codec; - snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); - ret = devm_regulator_bulk_get(wm8400->dev, ARRAY_SIZE(power), &power[0]); if (ret != 0) { @@ -1361,6 +1414,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { .remove = wm8400_codec_remove, .suspend = wm8400_suspend, .resume = wm8400_resume, + .read = snd_soc_read, + .write = wm8400_write, .set_bias_level = wm8400_set_bias_level, .controls = wm8400_snd_controls, |