1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2021, 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/regmap.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/cdev.h> |
11 | #include <sound/pcm.h> |
12 | #include <sound/pcm_params.h> |
13 | #include <sound/soc.h> |
14 | #include <linux/gpio/consumer.h> |
15 | #include <linux/of.h> |
16 | #include <sound/tlv.h> |
17 | #include "max98520.h" |
18 | |
19 | static struct reg_default max98520_reg[] = { |
20 | {MAX98520_R2000_SW_RESET, 0x00}, |
21 | {MAX98520_R2001_STATUS_1, 0x00}, |
22 | {MAX98520_R2002_STATUS_2, 0x00}, |
23 | {MAX98520_R2020_THERM_WARN_THRESH, 0x46}, |
24 | {MAX98520_R2021_THERM_SHDN_THRESH, 0x64}, |
25 | {MAX98520_R2022_THERM_HYSTERESIS, 0x02}, |
26 | {MAX98520_R2023_THERM_FOLDBACK_SET, 0x31}, |
27 | {MAX98520_R2027_THERM_FOLDBACK_EN, 0x01}, |
28 | {MAX98520_R2030_CLK_MON_CTRL, 0x00}, |
29 | {MAX98520_R2037_ERR_MON_CTRL, 0x01}, |
30 | {MAX98520_R2040_PCM_MODE_CFG, 0xC0}, |
31 | {MAX98520_R2041_PCM_CLK_SETUP, 0x04}, |
32 | {MAX98520_R2042_PCM_SR_SETUP, 0x08}, |
33 | {MAX98520_R2043_PCM_RX_SRC1, 0x00}, |
34 | {MAX98520_R2044_PCM_RX_SRC2, 0x00}, |
35 | {MAX98520_R204F_PCM_RX_EN, 0x00}, |
36 | {MAX98520_R2090_AMP_VOL_CTRL, 0x00}, |
37 | {MAX98520_R2091_AMP_PATH_GAIN, 0x03}, |
38 | {MAX98520_R2092_AMP_DSP_CFG, 0x02}, |
39 | {MAX98520_R2094_SSM_CFG, 0x01}, |
40 | {MAX98520_R2095_AMP_CFG, 0xF0}, |
41 | {MAX98520_R209F_AMP_EN, 0x00}, |
42 | {MAX98520_R20B0_ADC_SR, 0x00}, |
43 | {MAX98520_R20B1_ADC_RESOLUTION, 0x00}, |
44 | {MAX98520_R20B2_ADC_PVDD0_CFG, 0x02}, |
45 | {MAX98520_R20B3_ADC_THERMAL_CFG, 0x02}, |
46 | {MAX98520_R20B4_ADC_READBACK_CTRL, 0x00}, |
47 | {MAX98520_R20B5_ADC_READBACK_UPDATE, 0x00}, |
48 | {MAX98520_R20B6_ADC_PVDD_READBACK_MSB, 0x00}, |
49 | {MAX98520_R20B7_ADC_PVDD_READBACK_LSB, 0x00}, |
50 | {MAX98520_R20B8_ADC_TEMP_READBACK_MSB, 0x00}, |
51 | {MAX98520_R20B9_ADC_TEMP_READBACK_LSB, 0x00}, |
52 | {MAX98520_R20BA_ADC_LOW_PVDD_READBACK_MSB, 0xFF}, |
53 | {MAX98520_R20BB_ADC_LOW_READBACK_LSB, 0x01}, |
54 | {MAX98520_R20BC_ADC_HIGH_TEMP_READBACK_MSB, 0x00}, |
55 | {MAX98520_R20BD_ADC_HIGH_TEMP_READBACK_LSB, 0x00}, |
56 | {MAX98520_R20CF_MEAS_ADC_CFG, 0x00}, |
57 | {MAX98520_R20D0_DHT_CFG1, 0x00}, |
58 | {MAX98520_R20D1_LIMITER_CFG1, 0x08}, |
59 | {MAX98520_R20D2_LIMITER_CFG2, 0x00}, |
60 | {MAX98520_R20D3_DHT_CFG2, 0x14}, |
61 | {MAX98520_R20D4_DHT_CFG3, 0x02}, |
62 | {MAX98520_R20D5_DHT_CFG4, 0x04}, |
63 | {MAX98520_R20D6_DHT_HYSTERESIS_CFG, 0x07}, |
64 | {MAX98520_R20D8_DHT_EN, 0x00}, |
65 | {MAX98520_R210E_AUTO_RESTART_BEHAVIOR, 0x00}, |
66 | {MAX98520_R210F_GLOBAL_EN, 0x00}, |
67 | {MAX98520_R21FF_REVISION_ID, 0x00}, |
68 | }; |
69 | |
70 | static int max98520_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) |
71 | { |
72 | struct snd_soc_component *component = codec_dai->component; |
73 | struct max98520_priv *max98520 = |
74 | snd_soc_component_get_drvdata(c: component); |
75 | unsigned int format = 0; |
76 | unsigned int invert = 0; |
77 | |
78 | dev_dbg(component->dev, "%s: fmt 0x%08X\n" , __func__, fmt); |
79 | |
80 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
81 | case SND_SOC_DAIFMT_NB_NF: |
82 | break; |
83 | case SND_SOC_DAIFMT_IB_NF: |
84 | invert = MAX98520_PCM_MODE_CFG_PCM_BCLKEDGE; |
85 | break; |
86 | default: |
87 | dev_err(component->dev, "DAI invert mode unsupported\n" ); |
88 | return -EINVAL; |
89 | } |
90 | |
91 | regmap_update_bits(map: max98520->regmap, |
92 | MAX98520_R2041_PCM_CLK_SETUP, |
93 | MAX98520_PCM_MODE_CFG_PCM_BCLKEDGE, |
94 | val: invert); |
95 | |
96 | /* interface format */ |
97 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
98 | case SND_SOC_DAIFMT_I2S: |
99 | format = MAX98520_PCM_FORMAT_I2S; |
100 | break; |
101 | case SND_SOC_DAIFMT_LEFT_J: |
102 | format = MAX98520_PCM_FORMAT_LJ; |
103 | break; |
104 | case SND_SOC_DAIFMT_DSP_A: |
105 | format = MAX98520_PCM_FORMAT_TDM_MODE1; |
106 | break; |
107 | case SND_SOC_DAIFMT_DSP_B: |
108 | format = MAX98520_PCM_FORMAT_TDM_MODE0; |
109 | break; |
110 | default: |
111 | return -EINVAL; |
112 | } |
113 | |
114 | regmap_update_bits(map: max98520->regmap, |
115 | MAX98520_R2040_PCM_MODE_CFG, |
116 | MAX98520_PCM_MODE_CFG_FORMAT_MASK, |
117 | val: format << MAX98520_PCM_MODE_CFG_FORMAT_SHIFT); |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | /* BCLKs per LRCLK */ |
123 | static const int bclk_sel_table[] = { |
124 | 32, 48, 64, 96, 128, 192, 256, 384, 512, 320, |
125 | }; |
126 | |
127 | static int max98520_get_bclk_sel(int bclk) |
128 | { |
129 | int i; |
130 | /* match BCLKs per LRCLK */ |
131 | for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { |
132 | if (bclk_sel_table[i] == bclk) |
133 | return i + 2; |
134 | } |
135 | return 0; |
136 | } |
137 | |
138 | static int max98520_set_clock(struct snd_soc_component *component, |
139 | struct snd_pcm_hw_params *params) |
140 | { |
141 | struct max98520_priv *max98520 = |
142 | snd_soc_component_get_drvdata(c: component); |
143 | /* BCLK/LRCLK ratio calculation */ |
144 | int blr_clk_ratio = params_channels(p: params) * max98520->ch_size; |
145 | int value; |
146 | |
147 | if (!max98520->tdm_mode) { |
148 | /* BCLK configuration */ |
149 | value = max98520_get_bclk_sel(bclk: blr_clk_ratio); |
150 | if (!value) { |
151 | dev_err(component->dev, "format unsupported %d\n" , |
152 | params_format(params)); |
153 | return -EINVAL; |
154 | } |
155 | |
156 | regmap_update_bits(map: max98520->regmap, |
157 | MAX98520_R2041_PCM_CLK_SETUP, |
158 | MAX98520_PCM_CLK_SETUP_BSEL_MASK, |
159 | val: value); |
160 | } |
161 | dev_dbg(component->dev, "%s tdm_mode:%d out\n" , __func__, max98520->tdm_mode); |
162 | return 0; |
163 | } |
164 | |
165 | static int max98520_dai_hw_params(struct snd_pcm_substream *substream, |
166 | struct snd_pcm_hw_params *params, |
167 | struct snd_soc_dai *dai) |
168 | { |
169 | struct snd_soc_component *component = dai->component; |
170 | struct max98520_priv *max98520 = |
171 | snd_soc_component_get_drvdata(c: component); |
172 | unsigned int sampling_rate = 0; |
173 | unsigned int chan_sz = 0; |
174 | |
175 | /* pcm mode configuration */ |
176 | switch (snd_pcm_format_width(format: params_format(p: params))) { |
177 | case 16: |
178 | chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_16; |
179 | break; |
180 | case 24: |
181 | chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_24; |
182 | break; |
183 | case 32: |
184 | chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_32; |
185 | break; |
186 | default: |
187 | dev_err(component->dev, "format unsupported %d\n" , |
188 | params_format(params)); |
189 | goto err; |
190 | } |
191 | |
192 | max98520->ch_size = snd_pcm_format_width(format: params_format(p: params)); |
193 | |
194 | regmap_update_bits(map: max98520->regmap, |
195 | MAX98520_R2040_PCM_MODE_CFG, |
196 | MAX98520_PCM_MODE_CFG_CHANSZ_MASK, val: chan_sz); |
197 | |
198 | dev_dbg(component->dev, "format supported %d" , |
199 | params_format(params)); |
200 | |
201 | /* sampling rate configuration */ |
202 | switch (params_rate(p: params)) { |
203 | case 8000: |
204 | sampling_rate = MAX98520_PCM_SR_8000; |
205 | break; |
206 | case 11025: |
207 | sampling_rate = MAX98520_PCM_SR_11025; |
208 | break; |
209 | case 12000: |
210 | sampling_rate = MAX98520_PCM_SR_12000; |
211 | break; |
212 | case 16000: |
213 | sampling_rate = MAX98520_PCM_SR_16000; |
214 | break; |
215 | case 22050: |
216 | sampling_rate = MAX98520_PCM_SR_22050; |
217 | break; |
218 | case 24000: |
219 | sampling_rate = MAX98520_PCM_SR_24000; |
220 | break; |
221 | case 32000: |
222 | sampling_rate = MAX98520_PCM_SR_32000; |
223 | break; |
224 | case 44100: |
225 | sampling_rate = MAX98520_PCM_SR_44100; |
226 | break; |
227 | case 48000: |
228 | sampling_rate = MAX98520_PCM_SR_48000; |
229 | break; |
230 | case 88200: |
231 | sampling_rate = MAX98520_PCM_SR_88200; |
232 | break; |
233 | case 96000: |
234 | sampling_rate = MAX98520_PCM_SR_96000; |
235 | break; |
236 | case 176400: |
237 | sampling_rate = MAX98520_PCM_SR_176400; |
238 | break; |
239 | case 192000: |
240 | sampling_rate = MAX98520_PCM_SR_192000; |
241 | break; |
242 | default: |
243 | dev_err(component->dev, "rate %d not supported\n" , |
244 | params_rate(params)); |
245 | goto err; |
246 | } |
247 | |
248 | dev_dbg(component->dev, " %s ch_size: %d, sampling rate : %d out\n" , __func__, |
249 | snd_pcm_format_width(params_format(params)), params_rate(params)); |
250 | /* set DAI_SR to correct LRCLK frequency */ |
251 | regmap_update_bits(map: max98520->regmap, |
252 | MAX98520_R2042_PCM_SR_SETUP, |
253 | MAX98520_PCM_SR_MASK, |
254 | val: sampling_rate); |
255 | |
256 | return max98520_set_clock(component, params); |
257 | err: |
258 | dev_dbg(component->dev, "%s out error" , __func__); |
259 | return -EINVAL; |
260 | } |
261 | |
262 | static int max98520_dai_tdm_slot(struct snd_soc_dai *dai, |
263 | unsigned int tx_mask, unsigned int rx_mask, |
264 | int slots, int slot_width) |
265 | { |
266 | struct snd_soc_component *component = dai->component; |
267 | struct max98520_priv *max98520 = |
268 | snd_soc_component_get_drvdata(c: component); |
269 | int bsel; |
270 | unsigned int chan_sz = 0; |
271 | |
272 | if (!tx_mask && !rx_mask && !slots && !slot_width) |
273 | max98520->tdm_mode = false; |
274 | else |
275 | max98520->tdm_mode = true; |
276 | |
277 | /* BCLK configuration */ |
278 | bsel = max98520_get_bclk_sel(bclk: slots * slot_width); |
279 | if (bsel == 0) { |
280 | dev_err(component->dev, "BCLK %d not supported\n" , |
281 | slots * slot_width); |
282 | return -EINVAL; |
283 | } |
284 | |
285 | regmap_update_bits(map: max98520->regmap, |
286 | MAX98520_R2041_PCM_CLK_SETUP, |
287 | MAX98520_PCM_CLK_SETUP_BSEL_MASK, |
288 | val: bsel); |
289 | |
290 | /* Channel size configuration */ |
291 | switch (slot_width) { |
292 | case 16: |
293 | chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_16; |
294 | break; |
295 | case 24: |
296 | chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_24; |
297 | break; |
298 | case 32: |
299 | chan_sz = MAX98520_PCM_MODE_CFG_CHANSZ_32; |
300 | break; |
301 | default: |
302 | dev_err(component->dev, "format unsupported %d\n" , |
303 | slot_width); |
304 | return -EINVAL; |
305 | } |
306 | |
307 | regmap_update_bits(map: max98520->regmap, |
308 | MAX98520_R2040_PCM_MODE_CFG, |
309 | MAX98520_PCM_MODE_CFG_CHANSZ_MASK, val: chan_sz); |
310 | |
311 | /* Rx slot configuration */ |
312 | regmap_update_bits(map: max98520->regmap, |
313 | MAX98520_R2044_PCM_RX_SRC2, |
314 | MAX98520_PCM_DMIX_CH0_SRC_MASK, |
315 | val: rx_mask); |
316 | regmap_update_bits(map: max98520->regmap, |
317 | MAX98520_R2044_PCM_RX_SRC2, |
318 | MAX98520_PCM_DMIX_CH1_SRC_MASK, |
319 | val: rx_mask << MAX98520_PCM_DMIX_CH1_SHIFT); |
320 | |
321 | return 0; |
322 | } |
323 | |
324 | #define MAX98520_RATES SNDRV_PCM_RATE_8000_192000 |
325 | |
326 | #define MAX98520_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
327 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
328 | |
329 | static const struct snd_soc_dai_ops max98520_dai_ops = { |
330 | .set_fmt = max98520_dai_set_fmt, |
331 | .hw_params = max98520_dai_hw_params, |
332 | .set_tdm_slot = max98520_dai_tdm_slot, |
333 | }; |
334 | |
335 | static int max98520_dac_event(struct snd_soc_dapm_widget *w, |
336 | struct snd_kcontrol *kcontrol, int event) |
337 | { |
338 | struct snd_soc_component *component = |
339 | snd_soc_dapm_to_component(dapm: w->dapm); |
340 | struct max98520_priv *max98520 = |
341 | snd_soc_component_get_drvdata(c: component); |
342 | |
343 | switch (event) { |
344 | case SND_SOC_DAPM_POST_PMU: |
345 | dev_dbg(component->dev, " AMP ON\n" ); |
346 | |
347 | regmap_write(map: max98520->regmap, MAX98520_R209F_AMP_EN, val: 1); |
348 | regmap_write(map: max98520->regmap, MAX98520_R210F_GLOBAL_EN, val: 1); |
349 | usleep_range(min: 30000, max: 31000); |
350 | break; |
351 | case SND_SOC_DAPM_POST_PMD: |
352 | dev_dbg(component->dev, " AMP OFF\n" ); |
353 | |
354 | regmap_write(map: max98520->regmap, MAX98520_R210F_GLOBAL_EN, val: 0); |
355 | regmap_write(map: max98520->regmap, MAX98520_R209F_AMP_EN, val: 0); |
356 | usleep_range(min: 30000, max: 31000); |
357 | break; |
358 | default: |
359 | return 0; |
360 | } |
361 | return 0; |
362 | } |
363 | |
364 | static const char * const max98520_switch_text[] = { |
365 | "Left" , "Right" , "LeftRight" }; |
366 | |
367 | static const struct soc_enum dai_sel_enum = |
368 | SOC_ENUM_SINGLE(MAX98520_R2043_PCM_RX_SRC1, |
369 | 0, 3, max98520_switch_text); |
370 | |
371 | static const struct snd_kcontrol_new max98520_dai_controls = |
372 | SOC_DAPM_ENUM("DAI Sel" , dai_sel_enum); |
373 | |
374 | static const struct snd_kcontrol_new max98520_left_input_mixer_controls[] = { |
375 | SOC_DAPM_SINGLE("PCM_INPUT_CH0" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x0, 0), |
376 | SOC_DAPM_SINGLE("PCM_INPUT_CH1" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x1, 0), |
377 | SOC_DAPM_SINGLE("PCM_INPUT_CH2" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x2, 0), |
378 | SOC_DAPM_SINGLE("PCM_INPUT_CH3" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x3, 0), |
379 | SOC_DAPM_SINGLE("PCM_INPUT_CH4" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x4, 0), |
380 | SOC_DAPM_SINGLE("PCM_INPUT_CH5" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x5, 0), |
381 | SOC_DAPM_SINGLE("PCM_INPUT_CH6" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x6, 0), |
382 | SOC_DAPM_SINGLE("PCM_INPUT_CH7" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x7, 0), |
383 | SOC_DAPM_SINGLE("PCM_INPUT_CH8" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x8, 0), |
384 | SOC_DAPM_SINGLE("PCM_INPUT_CH9" , MAX98520_R2044_PCM_RX_SRC2, 0, 0x9, 0), |
385 | SOC_DAPM_SINGLE("PCM_INPUT_CH10" , MAX98520_R2044_PCM_RX_SRC2, 0, 0xa, 0), |
386 | SOC_DAPM_SINGLE("PCM_INPUT_CH11" , MAX98520_R2044_PCM_RX_SRC2, 0, 0xb, 0), |
387 | SOC_DAPM_SINGLE("PCM_INPUT_CH12" , MAX98520_R2044_PCM_RX_SRC2, 0, 0xc, 0), |
388 | SOC_DAPM_SINGLE("PCM_INPUT_CH13" , MAX98520_R2044_PCM_RX_SRC2, 0, 0xd, 0), |
389 | SOC_DAPM_SINGLE("PCM_INPUT_CH14" , MAX98520_R2044_PCM_RX_SRC2, 0, 0xe, 0), |
390 | SOC_DAPM_SINGLE("PCM_INPUT_CH15" , MAX98520_R2044_PCM_RX_SRC2, 0, 0xf, 0), |
391 | }; |
392 | |
393 | static const struct snd_kcontrol_new max98520_right_input_mixer_controls[] = { |
394 | SOC_DAPM_SINGLE("PCM_INPUT_CH0" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x0, 0), |
395 | SOC_DAPM_SINGLE("PCM_INPUT_CH1" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x1, 0), |
396 | SOC_DAPM_SINGLE("PCM_INPUT_CH2" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x2, 0), |
397 | SOC_DAPM_SINGLE("PCM_INPUT_CH3" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x3, 0), |
398 | SOC_DAPM_SINGLE("PCM_INPUT_CH4" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x4, 0), |
399 | SOC_DAPM_SINGLE("PCM_INPUT_CH5" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x5, 0), |
400 | SOC_DAPM_SINGLE("PCM_INPUT_CH6" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x6, 0), |
401 | SOC_DAPM_SINGLE("PCM_INPUT_CH7" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x7, 0), |
402 | SOC_DAPM_SINGLE("PCM_INPUT_CH8" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x8, 0), |
403 | SOC_DAPM_SINGLE("PCM_INPUT_CH9" , MAX98520_R2044_PCM_RX_SRC2, 4, 0x9, 0), |
404 | SOC_DAPM_SINGLE("PCM_INPUT_CH10" , MAX98520_R2044_PCM_RX_SRC2, 4, 0xa, 0), |
405 | SOC_DAPM_SINGLE("PCM_INPUT_CH11" , MAX98520_R2044_PCM_RX_SRC2, 4, 0xb, 0), |
406 | SOC_DAPM_SINGLE("PCM_INPUT_CH12" , MAX98520_R2044_PCM_RX_SRC2, 4, 0xc, 0), |
407 | SOC_DAPM_SINGLE("PCM_INPUT_CH13" , MAX98520_R2044_PCM_RX_SRC2, 4, 0xd, 0), |
408 | SOC_DAPM_SINGLE("PCM_INPUT_CH14" , MAX98520_R2044_PCM_RX_SRC2, 4, 0xe, 0), |
409 | SOC_DAPM_SINGLE("PCM_INPUT_CH15" , MAX98520_R2044_PCM_RX_SRC2, 4, 0xf, 0), |
410 | }; |
411 | |
412 | static const struct snd_soc_dapm_widget max98520_dapm_widgets[] = { |
413 | SND_SOC_DAPM_DAC_E("Amp Enable" , "HiFi Playback" , |
414 | SND_SOC_NOPM, 0, 0, max98520_dac_event, |
415 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
416 | SND_SOC_DAPM_MUX("DAI Sel Mux" , SND_SOC_NOPM, 0, 0, &max98520_dai_controls), |
417 | SND_SOC_DAPM_OUTPUT("BE_OUT" ), |
418 | /* Left Input Selection */ |
419 | SND_SOC_DAPM_MIXER("Left Input Selection" , SND_SOC_NOPM, 0, 0, |
420 | &max98520_left_input_mixer_controls[0], |
421 | ARRAY_SIZE(max98520_left_input_mixer_controls)), |
422 | /* Right Input Selection */ |
423 | SND_SOC_DAPM_MIXER("Right Input Selection" , SND_SOC_NOPM, 0, 0, |
424 | &max98520_right_input_mixer_controls[0], |
425 | ARRAY_SIZE(max98520_right_input_mixer_controls)), |
426 | }; |
427 | |
428 | static const DECLARE_TLV_DB_SCALE(max98520_digital_tlv, -6300, 50, 1); |
429 | static const DECLARE_TLV_DB_SCALE(max98520_spk_tlv, -600, 300, 0); |
430 | |
431 | static const DECLARE_TLV_DB_RANGE(max98520_dht_lim_thresh_tlv, |
432 | 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), |
433 | ); |
434 | |
435 | static const DECLARE_TLV_DB_RANGE(max98520_dht_hysteresis_tlv, |
436 | 0, 3, TLV_DB_SCALE_ITEM(100, 100, 0), |
437 | 4, 7, TLV_DB_SCALE_ITEM(600, 200, 0), |
438 | ); |
439 | |
440 | static const DECLARE_TLV_DB_RANGE(max98520_dht_rotation_point_tlv, |
441 | 0, 1, TLV_DB_SCALE_ITEM(-1500, 300, 0), |
442 | 2, 4, TLV_DB_SCALE_ITEM(-1000, 200, 0), |
443 | 5, 10, TLV_DB_SCALE_ITEM(-500, 100, 0), |
444 | ); |
445 | |
446 | static const DECLARE_TLV_DB_RANGE(max98520_dht_supply_hr_tlv, |
447 | 0, 16, TLV_DB_SCALE_ITEM(-2000, 250, 0), |
448 | ); |
449 | |
450 | static const DECLARE_TLV_DB_RANGE(max98520_dht_max_atten_tlv, |
451 | 1, 20, TLV_DB_SCALE_ITEM(-2000, 100, 0), |
452 | ); |
453 | |
454 | static const char * const max98520_dht_attack_rate_text[] = { |
455 | "20us" , "40us" , "80us" , "160us" , "320us" , "640us" , |
456 | "1.28ms" , "2.56ms" , "5.12ms" , "10.24ms" , "20.48ms" , "40.96ms" , |
457 | "81.92ms" , "163.84ms" |
458 | }; |
459 | |
460 | static SOC_ENUM_SINGLE_DECL(max98520_dht_attack_rate_enum, |
461 | MAX98520_R20D4_DHT_CFG3, 0, |
462 | max98520_dht_attack_rate_text); |
463 | |
464 | static const char * const max98520_dht_release_rate_text[] = { |
465 | "2ms" , "4ms" , "8ms" , "16ms" , "32ms" , "64ms" , "128ms" , "256ms" , "512ms" , |
466 | "1.024s" , "2.048s" , "4.096s" , "8.192s" , "16.384s" |
467 | }; |
468 | |
469 | static SOC_ENUM_SINGLE_DECL(max98520_dht_release_rate_enum, |
470 | MAX98520_R20D5_DHT_CFG4, 0, |
471 | max98520_dht_release_rate_text); |
472 | |
473 | static bool max98520_readable_register(struct device *dev, unsigned int reg) |
474 | { |
475 | switch (reg) { |
476 | case MAX98520_R2000_SW_RESET: |
477 | case MAX98520_R2027_THERM_FOLDBACK_EN: |
478 | case MAX98520_R2030_CLK_MON_CTRL: |
479 | case MAX98520_R2037_ERR_MON_CTRL: |
480 | case MAX98520_R204F_PCM_RX_EN: |
481 | case MAX98520_R209F_AMP_EN: |
482 | case MAX98520_R20CF_MEAS_ADC_CFG: |
483 | case MAX98520_R20D8_DHT_EN: |
484 | case MAX98520_R21FF_REVISION_ID: |
485 | case MAX98520_R2001_STATUS_1... MAX98520_R2002_STATUS_2: |
486 | case MAX98520_R2020_THERM_WARN_THRESH... MAX98520_R2023_THERM_FOLDBACK_SET: |
487 | case MAX98520_R2040_PCM_MODE_CFG... MAX98520_R2044_PCM_RX_SRC2: |
488 | case MAX98520_R2090_AMP_VOL_CTRL... MAX98520_R2092_AMP_DSP_CFG: |
489 | case MAX98520_R2094_SSM_CFG... MAX98520_R2095_AMP_CFG: |
490 | case MAX98520_R20B0_ADC_SR... MAX98520_R20BD_ADC_HIGH_TEMP_READBACK_LSB: |
491 | case MAX98520_R20D0_DHT_CFG1... MAX98520_R20D6_DHT_HYSTERESIS_CFG: |
492 | case MAX98520_R210E_AUTO_RESTART_BEHAVIOR... MAX98520_R210F_GLOBAL_EN: |
493 | case MAX98520_R2161_BOOST_TM1... MAX98520_R2163_BOOST_TM3: |
494 | return true; |
495 | default: |
496 | return false; |
497 | } |
498 | }; |
499 | |
500 | static bool max98520_volatile_reg(struct device *dev, unsigned int reg) |
501 | { |
502 | switch (reg) { |
503 | case MAX98520_R210F_GLOBAL_EN: |
504 | case MAX98520_R21FF_REVISION_ID: |
505 | case MAX98520_R2000_SW_RESET: |
506 | case MAX98520_R2001_STATUS_1 ... MAX98520_R2002_STATUS_2: |
507 | case MAX98520_R20B4_ADC_READBACK_CTRL |
508 | ... MAX98520_R20BD_ADC_HIGH_TEMP_READBACK_LSB: |
509 | return true; |
510 | default: |
511 | return false; |
512 | } |
513 | } |
514 | |
515 | static const struct snd_kcontrol_new max98520_snd_controls[] = { |
516 | /* Volume */ |
517 | SOC_SINGLE_TLV("Digital Volume" , MAX98520_R2090_AMP_VOL_CTRL, |
518 | 0, 0x7F, 1, max98520_digital_tlv), |
519 | SOC_SINGLE_TLV("Speaker Volume" , MAX98520_R2091_AMP_PATH_GAIN, |
520 | 0, 0x5, 0, max98520_spk_tlv), |
521 | /* Volume Ramp Up/Down Enable*/ |
522 | SOC_SINGLE("Ramp Up Switch" , MAX98520_R2092_AMP_DSP_CFG, |
523 | MAX98520_DSP_SPK_VOL_RMPUP_SHIFT, 1, 0), |
524 | SOC_SINGLE("Ramp Down Switch" , MAX98520_R2092_AMP_DSP_CFG, |
525 | MAX98520_DSP_SPK_VOL_RMPDN_SHIFT, 1, 0), |
526 | /* Clock Monitor Enable */ |
527 | SOC_SINGLE("CLK Monitor Switch" , MAX98520_R2037_ERR_MON_CTRL, |
528 | MAX98520_CTRL_CMON_EN_SHIFT, 1, 0), |
529 | /* Clock Monitor Config */ |
530 | SOC_SINGLE("CLKMON Autorestart Switch" , MAX98520_R2030_CLK_MON_CTRL, |
531 | MAX98520_CMON_AUTORESTART_SHIFT, 1, 0), |
532 | /* Dither Enable */ |
533 | SOC_SINGLE("Dither Switch" , MAX98520_R2092_AMP_DSP_CFG, |
534 | MAX98520_DSP_SPK_DITH_EN_SHIFT, 1, 0), |
535 | /* DC Blocker Enable */ |
536 | SOC_SINGLE("DC Blocker Switch" , MAX98520_R2092_AMP_DSP_CFG, |
537 | MAX98520_DSP_SPK_DCBLK_EN_SHIFT, 1, 0), |
538 | /* Speaker Safe Mode Enable */ |
539 | SOC_SINGLE("Speaker Safemode Switch" , MAX98520_R2092_AMP_DSP_CFG, |
540 | MAX98520_DSP_SPK_SAFE_EN_SHIFT, 1, 0), |
541 | /* AMP SSM Enable */ |
542 | SOC_SINGLE("CP Bypass Switch" , MAX98520_R2094_SSM_CFG, |
543 | MAX98520_SSM_RCVR_MODE_SHIFT, 1, 0), |
544 | /* Dynamic Headroom Tracking */ |
545 | SOC_SINGLE("DHT Switch" , MAX98520_R20D8_DHT_EN, 0, 1, 0), |
546 | SOC_SINGLE("DHT Limiter Mode" , MAX98520_R20D2_LIMITER_CFG2, |
547 | MAX98520_DHT_LIMITER_MODE_SHIFT, 1, 0), |
548 | SOC_SINGLE("DHT Hysteresis Switch" , MAX98520_R20D6_DHT_HYSTERESIS_CFG, |
549 | MAX98520_DHT_HYSTERESIS_SWITCH_SHIFT, 1, 0), |
550 | SOC_SINGLE_TLV("DHT Rot Pnt" , MAX98520_R20D0_DHT_CFG1, |
551 | MAX98520_DHT_VROT_PNT_SHIFT, 10, 1, max98520_dht_rotation_point_tlv), |
552 | SOC_SINGLE_TLV("DHT Supply Headroom" , MAX98520_R20D1_LIMITER_CFG1, |
553 | MAX98520_DHT_SUPPLY_HR_SHIFT, 16, 0, max98520_dht_supply_hr_tlv), |
554 | SOC_SINGLE_TLV("DHT Limiter Threshold" , MAX98520_R20D2_LIMITER_CFG2, |
555 | MAX98520_DHT_LIMITER_THRESHOLD_SHIFT, 0xF, 1, max98520_dht_lim_thresh_tlv), |
556 | SOC_SINGLE_TLV("DHT Max Attenuation" , MAX98520_R20D3_DHT_CFG2, |
557 | MAX98520_DHT_MAX_ATTEN_SHIFT, 20, 1, max98520_dht_max_atten_tlv), |
558 | SOC_SINGLE_TLV("DHT Hysteresis" , MAX98520_R20D6_DHT_HYSTERESIS_CFG, |
559 | MAX98520_DHT_HYSTERESIS_SHIFT, 0x7, 0, max98520_dht_hysteresis_tlv), |
560 | SOC_ENUM("DHT Attack Rate" , max98520_dht_attack_rate_enum), |
561 | SOC_ENUM("DHT Release Rate" , max98520_dht_release_rate_enum), |
562 | /* ADC configuration */ |
563 | SOC_SINGLE("ADC PVDD CH Switch" , MAX98520_R20CF_MEAS_ADC_CFG, 0, 1, 0), |
564 | SOC_SINGLE("ADC PVDD FLT Switch" , MAX98520_R20B2_ADC_PVDD0_CFG, MAX98520_FLT_EN_SHIFT, 1, 0), |
565 | SOC_SINGLE("ADC TEMP FLT Switch" , MAX98520_R20B3_ADC_THERMAL_CFG, MAX98520_FLT_EN_SHIFT, 1, 0), |
566 | SOC_SINGLE("ADC PVDD MSB" , MAX98520_R20B6_ADC_PVDD_READBACK_MSB, 0, 0xFF, 0), |
567 | SOC_SINGLE("ADC PVDD LSB" , MAX98520_R20B7_ADC_PVDD_READBACK_LSB, 0, 0x01, 0), |
568 | SOC_SINGLE("ADC TEMP MSB" , MAX98520_R20B8_ADC_TEMP_READBACK_MSB, 0, 0xFF, 0), |
569 | SOC_SINGLE("ADC TEMP LSB" , MAX98520_R20B9_ADC_TEMP_READBACK_LSB, 0, 0x01, 0), |
570 | }; |
571 | |
572 | static const struct snd_soc_dapm_route max98520_audio_map[] = { |
573 | /* Plabyack */ |
574 | {"DAI Sel Mux" , "Left" , "Amp Enable" }, |
575 | {"DAI Sel Mux" , "Right" , "Amp Enable" }, |
576 | {"DAI Sel Mux" , "LeftRight" , "Amp Enable" }, |
577 | {"BE_OUT" , NULL, "DAI Sel Mux" }, |
578 | }; |
579 | |
580 | static struct snd_soc_dai_driver max98520_dai[] = { |
581 | { |
582 | .name = "max98520-aif1" , |
583 | .playback = { |
584 | .stream_name = "HiFi Playback" , |
585 | .channels_min = 1, |
586 | .channels_max = 2, |
587 | .rates = MAX98520_RATES, |
588 | .formats = MAX98520_FORMATS, |
589 | }, |
590 | .ops = &max98520_dai_ops, |
591 | } |
592 | |
593 | }; |
594 | |
595 | static int max98520_probe(struct snd_soc_component *component) |
596 | { |
597 | struct max98520_priv *max98520 = |
598 | snd_soc_component_get_drvdata(c: component); |
599 | |
600 | /* Software Reset */ |
601 | regmap_write(map: max98520->regmap, MAX98520_R2000_SW_RESET, val: 1); |
602 | |
603 | /* L/R mono mix configuration : "DAI Sel" for 0x2043 */ |
604 | regmap_write(map: max98520->regmap, MAX98520_R2043_PCM_RX_SRC1, val: 0x2); |
605 | |
606 | /* PCM input channles configuration : "Left Input Selection" for 0x2044 */ |
607 | /* PCM input channles configuration : "Right Input Selection" for 0x2044 */ |
608 | regmap_write(map: max98520->regmap, MAX98520_R2044_PCM_RX_SRC2, val: 0x10); |
609 | |
610 | /* Enable DC blocker */ |
611 | regmap_update_bits(map: max98520->regmap, MAX98520_R2092_AMP_DSP_CFG, mask: 1, val: 1); |
612 | /* Enable Clock Monitor Auto-restart */ |
613 | regmap_write(map: max98520->regmap, MAX98520_R2030_CLK_MON_CTRL, val: 0x1); |
614 | |
615 | /* set Rx Enable */ |
616 | regmap_update_bits(map: max98520->regmap, |
617 | MAX98520_R204F_PCM_RX_EN, |
618 | MAX98520_PCM_RX_EN_MASK, |
619 | val: 1); |
620 | |
621 | return 0; |
622 | } |
623 | |
624 | static int __maybe_unused max98520_suspend(struct device *dev) |
625 | { |
626 | struct max98520_priv *max98520 = dev_get_drvdata(dev); |
627 | |
628 | regcache_cache_only(map: max98520->regmap, enable: true); |
629 | regcache_mark_dirty(map: max98520->regmap); |
630 | return 0; |
631 | } |
632 | |
633 | static int __maybe_unused max98520_resume(struct device *dev) |
634 | { |
635 | struct max98520_priv *max98520 = dev_get_drvdata(dev); |
636 | |
637 | regcache_cache_only(map: max98520->regmap, enable: false); |
638 | regmap_write(map: max98520->regmap, MAX98520_R2000_SW_RESET, val: 1); |
639 | regcache_sync(map: max98520->regmap); |
640 | return 0; |
641 | } |
642 | |
643 | static const struct dev_pm_ops max98520_pm = { |
644 | SET_SYSTEM_SLEEP_PM_OPS(max98520_suspend, max98520_resume) |
645 | }; |
646 | |
647 | static const struct snd_soc_component_driver soc_codec_dev_max98520 = { |
648 | .probe = max98520_probe, |
649 | .controls = max98520_snd_controls, |
650 | .num_controls = ARRAY_SIZE(max98520_snd_controls), |
651 | .dapm_widgets = max98520_dapm_widgets, |
652 | .num_dapm_widgets = ARRAY_SIZE(max98520_dapm_widgets), |
653 | .dapm_routes = max98520_audio_map, |
654 | .num_dapm_routes = ARRAY_SIZE(max98520_audio_map), |
655 | .idle_bias_on = 1, |
656 | .use_pmdown_time = 1, |
657 | .endianness = 1, |
658 | }; |
659 | |
660 | static const struct regmap_config max98520_regmap = { |
661 | .reg_bits = 16, |
662 | .val_bits = 8, |
663 | .max_register = MAX98520_R21FF_REVISION_ID, |
664 | .reg_defaults = max98520_reg, |
665 | .num_reg_defaults = ARRAY_SIZE(max98520_reg), |
666 | .readable_reg = max98520_readable_register, |
667 | .volatile_reg = max98520_volatile_reg, |
668 | .cache_type = REGCACHE_RBTREE, |
669 | }; |
670 | |
671 | static void max98520_power_on(struct max98520_priv *max98520, bool poweron) |
672 | { |
673 | if (max98520->reset_gpio) |
674 | gpiod_set_value_cansleep(desc: max98520->reset_gpio, value: !poweron); |
675 | } |
676 | |
677 | static int max98520_i2c_probe(struct i2c_client *i2c) |
678 | { |
679 | int ret; |
680 | int reg = 0; |
681 | struct max98520_priv *max98520; |
682 | struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent); |
683 | |
684 | ret = i2c_check_functionality(adap: adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA); |
685 | if (!ret) { |
686 | dev_err(&i2c->dev, "I2C check functionality failed\n" ); |
687 | return -ENXIO; |
688 | } |
689 | |
690 | max98520 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*max98520), GFP_KERNEL); |
691 | |
692 | if (!max98520) |
693 | return -ENOMEM; |
694 | |
695 | i2c_set_clientdata(client: i2c, data: max98520); |
696 | |
697 | /* regmap initialization */ |
698 | max98520->regmap = devm_regmap_init_i2c(i2c, &max98520_regmap); |
699 | if (IS_ERR(ptr: max98520->regmap)) { |
700 | ret = PTR_ERR(ptr: max98520->regmap); |
701 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n" , ret); |
702 | return ret; |
703 | } |
704 | |
705 | /* Power on device */ |
706 | max98520->reset_gpio = devm_gpiod_get_optional(dev: &i2c->dev, con_id: "reset" , flags: GPIOD_OUT_HIGH); |
707 | if (max98520->reset_gpio) { |
708 | if (IS_ERR(ptr: max98520->reset_gpio)) { |
709 | ret = PTR_ERR(ptr: max98520->reset_gpio); |
710 | dev_err(&i2c->dev, "Unable to request GPIO pin: %d.\n" , ret); |
711 | return ret; |
712 | } |
713 | |
714 | max98520_power_on(max98520, poweron: 1); |
715 | } |
716 | |
717 | /* Check Revision ID */ |
718 | ret = regmap_read(map: max98520->regmap, MAX98520_R21FF_REVISION_ID, val: ®); |
719 | if (ret < 0) { |
720 | dev_err(&i2c->dev, |
721 | "Failed to read: 0x%02X\n" , MAX98520_R21FF_REVISION_ID); |
722 | return ret; |
723 | } |
724 | dev_info(&i2c->dev, "MAX98520 revisionID: 0x%02X\n" , reg); |
725 | |
726 | /* codec registration */ |
727 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
728 | component_driver: &soc_codec_dev_max98520, |
729 | dai_drv: max98520_dai, ARRAY_SIZE(max98520_dai)); |
730 | if (ret < 0) |
731 | dev_err(&i2c->dev, "Failed to register codec: %d\n" , ret); |
732 | |
733 | return ret; |
734 | } |
735 | |
736 | static const struct i2c_device_id max98520_i2c_id[] = { |
737 | { "max98520" , 0}, |
738 | { }, |
739 | }; |
740 | |
741 | MODULE_DEVICE_TABLE(i2c, max98520_i2c_id); |
742 | |
743 | #if defined(CONFIG_OF) |
744 | static const struct of_device_id max98520_of_match[] = { |
745 | { .compatible = "maxim,max98520" , }, |
746 | { } |
747 | }; |
748 | MODULE_DEVICE_TABLE(of, max98520_of_match); |
749 | #endif |
750 | |
751 | static struct i2c_driver max98520_i2c_driver = { |
752 | .driver = { |
753 | .name = "max98520" , |
754 | .of_match_table = of_match_ptr(max98520_of_match), |
755 | .pm = &max98520_pm, |
756 | }, |
757 | .probe = max98520_i2c_probe, |
758 | .id_table = max98520_i2c_id, |
759 | }; |
760 | |
761 | module_i2c_driver(max98520_i2c_driver) |
762 | |
763 | MODULE_DESCRIPTION("ALSA SoC MAX98520 driver" ); |
764 | MODULE_AUTHOR("George Song <george.song@maximintegrated.com>" ); |
765 | MODULE_LICENSE("GPL" ); |
766 | |
767 | |