diff options
Diffstat (limited to 'sound/soc/codecs/wm8990.c')
| -rw-r--r-- | sound/soc/codecs/wm8990.c | 472 |
1 files changed, 143 insertions, 329 deletions
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 253c88bb7a4c..9f2b42025ec9 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * wm8990.c -- WM8990 ALSA Soc Audio driver * * Copyright 2008 Wolfson Microelectronics PLC. * Author: Liam Girdwood <lrg@slimlogic.co.uk> - * - * 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/module.h> @@ -17,6 +13,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <sound/core.h> #include <sound/pcm.h> @@ -30,92 +27,12 @@ /* codec private data */ struct wm8990_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; unsigned int sysclk; unsigned int pcmclk; }; -static int wm8990_volatile_register(struct snd_soc_codec *codec, - unsigned int reg) -{ - switch (reg) { - case WM8990_RESET: - return 1; - default: - return 0; - } -} - -static const u16 wm8990_reg[] = { - 0x8990, /* R0 - Reset */ - 0x0000, /* R1 - Power Management (1) */ - 0x6000, /* R2 - Power Management (2) */ - 0x0000, /* R3 - Power Management (3) */ - 0x4050, /* R4 - Audio Interface (1) */ - 0x4000, /* R5 - Audio Interface (2) */ - 0x01C8, /* R6 - Clocking (1) */ - 0x0000, /* R7 - Clocking (2) */ - 0x0040, /* R8 - Audio Interface (3) */ - 0x0040, /* R9 - Audio Interface (4) */ - 0x0004, /* R10 - DAC CTRL */ - 0x00C0, /* R11 - Left DAC Digital Volume */ - 0x00C0, /* R12 - Right DAC Digital Volume */ - 0x0000, /* R13 - Digital Side Tone */ - 0x0100, /* R14 - ADC CTRL */ - 0x00C0, /* R15 - Left ADC Digital Volume */ - 0x00C0, /* R16 - Right ADC Digital Volume */ - 0x0000, /* R17 */ - 0x0000, /* R18 - GPIO CTRL 1 */ - 0x1000, /* R19 - GPIO1 & GPIO2 */ - 0x1010, /* R20 - GPIO3 & GPIO4 */ - 0x1010, /* R21 - GPIO5 & GPIO6 */ - 0x8000, /* R22 - GPIOCTRL 2 */ - 0x0800, /* R23 - GPIO_POL */ - 0x008B, /* R24 - Left Line Input 1&2 Volume */ - 0x008B, /* R25 - Left Line Input 3&4 Volume */ - 0x008B, /* R26 - Right Line Input 1&2 Volume */ - 0x008B, /* R27 - Right Line Input 3&4 Volume */ - 0x0000, /* R28 - Left Output Volume */ - 0x0000, /* R29 - Right Output Volume */ - 0x0066, /* R30 - Line Outputs Volume */ - 0x0022, /* R31 - Out3/4 Volume */ - 0x0079, /* R32 - Left OPGA Volume */ - 0x0079, /* R33 - Right OPGA Volume */ - 0x0003, /* R34 - Speaker Volume */ - 0x0003, /* R35 - ClassD1 */ - 0x0000, /* R36 */ - 0x0100, /* R37 - ClassD3 */ - 0x0079, /* R38 - ClassD4 */ - 0x0000, /* R39 - Input Mixer1 */ - 0x0000, /* R40 - Input Mixer2 */ - 0x0000, /* R41 - Input Mixer3 */ - 0x0000, /* R42 - Input Mixer4 */ - 0x0000, /* R43 - Input Mixer5 */ - 0x0000, /* R44 - Input Mixer6 */ - 0x0000, /* R45 - Output Mixer1 */ - 0x0000, /* R46 - Output Mixer2 */ - 0x0000, /* R47 - Output Mixer3 */ - 0x0000, /* R48 - Output Mixer4 */ - 0x0000, /* R49 - Output Mixer5 */ - 0x0000, /* R50 - Output Mixer6 */ - 0x0180, /* R51 - Out3/4 Mixer */ - 0x0000, /* R52 - Line Mixer1 */ - 0x0000, /* R53 - Line Mixer2 */ - 0x0000, /* R54 - Speaker Mixer */ - 0x0000, /* R55 - Additional Control */ - 0x0000, /* R56 - AntiPOP1 */ - 0x0000, /* R57 - AntiPOP2 */ - 0x0000, /* R58 - MICBIAS */ - 0x0000, /* R59 */ - 0x0008, /* R60 - PLL1 */ - 0x0031, /* R61 - PLL2 */ - 0x0026, /* R62 - PLL3 */ - 0x0000, /* R63 - Driver internal */ -}; - -#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0) - -static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0); +#define wm8990_reset(c) snd_soc_component_write(c, WM8990_RESET, 0) static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0); @@ -123,8 +40,6 @@ static const DECLARE_TLV_DB_SCALE(out_mix_tlv, 0, -2100, 0); static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0); -static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0); - static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0); static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0); @@ -134,7 +49,7 @@ static const DECLARE_TLV_DB_SCALE(out_sidetone_tlv, -3600, 0, 0); static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; @@ -146,8 +61,8 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, return ret; /* now hit the volume update bits (always bit 8) */ - val = snd_soc_read(codec, reg); - return snd_soc_write(codec, reg, val | 0x0100); + val = snd_soc_component_read(component, reg); + return snd_soc_component_write(component, reg, val | 0x0100); } #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ @@ -159,26 +74,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, static const char *wm8990_digital_sidetone[] = {"None", "Left ADC", "Right ADC", "Reserved"}; -static const struct soc_enum wm8990_left_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, - WM8990_ADC_TO_DACL_SHIFT, - WM8990_ADC_TO_DACL_MASK, - wm8990_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8990_left_digital_sidetone_enum, + WM8990_DIGITAL_SIDE_TONE, + WM8990_ADC_TO_DACL_SHIFT, + wm8990_digital_sidetone); -static const struct soc_enum wm8990_right_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, - WM8990_ADC_TO_DACR_SHIFT, - WM8990_ADC_TO_DACR_MASK, - wm8990_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8990_right_digital_sidetone_enum, + WM8990_DIGITAL_SIDE_TONE, + WM8990_ADC_TO_DACR_SHIFT, + wm8990_digital_sidetone); static const char *wm8990_adcmode[] = {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; -static const struct soc_enum wm8990_right_adcmode_enum = -SOC_ENUM_SINGLE(WM8990_ADC_CTRL, - WM8990_ADC_HPF_CUT_SHIFT, - WM8990_ADC_HPF_CUT_MASK, - wm8990_adcmode); +static SOC_ENUM_SINGLE_DECL(wm8990_right_adcmode_enum, + WM8990_ADC_CTRL, + WM8990_ADC_HPF_CUT_SHIFT, + wm8990_adcmode); static const struct snd_kcontrol_new wm8990_snd_controls[] = { /* INMIXL */ @@ -376,42 +288,17 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_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, WM8990_POWER_MANAGEMENT_2); - fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS); - - if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | - (1 << WM8990_AINLMUX_PWR_BIT))) { - reg |= WM8990_AINL_ENA; - } else { - reg &= ~WM8990_AINL_ENA; - } - - if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | - (1 << WM8990_AINRMUX_PWR_BIT))) { - reg |= WM8990_AINR_ENA; - } else { - reg &= ~WM8990_AINR_ENA; - } - snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); - - return 0; -} - static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); u32 reg_shift = kcontrol->private_value & 0xfff; int ret = 0; u16 reg; switch (reg_shift) { case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : - reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1); + reg = snd_soc_component_read(component, WM8990_OUTPUT_MIXER1); if (reg & WM8990_LDLO) { printk(KERN_WARNING "Cannot set as Output Mixer 1 LDLO Set\n"); @@ -419,7 +306,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2); + reg = snd_soc_component_read(component, WM8990_OUTPUT_MIXER2); if (reg & WM8990_RDRO) { printk(KERN_WARNING "Cannot set as Output Mixer 2 RDRO Set\n"); @@ -427,7 +314,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); + reg = snd_soc_component_read(component, WM8990_SPEAKER_MIXER); if (reg & WM8990_LDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer LDSPK Set\n"); @@ -435,7 +322,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); + reg = snd_soc_component_read(component, WM8990_SPEAKER_MIXER); if (reg & WM8990_RDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer RDSPK Set\n"); @@ -448,10 +335,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } /* INMIX dB values */ -static const unsigned int in_mix_tlv[] = { - TLV_DB_RANGE_HEAD(1), - 0, 7, TLV_DB_SCALE_ITEM(-1200, 600, 0), -}; +static const DECLARE_TLV_DB_SCALE(in_mix_tlv, -1200, 600, 0); /* Left In PGA Connections */ static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { @@ -503,9 +387,9 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, static const char *wm8990_ainlmux[] = {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; -static const struct soc_enum wm8990_ainlmux_enum = -SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, - ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); +static SOC_ENUM_SINGLE_DECL(wm8990_ainlmux_enum, + WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, + wm8990_ainlmux); static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); @@ -516,21 +400,13 @@ SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); static const char *wm8990_ainrmux[] = {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; -static const struct soc_enum wm8990_ainrmux_enum = -SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, - ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); +static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum, + WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, + wm8990_ainrmux); static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); -/* RXVOICE */ -static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { -SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, - WM8990_LR4BVOL_MASK, 0, in_mix_tlv), -SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, - WM8990_RL4BVOL_MASK, 0, in_mix_tlv), -}; - /* LOMIX */ static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, @@ -656,6 +532,11 @@ SND_SOC_DAPM_INPUT("RIN1"), SND_SOC_DAPM_INPUT("RIN2"), SND_SOC_DAPM_INPUT("Internal ADC Source"), +SND_SOC_DAPM_SUPPLY("INL", WM8990_POWER_MANAGEMENT_2, WM8990_AINL_ENA_BIT, 0, + NULL, 0), +SND_SOC_DAPM_SUPPLY("INR", WM8990_POWER_MANAGEMENT_2, WM8990_AINR_ENA_BIT, 0, + NULL, 0), + /* DACs */ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, WM8990_ADCL_ENA_BIT, 0), @@ -677,26 +558,20 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT, ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), /* INMIXL */ -SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, +SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0, &wm8990_dapm_inmixl_controls[0], - ARRAY_SIZE(wm8990_dapm_inmixl_controls), - inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + ARRAY_SIZE(wm8990_dapm_inmixl_controls)), /* AINLMUX */ -SND_SOC_DAPM_MUX_E("AINLMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, - &wm8990_dapm_ainlmux_controls, inmixer_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainlmux_controls), /* INMIXR */ -SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, +SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0, &wm8990_dapm_inmixr_controls[0], - ARRAY_SIZE(wm8990_dapm_inmixr_controls), - inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + ARRAY_SIZE(wm8990_dapm_inmixr_controls)), /* AINRMUX */ -SND_SOC_DAPM_MUX_E("AINRMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, - &wm8990_dapm_ainrmux_controls, inmixer_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainrmux_controls), /* Output Side */ /* DACs */ @@ -787,7 +662,7 @@ SND_SOC_DAPM_OUTPUT("RON"), SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), }; -static const struct snd_soc_dapm_route audio_map[] = { +static const struct snd_soc_dapm_route wm8990_dapm_routes[] = { /* Make DACs turn on when playing even if not mixed into any outputs */ {"Internal DAC Sink", NULL, "Left DAC"}, {"Internal DAC Sink", NULL, "Right DAC"}, @@ -796,6 +671,11 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Left ADC", NULL, "Internal ADC Source"}, {"Right ADC", NULL, "Internal ADC Source"}, + {"AINLMUX", NULL, "INL"}, + {"INMIXL", NULL, "INL"}, + {"AINRMUX", NULL, "INR"}, + {"INMIXR", NULL, "INR"}, + /* Input Side */ /* LIN12 PGA */ {"LIN12 PGA", "LIN1 Switch", "LIN1"}, @@ -912,18 +792,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"RON", NULL, "RONMIX"}, }; -static int wm8990_add_widgets(struct snd_soc_codec *codec) -{ - struct snd_soc_dapm_context *dapm = &codec->dapm; - - snd_soc_dapm_new_controls(dapm, wm8990_dapm_widgets, - ARRAY_SIZE(wm8990_dapm_widgets)); - /* set up the WM8990 audio map */ - snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); - - return 0; -} - /* PLL divisors */ struct _pll_div { u32 div2; @@ -975,28 +843,28 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_component *component = codec_dai->component; struct _pll_div pll_div; if (freq_in && freq_out) { pll_factors(&pll_div, freq_out * 4, freq_in); /* Turn on PLL */ - snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2, + snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2, WM8990_PLL_ENA, WM8990_PLL_ENA); /* sysclk comes from PLL */ - snd_soc_update_bits(codec, WM8990_CLOCKING_2, + snd_soc_component_update_bits(component, WM8990_CLOCKING_2, WM8990_SYSCLK_SRC, WM8990_SYSCLK_SRC); /* set up N , fractional mode and pre-divisor if necessary */ - snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | + snd_soc_component_write(component, WM8990_PLL1, pll_div.n | WM8990_SDM | (pll_div.div2?WM8990_PRESCALE:0)); - snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); - snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); + snd_soc_component_write(component, WM8990_PLL2, (u8)(pll_div.k>>8)); + snd_soc_component_write(component, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); } else { /* Turn off PLL */ - snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2, + snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2, WM8990_PLL_ENA, 0); } return 0; @@ -1008,8 +876,8 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { - struct snd_soc_codec *codec = codec_dai->codec; - struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = codec_dai->component; + struct wm8990_priv *wm8990 = snd_soc_component_get_drvdata(component); wm8990->sysclk = freq; return 0; @@ -1021,18 +889,18 @@ static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_component *component = codec_dai->component; u16 audio1, audio3; - audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1); - audio3 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_3); + audio1 = snd_soc_component_read(component, WM8990_AUDIO_INTERFACE_1); + audio3 = snd_soc_component_read(component, WM8990_AUDIO_INTERFACE_3); /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: audio3 &= ~WM8990_AIF_MSTR1; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: audio3 |= WM8990_AIF_MSTR1; break; default: @@ -1066,31 +934,31 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); - snd_soc_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); + snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_1, audio1); + snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_3, audio3); return 0; } static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) { - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_component *component = codec_dai->component; switch (div_id) { case WM8990_MCLK_DIV: - snd_soc_update_bits(codec, WM8990_CLOCKING_2, + snd_soc_component_update_bits(component, WM8990_CLOCKING_2, WM8990_MCLK_DIV_MASK, div); break; case WM8990_DACCLK_DIV: - snd_soc_update_bits(codec, WM8990_CLOCKING_2, + snd_soc_component_update_bits(component, WM8990_CLOCKING_2, WM8990_DAC_CLKDIV_MASK, div); break; case WM8990_ADCCLK_DIV: - snd_soc_update_bits(codec, WM8990_CLOCKING_2, + snd_soc_component_update_bits(component, WM8990_CLOCKING_2, WM8990_ADC_CLKDIV_MASK, div); break; case WM8990_BCLK_DIV: - snd_soc_update_bits(codec, WM8990_CLOCKING_1, + snd_soc_component_update_bits(component, WM8990_CLOCKING_1, WM8990_BCLK_DIV_MASK, div); break; default: @@ -1107,47 +975,49 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1); + struct snd_soc_component *component = dai->component; + u16 audio1 = snd_soc_component_read(component, WM8990_AUDIO_INTERFACE_1); audio1 &= ~WM8990_AIF_WL_MASK; /* bit size */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: + switch (params_width(params)) { + case 16: break; - case SNDRV_PCM_FORMAT_S20_3LE: + case 20: audio1 |= WM8990_AIF_WL_20BITS; break; - case SNDRV_PCM_FORMAT_S24_LE: + case 24: audio1 |= WM8990_AIF_WL_24BITS; break; - case SNDRV_PCM_FORMAT_S32_LE: + case 32: audio1 |= WM8990_AIF_WL_32BITS; break; } - snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); + snd_soc_component_write(component, WM8990_AUDIO_INTERFACE_1, audio1); return 0; } -static int wm8990_mute(struct snd_soc_dai *dai, int mute) +static int wm8990_mute(struct snd_soc_dai *dai, int mute, int direction) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_component *component = dai->component; u16 val; - val = snd_soc_read(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; + val = snd_soc_component_read(component, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; if (mute) - snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); + snd_soc_component_write(component, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); else - snd_soc_write(codec, WM8990_DAC_CTRL, val); + snd_soc_component_write(component, WM8990_DAC_CTRL, val); return 0; } -static int wm8990_set_bias_level(struct snd_soc_codec *codec, +static int wm8990_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { + struct wm8990_priv *wm8990 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int ret; switch (level) { @@ -1156,26 +1026,26 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* VMID=2*50k */ - snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1, + snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_1, WM8990_VMID_MODE_MASK, 0x2); break; case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = snd_soc_cache_sync(codec); + if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) { + ret = regcache_sync(wm8990->regmap); if (ret < 0) { - dev_err(codec->dev, "Failed to sync cache: %d\n", ret); + dev_err(component->dev, "Failed to sync cache: %d\n", ret); return ret; } /* Enable all output discharge bits */ - snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | + snd_soc_component_write(component, 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 */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_VMIDTOG); @@ -1183,86 +1053,87 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, msleep(300); /* Disable VMIDTOG */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL); /* disable all output discharge bits */ - snd_soc_write(codec, WM8990_ANTIPOP1, 0); + snd_soc_component_write(component, WM8990_ANTIPOP1, 0); /* Enable outputs */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); + snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1b00); msleep(50); /* Enable VMID at 2x50k */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); + snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f02); msleep(100); /* Enable VREF */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); + snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f03); msleep(600); /* Enable BUFIOEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFIOEN); /* Disable outputs */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); + snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x3); /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); + snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_BUFIOEN); /* Enable workaround for ADC clocking issue. */ - 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); + snd_soc_component_write(component, WM8990_EXT_ACCESS_ENA, 0x2); + snd_soc_component_write(component, WM8990_EXT_CTL1, 0xa003); + snd_soc_component_write(component, WM8990_EXT_ACCESS_ENA, 0); } /* VMID=2*250k */ - snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1, + snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_1, WM8990_VMID_MODE_MASK, 0x4); break; case SND_SOC_BIAS_OFF: /* Enable POBCTRL and SOFT_ST */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_POBCTRL | WM8990_BUFIOEN); /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + snd_soc_component_write(component, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFIOEN); /* mute DAC */ - snd_soc_update_bits(codec, WM8990_DAC_CTRL, + snd_soc_component_update_bits(component, WM8990_DAC_CTRL, WM8990_DAC_MUTE, WM8990_DAC_MUTE); /* Enable any disabled outputs */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); + snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f03); /* Disable VMID */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); + snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x1f01); msleep(300); /* Enable all output discharge bits */ - snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | + snd_soc_component_write(component, WM8990_ANTIPOP1, WM8990_DIS_LLINE | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | WM8990_DIS_ROUT); /* Disable VREF */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); + snd_soc_component_write(component, WM8990_POWER_MANAGEMENT_1, 0x0); /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, 0x0); + snd_soc_component_write(component, WM8990_ANTIPOP2, 0x0); + + regcache_mark_dirty(wm8990->regmap); break; } - codec->dapm.bias_level = level; return 0; } @@ -1282,11 +1153,12 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, */ static const struct snd_soc_dai_ops wm8990_dai_ops = { .hw_params = wm8990_hw_params, - .digital_mute = wm8990_mute, + .mute_stream = wm8990_mute, .set_fmt = wm8990_set_dai_fmt, .set_clkdiv = wm8990_set_dai_clkdiv, .set_pll = wm8990_set_dai_pll, .set_sysclk = wm8990_set_dai_sysclk, + .no_capture_mute = 1, }; static struct snd_soc_dai_driver wm8990_dai = { @@ -1307,78 +1179,50 @@ static struct snd_soc_dai_driver wm8990_dai = { .ops = &wm8990_dai_ops, }; -static int wm8990_suspend(struct snd_soc_codec *codec) -{ - wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); - return 0; -} - -static int wm8990_resume(struct snd_soc_codec *codec) -{ - wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - return 0; -} - /* * initialise the WM8990 driver * register the mixer and dsp interfaces with the kernel */ -static int wm8990_probe(struct snd_soc_codec *codec) +static int wm8990_probe(struct snd_soc_component *component) { - int ret; - - 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); - return ret; - } + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - wm8990_reset(codec); + wm8990_reset(component); /* charge output caps */ - wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + snd_soc_dapm_force_bias_level(dapm, SND_SOC_BIAS_STANDBY); - snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4, + snd_soc_component_update_bits(component, WM8990_AUDIO_INTERFACE_4, WM8990_ALRCGPIO1, WM8990_ALRCGPIO1); - snd_soc_update_bits(codec, WM8990_GPIO1_GPIO2, + snd_soc_component_update_bits(component, WM8990_GPIO1_GPIO2, WM8990_GPIO1_SEL_MASK, 1); - snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2, + snd_soc_component_update_bits(component, WM8990_POWER_MANAGEMENT_2, WM8990_OPCLK_ENA, WM8990_OPCLK_ENA); - 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_codec_controls(codec, wm8990_snd_controls, - ARRAY_SIZE(wm8990_snd_controls)); - wm8990_add_widgets(codec); - - return 0; -} + snd_soc_component_write(component, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); + snd_soc_component_write(component, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); -/* power down chip */ -static int wm8990_remove(struct snd_soc_codec *codec) -{ - wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } -static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { - .probe = wm8990_probe, - .remove = wm8990_remove, - .suspend = wm8990_suspend, - .resume = wm8990_resume, - .set_bias_level = wm8990_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm8990_reg), - .reg_word_size = sizeof(u16), - .reg_cache_default = wm8990_reg, - .volatile_register = wm8990_volatile_register, +static const struct snd_soc_component_driver soc_component_dev_wm8990 = { + .probe = wm8990_probe, + .set_bias_level = wm8990_set_bias_level, + .controls = wm8990_snd_controls, + .num_controls = ARRAY_SIZE(wm8990_snd_controls), + .dapm_widgets = wm8990_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets), + .dapm_routes = wm8990_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes), + .suspend_bias_off = 1, + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, }; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static int wm8990_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8990_i2c_probe(struct i2c_client *i2c) { struct wm8990_priv *wm8990; int ret; @@ -1390,21 +1234,14 @@ static int wm8990_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8990); - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8990, &wm8990_dai, 1); + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_wm8990, &wm8990_dai, 1); return ret; } -static int wm8990_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - - return 0; -} - static const struct i2c_device_id wm8990_i2c_id[] = { - { "wm8990", 0 }, + { "wm8990" }, { } }; MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); @@ -1412,35 +1249,12 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); static struct i2c_driver wm8990_i2c_driver = { .driver = { .name = "wm8990", - .owner = THIS_MODULE, }, - .probe = wm8990_i2c_probe, - .remove = wm8990_i2c_remove, + .probe = wm8990_i2c_probe, .id_table = wm8990_i2c_id, }; -#endif -static int __init wm8990_modinit(void) -{ - int ret = 0; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - ret = i2c_add_driver(&wm8990_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n", - ret); - } -#endif - return ret; -} -module_init(wm8990_modinit); - -static void __exit wm8990_exit(void) -{ -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_del_driver(&wm8990_i2c_driver); -#endif -} -module_exit(wm8990_exit); +module_i2c_driver(wm8990_i2c_driver); MODULE_DESCRIPTION("ASoC WM8990 driver"); MODULE_AUTHOR("Liam Girdwood"); |
