diff options
Diffstat (limited to 'sound/soc/codecs/wm8962.c')
| -rw-r--r-- | sound/soc/codecs/wm8962.c | 651 |
1 files changed, 370 insertions, 281 deletions
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index fd2731d171dd..e9e317ce6898 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * wm8962.c -- WM8962 ALSA SoC Audio driver * * Copyright 2010-2 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 version 2 as - * published by the Free Software Foundation. */ #include <linux/module.h> @@ -55,7 +51,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = { struct wm8962_priv { struct wm8962_pdata pdata; struct regmap *regmap; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int sysclk; int sysclk_rate; @@ -86,6 +82,7 @@ struct wm8962_priv { #endif int irq; + bool master_flag; }; /* We can't use the same notifier block for more than one supply and @@ -122,7 +119,7 @@ static const struct reg_default wm8962_reg[] = { { 5, 0x0018 }, /* R5 - ADC & DAC Control 1 */ { 6, 0x2008 }, /* R6 - ADC & DAC Control 2 */ { 7, 0x000A }, /* R7 - Audio Interface 0 */ - + { 8, 0x01E4 }, /* R8 - Clocking2 */ { 9, 0x0300 }, /* R9 - Audio Interface 1 */ { 10, 0x00C0 }, /* R10 - Left DAC volume */ { 11, 0x00C0 }, /* R11 - Right DAC volume */ @@ -792,7 +789,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case WM8962_CLOCKING1: - case WM8962_CLOCKING2: case WM8962_SOFTWARE_RESET: case WM8962_THERMAL_SHUTDOWN_STATUS: case WM8962_ADDITIONAL_CONTROL_4: @@ -961,7 +957,6 @@ static bool wm8962_readable_register(struct device *dev, unsigned int reg) case WM8962_EQ39: case WM8962_EQ40: case WM8962_EQ41: - case WM8962_GPIO_BASE: case WM8962_GPIO_2: case WM8962_GPIO_3: case WM8962_GPIO_5: @@ -1475,55 +1470,55 @@ static const DECLARE_TLV_DB_RANGE(classd_tlv, ); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); -static int wm8962_dsp2_write_config(struct snd_soc_codec *codec) +static int wm8962_dsp2_write_config(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); return regcache_sync_region(wm8962->regmap, WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER); } -static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val) +static int wm8962_dsp2_set_enable(struct snd_soc_component *component, u16 val) { - u16 adcl = snd_soc_read(codec, WM8962_LEFT_ADC_VOLUME); - u16 adcr = snd_soc_read(codec, WM8962_RIGHT_ADC_VOLUME); - u16 dac = snd_soc_read(codec, WM8962_ADC_DAC_CONTROL_1); + u16 adcl = snd_soc_component_read(component, WM8962_LEFT_ADC_VOLUME); + u16 adcr = snd_soc_component_read(component, WM8962_RIGHT_ADC_VOLUME); + u16 dac = snd_soc_component_read(component, WM8962_ADC_DAC_CONTROL_1); /* Mute the ADCs and DACs */ - snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, 0); - snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU); - snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1, + snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, 0); + snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU); + snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1, WM8962_DAC_MUTE, WM8962_DAC_MUTE); - snd_soc_write(codec, WM8962_SOUNDSTAGE_ENABLES_0, val); + snd_soc_component_write(component, WM8962_SOUNDSTAGE_ENABLES_0, val); /* Restore the ADCs and DACs */ - snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, adcl); - snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, adcr); - snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1, + snd_soc_component_write(component, WM8962_LEFT_ADC_VOLUME, adcl); + snd_soc_component_write(component, WM8962_RIGHT_ADC_VOLUME, adcr); + snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1, WM8962_DAC_MUTE, dac); return 0; } -static int wm8962_dsp2_start(struct snd_soc_codec *codec) +static int wm8962_dsp2_start(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); - wm8962_dsp2_write_config(codec); + wm8962_dsp2_write_config(component); - snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR); + snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR); - wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena); + wm8962_dsp2_set_enable(component, wm8962->dsp2_ena); return 0; } -static int wm8962_dsp2_stop(struct snd_soc_codec *codec) +static int wm8962_dsp2_stop(struct snd_soc_component *component) { - wm8962_dsp2_set_enable(codec, 0); + wm8962_dsp2_set_enable(component, 0); - snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP); + snd_soc_component_write(component, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP); return 0; } @@ -1550,8 +1545,8 @@ static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int shift = kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift); @@ -1562,11 +1557,11 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int shift = kcontrol->private_value; - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int old = wm8962->dsp2_ena; int ret = 0; - int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) & + int dsp2_running = snd_soc_component_read(component, WM8962_DSP2_POWER_MANAGEMENT) & WM8962_DSP2_ENA; mutex_lock(&wm8962->dsp2_ena_lock); @@ -1583,9 +1578,9 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, if (dsp2_running) { if (wm8962->dsp2_ena) - wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena); + wm8962_dsp2_set_enable(component, wm8962->dsp2_ena); else - wm8962_dsp2_stop(codec); + wm8962_dsp2_stop(component); } out: @@ -1600,7 +1595,7 @@ out: static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); int ret; /* Apply the update (if any) */ @@ -1609,17 +1604,17 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol, return 0; /* If the left PGA is enabled hit that VU bit... */ - ret = snd_soc_read(codec, WM8962_PWR_MGMT_2); + ret = snd_soc_component_read(component, WM8962_PWR_MGMT_2); if (ret & WM8962_HPOUTL_PGA_ENA) { - snd_soc_write(codec, WM8962_HPOUTL_VOLUME, - snd_soc_read(codec, WM8962_HPOUTL_VOLUME)); + snd_soc_component_write(component, WM8962_HPOUTL_VOLUME, + snd_soc_component_read(component, WM8962_HPOUTL_VOLUME)); return 1; } /* ...otherwise the right. The VU is stereo. */ if (ret & WM8962_HPOUTR_PGA_ENA) - snd_soc_write(codec, WM8962_HPOUTR_VOLUME, - snd_soc_read(codec, WM8962_HPOUTR_VOLUME)); + snd_soc_component_write(component, WM8962_HPOUTR_VOLUME, + snd_soc_component_read(component, WM8962_HPOUTR_VOLUME)); return 1; } @@ -1630,7 +1625,7 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol, static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); int ret; /* Apply the update (if any) */ @@ -1639,17 +1634,17 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, return 0; /* If the left PGA is enabled hit that VU bit... */ - ret = snd_soc_read(codec, WM8962_PWR_MGMT_2); + ret = snd_soc_component_read(component, WM8962_PWR_MGMT_2); if (ret & WM8962_SPKOUTL_PGA_ENA) { - snd_soc_write(codec, WM8962_SPKOUTL_VOLUME, - snd_soc_read(codec, WM8962_SPKOUTL_VOLUME)); + snd_soc_component_write(component, WM8962_SPKOUTL_VOLUME, + snd_soc_component_read(component, WM8962_SPKOUTL_VOLUME)); return 1; } /* ...otherwise the right. The VU is stereo. */ if (ret & WM8962_SPKOUTR_PGA_ENA) - snd_soc_write(codec, WM8962_SPKOUTR_VOLUME, - snd_soc_read(codec, WM8962_SPKOUTR_VOLUME)); + snd_soc_component_write(component, WM8962_SPKOUTR_VOLUME, + snd_soc_component_read(component, WM8962_SPKOUTR_VOLUME)); return 1; } @@ -1708,6 +1703,8 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME, SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0), SOC_SINGLE("DAC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 5, 1, 0), SOC_SINGLE("ADC L/R Swap Switch", WM8962_AUDIO_INTERFACE_0, 8, 1, 0), +SOC_SINGLE("DAC Monomix Switch", WM8962_DAC_DSP_MIXING_1, WM8962_DAC_MONOMIX_SHIFT, 1, 0), +SOC_SINGLE("ADC Monomix Switch", WM8962_THREED1, WM8962_ADC_MONOMIX_SHIFT, 1, 0), SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1, 5, 1, 0), @@ -1844,6 +1841,49 @@ SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5, 4, 1, 0, inmix_tlv), }; +static int tp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int ret, reg, val, mask; + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + dev_err(component->dev, "Failed to resume device: %d\n", ret); + return ret; + } + + reg = WM8962_ADDITIONAL_CONTROL_4; + + if (!snd_soc_dapm_widget_name_cmp(w, "TEMP_HP")) { + mask = WM8962_TEMP_ENA_HP_MASK; + val = WM8962_TEMP_ENA_HP; + } else if (!snd_soc_dapm_widget_name_cmp(w, "TEMP_SPK")) { + mask = WM8962_TEMP_ENA_SPK_MASK; + val = WM8962_TEMP_ENA_SPK; + } else { + pm_runtime_put(component->dev); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + val = 0; + fallthrough; + case SND_SOC_DAPM_POST_PMU: + ret = snd_soc_component_update_bits(component, reg, mask, val); + break; + default: + WARN(1, "Invalid event %d\n", event); + pm_runtime_put(component->dev); + return -EINVAL; + } + + pm_runtime_put(component->dev); + + return 0; +} + static int cp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1863,7 +1903,7 @@ static int cp_event(struct snd_soc_dapm_widget *w, static int hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); int timeout; int reg; int expected = (WM8962_DCS_STARTUP_DONE_HP1L | @@ -1871,17 +1911,17 @@ static int hp_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0, + snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0, WM8962_HP1L_ENA | WM8962_HP1R_ENA, WM8962_HP1L_ENA | WM8962_HP1R_ENA); udelay(20); - snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0, + snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0, WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY, WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY); /* Start the DC servo */ - snd_soc_update_bits(codec, WM8962_DC_SERVO_1, + snd_soc_component_update_bits(component, WM8962_DC_SERVO_1, WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA | WM8962_HP1L_DCS_STARTUP | WM8962_HP1R_DCS_STARTUP, @@ -1893,30 +1933,30 @@ static int hp_event(struct snd_soc_dapm_widget *w, timeout = 0; do { msleep(1); - reg = snd_soc_read(codec, WM8962_DC_SERVO_6); + reg = snd_soc_component_read(component, WM8962_DC_SERVO_6); if (reg < 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to read DCS status: %d\n", reg); continue; } - dev_dbg(codec->dev, "DCS status: %x\n", reg); + dev_dbg(component->dev, "DCS status: %x\n", reg); } while (++timeout < 200 && (reg & expected) != expected); if ((reg & expected) != expected) - dev_err(codec->dev, "DC servo timed out\n"); + dev_err(component->dev, "DC servo timed out\n"); else - dev_dbg(codec->dev, "DC servo complete after %dms\n", + dev_dbg(component->dev, "DC servo complete after %dms\n", timeout); - snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0, + snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0, WM8962_HP1L_ENA_OUTP | WM8962_HP1R_ENA_OUTP, WM8962_HP1L_ENA_OUTP | WM8962_HP1R_ENA_OUTP); udelay(20); - snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0, + snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0, WM8962_HP1L_RMV_SHORT | WM8962_HP1R_RMV_SHORT, WM8962_HP1L_RMV_SHORT | @@ -1924,19 +1964,19 @@ static int hp_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: - snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0, + snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0, WM8962_HP1L_RMV_SHORT | WM8962_HP1R_RMV_SHORT, 0); udelay(20); - snd_soc_update_bits(codec, WM8962_DC_SERVO_1, + snd_soc_component_update_bits(component, WM8962_DC_SERVO_1, WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA | WM8962_HP1L_DCS_STARTUP | WM8962_HP1R_DCS_STARTUP, 0); - snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0, + snd_soc_component_update_bits(component, WM8962_ANALOGUE_HP_0, WM8962_HP1L_ENA | WM8962_HP1R_ENA | WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY | WM8962_HP1L_ENA_OUTP | @@ -1957,7 +1997,7 @@ static int hp_event(struct snd_soc_dapm_widget *w, static int out_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); int reg; switch (w->shift) { @@ -1980,7 +2020,8 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - return snd_soc_write(codec, reg, snd_soc_read(codec, reg)); + return snd_soc_component_write(component, reg, + snd_soc_component_read(component, reg)); default: WARN(1, "Invalid event %d\n", event); return -EINVAL; @@ -1990,18 +2031,18 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, static int dsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); switch (event) { case SND_SOC_DAPM_POST_PMU: if (wm8962->dsp2_ena) - wm8962_dsp2_start(codec); + wm8962_dsp2_start(component); break; case SND_SOC_DAPM_PRE_PMD: if (wm8962->dsp2_ena) - wm8962_dsp2_stop(codec); + wm8962_dsp2_stop(component); break; default: @@ -2052,6 +2093,13 @@ static SOC_ENUM_SINGLE_DECL(hpoutl_enum, static const struct snd_kcontrol_new hpoutl_mux = SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum); +static const char * const input_mode_text[] = { "Analog", "Digital" }; + +static SOC_ENUM_SINGLE_VIRT_DECL(input_mode_enum, input_mode_text); + +static const struct snd_kcontrol_new input_mode_mux = + SOC_DAPM_ENUM("Input Mode", input_mode_enum); + static const struct snd_kcontrol_new inpgal[] = { SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0), SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0), @@ -2136,8 +2184,10 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT, WM8962_DSP2_ENA_SHIFT, 0, dsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("TEMP_HP", SND_SOC_NOPM, 0, 0, tp_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("TEMP_SPK", SND_SOC_NOPM, 0, 0, tp_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0, inpgal, ARRAY_SIZE(inpgal)), @@ -2150,6 +2200,9 @@ SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0, SND_SOC_DAPM_AIF_IN("DMIC_ENA", NULL, 0, WM8962_PWR_MGMT_1, 10, 0), +SND_SOC_DAPM_MUX("Input Mode L", SND_SOC_NOPM, 0, 0, &input_mode_mux), +SND_SOC_DAPM_MUX("Input Mode R", SND_SOC_NOPM, 0, 0, &input_mode_mux), + SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0), SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0), @@ -2177,6 +2230,9 @@ SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event, SND_SOC_DAPM_OUTPUT("HPOUTL"), SND_SOC_DAPM_OUTPUT("HPOUTR"), + +SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0), +SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0), }; static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = { @@ -2184,7 +2240,6 @@ SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0, spkmixl, ARRAY_SIZE(spkmixl)), SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux, out_pga_event, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0), SND_SOC_DAPM_OUTPUT("SPKOUT"), }; @@ -2199,9 +2254,6 @@ SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux, SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux, out_pga_event, SND_SOC_DAPM_POST_PMU), -SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0), -SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0), - SND_SOC_DAPM_OUTPUT("SPKOUTL"), SND_SOC_DAPM_OUTPUT("SPKOUTR"), }; @@ -2229,16 +2281,19 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = { { "DMIC_ENA", NULL, "DMICDAT" }, + { "Input Mode L", "Analog", "MIXINL" }, + { "Input Mode L", "Digital", "DMIC_ENA" }, + { "Input Mode R", "Analog", "MIXINR" }, + { "Input Mode R", "Digital", "DMIC_ENA" }, + { "ADCL", NULL, "SYSCLK" }, { "ADCL", NULL, "TOCLK" }, - { "ADCL", NULL, "MIXINL" }, - { "ADCL", NULL, "DMIC_ENA" }, + { "ADCL", NULL, "Input Mode L" }, { "ADCL", NULL, "DSP2" }, { "ADCR", NULL, "SYSCLK" }, { "ADCR", NULL, "TOCLK" }, - { "ADCR", NULL, "MIXINR" }, - { "ADCR", NULL, "DMIC_ENA" }, + { "ADCR", NULL, "Input Mode R" }, { "ADCR", NULL, "DSP2" }, { "STL", "Left", "ADCL" }, @@ -2311,12 +2366,18 @@ static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = { { "Speaker PGA", "Mixer", "Speaker Mixer" }, { "Speaker PGA", "DAC", "DACL" }, - { "Speaker Output", NULL, "Speaker PGA" }, - { "Speaker Output", NULL, "SYSCLK" }, - { "Speaker Output", NULL, "TOCLK" }, - { "Speaker Output", NULL, "TEMP_SPK" }, + { "SPKOUTL Output", NULL, "Speaker PGA" }, + { "SPKOUTL Output", NULL, "SYSCLK" }, + { "SPKOUTL Output", NULL, "TOCLK" }, + { "SPKOUTL Output", NULL, "TEMP_SPK" }, - { "SPKOUT", NULL, "Speaker Output" }, + { "SPKOUTR Output", NULL, "Speaker PGA" }, + { "SPKOUTR Output", NULL, "SYSCLK" }, + { "SPKOUTR Output", NULL, "TOCLK" }, + { "SPKOUTR Output", NULL, "TEMP_SPK" }, + + { "SPKOUT", NULL, "SPKOUTL Output" }, + { "SPKOUT", NULL, "SPKOUTR Output" }, }; static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = { @@ -2354,19 +2415,19 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = { { "SPKOUTR", NULL, "SPKOUTR Output" }, }; -static int wm8962_add_widgets(struct snd_soc_codec *codec) +static int wm8962_add_widgets(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); struct wm8962_pdata *pdata = &wm8962->pdata; - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); - snd_soc_add_codec_controls(codec, wm8962_snd_controls, + snd_soc_add_component_controls(component, wm8962_snd_controls, ARRAY_SIZE(wm8962_snd_controls)); if (pdata->spk_mono) - snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls, + snd_soc_add_component_controls(component, wm8962_spk_mono_controls, ARRAY_SIZE(wm8962_spk_mono_controls)); else - snd_soc_add_codec_controls(codec, wm8962_spk_stereo_controls, + snd_soc_add_component_controls(component, wm8962_spk_stereo_controls, ARRAY_SIZE(wm8962_spk_stereo_controls)); @@ -2403,21 +2464,23 @@ static const int sysclk_rates[] = { 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, 3072, 6144 }; -static void wm8962_configure_bclk(struct snd_soc_codec *codec) +static void wm8962_configure_bclk(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); + int best, min_diff, diff; int dspclk, i; int clocking2 = 0; int clocking4 = 0; int aif2 = 0; if (!wm8962->sysclk_rate) { - dev_dbg(codec->dev, "No SYSCLK configured\n"); + dev_dbg(component->dev, "No SYSCLK configured\n"); return; } if (!wm8962->bclk || !wm8962->lrclk) { - dev_dbg(codec->dev, "No audio clocks configured\n"); + dev_dbg(component->dev, "No audio clocks configured\n"); return; } @@ -2429,32 +2492,40 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) } if (i == ARRAY_SIZE(sysclk_rates)) { - dev_err(codec->dev, "Unsupported sysclk ratio %d\n", + dev_err(component->dev, "Unsupported sysclk ratio %d\n", wm8962->sysclk_rate / wm8962->lrclk); return; } - dev_dbg(codec->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]); + dev_dbg(component->dev, "Selected sysclk ratio %d\n", sysclk_rates[i]); - snd_soc_update_bits(codec, WM8962_CLOCKING_4, + snd_soc_component_update_bits(component, WM8962_CLOCKING_4, WM8962_SYSCLK_RATE_MASK, clocking4); /* DSPCLK_DIV can be only generated correctly after enabling SYSCLK. * So we here provisionally enable it and then disable it afterward * if current bias_level hasn't reached SND_SOC_BIAS_ON. */ - if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON) - snd_soc_update_bits(codec, WM8962_CLOCKING2, + if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON) + snd_soc_component_update_bits(component, WM8962_CLOCKING2, WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA); - dspclk = snd_soc_read(codec, WM8962_CLOCKING1); + /* DSPCLK_DIV field in WM8962_CLOCKING1 register is used to generate + * correct frequency of LRCLK and BCLK. Sometimes the read-only value + * can't be updated timely after enabling SYSCLK. This results in wrong + * calculation values. Delay is introduced here to wait for newest + * value from register. The time of the delay should be at least + * 500~1000us according to test. + */ + usleep_range(500, 1000); + dspclk = snd_soc_component_read(component, WM8962_CLOCKING1); - if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON) - snd_soc_update_bits(codec, WM8962_CLOCKING2, + if (snd_soc_dapm_get_bias_level(dapm) != SND_SOC_BIAS_ON) + snd_soc_component_update_bits(component, WM8962_CLOCKING2, WM8962_SYSCLK_ENA_MASK, 0); if (dspclk < 0) { - dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); + dev_err(component->dev, "Failed to read DSPCLK: %d\n", dspclk); return; } @@ -2470,61 +2541,65 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) dspclk = wm8962->sysclk_rate / 4; break; default: - dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n"); + dev_warn(component->dev, "Unknown DSPCLK divisor read back\n"); dspclk = wm8962->sysclk_rate; } - dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk); + dev_dbg(component->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk); - /* We're expecting an exact match */ + /* Search a proper bclk, not exact match. */ + best = 0; + min_diff = INT_MAX; for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { if (bclk_divs[i] < 0) continue; - if (dspclk / bclk_divs[i] == wm8962->bclk) { - dev_dbg(codec->dev, "Selected BCLK_DIV %d for %dHz\n", - bclk_divs[i], wm8962->bclk); - clocking2 |= i; + diff = (dspclk / bclk_divs[i]) - wm8962->bclk; + if (diff < 0) /* Table is sorted */ break; + if (diff < min_diff) { + best = i; + min_diff = diff; } } - if (i == ARRAY_SIZE(bclk_divs)) { - dev_err(codec->dev, "Unsupported BCLK ratio %d\n", - dspclk / wm8962->bclk); - return; - } + wm8962->bclk = dspclk / bclk_divs[best]; + clocking2 |= best; + dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n", + bclk_divs[best], wm8962->bclk); aif2 |= wm8962->bclk / wm8962->lrclk; - dev_dbg(codec->dev, "Selected LRCLK divisor %d for %dHz\n", + dev_dbg(component->dev, "Selected LRCLK divisor %d for %dHz\n", wm8962->bclk / wm8962->lrclk, wm8962->lrclk); - snd_soc_update_bits(codec, WM8962_CLOCKING2, + snd_soc_component_update_bits(component, WM8962_CLOCKING2, WM8962_BCLK_DIV_MASK, clocking2); - snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_2, + snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_2, WM8962_AIF_RATE_MASK, aif2); } -static int wm8962_set_bias_level(struct snd_soc_codec *codec, +static int wm8962_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + switch (level) { case SND_SOC_BIAS_ON: break; case SND_SOC_BIAS_PREPARE: /* VMID 2*50k */ - snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, + snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x80); - wm8962_configure_bclk(codec); + wm8962_configure_bclk(component); break; case SND_SOC_BIAS_STANDBY: /* VMID 2*250k */ - snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, + snd_soc_component_update_bits(component, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK, 0x100); - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) + if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_OFF) msleep(100); break; @@ -2556,8 +2631,9 @@ static int wm8962_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; - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int i; int aif0 = 0; int adctl3 = 0; @@ -2575,7 +2651,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, } } if (i == ARRAY_SIZE(sr_vals)) { - dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk); + dev_err(component->dev, "Unsupported rate %dHz\n", wm8962->lrclk); return -EINVAL; } @@ -2598,17 +2674,17 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0, + snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0, WM8962_WL_MASK, aif0); - snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3, + snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_3, WM8962_SAMPLE_RATE_INT_MODE | WM8962_SAMPLE_RATE_MASK, adctl3); - dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n", + dev_dbg(component->dev, "hw_params set BCLK %dHz LRCLK %dHz\n", wm8962->bclk, wm8962->lrclk); - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) - wm8962_configure_bclk(codec); + if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_ON) + wm8962_configure_bclk(component); return 0; } @@ -2616,8 +2692,8 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - struct snd_soc_codec *codec = dai->codec; - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int src; switch (clk_id) { @@ -2633,7 +2709,7 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, return -EINVAL; } - snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK, + snd_soc_component_update_bits(component, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK, src); wm8962->sysclk_rate = freq; @@ -2643,12 +2719,14 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_component *component = dai->component; + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int aif0 = 0; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_B: aif0 |= WM8962_LRCLK_INV | 3; + fallthrough; case SND_SOC_DAIFMT_DSP_A: aif0 |= 3; @@ -2689,17 +2767,19 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } + wm8962->master_flag = false; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif0 |= WM8962_MSTR; + wm8962->master_flag = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; } - snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0, + snd_soc_component_update_bits(component, WM8962_AUDIO_INTERFACE_0, WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR | WM8962_LRCLK_INV, aif0); @@ -2791,7 +2871,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, if (target % Fref == 0) { fll_div->theta = 0; - fll_div->lambda = 0; + fll_div->lambda = 1; } else { gcd_fll = gcd(target, fratio * Fref); @@ -2809,12 +2889,12 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, return 0; } -static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, +static int wm8962_set_fll(struct snd_soc_component *component, int fll_id, int source, unsigned int Fref, unsigned int Fout) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); struct _fll_div fll_div; - unsigned long timeout; + unsigned long time_left; int ret; int fll1 = 0; @@ -2824,15 +2904,15 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return 0; if (Fout == 0) { - dev_dbg(codec->dev, "FLL disabled\n"); + dev_dbg(component->dev, "FLL disabled\n"); wm8962->fll_fref = 0; wm8962->fll_fout = 0; - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); - pm_runtime_put(codec->dev); + pm_runtime_put(component->dev); return 0; } @@ -2842,74 +2922,78 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return ret; /* Parameters good, disable so we can reprogram */ - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); switch (fll_id) { case WM8962_FLL_MCLK: case WM8962_FLL_BCLK: + fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT; + break; case WM8962_FLL_OSC: fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT; + snd_soc_component_update_bits(component, WM8962_PLL2, + WM8962_OSC_ENA, WM8962_OSC_ENA); break; case WM8962_FLL_INT: - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA); - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_5, + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_5, WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO); break; default: - dev_err(codec->dev, "Unknown FLL source %d\n", ret); + dev_err(component->dev, "Unknown FLL source %d\n", source); return -EINVAL; } - if (fll_div.theta || fll_div.lambda) + if (fll_div.theta) fll1 |= WM8962_FLL_FRAC; /* Stop the FLL while we reconfigure */ - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_2, + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_2, WM8962_FLL_OUTDIV_MASK | WM8962_FLL_REFCLK_DIV_MASK, (fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) | (fll_div.fll_refclk_div)); - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_3, + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_3, WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio); - snd_soc_write(codec, WM8962_FLL_CONTROL_6, fll_div.theta); - snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda); - snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n); + snd_soc_component_write(component, WM8962_FLL_CONTROL_6, fll_div.theta); + snd_soc_component_write(component, WM8962_FLL_CONTROL_7, fll_div.lambda); + snd_soc_component_write(component, WM8962_FLL_CONTROL_8, fll_div.n); reinit_completion(&wm8962->fll_lock); - ret = pm_runtime_get_sync(codec->dev); + ret = pm_runtime_resume_and_get(component->dev); if (ret < 0) { - dev_err(codec->dev, "Failed to resume device: %d\n", ret); + dev_err(component->dev, "Failed to resume device: %d\n", ret); return ret; } - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK | WM8962_FLL_ENA, fll1 | WM8962_FLL_ENA); - dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); + dev_dbg(component->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); /* This should be a massive overestimate but go even * higher if we'll error out */ if (wm8962->irq) - timeout = msecs_to_jiffies(5); + time_left = msecs_to_jiffies(5); else - timeout = msecs_to_jiffies(1); + time_left = msecs_to_jiffies(1); - timeout = wait_for_completion_timeout(&wm8962->fll_lock, - timeout); + time_left = wait_for_completion_timeout(&wm8962->fll_lock, + time_left); - if (timeout == 0 && wm8962->irq) { - dev_err(codec->dev, "FLL lock timed out"); - snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, + if (time_left == 0 && wm8962->irq) { + dev_err(component->dev, "FLL lock timed out"); + snd_soc_component_update_bits(component, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0); - pm_runtime_put(codec->dev); + pm_runtime_put(component->dev); return -ETIMEDOUT; } @@ -2920,9 +3004,9 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return 0; } -static int wm8962_mute(struct snd_soc_dai *dai, int mute) +static int wm8962_mute(struct snd_soc_dai *dai, int mute, int direction) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_component *component = dai->component; int val, ret; if (mute) @@ -2934,12 +3018,12 @@ static int wm8962_mute(struct snd_soc_dai *dai, int mute) * The DAC mute bit is mirrored in two registers, update both to keep * the register cache consistent. */ - ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1, + ret = snd_soc_component_update_bits(component, WM8962_CLASS_D_CONTROL_1, WM8962_DAC_MUTE_ALT, val); if (ret < 0) return ret; - return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1, + return snd_soc_component_update_bits(component, WM8962_ADC_DAC_CONTROL_1, WM8962_DAC_MUTE, val); } @@ -2953,7 +3037,8 @@ static const struct snd_soc_dai_ops wm8962_dai_ops = { .hw_params = wm8962_hw_params, .set_sysclk = wm8962_set_dai_sysclk, .set_fmt = wm8962_set_dai_fmt, - .digital_mute = wm8962_mute, + .mute_stream = wm8962_mute, + .no_capture_mute = 1, }; static struct snd_soc_dai_driver wm8962_dai = { @@ -2973,7 +3058,7 @@ static struct snd_soc_dai_driver wm8962_dai = { .formats = WM8962_FORMATS, }, .ops = &wm8962_dai_ops, - .symmetric_rates = 1, + .symmetric_rate = 1, }; static void wm8962_mic_work(struct work_struct *work) @@ -2981,12 +3066,12 @@ static void wm8962_mic_work(struct work_struct *work) struct wm8962_priv *wm8962 = container_of(work, struct wm8962_priv, mic_work.work); - struct snd_soc_codec *codec = wm8962->codec; + struct snd_soc_component *component = wm8962->component; int status = 0; int irq_pol = 0; int reg; - reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4); + reg = snd_soc_component_read(component, WM8962_ADDITIONAL_CONTROL_4); if (reg & WM8962_MICDET_STS) { status |= SND_JACK_MICROPHONE; @@ -3001,7 +3086,7 @@ static void wm8962_mic_work(struct work_struct *work) snd_soc_jack_report(wm8962->jack, status, SND_JACK_MICROPHONE | SND_JACK_BTN_0); - snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL, + snd_soc_component_update_bits(component, WM8962_MICINT_SOURCE_POL, WM8962_MICSCD_IRQ_POL | WM8962_MICD_IRQ_POL, irq_pol); } @@ -3014,7 +3099,7 @@ static irqreturn_t wm8962_irq(int irq, void *data) unsigned int active; int reg, ret; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { dev_err(dev, "Failed to resume: %d\n", ret); return IRQ_NONE; @@ -3099,7 +3184,7 @@ static irqreturn_t wm8962_irq(int irq, void *data) /** * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ * - * @codec: WM8962 codec + * @component: WM8962 component * @jack: jack to report detection events on * * Enable microphone detection via IRQ on the WM8962. If GPIOs are @@ -3109,10 +3194,10 @@ static irqreturn_t wm8962_irq(int irq, void *data) * * If no jack is supplied detection will be disabled. */ -int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) +int wm8962_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int irq_mask, enable; wm8962->jack = jack; @@ -3124,9 +3209,9 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) enable = 0; } - snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK, + snd_soc_component_update_bits(component, WM8962_INTERRUPT_STATUS_2_MASK, WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask); - snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4, + snd_soc_component_update_bits(component, WM8962_ADDITIONAL_CONTROL_4, WM8962_MICDET_ENA, enable); /* Send an initial empty report */ @@ -3157,8 +3242,8 @@ static void wm8962_beep_work(struct work_struct *work) { struct wm8962_priv *wm8962 = container_of(work, struct wm8962_priv, beep_work); - struct snd_soc_codec *codec = wm8962->codec; - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = wm8962->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int i; int reg = 0; int best = 0; @@ -3170,18 +3255,18 @@ static void wm8962_beep_work(struct work_struct *work) best = i; } - dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n", + dev_dbg(component->dev, "Set beep rate %dHz for requested %dHz\n", beep_rates[best], wm8962->beep_rate); reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT); snd_soc_dapm_enable_pin(dapm, "Beep"); } else { - dev_dbg(codec->dev, "Disabling beep\n"); + dev_dbg(component->dev, "Disabling beep\n"); snd_soc_dapm_disable_pin(dapm, "Beep"); } - snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, + snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg); snd_soc_dapm_sync(dapm); @@ -3193,15 +3278,16 @@ static void wm8962_beep_work(struct work_struct *work) static int wm8962_beep_event(struct input_dev *dev, unsigned int type, unsigned int code, int hz) { - struct snd_soc_codec *codec = input_get_drvdata(dev); - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = input_get_drvdata(dev); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); - dev_dbg(codec->dev, "Beep event %x %x\n", code, hz); + dev_dbg(component->dev, "Beep event %x %x\n", code, hz); switch (code) { case SND_BELL: if (hz) hz = 1000; + fallthrough; case SND_TONE: break; default: @@ -3214,9 +3300,8 @@ static int wm8962_beep_event(struct input_dev *dev, unsigned int type, return 0; } -static ssize_t wm8962_beep_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t beep_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); long int time; @@ -3231,16 +3316,16 @@ static ssize_t wm8962_beep_set(struct device *dev, return count; } -static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set); +static DEVICE_ATTR_WO(beep); -static void wm8962_init_beep(struct snd_soc_codec *codec) +static void wm8962_init_beep(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int ret; - wm8962->beep = devm_input_allocate_device(codec->dev); + wm8962->beep = devm_input_allocate_device(component->dev); if (!wm8962->beep) { - dev_err(codec->dev, "Failed to allocate beep device\n"); + dev_err(component->dev, "Failed to allocate beep device\n"); return; } @@ -3248,37 +3333,37 @@ static void wm8962_init_beep(struct snd_soc_codec *codec) wm8962->beep_rate = 0; wm8962->beep->name = "WM8962 Beep Generator"; - wm8962->beep->phys = dev_name(codec->dev); + wm8962->beep->phys = dev_name(component->dev); wm8962->beep->id.bustype = BUS_I2C; wm8962->beep->evbit[0] = BIT_MASK(EV_SND); wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); wm8962->beep->event = wm8962_beep_event; - wm8962->beep->dev.parent = codec->dev; - input_set_drvdata(wm8962->beep, codec); + wm8962->beep->dev.parent = component->dev; + input_set_drvdata(wm8962->beep, component); ret = input_register_device(wm8962->beep); if (ret != 0) { wm8962->beep = NULL; - dev_err(codec->dev, "Failed to register beep device\n"); + dev_err(component->dev, "Failed to register beep device\n"); } - ret = device_create_file(codec->dev, &dev_attr_beep); + ret = device_create_file(component->dev, &dev_attr_beep); if (ret != 0) { - dev_err(codec->dev, "Failed to create keyclick file: %d\n", + dev_err(component->dev, "Failed to create keyclick file: %d\n", ret); } } -static void wm8962_free_beep(struct snd_soc_codec *codec) +static void wm8962_free_beep(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); - device_remove_file(codec->dev, &dev_attr_beep); + device_remove_file(component->dev, &dev_attr_beep); cancel_work_sync(&wm8962->beep_work); wm8962->beep = NULL; - snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0); + snd_soc_component_update_bits(component, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0); } static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio) @@ -3330,26 +3415,29 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset) return 0; } -static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int wm8962_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct wm8962_priv *wm8962 = gpiochip_get_data(chip); - struct snd_soc_codec *codec = wm8962->codec; + struct snd_soc_component *component = wm8962->component; - snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, - WM8962_GP2_LVL, !!value << WM8962_GP2_LVL_SHIFT); + return snd_soc_component_update_bits(component, + WM8962_GPIO_BASE + offset, + WM8962_GP2_LVL, + !!value << WM8962_GP2_LVL_SHIFT); } static int wm8962_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct wm8962_priv *wm8962 = gpiochip_get_data(chip); - struct snd_soc_codec *codec = wm8962->codec; + struct snd_soc_component *component = wm8962->component; int ret, val; /* Force function 1 (logic output) */ val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT); - ret = snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, + ret = snd_soc_component_update_bits(component, WM8962_GPIO_BASE + offset, WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val); if (ret < 0) return ret; @@ -3366,15 +3454,15 @@ static const struct gpio_chip wm8962_template_chip = { .can_sleep = 1, }; -static void wm8962_init_gpio(struct snd_soc_codec *codec) +static void wm8962_init_gpio(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); struct wm8962_pdata *pdata = &wm8962->pdata; int ret; wm8962->gpio_chip = wm8962_template_chip; wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO; - wm8962->gpio_chip.parent = codec->dev; + wm8962->gpio_chip.parent = component->dev; if (pdata->gpio_base) wm8962->gpio_chip.base = pdata->gpio_base; @@ -3383,34 +3471,34 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec) ret = gpiochip_add_data(&wm8962->gpio_chip, wm8962); if (ret != 0) - dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); + dev_err(component->dev, "Failed to add GPIOs: %d\n", ret); } -static void wm8962_free_gpio(struct snd_soc_codec *codec) +static void wm8962_free_gpio(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); gpiochip_remove(&wm8962->gpio_chip); } #else -static void wm8962_init_gpio(struct snd_soc_codec *codec) +static void wm8962_init_gpio(struct snd_soc_component *component) { } -static void wm8962_free_gpio(struct snd_soc_codec *codec) +static void wm8962_free_gpio(struct snd_soc_component *component) { } #endif -static int wm8962_probe(struct snd_soc_codec *codec) +static int wm8962_probe(struct snd_soc_component *component) { - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); int ret; - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); int i; bool dmicclk, dmicdat; - wm8962->codec = codec; + wm8962->component = component; wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0; wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1; @@ -3423,22 +3511,29 @@ static int wm8962_probe(struct snd_soc_codec *codec) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) { - ret = regulator_register_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8962->supplies[i].consumer, + &wm8962->disable_nb[i]); if (ret != 0) { - dev_err(codec->dev, + dev_err(component->dev, "Failed to register regulator notifier: %d\n", ret); } } - wm8962_add_widgets(codec); + wm8962_add_widgets(component); /* Save boards having to disable DMIC when not in use */ dmicclk = false; dmicdat = false; - for (i = 0; i < WM8962_MAX_GPIO; i++) { - switch (snd_soc_read(codec, WM8962_GPIO_BASE + i) + for (i = 1; i < WM8962_MAX_GPIO; i++) { + /* + * Register 515 (WM8962_GPIO_BASE + 3) does not exist, + * so skip its access + */ + if (i == 3) + continue; + switch (snd_soc_component_read(component, WM8962_GPIO_BASE + i) & WM8962_GP2_FN_MASK) { case WM8962_GPIO_FN_DMICCLK: dmicclk = true; @@ -3451,40 +3546,35 @@ static int wm8962_probe(struct snd_soc_codec *codec) } } if (!dmicclk || !dmicdat) { - dev_dbg(codec->dev, "DMIC not in use, disabling\n"); - snd_soc_dapm_nc_pin(dapm, "DMICDAT"); + dev_dbg(component->dev, "DMIC not in use, disabling\n"); + snd_soc_dapm_disable_pin(dapm, "DMICDAT"); } if (dmicclk != dmicdat) - dev_warn(codec->dev, "DMIC GPIOs partially configured\n"); + dev_warn(component->dev, "DMIC GPIOs partially configured\n"); - wm8962_init_beep(codec); - wm8962_init_gpio(codec); + wm8962_init_beep(component); + wm8962_init_gpio(component); return 0; } -static int wm8962_remove(struct snd_soc_codec *codec) +static void wm8962_remove(struct snd_soc_component *component) { - struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); - int i; + struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); cancel_delayed_work_sync(&wm8962->mic_work); - wm8962_free_gpio(codec); - wm8962_free_beep(codec); - for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) - regulator_unregister_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); - - return 0; + wm8962_free_gpio(component); + wm8962_free_beep(component); } -static const struct snd_soc_codec_driver soc_codec_dev_wm8962 = { - .probe = wm8962_probe, - .remove = wm8962_remove, - .set_bias_level = wm8962_set_bias_level, - .set_pll = wm8962_set_fll, - .idle_bias_off = true, +static const struct snd_soc_component_driver soc_component_dev_wm8962 = { + .probe = wm8962_probe, + .remove = wm8962_remove, + .set_bias_level = wm8962_set_bias_level, + .set_pll = wm8962_set_fll, + .use_pmdown_time = 1, + .endianness = 1, }; /* Improve power consumption for IN4 DC measurement mode */ @@ -3503,7 +3593,7 @@ static const struct regmap_config wm8962_regmap = { .num_reg_defaults = ARRAY_SIZE(wm8962_reg), .volatile_reg = wm8962_volatile_register, .readable_reg = wm8962_readable_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int wm8962_set_pdata_from_of(struct i2c_client *i2c, @@ -3531,13 +3621,11 @@ static int wm8962_set_pdata_from_of(struct i2c_client *i2c, pdata->gpio_init[i] = 0x0; } - pdata->mclk = devm_clk_get(&i2c->dev, NULL); - - return 0; + pdata->mclk = devm_clk_get_optional(&i2c->dev, NULL); + return PTR_ERR_OR_ZERO(pdata->mclk); } -static int wm8962_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8962_i2c_probe(struct i2c_client *i2c) { struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev); struct wm8962_priv *wm8962; @@ -3565,14 +3653,6 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, return ret; } - /* Mark the mclk pointer to NULL if no mclk assigned */ - if (IS_ERR(wm8962->pdata.mclk)) { - /* But do not ignore the request for probe defer */ - if (PTR_ERR(wm8962->pdata.mclk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - wm8962->pdata.mclk = NULL; - } - for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) wm8962->supplies[i].supply = wm8962_supply_names[i]; @@ -3751,11 +3831,16 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, pm_runtime_enable(&i2c->dev); pm_request_idle(&i2c->dev); - ret = snd_soc_register_codec(&i2c->dev, - &soc_codec_dev_wm8962, &wm8962_dai, 1); + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_wm8962, &wm8962_dai, 1); if (ret < 0) goto err_pm_runtime; + regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4, + WM8962_TEMP_ENA_HP_MASK, 0); + regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4, + WM8962_TEMP_ENA_SPK_MASK, 0); + regcache_cache_only(wm8962->regmap, true); /* The drivers should power up as needed */ @@ -3771,14 +3856,11 @@ err: return ret; } -static int wm8962_i2c_remove(struct i2c_client *client) +static void wm8962_i2c_remove(struct i2c_client *client) { - snd_soc_unregister_codec(&client->dev); pm_runtime_disable(&client->dev); - return 0; } -#ifdef CONFIG_PM static int wm8962_runtime_resume(struct device *dev) { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); @@ -3806,8 +3888,8 @@ static int wm8962_runtime_resume(struct device *dev) /* SYSCLK defaults to on; make sure it is off so we can safely * write to registers if the device is declocked. */ - regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, - WM8962_SYSCLK_ENA, 0); + regmap_write_bits(wm8962->regmap, WM8962_CLOCKING2, + WM8962_SYSCLK_ENA, 0); /* Ensure we have soft control over all registers */ regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2, @@ -3829,6 +3911,9 @@ static int wm8962_runtime_resume(struct device *dev) WM8962_BIAS_ENA | WM8962_VMID_SEL_MASK, WM8962_BIAS_ENA | 0x180); + if (wm8962->master_flag) + regmap_update_bits(wm8962->regmap, WM8962_AUDIO_INTERFACE_0, + WM8962_MSTR, WM8962_MSTR); msleep(5); return 0; @@ -3842,6 +3927,10 @@ static int wm8962_runtime_suspend(struct device *dev) { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); + if (wm8962->master_flag) + regmap_update_bits(wm8962->regmap, WM8962_AUDIO_INTERFACE_0, + WM8962_MSTR, 0); + regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1, WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0); @@ -3858,14 +3947,14 @@ static int wm8962_runtime_suspend(struct device *dev) return 0; } -#endif static const struct dev_pm_ops wm8962_pm = { - SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) }; static const struct i2c_device_id wm8962_i2c_id[] = { - { "wm8962", 0 }, + { "wm8962" }, { } }; MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id); @@ -3880,7 +3969,7 @@ static struct i2c_driver wm8962_i2c_driver = { .driver = { .name = "wm8962", .of_match_table = wm8962_of_match, - .pm = &wm8962_pm, + .pm = pm_ptr(&wm8962_pm), }, .probe = wm8962_i2c_probe, .remove = wm8962_i2c_remove, |
