diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index f6bf4cfbea23..be1fc8a4aee9 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -5,24 +5,149 @@ * Copyright 2011-2012 Maxim Integrated Products */ +#include +#include #include #include #include +#include #include #include #include #include #include -#include -#include #include +#include #include #include #include #include -#include #include "max98090.h" +static void max98090_shdn_save_locked(struct max98090_priv *max98090) +{ + int shdn = 0; + + /* saved_shdn, saved_count, SHDN are protected by card->dapm_mutex */ + regmap_read(max98090->regmap, M98090_REG_DEVICE_SHUTDOWN, &shdn); + max98090->saved_shdn |= shdn; + ++max98090->saved_count; + + if (shdn) + regmap_write(max98090->regmap, M98090_REG_DEVICE_SHUTDOWN, 0x0); +} + +static void max98090_shdn_restore_locked(struct max98090_priv *max98090) +{ + /* saved_shdn, saved_count, SHDN are protected by card->dapm_mutex */ + if (--max98090->saved_count == 0) { + if (max98090->saved_shdn) { + regmap_write(max98090->regmap, + M98090_REG_DEVICE_SHUTDOWN, + M98090_SHDNN_MASK); + max98090->saved_shdn = 0; + } + } +} + +static void max98090_shdn_save(struct max98090_priv *max98090) +{ + mutex_lock(&max98090->component->card->dapm_mutex); + max98090_shdn_save_locked(max98090); +} + +static void max98090_shdn_restore(struct max98090_priv *max98090) +{ + max98090_shdn_restore_locked(max98090); + mutex_unlock(&max98090->component->card->dapm_mutex); +} + +static int max98090_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct max98090_priv *max98090 = + snd_soc_component_get_drvdata(component); + int ret; + + max98090_shdn_save(max98090); + ret = snd_soc_put_volsw(kcontrol, ucontrol); + max98090_shdn_restore(max98090); + + return ret; +} + +static int max98090_dapm_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct max98090_priv *max98090 = + snd_soc_component_get_drvdata(component); + int ret; + + max98090_shdn_save(max98090); + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + max98090_shdn_restore(max98090); + + return ret; +} + +static int max98090_put_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct max98090_priv *max98090 = + snd_soc_component_get_drvdata(component); + int ret; + + max98090_shdn_save(max98090); + ret = snd_soc_put_enum_double(kcontrol, ucontrol); + max98090_shdn_restore(max98090); + + return ret; +} + +static int max98090_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct max98090_priv *max98090 = + snd_soc_component_get_drvdata(component); + int ret; + + max98090_shdn_save(max98090); + ret = snd_soc_bytes_put(kcontrol, ucontrol); + max98090_shdn_restore(max98090); + + return ret; +} + +static int max98090_dapm_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); + struct max98090_priv *max98090 = + snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_PRE_PMD: + max98090_shdn_save_locked(max98090); + break; + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_POST_PMD: + max98090_shdn_restore_locked(max98090); + break; + } + + return 0; +} + /* Allows for sparsely populated register maps */ static const struct reg_default max98090_reg[] = { { 0x00, 0x00 }, /* 00 Software Reset */ @@ -506,10 +631,13 @@ static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum, max98090_pwr_perf_text); static const struct snd_kcontrol_new max98090_snd_controls[] = { - SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), + SOC_ENUM_EXT("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum, + snd_soc_get_enum_double, max98090_put_enum_double), - SOC_SINGLE("DMIC MIC Comp Filter Config", M98090_REG_DIGITAL_MIC_CONFIG, - M98090_DMIC_COMP_SHIFT, M98090_DMIC_COMP_NUM - 1, 0), + SOC_SINGLE_EXT("DMIC MIC Comp Filter Config", + M98090_REG_DIGITAL_MIC_CONFIG, + M98090_DMIC_COMP_SHIFT, M98090_DMIC_COMP_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), SOC_SINGLE_EXT_TLV("MIC1 Boost Volume", M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, @@ -564,24 +692,34 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = { M98090_AVR_SHIFT, M98090_AVR_NUM - 1, 1, max98090_av_tlv), - SOC_ENUM("ADC Oversampling Rate", max98090_osr128_enum), - SOC_SINGLE("ADC Quantizer Dither", M98090_REG_ADC_CONTROL, - M98090_ADCDITHER_SHIFT, M98090_ADCDITHER_NUM - 1, 0), - SOC_ENUM("ADC High Performance Mode", max98090_adchp_enum), + SOC_ENUM_EXT("ADC Oversampling Rate", max98090_osr128_enum, + snd_soc_get_enum_double, max98090_put_enum_double), + SOC_SINGLE_EXT("ADC Quantizer Dither", M98090_REG_ADC_CONTROL, + M98090_ADCDITHER_SHIFT, M98090_ADCDITHER_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_ENUM_EXT("ADC High Performance Mode", max98090_adchp_enum, + snd_soc_get_enum_double, max98090_put_enum_double), - SOC_SINGLE("DAC Mono Mode", M98090_REG_IO_CONFIGURATION, - M98090_DMONO_SHIFT, M98090_DMONO_NUM - 1, 0), - SOC_SINGLE("SDIN Mode", M98090_REG_IO_CONFIGURATION, - M98090_SDIEN_SHIFT, M98090_SDIEN_NUM - 1, 0), - SOC_SINGLE("SDOUT Mode", M98090_REG_IO_CONFIGURATION, - M98090_SDOEN_SHIFT, M98090_SDOEN_NUM - 1, 0), - SOC_SINGLE("SDOUT Hi-Z Mode", M98090_REG_IO_CONFIGURATION, - M98090_HIZOFF_SHIFT, M98090_HIZOFF_NUM - 1, 1), - SOC_ENUM("Filter Mode", max98090_mode_enum), - SOC_SINGLE("Record Path DC Blocking", M98090_REG_FILTER_CONFIG, - M98090_AHPF_SHIFT, M98090_AHPF_NUM - 1, 0), - SOC_SINGLE("Playback Path DC Blocking", M98090_REG_FILTER_CONFIG, - M98090_DHPF_SHIFT, M98090_DHPF_NUM - 1, 0), + SOC_SINGLE_EXT("DAC Mono Mode", M98090_REG_IO_CONFIGURATION, + M98090_DMONO_SHIFT, M98090_DMONO_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_SINGLE_EXT("SDIN Mode", M98090_REG_IO_CONFIGURATION, + M98090_SDIEN_SHIFT, M98090_SDIEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_SINGLE_EXT("SDOUT Mode", M98090_REG_IO_CONFIGURATION, + M98090_SDOEN_SHIFT, M98090_SDOEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_SINGLE_EXT("SDOUT Hi-Z Mode", M98090_REG_IO_CONFIGURATION, + M98090_HIZOFF_SHIFT, M98090_HIZOFF_NUM - 1, 1, + snd_soc_get_volsw, max98090_put_volsw), + SOC_ENUM_EXT("Filter Mode", max98090_mode_enum, + snd_soc_get_enum_double, max98090_put_enum_double), + SOC_SINGLE_EXT("Record Path DC Blocking", M98090_REG_FILTER_CONFIG, + M98090_AHPF_SHIFT, M98090_AHPF_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_SINGLE_EXT("Playback Path DC Blocking", M98090_REG_FILTER_CONFIG, + M98090_DHPF_SHIFT, M98090_DHPF_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), SOC_SINGLE_TLV("Digital BQ Volume", M98090_REG_ADC_BIQUAD_LEVEL, M98090_AVBQ_SHIFT, M98090_AVBQ_NUM - 1, 1, max98090_dv_tlv), SOC_SINGLE_EXT_TLV("Digital Sidetone Volume", @@ -594,13 +732,17 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = { SOC_SINGLE_TLV("Digital Volume", M98090_REG_DAI_PLAYBACK_LEVEL, M98090_DV_SHIFT, M98090_DV_NUM - 1, 1, max98090_dv_tlv), - SND_SOC_BYTES("EQ Coefficients", M98090_REG_EQUALIZER_BASE, 105), - SOC_SINGLE("Digital EQ 3 Band Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_EQ3BANDEN_SHIFT, M98090_EQ3BANDEN_NUM - 1, 0), - SOC_SINGLE("Digital EQ 5 Band Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_EQ5BANDEN_SHIFT, M98090_EQ5BANDEN_NUM - 1, 0), - SOC_SINGLE("Digital EQ 7 Band Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_EQ7BANDEN_SHIFT, M98090_EQ7BANDEN_NUM - 1, 0), + SND_SOC_BYTES_E("EQ Coefficients", M98090_REG_EQUALIZER_BASE, 105, + snd_soc_bytes_get, max98090_bytes_put), + SOC_SINGLE_EXT("Digital EQ 3 Band Switch", M98090_REG_DSP_FILTER_ENABLE, + M98090_EQ3BANDEN_SHIFT, M98090_EQ3BANDEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_SINGLE_EXT("Digital EQ 5 Band Switch", M98090_REG_DSP_FILTER_ENABLE, + M98090_EQ5BANDEN_SHIFT, M98090_EQ5BANDEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_SINGLE_EXT("Digital EQ 7 Band Switch", M98090_REG_DSP_FILTER_ENABLE, + M98090_EQ7BANDEN_SHIFT, M98090_EQ7BANDEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), SOC_SINGLE("Digital EQ Clipping Detection", M98090_REG_DAI_PLAYBACK_LEVEL_EQ, M98090_EQCLPN_SHIFT, M98090_EQCLPN_NUM - 1, 1), @@ -608,25 +750,34 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = { M98090_DVEQ_SHIFT, M98090_DVEQ_NUM - 1, 1, max98090_dv_tlv), - SOC_SINGLE("ALC Enable", M98090_REG_DRC_TIMING, - M98090_DRCEN_SHIFT, M98090_DRCEN_NUM - 1, 0), - SOC_ENUM("ALC Attack Time", max98090_drcatk_enum), - SOC_ENUM("ALC Release Time", max98090_drcrls_enum), + SOC_SINGLE_EXT("ALC Enable", M98090_REG_DRC_TIMING, + M98090_DRCEN_SHIFT, M98090_DRCEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), + SOC_ENUM_EXT("ALC Attack Time", max98090_drcatk_enum, + snd_soc_get_enum_double, max98090_put_enum_double), + SOC_ENUM_EXT("ALC Release Time", max98090_drcrls_enum, + snd_soc_get_enum_double, max98090_put_enum_double), SOC_SINGLE_TLV("ALC Make Up Volume", M98090_REG_DRC_GAIN, M98090_DRCG_SHIFT, M98090_DRCG_NUM - 1, 0, max98090_alcmakeup_tlv), - SOC_ENUM("ALC Compression Ratio", max98090_alccmp_enum), - SOC_ENUM("ALC Expansion Ratio", max98090_drcexp_enum), - SOC_SINGLE_TLV("ALC Compression Threshold Volume", + SOC_ENUM_EXT("ALC Compression Ratio", max98090_alccmp_enum, + snd_soc_get_enum_double, max98090_put_enum_double), + SOC_ENUM_EXT("ALC Expansion Ratio", max98090_drcexp_enum, + snd_soc_get_enum_double, max98090_put_enum_double), + SOC_SINGLE_EXT_TLV("ALC Compression Threshold Volume", M98090_REG_DRC_COMPRESSOR, M98090_DRCTHC_SHIFT, - M98090_DRCTHC_NUM - 1, 1, max98090_alccomp_tlv), - SOC_SINGLE_TLV("ALC Expansion Threshold Volume", + M98090_DRCTHC_NUM - 1, 1, + snd_soc_get_volsw, max98090_put_volsw, max98090_alccomp_tlv), + SOC_SINGLE_EXT_TLV("ALC Expansion Threshold Volume", M98090_REG_DRC_EXPANDER, M98090_DRCTHE_SHIFT, - M98090_DRCTHE_NUM - 1, 1, max98090_drcexp_tlv), + M98090_DRCTHE_NUM - 1, 1, + snd_soc_get_volsw, max98090_put_volsw, max98090_drcexp_tlv), - SOC_ENUM("DAC HP Playback Performance Mode", - max98090_dac_perfmode_enum), - SOC_ENUM("DAC High Performance Mode", max98090_dachp_enum), + SOC_ENUM_EXT("DAC HP Playback Performance Mode", + max98090_dac_perfmode_enum, + snd_soc_get_enum_double, max98090_put_enum_double), + SOC_ENUM_EXT("DAC High Performance Mode", max98090_dachp_enum, + snd_soc_get_enum_double, max98090_put_enum_double), SOC_SINGLE_TLV("Headphone Left Mixer Volume", M98090_REG_HP_CONTROL, M98090_MIXHPLG_SHIFT, @@ -684,9 +835,12 @@ static const struct snd_kcontrol_new max98090_snd_controls[] = { SOC_SINGLE("Volume Adjustment Smoothing", M98090_REG_LEVEL_CONTROL, M98090_VSENN_SHIFT, M98090_VSENN_NUM - 1, 1), - SND_SOC_BYTES("Biquad Coefficients", M98090_REG_RECORD_BIQUAD_BASE, 15), - SOC_SINGLE("Biquad Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_ADCBQEN_SHIFT, M98090_ADCBQEN_NUM - 1, 0), + SND_SOC_BYTES_E("Biquad Coefficients", + M98090_REG_RECORD_BIQUAD_BASE, 15, + snd_soc_bytes_get, max98090_bytes_put), + SOC_SINGLE_EXT("Biquad Switch", M98090_REG_DSP_FILTER_ENABLE, + M98090_ADCBQEN_SHIFT, M98090_ADCBQEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), }; static const struct snd_kcontrol_new max98091_snd_controls[] = { @@ -695,10 +849,12 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = { M98090_DMIC34_ZEROPAD_SHIFT, M98090_DMIC34_ZEROPAD_NUM - 1, 0), - SOC_ENUM("Filter DMIC34 Mode", max98090_filter_dmic34mode_enum), - SOC_SINGLE("DMIC34 DC Blocking", M98090_REG_FILTER_CONFIG, + SOC_ENUM_EXT("Filter DMIC34 Mode", max98090_filter_dmic34mode_enum, + snd_soc_get_enum_double, max98090_put_enum_double), + SOC_SINGLE_EXT("DMIC34 DC Blocking", M98090_REG_FILTER_CONFIG, M98090_FLT_DMIC34HPF_SHIFT, - M98090_FLT_DMIC34HPF_NUM - 1, 0), + M98090_FLT_DMIC34HPF_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), SOC_SINGLE_TLV("DMIC3 Boost Volume", M98090_REG_DMIC3_VOLUME, M98090_DMIC_AV3G_SHIFT, M98090_DMIC_AV3G_NUM - 1, 0, @@ -716,8 +872,9 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = { SND_SOC_BYTES("DMIC34 Biquad Coefficients", M98090_REG_DMIC34_BIQUAD_BASE, 15), - SOC_SINGLE("DMIC34 Biquad Switch", M98090_REG_DSP_FILTER_ENABLE, - M98090_DMIC34BQEN_SHIFT, M98090_DMIC34BQEN_NUM - 1, 0), + SOC_SINGLE_EXT("DMIC34 Biquad Switch", M98090_REG_DSP_FILTER_ENABLE, + M98090_DMIC34BQEN_SHIFT, M98090_DMIC34BQEN_NUM - 1, 0, + snd_soc_get_volsw, max98090_put_volsw), SOC_SINGLE_TLV("DMIC34 BQ PreAttenuation Volume", M98090_REG_DMIC34_BQ_PREATTEN, M98090_AV34BQ_SHIFT, @@ -771,19 +928,6 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, return 0; } -static int max98090_shdn_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); - struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component); - - if (event & SND_SOC_DAPM_POST_PMU) - max98090->shdn_pending = true; - - return 0; - -} - static const char *mic1_mux_text[] = { "IN12", "IN56" }; static SOC_ENUM_SINGLE_DECL(mic1_mux_enum, @@ -884,10 +1028,14 @@ static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum, lten_mux_text); static const struct snd_kcontrol_new max98090_ltenl_mux = - SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); + SOC_DAPM_ENUM_EXT("LTENL Mux", ltenl_mux_enum, + snd_soc_dapm_get_enum_double, + max98090_dapm_put_enum_double); static const struct snd_kcontrol_new max98090_ltenr_mux = - SOC_DAPM_ENUM("LTENR Mux", ltenr_mux_enum); + SOC_DAPM_ENUM_EXT("LTENR Mux", ltenr_mux_enum, + snd_soc_dapm_get_enum_double, + max98090_dapm_put_enum_double); static const char *lben_mux_text[] = { "Normal", "Loopback" }; @@ -902,10 +1050,14 @@ static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum, lben_mux_text); static const struct snd_kcontrol_new max98090_lbenl_mux = - SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); + SOC_DAPM_ENUM_EXT("LBENL Mux", lbenl_mux_enum, + snd_soc_dapm_get_enum_double, + max98090_dapm_put_enum_double); static const struct snd_kcontrol_new max98090_lbenr_mux = - SOC_DAPM_ENUM("LBENR Mux", lbenr_mux_enum); + SOC_DAPM_ENUM_EXT("LBENR Mux", lbenr_mux_enum, + snd_soc_dapm_get_enum_double, + max98090_dapm_put_enum_double); static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" }; @@ -1072,21 +1224,25 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { SND_SOC_DAPM_INPUT("IN56"), SND_SOC_DAPM_SUPPLY("MICBIAS", M98090_REG_INPUT_ENABLE, - M98090_MBEN_SHIFT, 0, NULL, 0), + M98090_MBEN_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_SUPPLY("SHDN", M98090_REG_DEVICE_SHUTDOWN, M98090_SHDNN_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("SDIEN", M98090_REG_IO_CONFIGURATION, - M98090_SDIEN_SHIFT, 0, NULL, 0), + M98090_SDIEN_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_SUPPLY("SDOEN", M98090_REG_IO_CONFIGURATION, - M98090_SDOEN_SHIFT, 0, NULL, 0), + M98090_SDOEN_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_SUPPLY("DMICL_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMICL_SHIFT, 0, max98090_shdn_event, - SND_SOC_DAPM_POST_PMU), + M98090_DIGMICL_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_SUPPLY("DMICR_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMICR_SHIFT, 0, max98090_shdn_event, - SND_SOC_DAPM_POST_PMU), + M98090_DIGMICR_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_SUPPLY("AHPF", M98090_REG_FILTER_CONFIG, - M98090_AHPF_SHIFT, 0, NULL, 0), + M98090_AHPF_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), /* * Note: Sysclk and misc power supplies are taken care of by SHDN @@ -1116,10 +1272,12 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { &max98090_lineb_mixer_controls[0], ARRAY_SIZE(max98090_lineb_mixer_controls)), - SND_SOC_DAPM_PGA("LINEA Input", M98090_REG_INPUT_ENABLE, - M98090_LINEAEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("LINEB Input", M98090_REG_INPUT_ENABLE, - M98090_LINEBEN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("LINEA Input", M98090_REG_INPUT_ENABLE, + M98090_LINEAEN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEB Input", M98090_REG_INPUT_ENABLE, + M98090_LINEBEN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0, &max98090_left_adc_mixer_controls[0], @@ -1130,11 +1288,11 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { ARRAY_SIZE(max98090_right_adc_mixer_controls)), SND_SOC_DAPM_ADC_E("ADCL", NULL, M98090_REG_INPUT_ENABLE, - M98090_ADLEN_SHIFT, 0, max98090_shdn_event, - SND_SOC_DAPM_POST_PMU), + M98090_ADLEN_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_ADC_E("ADCR", NULL, M98090_REG_INPUT_ENABLE, - M98090_ADREN_SHIFT, 0, max98090_shdn_event, - SND_SOC_DAPM_POST_PMU), + M98090_ADREN_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_AIF_OUT("AIFOUTL", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), @@ -1162,10 +1320,12 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DACL", NULL, M98090_REG_OUTPUT_ENABLE, - M98090_DALEN_SHIFT, 0), - SND_SOC_DAPM_DAC("DACR", NULL, M98090_REG_OUTPUT_ENABLE, - M98090_DAREN_SHIFT, 0), + SND_SOC_DAPM_DAC_E("DACL", NULL, M98090_REG_OUTPUT_ENABLE, + M98090_DALEN_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_DAC_E("DACR", NULL, M98090_REG_OUTPUT_ENABLE, + M98090_DAREN_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0, &max98090_left_hp_mixer_controls[0], @@ -1200,20 +1360,26 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { SND_SOC_DAPM_MUX("MIXHPRSEL Mux", SND_SOC_NOPM, 0, 0, &max98090_mixhprsel_mux), - SND_SOC_DAPM_PGA("HP Left Out", M98090_REG_OUTPUT_ENABLE, - M98090_HPLEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("HP Right Out", M98090_REG_OUTPUT_ENABLE, - M98090_HPREN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HP Left Out", M98090_REG_OUTPUT_ENABLE, + M98090_HPLEN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_PGA_E("HP Right Out", M98090_REG_OUTPUT_ENABLE, + M98090_HPREN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), - SND_SOC_DAPM_PGA("SPK Left Out", M98090_REG_OUTPUT_ENABLE, - M98090_SPLEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("SPK Right Out", M98090_REG_OUTPUT_ENABLE, - M98090_SPREN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("SPK Left Out", M98090_REG_OUTPUT_ENABLE, + M98090_SPLEN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_PGA_E("SPK Right Out", M98090_REG_OUTPUT_ENABLE, + M98090_SPREN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), - SND_SOC_DAPM_PGA("RCV Left Out", M98090_REG_OUTPUT_ENABLE, - M98090_RCVLEN_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_PGA("RCV Right Out", M98090_REG_OUTPUT_ENABLE, - M98090_RCVREN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("RCV Left Out", M98090_REG_OUTPUT_ENABLE, + M98090_RCVLEN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_PGA_E("RCV Right Out", M98090_REG_OUTPUT_ENABLE, + M98090_RCVREN_SHIFT, 0, NULL, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), @@ -1228,9 +1394,11 @@ static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { SND_SOC_DAPM_INPUT("DMIC4"), SND_SOC_DAPM_SUPPLY("DMIC3_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMIC3_SHIFT, 0, NULL, 0), + M98090_DIGMIC3_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_SUPPLY("DMIC4_ENA", M98090_REG_DIGITAL_MIC_ENABLE, - M98090_DIGMIC4_SHIFT, 0, NULL, 0), + M98090_DIGMIC4_SHIFT, 0, max98090_dapm_event, + SND_SOC_DAPM_PRE_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD), }; static const struct snd_soc_dapm_route max98090_dapm_routes[] = { @@ -1501,6 +1669,11 @@ static void max98090_configure_bclk(struct snd_soc_component *component) return; } + /* + * Master mode: no need to save and restore SHDN for the following + * sensitive registers. + */ + /* Check for supported PCLK to LRCLK ratios */ for (i = 0; i < ARRAY_SIZE(pclk_rates); i++) { if ((pclk_rates[i] == max98090->sysclk) && @@ -1587,12 +1760,14 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* Set to slave mode PLL - MAS mode off */ + max98090_shdn_save(max98090); snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_MSB, 0x00); snd_soc_component_write(component, M98090_REG_CLOCK_RATIO_NI_LSB, 0x00); snd_soc_component_update_bits(component, M98090_REG_CLOCK_MODE, M98090_USE_M1_MASK, 0); + max98090_shdn_restore(max98090); max98090->master = false; break; case SND_SOC_DAIFMT_CBM_CFM: @@ -1618,7 +1793,9 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, dev_err(component->dev, "DAI clock mode unsupported"); return -EINVAL; } + max98090_shdn_save(max98090); snd_soc_component_write(component, M98090_REG_MASTER_MODE, regval); + max98090_shdn_restore(max98090); regval = 0; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -1663,8 +1840,10 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai, if (max98090->tdm_slots > 1) regval ^= M98090_BCI_MASK; + max98090_shdn_save(max98090); snd_soc_component_write(component, M98090_REG_INTERFACE_FORMAT, regval); + max98090_shdn_restore(max98090); } return 0; @@ -1676,6 +1855,7 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai, struct snd_soc_component *component = codec_dai->component; struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component); struct max98090_cdata *cdata; + cdata = &max98090->dai[0]; if (slots < 0 || slots > 4) @@ -1685,6 +1865,7 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai, max98090->tdm_width = slot_width; if (max98090->tdm_slots > 1) { + max98090_shdn_save(max98090); /* SLOTL SLOTR SLOTDLY */ snd_soc_component_write(component, M98090_REG_TDM_FORMAT, 0 << M98090_TDM_SLOTL_SHIFT | @@ -1695,6 +1876,7 @@ static int max98090_set_tdm_slot(struct snd_soc_dai *codec_dai, snd_soc_component_update_bits(component, M98090_REG_TDM_CONTROL, M98090_TDM_MASK, M98090_TDM_MASK); + max98090_shdn_restore(max98090); } /* @@ -1894,6 +2076,7 @@ static int max98090_configure_dmic(struct max98090_priv *max98090, dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq; dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i]; + max98090_shdn_save(max98090); regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE, M98090_MICCLK_MASK, micclk_index << M98090_MICCLK_SHIFT); @@ -1902,6 +2085,7 @@ static int max98090_configure_dmic(struct max98090_priv *max98090, M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK, dmic_comp << M98090_DMIC_COMP_SHIFT | dmic_freq << M98090_DMIC_FREQ_SHIFT); + max98090_shdn_restore(max98090); return 0; } @@ -1938,8 +2122,10 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, switch (params_width(params)) { case 16: + max98090_shdn_save(max98090); snd_soc_component_update_bits(component, M98090_REG_INTERFACE_FORMAT, M98090_WS_MASK, 0); + max98090_shdn_restore(max98090); break; default: return -EINVAL; @@ -1950,6 +2136,7 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, cdata->rate = max98090->lrclk; + max98090_shdn_save(max98090); /* Update filter mode */ if (max98090->lrclk < 24000) snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG, @@ -1965,6 +2152,7 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, else snd_soc_component_update_bits(component, M98090_REG_FILTER_CONFIG, M98090_DHF_MASK, M98090_DHF_MASK); + max98090_shdn_restore(max98090); max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk, max98090->lrclk); @@ -1995,6 +2183,7 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, * 0x02 (when master clk is 20MHz to 40MHz).. * 0x03 (when master clk is 40MHz to 60MHz).. */ + max98090_shdn_save(max98090); if ((freq >= 10000000) && (freq <= 20000000)) { snd_soc_component_write(component, M98090_REG_SYSTEM_CLOCK, M98090_PSCLK_DIV1); @@ -2009,8 +2198,10 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, max98090->pclk = freq >> 2; } else { dev_err(component->dev, "Invalid master clock frequency\n"); + max98090_shdn_restore(max98090); return -EINVAL; } + max98090_shdn_restore(max98090); max98090->sysclk = freq; @@ -2115,11 +2306,13 @@ static void max98090_pll_work(struct work_struct *work) dev_info_ratelimited(component->dev, "PLL unlocked\n"); /* Toggle shutdown OFF then ON */ + mutex_lock(&component->card->dapm_mutex); snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN, M98090_SHDNN_MASK, 0); msleep(10); snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN, M98090_SHDNN_MASK, M98090_SHDNN_MASK); + mutex_unlock(&component->card->dapm_mutex); /* Give PLL time to lock */ msleep(10); @@ -2435,7 +2628,12 @@ static int max98090_probe(struct snd_soc_component *component) */ snd_soc_component_read32(component, M98090_REG_DEVICE_STATUS); - /* High Performance is default */ + /* + * SHDN should be 0 at the point, no need to save/restore for the + * following registers. + * + * High Performance is default + */ snd_soc_component_update_bits(component, M98090_REG_DAC_CONTROL, M98090_DACHP_MASK, 1 << M98090_DACHP_SHIFT); @@ -2446,7 +2644,12 @@ static int max98090_probe(struct snd_soc_component *component) M98090_ADCHP_MASK, 1 << M98090_ADCHP_SHIFT); - /* Turn on VCM bandgap reference */ + /* + * SHDN should be 0 at the point, no need to save/restore for the + * following registers. + * + * Turn on VCM bandgap reference + */ snd_soc_component_write(component, M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_MASK); @@ -2479,25 +2682,9 @@ static void max98090_remove(struct snd_soc_component *component) max98090->component = NULL; } -static void max98090_seq_notifier(struct snd_soc_component *component, - enum snd_soc_dapm_type event, int subseq) -{ - struct max98090_priv *max98090 = snd_soc_component_get_drvdata(component); - - if (max98090->shdn_pending) { - snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN, - M98090_SHDNN_MASK, 0); - msleep(40); - snd_soc_component_update_bits(component, M98090_REG_DEVICE_SHUTDOWN, - M98090_SHDNN_MASK, M98090_SHDNN_MASK); - max98090->shdn_pending = false; - } -} - static const struct snd_soc_component_driver soc_component_dev_max98090 = { .probe = max98090_probe, .remove = max98090_remove, - .seq_notifier = max98090_seq_notifier, .set_bias_level = max98090_set_bias_level, .idle_bias_on = 1, .use_pmdown_time = 1, diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index 57965cd678b4..697cb568ac25 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h @@ -1540,7 +1540,8 @@ struct max98090_priv { unsigned int pa2en; unsigned int sidetone; bool master; - bool shdn_pending; + int saved_count; + int saved_shdn; }; int max98090_mic_detect(struct snd_soc_component *component,