1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2017, Maxim Integrated |
3 | |
4 | #include <linux/acpi.h> |
5 | #include <linux/delay.h> |
6 | #include <linux/i2c.h> |
7 | #include <linux/module.h> |
8 | #include <linux/pm_runtime.h> |
9 | #include <linux/regmap.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/cdev.h> |
12 | #include <sound/pcm.h> |
13 | #include <sound/pcm_params.h> |
14 | #include <sound/soc.h> |
15 | #include <linux/gpio/consumer.h> |
16 | #include <linux/of.h> |
17 | #include <sound/tlv.h> |
18 | #include "max98373.h" |
19 | |
20 | static int max98373_dac_event(struct snd_soc_dapm_widget *w, |
21 | struct snd_kcontrol *kcontrol, int event) |
22 | { |
23 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
24 | struct max98373_priv *max98373 = snd_soc_component_get_drvdata(c: component); |
25 | |
26 | switch (event) { |
27 | case SND_SOC_DAPM_POST_PMU: |
28 | regmap_update_bits(map: max98373->regmap, |
29 | MAX98373_R20FF_GLOBAL_SHDN, |
30 | MAX98373_GLOBAL_EN_MASK, val: 1); |
31 | usleep_range(min: 30000, max: 31000); |
32 | break; |
33 | case SND_SOC_DAPM_PRE_PMD: |
34 | regmap_update_bits(map: max98373->regmap, |
35 | MAX98373_R20FF_GLOBAL_SHDN, |
36 | MAX98373_GLOBAL_EN_MASK, val: 0); |
37 | usleep_range(min: 30000, max: 31000); |
38 | max98373->tdm_mode = false; |
39 | break; |
40 | default: |
41 | return 0; |
42 | } |
43 | return 0; |
44 | } |
45 | |
46 | static const char * const max98373_switch_text[] = { |
47 | "Left" , "Right" , "LeftRight" }; |
48 | |
49 | static const struct soc_enum dai_sel_enum = |
50 | SOC_ENUM_SINGLE(MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, |
51 | MAX98373_PCM_TO_SPK_MONOMIX_CFG_SHIFT, |
52 | 3, max98373_switch_text); |
53 | |
54 | static const struct snd_kcontrol_new max98373_dai_controls = |
55 | SOC_DAPM_ENUM("DAI Sel" , dai_sel_enum); |
56 | |
57 | static const struct snd_kcontrol_new max98373_vi_control = |
58 | SOC_DAPM_SINGLE("Switch" , MAX98373_R202C_PCM_TX_EN, 0, 1, 0); |
59 | |
60 | static const struct snd_kcontrol_new max98373_spkfb_control = |
61 | SOC_DAPM_SINGLE("Switch" , MAX98373_R2043_AMP_EN, 1, 1, 0); |
62 | |
63 | static const struct snd_soc_dapm_widget max98373_dapm_widgets[] = { |
64 | SND_SOC_DAPM_DAC_E("Amp Enable" , "HiFi Playback" , |
65 | MAX98373_R202B_PCM_RX_EN, 0, 0, max98373_dac_event, |
66 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
67 | SND_SOC_DAPM_MUX("DAI Sel Mux" , SND_SOC_NOPM, 0, 0, |
68 | &max98373_dai_controls), |
69 | SND_SOC_DAPM_OUTPUT("BE_OUT" ), |
70 | SND_SOC_DAPM_AIF_OUT("Voltage Sense" , "HiFi Capture" , 0, |
71 | MAX98373_R2047_IV_SENSE_ADC_EN, 0, 0), |
72 | SND_SOC_DAPM_AIF_OUT("Current Sense" , "HiFi Capture" , 0, |
73 | MAX98373_R2047_IV_SENSE_ADC_EN, 1, 0), |
74 | SND_SOC_DAPM_AIF_OUT("Speaker FB Sense" , "HiFi Capture" , 0, |
75 | SND_SOC_NOPM, 0, 0), |
76 | SND_SOC_DAPM_SWITCH("VI Sense" , SND_SOC_NOPM, 0, 0, |
77 | &max98373_vi_control), |
78 | SND_SOC_DAPM_SWITCH("SpkFB Sense" , SND_SOC_NOPM, 0, 0, |
79 | &max98373_spkfb_control), |
80 | SND_SOC_DAPM_SIGGEN("VMON" ), |
81 | SND_SOC_DAPM_SIGGEN("IMON" ), |
82 | SND_SOC_DAPM_SIGGEN("FBMON" ), |
83 | }; |
84 | |
85 | static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1); |
86 | static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv, |
87 | 0, 8, TLV_DB_SCALE_ITEM(0, 50, 0), |
88 | 9, 10, TLV_DB_SCALE_ITEM(500, 100, 0), |
89 | ); |
90 | static const DECLARE_TLV_DB_RANGE(max98373_spkgain_max_tlv, |
91 | 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0), |
92 | ); |
93 | static const DECLARE_TLV_DB_RANGE(max98373_dht_step_size_tlv, |
94 | 0, 1, TLV_DB_SCALE_ITEM(25, 25, 0), |
95 | 2, 4, TLV_DB_SCALE_ITEM(100, 100, 0), |
96 | ); |
97 | static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv, |
98 | 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0), |
99 | ); |
100 | static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, |
101 | 0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0), |
102 | 2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0), |
103 | 5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0), |
104 | 7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0), |
105 | 10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0), |
106 | 14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0), |
107 | ); |
108 | static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, |
109 | 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), |
110 | ); |
111 | |
112 | static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, |
113 | 0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0), |
114 | ); |
115 | |
116 | static const char * const max98373_output_voltage_lvl_text[] = { |
117 | "5.43V" , "6.09V" , "6.83V" , "7.67V" , "8.60V" , |
118 | "9.65V" , "10.83V" , "12.15V" , "13.63V" , "15.29V" |
119 | }; |
120 | |
121 | static SOC_ENUM_SINGLE_DECL(max98373_out_volt_enum, |
122 | MAX98373_R203E_AMP_PATH_GAIN, 0, |
123 | max98373_output_voltage_lvl_text); |
124 | |
125 | static const char * const max98373_dht_attack_rate_text[] = { |
126 | "17.5us" , "35us" , "70us" , "140us" , |
127 | "280us" , "560us" , "1120us" , "2240us" |
128 | }; |
129 | |
130 | static SOC_ENUM_SINGLE_DECL(max98373_dht_attack_rate_enum, |
131 | MAX98373_R20D2_DHT_ATTACK_CFG, 0, |
132 | max98373_dht_attack_rate_text); |
133 | |
134 | static const char * const max98373_dht_release_rate_text[] = { |
135 | "45ms" , "225ms" , "450ms" , "1150ms" , |
136 | "2250ms" , "3100ms" , "4500ms" , "6750ms" |
137 | }; |
138 | |
139 | static SOC_ENUM_SINGLE_DECL(max98373_dht_release_rate_enum, |
140 | MAX98373_R20D3_DHT_RELEASE_CFG, 0, |
141 | max98373_dht_release_rate_text); |
142 | |
143 | static const char * const max98373_limiter_attack_rate_text[] = { |
144 | "10us" , "20us" , "40us" , "80us" , |
145 | "160us" , "320us" , "640us" , "1.28ms" , |
146 | "2.56ms" , "5.12ms" , "10.24ms" , "20.48ms" , |
147 | "40.96ms" , "81.92ms" , "16.384ms" , "32.768ms" |
148 | }; |
149 | |
150 | static SOC_ENUM_SINGLE_DECL(max98373_limiter_attack_rate_enum, |
151 | MAX98373_R20E1_LIMITER_ATK_REL_RATES, 4, |
152 | max98373_limiter_attack_rate_text); |
153 | |
154 | static const char * const max98373_limiter_release_rate_text[] = { |
155 | "40us" , "80us" , "160us" , "320us" , |
156 | "640us" , "1.28ms" , "2.56ms" , "5.120ms" , |
157 | "10.24ms" , "20.48ms" , "40.96ms" , "81.92ms" , |
158 | "163.84ms" , "327.68ms" , "655.36ms" , "1310.72ms" |
159 | }; |
160 | |
161 | static SOC_ENUM_SINGLE_DECL(max98373_limiter_release_rate_enum, |
162 | MAX98373_R20E1_LIMITER_ATK_REL_RATES, 0, |
163 | max98373_limiter_release_rate_text); |
164 | |
165 | static const char * const max98373_ADC_samplerate_text[] = { |
166 | "333kHz" , "192kHz" , "64kHz" , "48kHz" |
167 | }; |
168 | |
169 | static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum, |
170 | MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0, |
171 | max98373_ADC_samplerate_text); |
172 | |
173 | static int max98373_feedback_get(struct snd_kcontrol *kcontrol, |
174 | struct snd_ctl_elem_value *ucontrol) |
175 | { |
176 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
177 | struct soc_mixer_control *mc = |
178 | (struct soc_mixer_control *)kcontrol->private_value; |
179 | struct max98373_priv *max98373 = snd_soc_component_get_drvdata(c: component); |
180 | int i; |
181 | |
182 | if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { |
183 | /* |
184 | * Register values will be cached before suspend. The cached value |
185 | * will be a valid value and userspace will happy with that. |
186 | */ |
187 | for (i = 0; i < max98373->cache_num; i++) { |
188 | if (mc->reg == max98373->cache[i].reg) { |
189 | ucontrol->value.integer.value[0] = max98373->cache[i].val; |
190 | return 0; |
191 | } |
192 | } |
193 | } |
194 | |
195 | return snd_soc_get_volsw(kcontrol, ucontrol); |
196 | } |
197 | |
198 | static const struct snd_kcontrol_new max98373_snd_controls[] = { |
199 | SOC_SINGLE("Digital Vol Sel Switch" , MAX98373_R203F_AMP_DSP_CFG, |
200 | MAX98373_AMP_VOL_SEL_SHIFT, 1, 0), |
201 | SOC_SINGLE("Volume Location Switch" , MAX98373_R203F_AMP_DSP_CFG, |
202 | MAX98373_AMP_VOL_SEL_SHIFT, 1, 0), |
203 | SOC_SINGLE("Ramp Up Switch" , MAX98373_R203F_AMP_DSP_CFG, |
204 | MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0), |
205 | SOC_SINGLE("Ramp Down Switch" , MAX98373_R203F_AMP_DSP_CFG, |
206 | MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0), |
207 | /* Speaker Amplifier Overcurrent Automatic Restart Enable */ |
208 | SOC_SINGLE("OVC Autorestart Switch" , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, |
209 | MAX98373_OVC_AUTORESTART_SHIFT, 1, 0), |
210 | /* Thermal Shutdown Automatic Restart Enable */ |
211 | SOC_SINGLE("THERM Autorestart Switch" , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, |
212 | MAX98373_THERM_AUTORESTART_SHIFT, 1, 0), |
213 | /* Clock Monitor Automatic Restart Enable */ |
214 | SOC_SINGLE("CMON Autorestart Switch" , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, |
215 | MAX98373_CMON_AUTORESTART_SHIFT, 1, 0), |
216 | SOC_SINGLE("CLK Monitor Switch" , MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, |
217 | MAX98373_CLOCK_MON_SHIFT, 1, 0), |
218 | SOC_SINGLE("Dither Switch" , MAX98373_R203F_AMP_DSP_CFG, |
219 | MAX98373_AMP_DSP_CFG_DITH_SHIFT, 1, 0), |
220 | SOC_SINGLE("DC Blocker Switch" , MAX98373_R203F_AMP_DSP_CFG, |
221 | MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0), |
222 | SOC_SINGLE_TLV("Digital Volume" , MAX98373_R203D_AMP_DIG_VOL_CTRL, |
223 | 0, 0x7F, 1, max98373_digital_tlv), |
224 | SOC_SINGLE_TLV("Speaker Volume" , MAX98373_R203E_AMP_PATH_GAIN, |
225 | MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv), |
226 | SOC_SINGLE_TLV("FS Max Volume" , MAX98373_R203E_AMP_PATH_GAIN, |
227 | MAX98373_FS_GAIN_MAX_SHIFT, 9, 0, max98373_spkgain_max_tlv), |
228 | SOC_ENUM("Output Voltage" , max98373_out_volt_enum), |
229 | /* Dynamic Headroom Tracking */ |
230 | SOC_SINGLE("DHT Switch" , MAX98373_R20D4_DHT_EN, |
231 | MAX98373_DHT_EN_SHIFT, 1, 0), |
232 | SOC_SINGLE_TLV("DHT Min Volume" , MAX98373_R20D1_DHT_CFG, |
233 | MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv), |
234 | SOC_SINGLE_TLV("DHT Rot Pnt Volume" , MAX98373_R20D1_DHT_CFG, |
235 | MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv), |
236 | SOC_SINGLE_TLV("DHT Attack Step Volume" , MAX98373_R20D2_DHT_ATTACK_CFG, |
237 | MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), |
238 | SOC_SINGLE_TLV("DHT Release Step Volume" , MAX98373_R20D3_DHT_RELEASE_CFG, |
239 | MAX98373_DHT_RELEASE_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), |
240 | SOC_ENUM("DHT Attack Rate" , max98373_dht_attack_rate_enum), |
241 | SOC_ENUM("DHT Release Rate" , max98373_dht_release_rate_enum), |
242 | /* ADC configuration */ |
243 | SOC_SINGLE("ADC PVDD CH Switch" , MAX98373_R2056_MEAS_ADC_PVDD_CH_EN, 0, 1, 0), |
244 | SOC_SINGLE("ADC PVDD FLT Switch" , MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG, |
245 | MAX98373_FLT_EN_SHIFT, 1, 0), |
246 | SOC_SINGLE("ADC TEMP FLT Switch" , MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG, |
247 | MAX98373_FLT_EN_SHIFT, 1, 0), |
248 | SOC_SINGLE_EXT("ADC PVDD" , MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0, |
249 | max98373_feedback_get, NULL), |
250 | SOC_SINGLE_EXT("ADC TEMP" , MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0, |
251 | max98373_feedback_get, NULL), |
252 | SOC_SINGLE("ADC PVDD FLT Coeff" , MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG, |
253 | 0, 0x3, 0), |
254 | SOC_SINGLE("ADC TEMP FLT Coeff" , MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG, |
255 | 0, 0x3, 0), |
256 | SOC_ENUM("ADC SampleRate" , max98373_adc_samplerate_enum), |
257 | /* Brownout Detection Engine */ |
258 | SOC_SINGLE("BDE Switch" , MAX98373_R20B5_BDE_EN, MAX98373_BDE_EN_SHIFT, 1, 0), |
259 | SOC_SINGLE("BDE LVL4 Mute Switch" , MAX98373_R20B2_BDE_L4_CFG_2, |
260 | MAX98373_LVL4_MUTE_EN_SHIFT, 1, 0), |
261 | SOC_SINGLE("BDE LVL4 Hold Switch" , MAX98373_R20B2_BDE_L4_CFG_2, |
262 | MAX98373_LVL4_HOLD_EN_SHIFT, 1, 0), |
263 | SOC_SINGLE("BDE LVL1 Thresh" , MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0), |
264 | SOC_SINGLE("BDE LVL2 Thresh" , MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0), |
265 | SOC_SINGLE("BDE LVL3 Thresh" , MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0), |
266 | SOC_SINGLE("BDE LVL4 Thresh" , MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0), |
267 | SOC_SINGLE_EXT("BDE Active Level" , MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0, |
268 | max98373_feedback_get, NULL), |
269 | SOC_SINGLE("BDE Clip Mode Switch" , MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0), |
270 | SOC_SINGLE("BDE Thresh Hysteresis" , MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0), |
271 | SOC_SINGLE("BDE Hold Time" , MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0), |
272 | SOC_SINGLE("BDE Attack Rate" , MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0), |
273 | SOC_SINGLE("BDE Release Rate" , MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0), |
274 | SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume" , MAX98373_R20A9_BDE_L1_CFG_2, |
275 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
276 | SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume" , MAX98373_R20AC_BDE_L2_CFG_2, |
277 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
278 | SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume" , MAX98373_R20AF_BDE_L3_CFG_2, |
279 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
280 | SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume" , MAX98373_R20B2_BDE_L4_CFG_2, |
281 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
282 | SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume" , MAX98373_R20AA_BDE_L1_CFG_3, |
283 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
284 | SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume" , MAX98373_R20AD_BDE_L2_CFG_3, |
285 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
286 | SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume" , MAX98373_R20B0_BDE_L3_CFG_3, |
287 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
288 | SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume" , MAX98373_R20B3_BDE_L4_CFG_3, |
289 | 0, 0x3C, 1, max98373_bde_gain_tlv), |
290 | SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume" , MAX98373_R20A8_BDE_L1_CFG_1, |
291 | 0, 0xF, 1, max98373_limiter_thresh_tlv), |
292 | SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume" , MAX98373_R20AB_BDE_L2_CFG_1, |
293 | 0, 0xF, 1, max98373_limiter_thresh_tlv), |
294 | SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume" , MAX98373_R20AE_BDE_L3_CFG_1, |
295 | 0, 0xF, 1, max98373_limiter_thresh_tlv), |
296 | SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume" , MAX98373_R20B1_BDE_L4_CFG_1, |
297 | 0, 0xF, 1, max98373_limiter_thresh_tlv), |
298 | /* Limiter */ |
299 | SOC_SINGLE("Limiter Switch" , MAX98373_R20E2_LIMITER_EN, |
300 | MAX98373_LIMITER_EN_SHIFT, 1, 0), |
301 | SOC_SINGLE("Limiter Src Switch" , MAX98373_R20E0_LIMITER_THRESH_CFG, |
302 | MAX98373_LIMITER_THRESH_SRC_SHIFT, 1, 0), |
303 | SOC_SINGLE_TLV("Limiter Thresh Volume" , MAX98373_R20E0_LIMITER_THRESH_CFG, |
304 | MAX98373_LIMITER_THRESH_SHIFT, 15, 0, max98373_limiter_thresh_tlv), |
305 | SOC_ENUM("Limiter Attack Rate" , max98373_limiter_attack_rate_enum), |
306 | SOC_ENUM("Limiter Release Rate" , max98373_limiter_release_rate_enum), |
307 | }; |
308 | |
309 | static const struct snd_soc_dapm_route max98373_audio_map[] = { |
310 | /* Plabyack */ |
311 | {"DAI Sel Mux" , "Left" , "Amp Enable" }, |
312 | {"DAI Sel Mux" , "Right" , "Amp Enable" }, |
313 | {"DAI Sel Mux" , "LeftRight" , "Amp Enable" }, |
314 | {"BE_OUT" , NULL, "DAI Sel Mux" }, |
315 | /* Capture */ |
316 | { "VI Sense" , "Switch" , "VMON" }, |
317 | { "VI Sense" , "Switch" , "IMON" }, |
318 | { "SpkFB Sense" , "Switch" , "FBMON" }, |
319 | { "Voltage Sense" , NULL, "VI Sense" }, |
320 | { "Current Sense" , NULL, "VI Sense" }, |
321 | { "Speaker FB Sense" , NULL, "SpkFB Sense" }, |
322 | }; |
323 | |
324 | void max98373_reset(struct max98373_priv *max98373, struct device *dev) |
325 | { |
326 | int ret, reg, count; |
327 | |
328 | /* Software Reset */ |
329 | ret = regmap_update_bits(map: max98373->regmap, |
330 | MAX98373_R2000_SW_RESET, |
331 | MAX98373_SOFT_RESET, |
332 | MAX98373_SOFT_RESET); |
333 | if (ret) |
334 | dev_err(dev, "Reset command failed. (ret:%d)\n" , ret); |
335 | |
336 | count = 0; |
337 | while (count < 3) { |
338 | usleep_range(min: 10000, max: 11000); |
339 | /* Software Reset Verification */ |
340 | ret = regmap_read(map: max98373->regmap, |
341 | MAX98373_R21FF_REV_ID, val: ®); |
342 | if (!ret) { |
343 | dev_info(dev, "Reset completed (retry:%d)\n" , count); |
344 | return; |
345 | } |
346 | count++; |
347 | } |
348 | dev_err(dev, "Reset failed. (ret:%d)\n" , ret); |
349 | } |
350 | EXPORT_SYMBOL_GPL(max98373_reset); |
351 | |
352 | static int max98373_probe(struct snd_soc_component *component) |
353 | { |
354 | struct max98373_priv *max98373 = snd_soc_component_get_drvdata(c: component); |
355 | |
356 | /* Software Reset */ |
357 | max98373_reset(max98373, component->dev); |
358 | |
359 | /* IV default slot configuration */ |
360 | regmap_write(map: max98373->regmap, |
361 | MAX98373_R2020_PCM_TX_HIZ_EN_1, |
362 | val: 0xFF); |
363 | regmap_write(map: max98373->regmap, |
364 | MAX98373_R2021_PCM_TX_HIZ_EN_2, |
365 | val: 0xFF); |
366 | /* L/R mix configuration */ |
367 | regmap_write(map: max98373->regmap, |
368 | MAX98373_R2029_PCM_TO_SPK_MONO_MIX_1, |
369 | val: 0x80); |
370 | regmap_write(map: max98373->regmap, |
371 | MAX98373_R202A_PCM_TO_SPK_MONO_MIX_2, |
372 | val: 0x1); |
373 | /* Enable DC blocker */ |
374 | regmap_write(map: max98373->regmap, |
375 | MAX98373_R203F_AMP_DSP_CFG, |
376 | val: 0x3); |
377 | /* Enable IMON VMON DC blocker */ |
378 | regmap_write(map: max98373->regmap, |
379 | MAX98373_R2046_IV_SENSE_ADC_DSP_CFG, |
380 | val: 0x7); |
381 | /* voltage, current slot configuration */ |
382 | regmap_write(map: max98373->regmap, |
383 | MAX98373_R2022_PCM_TX_SRC_1, |
384 | val: (max98373->i_slot << MAX98373_PCM_TX_CH_SRC_A_I_SHIFT | |
385 | max98373->v_slot) & 0xFF); |
386 | if (max98373->v_slot < 8) |
387 | regmap_update_bits(map: max98373->regmap, |
388 | MAX98373_R2020_PCM_TX_HIZ_EN_1, |
389 | mask: 1 << max98373->v_slot, val: 0); |
390 | else |
391 | regmap_update_bits(map: max98373->regmap, |
392 | MAX98373_R2021_PCM_TX_HIZ_EN_2, |
393 | mask: 1 << (max98373->v_slot - 8), val: 0); |
394 | |
395 | if (max98373->i_slot < 8) |
396 | regmap_update_bits(map: max98373->regmap, |
397 | MAX98373_R2020_PCM_TX_HIZ_EN_1, |
398 | mask: 1 << max98373->i_slot, val: 0); |
399 | else |
400 | regmap_update_bits(map: max98373->regmap, |
401 | MAX98373_R2021_PCM_TX_HIZ_EN_2, |
402 | mask: 1 << (max98373->i_slot - 8), val: 0); |
403 | |
404 | /* enable auto restart function by default */ |
405 | regmap_write(map: max98373->regmap, |
406 | MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, |
407 | val: 0xF); |
408 | |
409 | /* speaker feedback slot configuration */ |
410 | regmap_write(map: max98373->regmap, |
411 | MAX98373_R2023_PCM_TX_SRC_2, |
412 | val: max98373->spkfb_slot & 0xFF); |
413 | |
414 | /* Set interleave mode */ |
415 | if (max98373->interleave_mode) |
416 | regmap_update_bits(map: max98373->regmap, |
417 | MAX98373_R2024_PCM_DATA_FMT_CFG, |
418 | MAX98373_PCM_TX_CH_INTERLEAVE_MASK, |
419 | MAX98373_PCM_TX_CH_INTERLEAVE_MASK); |
420 | |
421 | /* Speaker enable */ |
422 | regmap_update_bits(map: max98373->regmap, |
423 | MAX98373_R2043_AMP_EN, |
424 | MAX98373_SPK_EN_MASK, val: 1); |
425 | |
426 | return 0; |
427 | } |
428 | |
429 | const struct snd_soc_component_driver soc_codec_dev_max98373 = { |
430 | .probe = max98373_probe, |
431 | .controls = max98373_snd_controls, |
432 | .num_controls = ARRAY_SIZE(max98373_snd_controls), |
433 | .dapm_widgets = max98373_dapm_widgets, |
434 | .num_dapm_widgets = ARRAY_SIZE(max98373_dapm_widgets), |
435 | .dapm_routes = max98373_audio_map, |
436 | .num_dapm_routes = ARRAY_SIZE(max98373_audio_map), |
437 | .use_pmdown_time = 1, |
438 | .endianness = 1, |
439 | }; |
440 | EXPORT_SYMBOL_GPL(soc_codec_dev_max98373); |
441 | |
442 | static int max98373_sdw_probe(struct snd_soc_component *component) |
443 | { |
444 | int ret; |
445 | |
446 | ret = pm_runtime_resume(dev: component->dev); |
447 | if (ret < 0 && ret != -EACCES) |
448 | return ret; |
449 | |
450 | return 0; |
451 | } |
452 | |
453 | const struct snd_soc_component_driver soc_codec_dev_max98373_sdw = { |
454 | .probe = max98373_sdw_probe, |
455 | .controls = max98373_snd_controls, |
456 | .num_controls = ARRAY_SIZE(max98373_snd_controls), |
457 | .dapm_widgets = max98373_dapm_widgets, |
458 | .num_dapm_widgets = ARRAY_SIZE(max98373_dapm_widgets), |
459 | .dapm_routes = max98373_audio_map, |
460 | .num_dapm_routes = ARRAY_SIZE(max98373_audio_map), |
461 | .use_pmdown_time = 1, |
462 | .endianness = 1, |
463 | }; |
464 | EXPORT_SYMBOL_GPL(soc_codec_dev_max98373_sdw); |
465 | |
466 | void max98373_slot_config(struct device *dev, |
467 | struct max98373_priv *max98373) |
468 | { |
469 | int value; |
470 | |
471 | if (!device_property_read_u32(dev, propname: "maxim,vmon-slot-no" , val: &value)) |
472 | max98373->v_slot = value & 0xF; |
473 | else |
474 | max98373->v_slot = 0; |
475 | |
476 | if (!device_property_read_u32(dev, propname: "maxim,imon-slot-no" , val: &value)) |
477 | max98373->i_slot = value & 0xF; |
478 | else |
479 | max98373->i_slot = 1; |
480 | |
481 | /* This will assert RESET */ |
482 | max98373->reset = devm_gpiod_get_optional(dev, |
483 | con_id: "maxim,reset" , |
484 | flags: GPIOD_OUT_HIGH); |
485 | if (IS_ERR(ptr: max98373->reset)) { |
486 | dev_err(dev, "error %ld looking up RESET GPIO line\n" , |
487 | PTR_ERR(max98373->reset)); |
488 | return; |
489 | } |
490 | |
491 | /* Cycle reset */ |
492 | if (max98373->reset) { |
493 | gpiod_set_consumer_name(desc: max98373->reset ,name: "MAX98373_RESET" ); |
494 | gpiod_direction_output(desc: max98373->reset, value: 1); |
495 | msleep(msecs: 50); |
496 | gpiod_direction_output(desc: max98373->reset, value: 0); |
497 | msleep(msecs: 20); |
498 | } |
499 | |
500 | if (!device_property_read_u32(dev, propname: "maxim,spkfb-slot-no" , val: &value)) |
501 | max98373->spkfb_slot = value & 0xF; |
502 | else |
503 | max98373->spkfb_slot = 2; |
504 | } |
505 | EXPORT_SYMBOL_GPL(max98373_slot_config); |
506 | |
507 | MODULE_DESCRIPTION("ALSA SoC MAX98373 driver" ); |
508 | MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>" ); |
509 | MODULE_LICENSE("GPL" ); |
510 | |