1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * max98925.c -- ALSA SoC Stereo MAX98925 driver |
4 | * Copyright 2013-15 Maxim Integrated Products |
5 | */ |
6 | #include <linux/delay.h> |
7 | #include <linux/i2c.h> |
8 | #include <linux/module.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 <sound/tlv.h> |
16 | #include "max98925.h" |
17 | |
18 | static const char *const dai_text[] = { |
19 | "Left" , "Right" , "LeftRight" , "LeftRightDiv2" , |
20 | }; |
21 | |
22 | static const char * const max98925_boost_voltage_text[] = { |
23 | "8.5V" , "8.25V" , "8.0V" , "7.75V" , "7.5V" , "7.25V" , "7.0V" , "6.75V" , |
24 | "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" |
25 | }; |
26 | |
27 | static SOC_ENUM_SINGLE_DECL(max98925_boost_voltage, |
28 | MAX98925_CONFIGURATION, M98925_BST_VOUT_SHIFT, |
29 | max98925_boost_voltage_text); |
30 | |
31 | static const char *const hpf_text[] = { |
32 | "Disable" , "DC Block" , "100Hz" , "200Hz" , "400Hz" , "800Hz" , |
33 | }; |
34 | |
35 | static const struct reg_default max98925_reg[] = { |
36 | { 0x0B, 0x00 }, /* IRQ Enable0 */ |
37 | { 0x0C, 0x00 }, /* IRQ Enable1 */ |
38 | { 0x0D, 0x00 }, /* IRQ Enable2 */ |
39 | { 0x0E, 0x00 }, /* IRQ Clear0 */ |
40 | { 0x0F, 0x00 }, /* IRQ Clear1 */ |
41 | { 0x10, 0x00 }, /* IRQ Clear2 */ |
42 | { 0x11, 0xC0 }, /* Map0 */ |
43 | { 0x12, 0x00 }, /* Map1 */ |
44 | { 0x13, 0x00 }, /* Map2 */ |
45 | { 0x14, 0xF0 }, /* Map3 */ |
46 | { 0x15, 0x00 }, /* Map4 */ |
47 | { 0x16, 0xAB }, /* Map5 */ |
48 | { 0x17, 0x89 }, /* Map6 */ |
49 | { 0x18, 0x00 }, /* Map7 */ |
50 | { 0x19, 0x00 }, /* Map8 */ |
51 | { 0x1A, 0x06 }, /* DAI Clock Mode 1 */ |
52 | { 0x1B, 0xC0 }, /* DAI Clock Mode 2 */ |
53 | { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */ |
54 | { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */ |
55 | { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */ |
56 | { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */ |
57 | { 0x20, 0x50 }, /* Format */ |
58 | { 0x21, 0x00 }, /* TDM Slot Select */ |
59 | { 0x22, 0x00 }, /* DOUT Configuration VMON */ |
60 | { 0x23, 0x00 }, /* DOUT Configuration IMON */ |
61 | { 0x24, 0x00 }, /* DOUT Configuration VBAT */ |
62 | { 0x25, 0x00 }, /* DOUT Configuration VBST */ |
63 | { 0x26, 0x00 }, /* DOUT Configuration FLAG */ |
64 | { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */ |
65 | { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */ |
66 | { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */ |
67 | { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */ |
68 | { 0x2B, 0x02 }, /* DOUT Drive Strength */ |
69 | { 0x2C, 0x90 }, /* Filters */ |
70 | { 0x2D, 0x00 }, /* Gain */ |
71 | { 0x2E, 0x02 }, /* Gain Ramping */ |
72 | { 0x2F, 0x00 }, /* Speaker Amplifier */ |
73 | { 0x30, 0x0A }, /* Threshold */ |
74 | { 0x31, 0x00 }, /* ALC Attack */ |
75 | { 0x32, 0x80 }, /* ALC Atten and Release */ |
76 | { 0x33, 0x00 }, /* ALC Infinite Hold Release */ |
77 | { 0x34, 0x92 }, /* ALC Configuration */ |
78 | { 0x35, 0x01 }, /* Boost Converter */ |
79 | { 0x36, 0x00 }, /* Block Enable */ |
80 | { 0x37, 0x00 }, /* Configuration */ |
81 | { 0x38, 0x00 }, /* Global Enable */ |
82 | { 0x3A, 0x00 }, /* Boost Limiter */ |
83 | }; |
84 | |
85 | static const struct soc_enum max98925_dai_enum = |
86 | SOC_ENUM_SINGLE(MAX98925_GAIN, 5, ARRAY_SIZE(dai_text), dai_text); |
87 | |
88 | static const struct soc_enum max98925_hpf_enum = |
89 | SOC_ENUM_SINGLE(MAX98925_FILTERS, 0, ARRAY_SIZE(hpf_text), hpf_text); |
90 | |
91 | static const struct snd_kcontrol_new max98925_hpf_sel_mux = |
92 | SOC_DAPM_ENUM("Rc Filter MUX Mux" , max98925_hpf_enum); |
93 | |
94 | static const struct snd_kcontrol_new max98925_dai_sel_mux = |
95 | SOC_DAPM_ENUM("DAI IN MUX Mux" , max98925_dai_enum); |
96 | |
97 | static int max98925_dac_event(struct snd_soc_dapm_widget *w, |
98 | struct snd_kcontrol *kcontrol, int event) |
99 | { |
100 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
101 | struct max98925_priv *max98925 = snd_soc_component_get_drvdata(c: component); |
102 | |
103 | switch (event) { |
104 | case SND_SOC_DAPM_PRE_PMU: |
105 | regmap_update_bits(map: max98925->regmap, |
106 | MAX98925_BLOCK_ENABLE, |
107 | M98925_BST_EN_MASK | |
108 | M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, |
109 | M98925_BST_EN_MASK | |
110 | M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK); |
111 | break; |
112 | case SND_SOC_DAPM_POST_PMD: |
113 | regmap_update_bits(map: max98925->regmap, |
114 | MAX98925_BLOCK_ENABLE, M98925_BST_EN_MASK | |
115 | M98925_ADC_IMON_EN_MASK | M98925_ADC_VMON_EN_MASK, val: 0); |
116 | break; |
117 | default: |
118 | return 0; |
119 | } |
120 | return 0; |
121 | } |
122 | |
123 | static const struct snd_soc_dapm_widget max98925_dapm_widgets[] = { |
124 | SND_SOC_DAPM_AIF_IN("DAI_OUT" , "HiFi Playback" , 0, SND_SOC_NOPM, 0, 0), |
125 | SND_SOC_DAPM_MUX("DAI IN MUX" , SND_SOC_NOPM, 0, 0, |
126 | &max98925_dai_sel_mux), |
127 | SND_SOC_DAPM_MUX("Rc Filter MUX" , SND_SOC_NOPM, 0, 0, |
128 | &max98925_hpf_sel_mux), |
129 | SND_SOC_DAPM_DAC_E("Amp Enable" , NULL, MAX98925_BLOCK_ENABLE, |
130 | M98925_SPK_EN_SHIFT, 0, max98925_dac_event, |
131 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
132 | SND_SOC_DAPM_SUPPLY("Global Enable" , MAX98925_GLOBAL_ENABLE, |
133 | M98925_EN_SHIFT, 0, NULL, 0), |
134 | SND_SOC_DAPM_OUTPUT("BE_OUT" ), |
135 | }; |
136 | |
137 | static const struct snd_soc_dapm_route max98925_audio_map[] = { |
138 | {"DAI IN MUX" , "Left" , "DAI_OUT" }, |
139 | {"DAI IN MUX" , "Right" , "DAI_OUT" }, |
140 | {"DAI IN MUX" , "LeftRight" , "DAI_OUT" }, |
141 | {"DAI IN MUX" , "LeftRightDiv2" , "DAI_OUT" }, |
142 | {"Rc Filter MUX" , "Disable" , "DAI IN MUX" }, |
143 | {"Rc Filter MUX" , "DC Block" , "DAI IN MUX" }, |
144 | {"Rc Filter MUX" , "100Hz" , "DAI IN MUX" }, |
145 | {"Rc Filter MUX" , "200Hz" , "DAI IN MUX" }, |
146 | {"Rc Filter MUX" , "400Hz" , "DAI IN MUX" }, |
147 | {"Rc Filter MUX" , "800Hz" , "DAI IN MUX" }, |
148 | {"Amp Enable" , NULL, "Rc Filter MUX" }, |
149 | {"BE_OUT" , NULL, "Amp Enable" }, |
150 | {"BE_OUT" , NULL, "Global Enable" }, |
151 | }; |
152 | |
153 | static bool max98925_volatile_register(struct device *dev, unsigned int reg) |
154 | { |
155 | switch (reg) { |
156 | case MAX98925_VBAT_DATA: |
157 | case MAX98925_VBST_DATA: |
158 | case MAX98925_LIVE_STATUS0: |
159 | case MAX98925_LIVE_STATUS1: |
160 | case MAX98925_LIVE_STATUS2: |
161 | case MAX98925_STATE0: |
162 | case MAX98925_STATE1: |
163 | case MAX98925_STATE2: |
164 | case MAX98925_FLAG0: |
165 | case MAX98925_FLAG1: |
166 | case MAX98925_FLAG2: |
167 | case MAX98925_REV_VERSION: |
168 | return true; |
169 | default: |
170 | return false; |
171 | } |
172 | } |
173 | |
174 | static bool max98925_readable_register(struct device *dev, unsigned int reg) |
175 | { |
176 | switch (reg) { |
177 | case MAX98925_IRQ_CLEAR0: |
178 | case MAX98925_IRQ_CLEAR1: |
179 | case MAX98925_IRQ_CLEAR2: |
180 | case MAX98925_ALC_HOLD_RLS: |
181 | return false; |
182 | default: |
183 | return true; |
184 | } |
185 | } |
186 | |
187 | static DECLARE_TLV_DB_SCALE(max98925_spk_tlv, -600, 100, 0); |
188 | |
189 | static const struct snd_kcontrol_new max98925_snd_controls[] = { |
190 | SOC_SINGLE_TLV("Speaker Volume" , MAX98925_GAIN, |
191 | M98925_SPK_GAIN_SHIFT, (1<<M98925_SPK_GAIN_WIDTH)-1, 0, |
192 | max98925_spk_tlv), |
193 | SOC_SINGLE("Ramp Switch" , MAX98925_GAIN_RAMPING, |
194 | M98925_SPK_RMP_EN_SHIFT, 1, 0), |
195 | SOC_SINGLE("ZCD Switch" , MAX98925_GAIN_RAMPING, |
196 | M98925_SPK_ZCD_EN_SHIFT, 1, 0), |
197 | SOC_SINGLE("ALC Switch" , MAX98925_THRESHOLD, |
198 | M98925_ALC_EN_SHIFT, 1, 0), |
199 | SOC_SINGLE("ALC Threshold" , MAX98925_THRESHOLD, M98925_ALC_TH_SHIFT, |
200 | (1<<M98925_ALC_TH_WIDTH)-1, 0), |
201 | SOC_ENUM("Boost Output Voltage" , max98925_boost_voltage), |
202 | }; |
203 | |
204 | /* codec sample rate and n/m dividers parameter table */ |
205 | static const struct { |
206 | int rate; |
207 | int sr; |
208 | int divisors[3][2]; |
209 | } rate_table[] = { |
210 | { |
211 | .rate = 8000, |
212 | .sr = 0, |
213 | .divisors = { {1, 375}, {5, 1764}, {1, 384} } |
214 | }, |
215 | { |
216 | .rate = 11025, |
217 | .sr = 1, |
218 | .divisors = { {147, 40000}, {1, 256}, {147, 40960} } |
219 | }, |
220 | { |
221 | .rate = 12000, |
222 | .sr = 2, |
223 | .divisors = { {1, 250}, {5, 1176}, {1, 256} } |
224 | }, |
225 | { |
226 | .rate = 16000, |
227 | .sr = 3, |
228 | .divisors = { {2, 375}, {5, 882}, {1, 192} } |
229 | }, |
230 | { |
231 | .rate = 22050, |
232 | .sr = 4, |
233 | .divisors = { {147, 20000}, {1, 128}, {147, 20480} } |
234 | }, |
235 | { |
236 | .rate = 24000, |
237 | .sr = 5, |
238 | .divisors = { {1, 125}, {5, 588}, {1, 128} } |
239 | }, |
240 | { |
241 | .rate = 32000, |
242 | .sr = 6, |
243 | .divisors = { {4, 375}, {5, 441}, {1, 96} } |
244 | }, |
245 | { |
246 | .rate = 44100, |
247 | .sr = 7, |
248 | .divisors = { {147, 10000}, {1, 64}, {147, 10240} } |
249 | }, |
250 | { |
251 | .rate = 48000, |
252 | .sr = 8, |
253 | .divisors = { {2, 125}, {5, 294}, {1, 64} } |
254 | }, |
255 | }; |
256 | |
257 | static inline int max98925_rate_value(struct snd_soc_component *component, |
258 | int rate, int clock, int *value, int *n, int *m) |
259 | { |
260 | int ret = -EINVAL; |
261 | int i; |
262 | |
263 | for (i = 0; i < ARRAY_SIZE(rate_table); i++) { |
264 | if (rate_table[i].rate >= rate) { |
265 | *value = rate_table[i].sr; |
266 | *n = rate_table[i].divisors[clock][0]; |
267 | *m = rate_table[i].divisors[clock][1]; |
268 | ret = 0; |
269 | break; |
270 | } |
271 | } |
272 | return ret; |
273 | } |
274 | |
275 | static void max98925_set_sense_data(struct max98925_priv *max98925) |
276 | { |
277 | /* set VMON slots */ |
278 | regmap_update_bits(map: max98925->regmap, |
279 | MAX98925_DOUT_CFG_VMON, |
280 | M98925_DAI_VMON_EN_MASK, M98925_DAI_VMON_EN_MASK); |
281 | regmap_update_bits(map: max98925->regmap, |
282 | MAX98925_DOUT_CFG_VMON, |
283 | M98925_DAI_VMON_SLOT_MASK, |
284 | val: max98925->v_slot << M98925_DAI_VMON_SLOT_SHIFT); |
285 | /* set IMON slots */ |
286 | regmap_update_bits(map: max98925->regmap, |
287 | MAX98925_DOUT_CFG_IMON, |
288 | M98925_DAI_IMON_EN_MASK, M98925_DAI_IMON_EN_MASK); |
289 | regmap_update_bits(map: max98925->regmap, |
290 | MAX98925_DOUT_CFG_IMON, |
291 | M98925_DAI_IMON_SLOT_MASK, |
292 | val: max98925->i_slot << M98925_DAI_IMON_SLOT_SHIFT); |
293 | } |
294 | |
295 | static int max98925_dai_set_fmt(struct snd_soc_dai *codec_dai, |
296 | unsigned int fmt) |
297 | { |
298 | struct snd_soc_component *component = codec_dai->component; |
299 | struct max98925_priv *max98925 = snd_soc_component_get_drvdata(c: component); |
300 | unsigned int invert = 0; |
301 | |
302 | dev_dbg(component->dev, "%s: fmt 0x%08X\n" , __func__, fmt); |
303 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
304 | case SND_SOC_DAIFMT_CBC_CFC: |
305 | regmap_update_bits(map: max98925->regmap, |
306 | MAX98925_DAI_CLK_MODE2, |
307 | M98925_DAI_MAS_MASK, val: 0); |
308 | max98925_set_sense_data(max98925); |
309 | break; |
310 | case SND_SOC_DAIFMT_CBP_CFP: |
311 | /* |
312 | * set left channel DAI to provider mode, |
313 | * right channel always consumer |
314 | */ |
315 | regmap_update_bits(map: max98925->regmap, |
316 | MAX98925_DAI_CLK_MODE2, |
317 | M98925_DAI_MAS_MASK, M98925_DAI_MAS_MASK); |
318 | break; |
319 | default: |
320 | dev_err(component->dev, "DAI clock mode unsupported" ); |
321 | return -EINVAL; |
322 | } |
323 | |
324 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
325 | case SND_SOC_DAIFMT_NB_NF: |
326 | break; |
327 | case SND_SOC_DAIFMT_NB_IF: |
328 | invert = M98925_DAI_WCI_MASK; |
329 | break; |
330 | case SND_SOC_DAIFMT_IB_NF: |
331 | invert = M98925_DAI_BCI_MASK; |
332 | break; |
333 | case SND_SOC_DAIFMT_IB_IF: |
334 | invert = M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK; |
335 | break; |
336 | default: |
337 | dev_err(component->dev, "DAI invert mode unsupported" ); |
338 | return -EINVAL; |
339 | } |
340 | |
341 | regmap_update_bits(map: max98925->regmap, MAX98925_FORMAT, |
342 | M98925_DAI_BCI_MASK | M98925_DAI_WCI_MASK, val: invert); |
343 | return 0; |
344 | } |
345 | |
346 | static int max98925_set_clock(struct max98925_priv *max98925, |
347 | struct snd_pcm_hw_params *params) |
348 | { |
349 | unsigned int dai_sr = 0, clock, mdll, n, m; |
350 | struct snd_soc_component *component = max98925->component; |
351 | int rate = params_rate(p: params); |
352 | /* BCLK/LRCLK ratio calculation */ |
353 | int blr_clk_ratio = params_channels(p: params) * max98925->ch_size; |
354 | |
355 | switch (blr_clk_ratio) { |
356 | case 32: |
357 | regmap_update_bits(map: max98925->regmap, |
358 | MAX98925_DAI_CLK_MODE2, |
359 | M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_32); |
360 | break; |
361 | case 48: |
362 | regmap_update_bits(map: max98925->regmap, |
363 | MAX98925_DAI_CLK_MODE2, |
364 | M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_48); |
365 | break; |
366 | case 64: |
367 | regmap_update_bits(map: max98925->regmap, |
368 | MAX98925_DAI_CLK_MODE2, |
369 | M98925_DAI_BSEL_MASK, M98925_DAI_BSEL_64); |
370 | break; |
371 | default: |
372 | return -EINVAL; |
373 | } |
374 | |
375 | switch (max98925->sysclk) { |
376 | case 6000000: |
377 | clock = 0; |
378 | mdll = M98925_MDLL_MULT_MCLKx16; |
379 | break; |
380 | case 11289600: |
381 | clock = 1; |
382 | mdll = M98925_MDLL_MULT_MCLKx8; |
383 | break; |
384 | case 12000000: |
385 | clock = 0; |
386 | mdll = M98925_MDLL_MULT_MCLKx8; |
387 | break; |
388 | case 12288000: |
389 | clock = 2; |
390 | mdll = M98925_MDLL_MULT_MCLKx8; |
391 | break; |
392 | default: |
393 | dev_info(max98925->component->dev, "unsupported sysclk %d\n" , |
394 | max98925->sysclk); |
395 | return -EINVAL; |
396 | } |
397 | |
398 | if (max98925_rate_value(component, rate, clock, value: &dai_sr, n: &n, m: &m)) |
399 | return -EINVAL; |
400 | |
401 | /* set DAI_SR to correct LRCLK frequency */ |
402 | regmap_update_bits(map: max98925->regmap, |
403 | MAX98925_DAI_CLK_MODE2, |
404 | M98925_DAI_SR_MASK, val: dai_sr << M98925_DAI_SR_SHIFT); |
405 | /* set DAI m divider */ |
406 | regmap_write(map: max98925->regmap, |
407 | MAX98925_DAI_CLK_DIV_M_MSBS, val: m >> 8); |
408 | regmap_write(map: max98925->regmap, |
409 | MAX98925_DAI_CLK_DIV_M_LSBS, val: m & 0xFF); |
410 | /* set DAI n divider */ |
411 | regmap_write(map: max98925->regmap, |
412 | MAX98925_DAI_CLK_DIV_N_MSBS, val: n >> 8); |
413 | regmap_write(map: max98925->regmap, |
414 | MAX98925_DAI_CLK_DIV_N_LSBS, val: n & 0xFF); |
415 | /* set MDLL */ |
416 | regmap_update_bits(map: max98925->regmap, MAX98925_DAI_CLK_MODE1, |
417 | M98925_MDLL_MULT_MASK, val: mdll << M98925_MDLL_MULT_SHIFT); |
418 | return 0; |
419 | } |
420 | |
421 | static int max98925_dai_hw_params(struct snd_pcm_substream *substream, |
422 | struct snd_pcm_hw_params *params, |
423 | struct snd_soc_dai *dai) |
424 | { |
425 | struct snd_soc_component *component = dai->component; |
426 | struct max98925_priv *max98925 = snd_soc_component_get_drvdata(c: component); |
427 | |
428 | switch (params_width(p: params)) { |
429 | case 16: |
430 | regmap_update_bits(map: max98925->regmap, |
431 | MAX98925_FORMAT, |
432 | M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_16); |
433 | max98925->ch_size = 16; |
434 | break; |
435 | case 24: |
436 | regmap_update_bits(map: max98925->regmap, |
437 | MAX98925_FORMAT, |
438 | M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_24); |
439 | max98925->ch_size = 24; |
440 | break; |
441 | case 32: |
442 | regmap_update_bits(map: max98925->regmap, |
443 | MAX98925_FORMAT, |
444 | M98925_DAI_CHANSZ_MASK, M98925_DAI_CHANSZ_32); |
445 | max98925->ch_size = 32; |
446 | break; |
447 | default: |
448 | pr_err("%s: format unsupported %d" , |
449 | __func__, params_format(params)); |
450 | return -EINVAL; |
451 | } |
452 | dev_dbg(component->dev, "%s: format supported %d" , |
453 | __func__, params_format(params)); |
454 | return max98925_set_clock(max98925, params); |
455 | } |
456 | |
457 | static int max98925_dai_set_sysclk(struct snd_soc_dai *dai, |
458 | int clk_id, unsigned int freq, int dir) |
459 | { |
460 | struct snd_soc_component *component = dai->component; |
461 | struct max98925_priv *max98925 = snd_soc_component_get_drvdata(c: component); |
462 | |
463 | switch (clk_id) { |
464 | case 0: |
465 | /* use MCLK for Left channel, right channel always BCLK */ |
466 | regmap_update_bits(map: max98925->regmap, |
467 | MAX98925_DAI_CLK_MODE1, |
468 | M98925_DAI_CLK_SOURCE_MASK, val: 0); |
469 | break; |
470 | case 1: |
471 | /* configure dai clock source to BCLK instead of MCLK */ |
472 | regmap_update_bits(map: max98925->regmap, |
473 | MAX98925_DAI_CLK_MODE1, |
474 | M98925_DAI_CLK_SOURCE_MASK, |
475 | M98925_DAI_CLK_SOURCE_MASK); |
476 | break; |
477 | default: |
478 | return -EINVAL; |
479 | } |
480 | max98925->sysclk = freq; |
481 | return 0; |
482 | } |
483 | |
484 | #define MAX98925_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
485 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
486 | |
487 | static const struct snd_soc_dai_ops max98925_dai_ops = { |
488 | .set_sysclk = max98925_dai_set_sysclk, |
489 | .set_fmt = max98925_dai_set_fmt, |
490 | .hw_params = max98925_dai_hw_params, |
491 | }; |
492 | |
493 | static struct snd_soc_dai_driver max98925_dai[] = { |
494 | { |
495 | .name = "max98925-aif1" , |
496 | .playback = { |
497 | .stream_name = "HiFi Playback" , |
498 | .channels_min = 1, |
499 | .channels_max = 2, |
500 | .rates = SNDRV_PCM_RATE_8000_48000, |
501 | .formats = MAX98925_FORMATS, |
502 | }, |
503 | .capture = { |
504 | .stream_name = "HiFi Capture" , |
505 | .channels_min = 1, |
506 | .channels_max = 2, |
507 | .rates = SNDRV_PCM_RATE_8000_48000, |
508 | .formats = MAX98925_FORMATS, |
509 | }, |
510 | .ops = &max98925_dai_ops, |
511 | } |
512 | }; |
513 | |
514 | static int max98925_probe(struct snd_soc_component *component) |
515 | { |
516 | struct max98925_priv *max98925 = snd_soc_component_get_drvdata(c: component); |
517 | |
518 | max98925->component = component; |
519 | regmap_write(map: max98925->regmap, MAX98925_GLOBAL_ENABLE, val: 0x00); |
520 | /* It's not the default but we need to set DAI_DLY */ |
521 | regmap_write(map: max98925->regmap, |
522 | MAX98925_FORMAT, M98925_DAI_DLY_MASK); |
523 | regmap_write(map: max98925->regmap, MAX98925_TDM_SLOT_SELECT, val: 0xC8); |
524 | regmap_write(map: max98925->regmap, MAX98925_DOUT_HIZ_CFG1, val: 0xFF); |
525 | regmap_write(map: max98925->regmap, MAX98925_DOUT_HIZ_CFG2, val: 0xFF); |
526 | regmap_write(map: max98925->regmap, MAX98925_DOUT_HIZ_CFG3, val: 0xFF); |
527 | regmap_write(map: max98925->regmap, MAX98925_DOUT_HIZ_CFG4, val: 0xF0); |
528 | regmap_write(map: max98925->regmap, MAX98925_FILTERS, val: 0xD8); |
529 | regmap_write(map: max98925->regmap, MAX98925_ALC_CONFIGURATION, val: 0xF8); |
530 | regmap_write(map: max98925->regmap, MAX98925_CONFIGURATION, val: 0xF0); |
531 | /* Disable ALC muting */ |
532 | regmap_write(map: max98925->regmap, MAX98925_BOOST_LIMITER, val: 0xF8); |
533 | return 0; |
534 | } |
535 | |
536 | static const struct snd_soc_component_driver soc_component_dev_max98925 = { |
537 | .probe = max98925_probe, |
538 | .controls = max98925_snd_controls, |
539 | .num_controls = ARRAY_SIZE(max98925_snd_controls), |
540 | .dapm_routes = max98925_audio_map, |
541 | .num_dapm_routes = ARRAY_SIZE(max98925_audio_map), |
542 | .dapm_widgets = max98925_dapm_widgets, |
543 | .num_dapm_widgets = ARRAY_SIZE(max98925_dapm_widgets), |
544 | .idle_bias_on = 1, |
545 | .use_pmdown_time = 1, |
546 | .endianness = 1, |
547 | }; |
548 | |
549 | static const struct regmap_config max98925_regmap = { |
550 | .reg_bits = 8, |
551 | .val_bits = 8, |
552 | .max_register = MAX98925_REV_VERSION, |
553 | .reg_defaults = max98925_reg, |
554 | .num_reg_defaults = ARRAY_SIZE(max98925_reg), |
555 | .volatile_reg = max98925_volatile_register, |
556 | .readable_reg = max98925_readable_register, |
557 | .cache_type = REGCACHE_RBTREE, |
558 | }; |
559 | |
560 | static int max98925_i2c_probe(struct i2c_client *i2c) |
561 | { |
562 | int ret, reg; |
563 | u32 value; |
564 | struct max98925_priv *max98925; |
565 | |
566 | max98925 = devm_kzalloc(dev: &i2c->dev, |
567 | size: sizeof(*max98925), GFP_KERNEL); |
568 | if (!max98925) |
569 | return -ENOMEM; |
570 | |
571 | i2c_set_clientdata(client: i2c, data: max98925); |
572 | max98925->regmap = devm_regmap_init_i2c(i2c, &max98925_regmap); |
573 | if (IS_ERR(ptr: max98925->regmap)) { |
574 | ret = PTR_ERR(ptr: max98925->regmap); |
575 | dev_err(&i2c->dev, |
576 | "Failed to allocate regmap: %d\n" , ret); |
577 | return ret; |
578 | } |
579 | |
580 | if (!of_property_read_u32(np: i2c->dev.of_node, propname: "vmon-slot-no" , out_value: &value)) { |
581 | if (value > M98925_DAI_VMON_SLOT_1E_1F) { |
582 | dev_err(&i2c->dev, "vmon slot number is wrong:\n" ); |
583 | return -EINVAL; |
584 | } |
585 | max98925->v_slot = value; |
586 | } |
587 | if (!of_property_read_u32(np: i2c->dev.of_node, propname: "imon-slot-no" , out_value: &value)) { |
588 | if (value > M98925_DAI_IMON_SLOT_1E_1F) { |
589 | dev_err(&i2c->dev, "imon slot number is wrong:\n" ); |
590 | return -EINVAL; |
591 | } |
592 | max98925->i_slot = value; |
593 | } |
594 | |
595 | ret = regmap_read(map: max98925->regmap, MAX98925_REV_VERSION, val: ®); |
596 | if (ret < 0) { |
597 | dev_err(&i2c->dev, "Read revision failed\n" ); |
598 | return ret; |
599 | } |
600 | |
601 | if ((reg != MAX98925_VERSION) && (reg != MAX98925_VERSION1)) { |
602 | ret = -ENODEV; |
603 | dev_err(&i2c->dev, "Invalid revision (%d 0x%02X)\n" , |
604 | ret, reg); |
605 | return ret; |
606 | } |
607 | |
608 | dev_info(&i2c->dev, "device version 0x%02X\n" , reg); |
609 | |
610 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
611 | component_driver: &soc_component_dev_max98925, |
612 | dai_drv: max98925_dai, ARRAY_SIZE(max98925_dai)); |
613 | if (ret < 0) |
614 | dev_err(&i2c->dev, |
615 | "Failed to register component: %d\n" , ret); |
616 | return ret; |
617 | } |
618 | |
619 | static const struct i2c_device_id max98925_i2c_id[] = { |
620 | { "max98925" , 0 }, |
621 | { } |
622 | }; |
623 | MODULE_DEVICE_TABLE(i2c, max98925_i2c_id); |
624 | |
625 | #ifdef CONFIG_OF |
626 | static const struct of_device_id max98925_of_match[] = { |
627 | { .compatible = "maxim,max98925" , }, |
628 | { } |
629 | }; |
630 | MODULE_DEVICE_TABLE(of, max98925_of_match); |
631 | #endif |
632 | |
633 | static struct i2c_driver max98925_i2c_driver = { |
634 | .driver = { |
635 | .name = "max98925" , |
636 | .of_match_table = of_match_ptr(max98925_of_match), |
637 | }, |
638 | .probe = max98925_i2c_probe, |
639 | .id_table = max98925_i2c_id, |
640 | }; |
641 | |
642 | module_i2c_driver(max98925_i2c_driver) |
643 | |
644 | MODULE_DESCRIPTION("ALSA SoC MAX98925 driver" ); |
645 | MODULE_AUTHOR("Ralph Birt <rdbirt@gmail.com>, Anish kumar <anish.kumar@maximintegrated.com>" ); |
646 | MODULE_LICENSE("GPL" ); |
647 | |