Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: max9867: shutdown codec when changing filter type

Changing filter type without disabling codec results in filter
malfunction. Disable codec when changing filter type.

Signed-off-by: Pavel Dobias <dobias@2n.cz>
Link: https://lore.kernel.org/r/20200827102528.29677-1-dobias@2n.cz
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Pavel Dobias and committed by
Mark Brown
a11ffbba f7660445

+120 -15
+117 -14
sound/soc/codecs/max9867.c
··· 15 15 #include <sound/tlv.h> 16 16 #include "max9867.h" 17 17 18 + struct max9867_priv { 19 + struct regmap *regmap; 20 + const struct snd_pcm_hw_constraint_list *constraints; 21 + unsigned int sysclk, pclk; 22 + bool master, dsp_a; 23 + unsigned int adc_dac_active; 24 + }; 25 + 18 26 static const char *const max9867_spmode[] = { 19 27 "Stereo Diff", "Mono Diff", 20 28 "Stereo Cap", "Mono Cap", ··· 40 32 "Butterworth/8-24" 41 33 }; 42 34 43 - static SOC_ENUM_SINGLE_DECL(max9867_filter, MAX9867_CODECFLTR, 7, 44 - max9867_filter_text); 35 + enum max9867_adc_dac { 36 + MAX9867_ADC_LEFT, 37 + MAX9867_ADC_RIGHT, 38 + MAX9867_DAC_LEFT, 39 + MAX9867_DAC_RIGHT, 40 + }; 41 + 42 + static int max9867_adc_dac_event(struct snd_soc_dapm_widget *w, 43 + struct snd_kcontrol *kcontrol, int event) 44 + { 45 + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 46 + struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 47 + enum max9867_adc_dac adc_dac; 48 + 49 + if (!strcmp(w->name, "ADCL")) 50 + adc_dac = MAX9867_ADC_LEFT; 51 + else if (!strcmp(w->name, "ADCR")) 52 + adc_dac = MAX9867_ADC_RIGHT; 53 + else if (!strcmp(w->name, "DACL")) 54 + adc_dac = MAX9867_DAC_LEFT; 55 + else if (!strcmp(w->name, "DACR")) 56 + adc_dac = MAX9867_DAC_RIGHT; 57 + else 58 + return 0; 59 + 60 + if (SND_SOC_DAPM_EVENT_ON(event)) 61 + max9867->adc_dac_active |= BIT(adc_dac); 62 + else if (SND_SOC_DAPM_EVENT_OFF(event)) 63 + max9867->adc_dac_active &= ~BIT(adc_dac); 64 + 65 + return 0; 66 + } 67 + 68 + static int max9867_filter_get(struct snd_kcontrol *kcontrol, 69 + struct snd_ctl_elem_value *ucontrol) 70 + { 71 + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 72 + struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 73 + unsigned int reg; 74 + int ret; 75 + 76 + ret = regmap_read(max9867->regmap, MAX9867_CODECFLTR, &reg); 77 + if (ret) 78 + return -EINVAL; 79 + 80 + if (reg & MAX9867_CODECFLTR_MODE) 81 + ucontrol->value.enumerated.item[0] = 1; 82 + else 83 + ucontrol->value.enumerated.item[0] = 0; 84 + 85 + return 0; 86 + } 87 + 88 + static int max9867_filter_set(struct snd_kcontrol *kcontrol, 89 + struct snd_ctl_elem_value *ucontrol) 90 + { 91 + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 92 + struct max9867_priv *max9867 = snd_soc_component_get_drvdata(component); 93 + unsigned int reg, mode = ucontrol->value.enumerated.item[0]; 94 + int ret; 95 + 96 + if (mode > 1) 97 + return -EINVAL; 98 + 99 + /* don't allow change if ADC/DAC active */ 100 + if (max9867->adc_dac_active) 101 + return -EBUSY; 102 + 103 + /* read current filter mode */ 104 + ret = regmap_read(max9867->regmap, MAX9867_CODECFLTR, &reg); 105 + if (ret) 106 + return -EINVAL; 107 + 108 + if (mode) 109 + mode = MAX9867_CODECFLTR_MODE; 110 + 111 + /* check if change is needed */ 112 + if ((reg & MAX9867_CODECFLTR_MODE) == mode) 113 + return 0; 114 + 115 + /* shutdown codec before switching filter mode */ 116 + regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, 117 + MAX9867_PWRMAN_SHDN, 0); 118 + 119 + /* switch filter mode */ 120 + regmap_update_bits(max9867->regmap, MAX9867_CODECFLTR, 121 + MAX9867_CODECFLTR_MODE, mode); 122 + 123 + /* out of shutdown now */ 124 + regmap_update_bits(max9867->regmap, MAX9867_PWRMAN, 125 + MAX9867_PWRMAN_SHDN, MAX9867_PWRMAN_SHDN); 126 + 127 + return 0; 128 + } 129 + 130 + static SOC_ENUM_SINGLE_EXT_DECL(max9867_filter, max9867_filter_text); 45 131 static SOC_ENUM_SINGLE_DECL(max9867_dac_filter, MAX9867_CODECFLTR, 0, 46 132 max9867_adc_dac_filter_text); 47 133 static SOC_ENUM_SINGLE_DECL(max9867_adc_filter, MAX9867_CODECFLTR, 4, ··· 178 76 SOC_ENUM("Speaker Mode", max9867_spkmode), 179 77 SOC_SINGLE("Volume Smoothing Switch", MAX9867_MODECONFIG, 6, 1, 0), 180 78 SOC_SINGLE("Line ZC Switch", MAX9867_MODECONFIG, 5, 1, 0), 181 - SOC_ENUM("DSP Filter", max9867_filter), 79 + SOC_ENUM_EXT("DSP Filter", max9867_filter, max9867_filter_get, max9867_filter_set), 182 80 SOC_ENUM("ADC Filter", max9867_adc_filter), 183 81 SOC_ENUM("DAC Filter", max9867_dac_filter), 184 82 SOC_SINGLE("Mono Playback Switch", MAX9867_IFC1B, 3, 1, 0), ··· 236 134 &max9867_left_dmic_mux), 237 135 SND_SOC_DAPM_MUX("DMICR Mux", SND_SOC_NOPM, 0, 0, 238 136 &max9867_right_dmic_mux), 239 - SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", SND_SOC_NOPM, 0, 0), 240 - SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", SND_SOC_NOPM, 0, 0), 137 + SND_SOC_DAPM_ADC_E("ADCL", "HiFi Capture", SND_SOC_NOPM, 0, 0, 138 + max9867_adc_dac_event, 139 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 140 + SND_SOC_DAPM_ADC_E("ADCR", "HiFi Capture", SND_SOC_NOPM, 0, 0, 141 + max9867_adc_dac_event, 142 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 241 143 242 144 SND_SOC_DAPM_MIXER("Digital", SND_SOC_NOPM, 0, 0, 243 145 max9867_sidetone_mixer_controls, ··· 249 143 SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", SND_SOC_NOPM, 0, 0, 250 144 max9867_output_mixer_controls, 251 145 ARRAY_SIZE(max9867_output_mixer_controls)), 252 - SND_SOC_DAPM_DAC("DACL", "HiFi Playback", SND_SOC_NOPM, 0, 0), 253 - SND_SOC_DAPM_DAC("DACR", "HiFi Playback", SND_SOC_NOPM, 0, 0), 146 + SND_SOC_DAPM_DAC_E("DACL", "HiFi Playback", SND_SOC_NOPM, 0, 0, 147 + max9867_adc_dac_event, 148 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 149 + SND_SOC_DAPM_DAC_E("DACR", "HiFi Playback", SND_SOC_NOPM, 0, 0, 150 + max9867_adc_dac_event, 151 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 254 152 SND_SOC_DAPM_SWITCH("Master Playback", SND_SOC_NOPM, 0, 0, 255 153 &max9867_line_out_control), 256 154 SND_SOC_DAPM_OUTPUT("LOUT"), ··· 305 195 static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = { 306 196 .list = max9867_rates_48k, 307 197 .count = ARRAY_SIZE(max9867_rates_48k), 308 - }; 309 - 310 - struct max9867_priv { 311 - struct regmap *regmap; 312 - const struct snd_pcm_hw_constraint_list *constraints; 313 - unsigned int sysclk, pclk; 314 - bool master, dsp_a; 315 198 }; 316 199 317 200 static int max9867_startup(struct snd_pcm_substream *substream,
+3 -1
sound/soc/codecs/max9867.h
··· 44 44 #define MAX9867_IFC1B_PCLK_4 0x05 45 45 #define MAX9867_IFC1B_PCLK_8 0x06 46 46 #define MAX9867_IFC1B_PCLK_16 0x07 47 - #define MAX9867_CODECFLTR 0x0a 47 + #define MAX9867_CODECFLTR 0x0a 48 + #define MAX9867_CODECFLTR_MODE (1<<7) 48 49 #define MAX9867_SIDETONE 0x0b 49 50 #define MAX9867_DACLEVEL 0x0c 50 51 #define MAX9867_ADCLEVEL 0x0d ··· 59 58 #define MAX9867_MICCONFIG 0x15 60 59 #define MAX9867_MODECONFIG 0x16 61 60 #define MAX9867_PWRMAN 0x17 61 + #define MAX9867_PWRMAN_SHDN (1<<7) 62 62 #define MAX9867_REVISION 0xff 63 63 64 64 #define MAX9867_CACHEREGNUM 10