1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * max98926.c -- ALSA SoC MAX98926 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 "max98926.h" |
17 | |
18 | static const char * const max98926_boost_voltage_txt[] = { |
19 | "8.5V" , "8.25V" , "8.0V" , "7.75V" , "7.5V" , "7.25V" , "7.0V" , "6.75V" , |
20 | "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" , "6.5V" |
21 | }; |
22 | |
23 | static const char *const max98926_pdm_ch_text[] = { |
24 | "Current" , "Voltage" , |
25 | }; |
26 | |
27 | static const char *const max98926_hpf_cutoff_txt[] = { |
28 | "Disable" , "DC Block" , "100Hz" , |
29 | "200Hz" , "400Hz" , "800Hz" , |
30 | }; |
31 | |
32 | static const struct reg_default max98926_reg[] = { |
33 | { 0x0B, 0x00 }, /* IRQ Enable0 */ |
34 | { 0x0C, 0x00 }, /* IRQ Enable1 */ |
35 | { 0x0D, 0x00 }, /* IRQ Enable2 */ |
36 | { 0x0E, 0x00 }, /* IRQ Clear0 */ |
37 | { 0x0F, 0x00 }, /* IRQ Clear1 */ |
38 | { 0x10, 0x00 }, /* IRQ Clear2 */ |
39 | { 0x11, 0xC0 }, /* Map0 */ |
40 | { 0x12, 0x00 }, /* Map1 */ |
41 | { 0x13, 0x00 }, /* Map2 */ |
42 | { 0x14, 0xF0 }, /* Map3 */ |
43 | { 0x15, 0x00 }, /* Map4 */ |
44 | { 0x16, 0xAB }, /* Map5 */ |
45 | { 0x17, 0x89 }, /* Map6 */ |
46 | { 0x18, 0x00 }, /* Map7 */ |
47 | { 0x19, 0x00 }, /* Map8 */ |
48 | { 0x1A, 0x04 }, /* DAI Clock Mode 1 */ |
49 | { 0x1B, 0x00 }, /* DAI Clock Mode 2 */ |
50 | { 0x1C, 0x00 }, /* DAI Clock Divider Denominator MSBs */ |
51 | { 0x1D, 0x00 }, /* DAI Clock Divider Denominator LSBs */ |
52 | { 0x1E, 0xF0 }, /* DAI Clock Divider Numerator MSBs */ |
53 | { 0x1F, 0x00 }, /* DAI Clock Divider Numerator LSBs */ |
54 | { 0x20, 0x50 }, /* Format */ |
55 | { 0x21, 0x00 }, /* TDM Slot Select */ |
56 | { 0x22, 0x00 }, /* DOUT Configuration VMON */ |
57 | { 0x23, 0x00 }, /* DOUT Configuration IMON */ |
58 | { 0x24, 0x00 }, /* DOUT Configuration VBAT */ |
59 | { 0x25, 0x00 }, /* DOUT Configuration VBST */ |
60 | { 0x26, 0x00 }, /* DOUT Configuration FLAG */ |
61 | { 0x27, 0xFF }, /* DOUT HiZ Configuration 1 */ |
62 | { 0x28, 0xFF }, /* DOUT HiZ Configuration 2 */ |
63 | { 0x29, 0xFF }, /* DOUT HiZ Configuration 3 */ |
64 | { 0x2A, 0xFF }, /* DOUT HiZ Configuration 4 */ |
65 | { 0x2B, 0x02 }, /* DOUT Drive Strength */ |
66 | { 0x2C, 0x90 }, /* Filters */ |
67 | { 0x2D, 0x00 }, /* Gain */ |
68 | { 0x2E, 0x02 }, /* Gain Ramping */ |
69 | { 0x2F, 0x00 }, /* Speaker Amplifier */ |
70 | { 0x30, 0x0A }, /* Threshold */ |
71 | { 0x31, 0x00 }, /* ALC Attack */ |
72 | { 0x32, 0x80 }, /* ALC Atten and Release */ |
73 | { 0x33, 0x00 }, /* ALC Infinite Hold Release */ |
74 | { 0x34, 0x92 }, /* ALC Configuration */ |
75 | { 0x35, 0x01 }, /* Boost Converter */ |
76 | { 0x36, 0x00 }, /* Block Enable */ |
77 | { 0x37, 0x00 }, /* Configuration */ |
78 | { 0x38, 0x00 }, /* Global Enable */ |
79 | { 0x3A, 0x00 }, /* Boost Limiter */ |
80 | }; |
81 | |
82 | static const struct soc_enum max98926_voltage_enum[] = { |
83 | SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS, 0, |
84 | ARRAY_SIZE(max98926_pdm_ch_text), |
85 | max98926_pdm_ch_text), |
86 | }; |
87 | |
88 | static const struct snd_kcontrol_new max98926_voltage_control = |
89 | SOC_DAPM_ENUM("Route" , max98926_voltage_enum); |
90 | |
91 | static const struct soc_enum max98926_current_enum[] = { |
92 | SOC_ENUM_SINGLE(MAX98926_DAI_CLK_DIV_N_LSBS, |
93 | MAX98926_PDM_SOURCE_1_SHIFT, |
94 | ARRAY_SIZE(max98926_pdm_ch_text), |
95 | max98926_pdm_ch_text), |
96 | }; |
97 | |
98 | static const struct snd_kcontrol_new max98926_current_control = |
99 | SOC_DAPM_ENUM("Route" , max98926_current_enum); |
100 | |
101 | static const struct snd_kcontrol_new max98926_mixer_controls[] = { |
102 | SOC_DAPM_SINGLE("PCM Single Switch" , MAX98926_SPK_AMP, |
103 | MAX98926_INSELECT_MODE_SHIFT, 0, 0), |
104 | SOC_DAPM_SINGLE("PDM Single Switch" , MAX98926_SPK_AMP, |
105 | MAX98926_INSELECT_MODE_SHIFT, 1, 0), |
106 | }; |
107 | |
108 | static const struct snd_kcontrol_new max98926_dai_controls[] = { |
109 | SOC_DAPM_SINGLE("Left" , MAX98926_GAIN, |
110 | MAX98926_DAC_IN_SEL_SHIFT, 0, 0), |
111 | SOC_DAPM_SINGLE("Right" , MAX98926_GAIN, |
112 | MAX98926_DAC_IN_SEL_SHIFT, 1, 0), |
113 | SOC_DAPM_SINGLE("LeftRight" , MAX98926_GAIN, |
114 | MAX98926_DAC_IN_SEL_SHIFT, 2, 0), |
115 | SOC_DAPM_SINGLE("(Left+Right)/2 Switch" , MAX98926_GAIN, |
116 | MAX98926_DAC_IN_SEL_SHIFT, 3, 0), |
117 | }; |
118 | |
119 | static const struct snd_soc_dapm_widget max98926_dapm_widgets[] = { |
120 | SND_SOC_DAPM_AIF_IN("DAI_OUT" , "HiFi Playback" , 0, |
121 | SND_SOC_NOPM, 0, 0), |
122 | SND_SOC_DAPM_DAC("Amp Enable" , NULL, MAX98926_BLOCK_ENABLE, |
123 | MAX98926_SPK_EN_SHIFT, 0), |
124 | SND_SOC_DAPM_SUPPLY("Global Enable" , MAX98926_GLOBAL_ENABLE, |
125 | MAX98926_EN_SHIFT, 0, NULL, 0), |
126 | SND_SOC_DAPM_SUPPLY("VI Enable" , MAX98926_BLOCK_ENABLE, |
127 | MAX98926_ADC_IMON_EN_WIDTH | |
128 | MAX98926_ADC_VMON_EN_SHIFT, |
129 | 0, NULL, 0), |
130 | SND_SOC_DAPM_PGA("BST Enable" , MAX98926_BLOCK_ENABLE, |
131 | MAX98926_BST_EN_SHIFT, 0, NULL, 0), |
132 | SND_SOC_DAPM_OUTPUT("BE_OUT" ), |
133 | SND_SOC_DAPM_MIXER("PCM Sel" , MAX98926_SPK_AMP, |
134 | MAX98926_INSELECT_MODE_SHIFT, 0, |
135 | &max98926_mixer_controls[0], |
136 | ARRAY_SIZE(max98926_mixer_controls)), |
137 | SND_SOC_DAPM_MIXER("DAI Sel" , |
138 | MAX98926_GAIN, MAX98926_DAC_IN_SEL_SHIFT, 0, |
139 | &max98926_dai_controls[0], |
140 | ARRAY_SIZE(max98926_dai_controls)), |
141 | SND_SOC_DAPM_MUX("PDM CH1 Source" , |
142 | MAX98926_DAI_CLK_DIV_N_LSBS, |
143 | MAX98926_PDM_CURRENT_SHIFT, |
144 | 0, &max98926_current_control), |
145 | SND_SOC_DAPM_MUX("PDM CH0 Source" , |
146 | MAX98926_DAI_CLK_DIV_N_LSBS, |
147 | MAX98926_PDM_VOLTAGE_SHIFT, |
148 | 0, &max98926_voltage_control), |
149 | }; |
150 | |
151 | static const struct snd_soc_dapm_route max98926_audio_map[] = { |
152 | {"VI Enable" , NULL, "DAI_OUT" }, |
153 | {"DAI Sel" , "Left" , "VI Enable" }, |
154 | {"DAI Sel" , "Right" , "VI Enable" }, |
155 | {"DAI Sel" , "LeftRight" , "VI Enable" }, |
156 | {"DAI Sel" , "LeftRightDiv2" , "VI Enable" }, |
157 | {"PCM Sel" , "PCM" , "DAI Sel" }, |
158 | |
159 | {"PDM CH1 Source" , "Current" , "DAI_OUT" }, |
160 | {"PDM CH1 Source" , "Voltage" , "DAI_OUT" }, |
161 | {"PDM CH0 Source" , "Current" , "DAI_OUT" }, |
162 | {"PDM CH0 Source" , "Voltage" , "DAI_OUT" }, |
163 | {"PCM Sel" , "Analog" , "PDM CH1 Source" }, |
164 | {"PCM Sel" , "Analog" , "PDM CH0 Source" }, |
165 | {"Amp Enable" , NULL, "PCM Sel" }, |
166 | |
167 | {"BST Enable" , NULL, "Amp Enable" }, |
168 | {"BE_OUT" , NULL, "BST Enable" }, |
169 | }; |
170 | |
171 | static bool max98926_volatile_register(struct device *dev, unsigned int reg) |
172 | { |
173 | switch (reg) { |
174 | case MAX98926_VBAT_DATA: |
175 | case MAX98926_VBST_DATA: |
176 | case MAX98926_LIVE_STATUS0: |
177 | case MAX98926_LIVE_STATUS1: |
178 | case MAX98926_LIVE_STATUS2: |
179 | case MAX98926_STATE0: |
180 | case MAX98926_STATE1: |
181 | case MAX98926_STATE2: |
182 | case MAX98926_FLAG0: |
183 | case MAX98926_FLAG1: |
184 | case MAX98926_FLAG2: |
185 | case MAX98926_VERSION: |
186 | return true; |
187 | default: |
188 | return false; |
189 | } |
190 | } |
191 | |
192 | static bool max98926_readable_register(struct device *dev, unsigned int reg) |
193 | { |
194 | switch (reg) { |
195 | case MAX98926_IRQ_CLEAR0: |
196 | case MAX98926_IRQ_CLEAR1: |
197 | case MAX98926_IRQ_CLEAR2: |
198 | case MAX98926_ALC_HOLD_RLS: |
199 | return false; |
200 | default: |
201 | return true; |
202 | } |
203 | }; |
204 | |
205 | static DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0); |
206 | static DECLARE_TLV_DB_RANGE(max98926_current_tlv, |
207 | 0, 11, TLV_DB_SCALE_ITEM(20, 20, 0), |
208 | 12, 15, TLV_DB_SCALE_ITEM(320, 40, 0), |
209 | ); |
210 | |
211 | static SOC_ENUM_SINGLE_DECL(max98926_dac_hpf_cutoff, |
212 | MAX98926_FILTERS, MAX98926_DAC_HPF_SHIFT, |
213 | max98926_hpf_cutoff_txt); |
214 | |
215 | static SOC_ENUM_SINGLE_DECL(max98926_boost_voltage, |
216 | MAX98926_CONFIGURATION, MAX98926_BST_VOUT_SHIFT, |
217 | max98926_boost_voltage_txt); |
218 | |
219 | static const struct snd_kcontrol_new max98926_snd_controls[] = { |
220 | SOC_SINGLE_TLV("Speaker Volume" , MAX98926_GAIN, |
221 | MAX98926_SPK_GAIN_SHIFT, |
222 | (1<<MAX98926_SPK_GAIN_WIDTH)-1, 0, |
223 | max98926_spk_tlv), |
224 | SOC_SINGLE("Ramp Switch" , MAX98926_GAIN_RAMPING, |
225 | MAX98926_SPK_RMP_EN_SHIFT, 1, 0), |
226 | SOC_SINGLE("ZCD Switch" , MAX98926_GAIN_RAMPING, |
227 | MAX98926_SPK_ZCD_EN_SHIFT, 1, 0), |
228 | SOC_SINGLE("ALC Switch" , MAX98926_THRESHOLD, |
229 | MAX98926_ALC_EN_SHIFT, 1, 0), |
230 | SOC_SINGLE("ALC Threshold" , MAX98926_THRESHOLD, |
231 | MAX98926_ALC_TH_SHIFT, |
232 | (1<<MAX98926_ALC_TH_WIDTH)-1, 0), |
233 | SOC_ENUM("Boost Output Voltage" , max98926_boost_voltage), |
234 | SOC_SINGLE_TLV("Boost Current Limit" , MAX98926_BOOST_LIMITER, |
235 | MAX98926_BST_ILIM_SHIFT, |
236 | (1<<MAX98926_BST_ILIM_SHIFT)-1, 0, |
237 | max98926_current_tlv), |
238 | SOC_ENUM("DAC HPF Cutoff" , max98926_dac_hpf_cutoff), |
239 | SOC_DOUBLE("PDM Channel One" , MAX98926_DAI_CLK_DIV_N_LSBS, |
240 | MAX98926_PDM_CHANNEL_1_SHIFT, |
241 | MAX98926_PDM_CHANNEL_1_HIZ, 1, 0), |
242 | SOC_DOUBLE("PDM Channel Zero" , MAX98926_DAI_CLK_DIV_N_LSBS, |
243 | MAX98926_PDM_CHANNEL_0_SHIFT, |
244 | MAX98926_PDM_CHANNEL_0_HIZ, 1, 0), |
245 | }; |
246 | |
247 | static const struct { |
248 | int rate; |
249 | int sr; |
250 | } rate_table[] = { |
251 | { |
252 | .rate = 8000, |
253 | .sr = 0, |
254 | }, |
255 | { |
256 | .rate = 11025, |
257 | .sr = 1, |
258 | }, |
259 | { |
260 | .rate = 12000, |
261 | .sr = 2, |
262 | }, |
263 | { |
264 | .rate = 16000, |
265 | .sr = 3, |
266 | }, |
267 | { |
268 | .rate = 22050, |
269 | .sr = 4, |
270 | }, |
271 | { |
272 | .rate = 24000, |
273 | .sr = 5, |
274 | }, |
275 | { |
276 | .rate = 32000, |
277 | .sr = 6, |
278 | }, |
279 | { |
280 | .rate = 44100, |
281 | .sr = 7, |
282 | }, |
283 | { |
284 | .rate = 48000, |
285 | .sr = 8, |
286 | }, |
287 | }; |
288 | |
289 | static void max98926_set_sense_data(struct max98926_priv *max98926) |
290 | { |
291 | regmap_update_bits(map: max98926->regmap, |
292 | MAX98926_DOUT_CFG_VMON, |
293 | MAX98926_DAI_VMON_EN_MASK, |
294 | MAX98926_DAI_VMON_EN_MASK); |
295 | regmap_update_bits(map: max98926->regmap, |
296 | MAX98926_DOUT_CFG_IMON, |
297 | MAX98926_DAI_IMON_EN_MASK, |
298 | MAX98926_DAI_IMON_EN_MASK); |
299 | |
300 | if (!max98926->interleave_mode) { |
301 | /* set VMON slots */ |
302 | regmap_update_bits(map: max98926->regmap, |
303 | MAX98926_DOUT_CFG_VMON, |
304 | MAX98926_DAI_VMON_SLOT_MASK, |
305 | val: max98926->v_slot); |
306 | /* set IMON slots */ |
307 | regmap_update_bits(map: max98926->regmap, |
308 | MAX98926_DOUT_CFG_IMON, |
309 | MAX98926_DAI_IMON_SLOT_MASK, |
310 | val: max98926->i_slot); |
311 | } else { |
312 | /* enable interleave mode */ |
313 | regmap_update_bits(map: max98926->regmap, |
314 | MAX98926_FORMAT, |
315 | MAX98926_DAI_INTERLEAVE_MASK, |
316 | MAX98926_DAI_INTERLEAVE_MASK); |
317 | /* set interleave slots */ |
318 | regmap_update_bits(map: max98926->regmap, |
319 | MAX98926_DOUT_CFG_VBAT, |
320 | MAX98926_DAI_INTERLEAVE_SLOT_MASK, |
321 | val: max98926->v_slot); |
322 | } |
323 | } |
324 | |
325 | static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, |
326 | unsigned int fmt) |
327 | { |
328 | struct snd_soc_component *component = codec_dai->component; |
329 | struct max98926_priv *max98926 = snd_soc_component_get_drvdata(c: component); |
330 | unsigned int invert = 0; |
331 | |
332 | dev_dbg(component->dev, "%s: fmt 0x%08X\n" , __func__, fmt); |
333 | |
334 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
335 | case SND_SOC_DAIFMT_CBC_CFC: |
336 | max98926_set_sense_data(max98926); |
337 | break; |
338 | default: |
339 | dev_err(component->dev, "DAI clock mode unsupported\n" ); |
340 | return -EINVAL; |
341 | } |
342 | |
343 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
344 | case SND_SOC_DAIFMT_NB_NF: |
345 | break; |
346 | case SND_SOC_DAIFMT_NB_IF: |
347 | invert = MAX98926_DAI_WCI_MASK; |
348 | break; |
349 | case SND_SOC_DAIFMT_IB_NF: |
350 | invert = MAX98926_DAI_BCI_MASK; |
351 | break; |
352 | case SND_SOC_DAIFMT_IB_IF: |
353 | invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK; |
354 | break; |
355 | default: |
356 | dev_err(component->dev, "DAI invert mode unsupported\n" ); |
357 | return -EINVAL; |
358 | } |
359 | |
360 | regmap_write(map: max98926->regmap, |
361 | MAX98926_FORMAT, MAX98926_DAI_DLY_MASK); |
362 | regmap_update_bits(map: max98926->regmap, MAX98926_FORMAT, |
363 | MAX98926_DAI_BCI_MASK, val: invert); |
364 | return 0; |
365 | } |
366 | |
367 | static int max98926_dai_hw_params(struct snd_pcm_substream *substream, |
368 | struct snd_pcm_hw_params *params, |
369 | struct snd_soc_dai *dai) |
370 | { |
371 | int dai_sr = -EINVAL; |
372 | int rate = params_rate(p: params), i; |
373 | struct snd_soc_component *component = dai->component; |
374 | struct max98926_priv *max98926 = snd_soc_component_get_drvdata(c: component); |
375 | int blr_clk_ratio; |
376 | |
377 | switch (params_format(p: params)) { |
378 | case SNDRV_PCM_FORMAT_S16_LE: |
379 | regmap_update_bits(map: max98926->regmap, |
380 | MAX98926_FORMAT, |
381 | MAX98926_DAI_CHANSZ_MASK, |
382 | MAX98926_DAI_CHANSZ_16); |
383 | max98926->ch_size = 16; |
384 | break; |
385 | case SNDRV_PCM_FORMAT_S24_LE: |
386 | regmap_update_bits(map: max98926->regmap, |
387 | MAX98926_FORMAT, |
388 | MAX98926_DAI_CHANSZ_MASK, |
389 | MAX98926_DAI_CHANSZ_24); |
390 | max98926->ch_size = 24; |
391 | break; |
392 | case SNDRV_PCM_FORMAT_S32_LE: |
393 | regmap_update_bits(map: max98926->regmap, |
394 | MAX98926_FORMAT, |
395 | MAX98926_DAI_CHANSZ_MASK, |
396 | MAX98926_DAI_CHANSZ_32); |
397 | max98926->ch_size = 32; |
398 | break; |
399 | default: |
400 | dev_dbg(component->dev, "format unsupported %d\n" , |
401 | params_format(params)); |
402 | return -EINVAL; |
403 | } |
404 | |
405 | /* BCLK/LRCLK ratio calculation */ |
406 | blr_clk_ratio = params_channels(p: params) * max98926->ch_size; |
407 | |
408 | switch (blr_clk_ratio) { |
409 | case 32: |
410 | regmap_update_bits(map: max98926->regmap, |
411 | MAX98926_DAI_CLK_MODE2, |
412 | MAX98926_DAI_BSEL_MASK, |
413 | MAX98926_DAI_BSEL_32); |
414 | break; |
415 | case 48: |
416 | regmap_update_bits(map: max98926->regmap, |
417 | MAX98926_DAI_CLK_MODE2, |
418 | MAX98926_DAI_BSEL_MASK, |
419 | MAX98926_DAI_BSEL_48); |
420 | break; |
421 | case 64: |
422 | regmap_update_bits(map: max98926->regmap, |
423 | MAX98926_DAI_CLK_MODE2, |
424 | MAX98926_DAI_BSEL_MASK, |
425 | MAX98926_DAI_BSEL_64); |
426 | break; |
427 | default: |
428 | return -EINVAL; |
429 | } |
430 | |
431 | /* find the closest rate */ |
432 | for (i = 0; i < ARRAY_SIZE(rate_table); i++) { |
433 | if (rate_table[i].rate >= rate) { |
434 | dai_sr = rate_table[i].sr; |
435 | break; |
436 | } |
437 | } |
438 | if (dai_sr < 0) |
439 | return -EINVAL; |
440 | |
441 | /* set DAI_SR to correct LRCLK frequency */ |
442 | regmap_update_bits(map: max98926->regmap, |
443 | MAX98926_DAI_CLK_MODE2, |
444 | MAX98926_DAI_SR_MASK, val: dai_sr << MAX98926_DAI_SR_SHIFT); |
445 | return 0; |
446 | } |
447 | |
448 | #define MAX98926_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
449 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
450 | |
451 | static const struct snd_soc_dai_ops max98926_dai_ops = { |
452 | .set_fmt = max98926_dai_set_fmt, |
453 | .hw_params = max98926_dai_hw_params, |
454 | }; |
455 | |
456 | static struct snd_soc_dai_driver max98926_dai[] = { |
457 | { |
458 | .name = "max98926-aif1" , |
459 | .playback = { |
460 | .stream_name = "HiFi Playback" , |
461 | .channels_min = 1, |
462 | .channels_max = 2, |
463 | .rates = SNDRV_PCM_RATE_8000_48000, |
464 | .formats = MAX98926_FORMATS, |
465 | }, |
466 | .capture = { |
467 | .stream_name = "HiFi Capture" , |
468 | .channels_min = 1, |
469 | .channels_max = 2, |
470 | .rates = SNDRV_PCM_RATE_8000_48000, |
471 | .formats = MAX98926_FORMATS, |
472 | }, |
473 | .ops = &max98926_dai_ops, |
474 | } |
475 | }; |
476 | |
477 | static int max98926_probe(struct snd_soc_component *component) |
478 | { |
479 | struct max98926_priv *max98926 = snd_soc_component_get_drvdata(c: component); |
480 | |
481 | max98926->component = component; |
482 | |
483 | /* Hi-Z all the slots */ |
484 | regmap_write(map: max98926->regmap, MAX98926_DOUT_HIZ_CFG4, val: 0xF0); |
485 | return 0; |
486 | } |
487 | |
488 | static const struct snd_soc_component_driver soc_component_dev_max98926 = { |
489 | .probe = max98926_probe, |
490 | .controls = max98926_snd_controls, |
491 | .num_controls = ARRAY_SIZE(max98926_snd_controls), |
492 | .dapm_routes = max98926_audio_map, |
493 | .num_dapm_routes = ARRAY_SIZE(max98926_audio_map), |
494 | .dapm_widgets = max98926_dapm_widgets, |
495 | .num_dapm_widgets = ARRAY_SIZE(max98926_dapm_widgets), |
496 | .idle_bias_on = 1, |
497 | .use_pmdown_time = 1, |
498 | .endianness = 1, |
499 | }; |
500 | |
501 | static const struct regmap_config max98926_regmap = { |
502 | .reg_bits = 8, |
503 | .val_bits = 8, |
504 | .max_register = MAX98926_VERSION, |
505 | .reg_defaults = max98926_reg, |
506 | .num_reg_defaults = ARRAY_SIZE(max98926_reg), |
507 | .volatile_reg = max98926_volatile_register, |
508 | .readable_reg = max98926_readable_register, |
509 | .cache_type = REGCACHE_RBTREE, |
510 | }; |
511 | |
512 | static int max98926_i2c_probe(struct i2c_client *i2c) |
513 | { |
514 | int ret, reg; |
515 | u32 value; |
516 | struct max98926_priv *max98926; |
517 | |
518 | max98926 = devm_kzalloc(dev: &i2c->dev, |
519 | size: sizeof(*max98926), GFP_KERNEL); |
520 | if (!max98926) |
521 | return -ENOMEM; |
522 | |
523 | i2c_set_clientdata(client: i2c, data: max98926); |
524 | max98926->regmap = devm_regmap_init_i2c(i2c, &max98926_regmap); |
525 | if (IS_ERR(ptr: max98926->regmap)) { |
526 | ret = PTR_ERR(ptr: max98926->regmap); |
527 | dev_err(&i2c->dev, |
528 | "Failed to allocate regmap: %d\n" , ret); |
529 | goto err_out; |
530 | } |
531 | if (of_property_read_bool(np: i2c->dev.of_node, propname: "maxim,interleave-mode" ) || |
532 | of_property_read_bool(np: i2c->dev.of_node, propname: "interleave-mode" )) |
533 | max98926->interleave_mode = true; |
534 | |
535 | if (!of_property_read_u32(np: i2c->dev.of_node, propname: "vmon-slot-no" , out_value: &value)) { |
536 | if (value > MAX98926_DAI_VMON_SLOT_1E_1F) { |
537 | dev_err(&i2c->dev, "vmon slot number is wrong:\n" ); |
538 | return -EINVAL; |
539 | } |
540 | max98926->v_slot = value; |
541 | } |
542 | if (!of_property_read_u32(np: i2c->dev.of_node, propname: "imon-slot-no" , out_value: &value)) { |
543 | if (value > MAX98926_DAI_IMON_SLOT_1E_1F) { |
544 | dev_err(&i2c->dev, "imon slot number is wrong:\n" ); |
545 | return -EINVAL; |
546 | } |
547 | max98926->i_slot = value; |
548 | } |
549 | ret = regmap_read(map: max98926->regmap, |
550 | MAX98926_VERSION, val: ®); |
551 | if (ret < 0) { |
552 | dev_err(&i2c->dev, "Failed to read: %x\n" , reg); |
553 | return ret; |
554 | } |
555 | |
556 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
557 | component_driver: &soc_component_dev_max98926, |
558 | dai_drv: max98926_dai, ARRAY_SIZE(max98926_dai)); |
559 | if (ret < 0) |
560 | dev_err(&i2c->dev, |
561 | "Failed to register component: %d\n" , ret); |
562 | dev_info(&i2c->dev, "device version: %x\n" , reg); |
563 | err_out: |
564 | return ret; |
565 | } |
566 | |
567 | static const struct i2c_device_id max98926_i2c_id[] = { |
568 | { "max98926" , 0 }, |
569 | { } |
570 | }; |
571 | MODULE_DEVICE_TABLE(i2c, max98926_i2c_id); |
572 | |
573 | #ifdef CONFIG_OF |
574 | static const struct of_device_id max98926_of_match[] = { |
575 | { .compatible = "maxim,max98926" , }, |
576 | { } |
577 | }; |
578 | MODULE_DEVICE_TABLE(of, max98926_of_match); |
579 | #endif |
580 | |
581 | static struct i2c_driver max98926_i2c_driver = { |
582 | .driver = { |
583 | .name = "max98926" , |
584 | .of_match_table = of_match_ptr(max98926_of_match), |
585 | }, |
586 | .probe = max98926_i2c_probe, |
587 | .id_table = max98926_i2c_id, |
588 | }; |
589 | |
590 | module_i2c_driver(max98926_i2c_driver) |
591 | MODULE_DESCRIPTION("ALSA SoC MAX98926 driver" ); |
592 | MODULE_AUTHOR("Anish kumar <anish.kumar@maximintegrated.com>" ); |
593 | MODULE_LICENSE("GPL" ); |
594 | |