]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
a2e2876a | 2 | /* |
3 | * max98926.c -- ALSA SoC MAX98926 driver | |
4 | * Copyright 2013-15 Maxim Integrated Products | |
a2e2876a | 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 | ||
a2e2876a | 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 | ||
e354d86e | 32 | static const struct reg_default max98926_reg[] = { |
a2e2876a | 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 | ||
9ab51b94 CIK |
205 | static DECLARE_TLV_DB_SCALE(max98926_spk_tlv, -600, 100, 0); |
206 | static DECLARE_TLV_DB_RANGE(max98926_current_tlv, | |
a2e2876a | 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(max98926->regmap, | |
292 | MAX98926_DOUT_CFG_VMON, | |
293 | MAX98926_DAI_VMON_EN_MASK, | |
294 | MAX98926_DAI_VMON_EN_MASK); | |
295 | regmap_update_bits(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(max98926->regmap, | |
303 | MAX98926_DOUT_CFG_VMON, | |
304 | MAX98926_DAI_VMON_SLOT_MASK, | |
305 | max98926->v_slot); | |
306 | /* set IMON slots */ | |
307 | regmap_update_bits(max98926->regmap, | |
308 | MAX98926_DOUT_CFG_IMON, | |
309 | MAX98926_DAI_IMON_SLOT_MASK, | |
310 | max98926->i_slot); | |
311 | } else { | |
312 | /* enable interleave mode */ | |
313 | regmap_update_bits(max98926->regmap, | |
314 | MAX98926_FORMAT, | |
315 | MAX98926_DAI_INTERLEAVE_MASK, | |
316 | MAX98926_DAI_INTERLEAVE_MASK); | |
317 | /* set interleave slots */ | |
318 | regmap_update_bits(max98926->regmap, | |
319 | MAX98926_DOUT_CFG_VBAT, | |
320 | MAX98926_DAI_INTERLEAVE_SLOT_MASK, | |
321 | max98926->v_slot); | |
322 | } | |
323 | } | |
324 | ||
325 | static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, | |
326 | unsigned int fmt) | |
327 | { | |
6f2b5d0d KM |
328 | struct snd_soc_component *component = codec_dai->component; |
329 | struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component); | |
a2e2876a | 330 | unsigned int invert = 0; |
331 | ||
6f2b5d0d | 332 | dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); |
a2e2876a | 333 | |
334 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | |
335 | case SND_SOC_DAIFMT_CBS_CFS: | |
336 | max98926_set_sense_data(max98926); | |
337 | break; | |
338 | default: | |
6f2b5d0d | 339 | dev_err(component->dev, "DAI clock mode unsupported\n"); |
a2e2876a | 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: | |
6f2b5d0d | 356 | dev_err(component->dev, "DAI invert mode unsupported\n"); |
a2e2876a | 357 | return -EINVAL; |
358 | } | |
359 | ||
360 | regmap_write(max98926->regmap, | |
361 | MAX98926_FORMAT, MAX98926_DAI_DLY_MASK); | |
362 | regmap_update_bits(max98926->regmap, MAX98926_FORMAT, | |
363 | MAX98926_DAI_BCI_MASK, 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(params), i; | |
6f2b5d0d KM |
373 | struct snd_soc_component *component = dai->component; |
374 | struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component); | |
cffee535 | 375 | int blr_clk_ratio; |
a2e2876a | 376 | |
377 | switch (params_format(params)) { | |
378 | case SNDRV_PCM_FORMAT_S16_LE: | |
379 | regmap_update_bits(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(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(max98926->regmap, | |
394 | MAX98926_FORMAT, | |
395 | MAX98926_DAI_CHANSZ_MASK, | |
396 | MAX98926_DAI_CHANSZ_32); | |
397 | max98926->ch_size = 32; | |
398 | break; | |
399 | default: | |
6f2b5d0d | 400 | dev_dbg(component->dev, "format unsupported %d\n", |
a2e2876a | 401 | params_format(params)); |
402 | return -EINVAL; | |
403 | } | |
404 | ||
cffee535 AL |
405 | /* BCLK/LRCLK ratio calculation */ |
406 | blr_clk_ratio = params_channels(params) * max98926->ch_size; | |
407 | ||
a2e2876a | 408 | switch (blr_clk_ratio) { |
409 | case 32: | |
410 | regmap_update_bits(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(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(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(max98926->regmap, | |
443 | MAX98926_DAI_CLK_MODE2, | |
444 | MAX98926_DAI_SR_MASK, 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 | ||
eb59d73c | 451 | static const struct snd_soc_dai_ops max98926_dai_ops = { |
a2e2876a | 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 | ||
6f2b5d0d | 477 | static int max98926_probe(struct snd_soc_component *component) |
a2e2876a | 478 | { |
6f2b5d0d | 479 | struct max98926_priv *max98926 = snd_soc_component_get_drvdata(component); |
a2e2876a | 480 | |
6f2b5d0d | 481 | max98926->component = component; |
866b9c81 | 482 | |
a2e2876a | 483 | /* Hi-Z all the slots */ |
484 | regmap_write(max98926->regmap, MAX98926_DOUT_HIZ_CFG4, 0xF0); | |
485 | return 0; | |
486 | } | |
487 | ||
6f2b5d0d KM |
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 | .non_legacy_dai_naming = 1, | |
a2e2876a | 500 | }; |
501 | ||
e354d86e | 502 | static const struct regmap_config max98926_regmap = { |
a2e2876a | 503 | .reg_bits = 8, |
504 | .val_bits = 8, | |
505 | .max_register = MAX98926_VERSION, | |
506 | .reg_defaults = max98926_reg, | |
507 | .num_reg_defaults = ARRAY_SIZE(max98926_reg), | |
508 | .volatile_reg = max98926_volatile_register, | |
509 | .readable_reg = max98926_readable_register, | |
510 | .cache_type = REGCACHE_RBTREE, | |
511 | }; | |
512 | ||
513 | static int max98926_i2c_probe(struct i2c_client *i2c, | |
514 | const struct i2c_device_id *id) | |
515 | { | |
516 | int ret, reg; | |
517 | u32 value; | |
518 | struct max98926_priv *max98926; | |
519 | ||
520 | max98926 = devm_kzalloc(&i2c->dev, | |
521 | sizeof(*max98926), GFP_KERNEL); | |
522 | if (!max98926) | |
523 | return -ENOMEM; | |
524 | ||
525 | i2c_set_clientdata(i2c, max98926); | |
526 | max98926->regmap = devm_regmap_init_i2c(i2c, &max98926_regmap); | |
527 | if (IS_ERR(max98926->regmap)) { | |
528 | ret = PTR_ERR(max98926->regmap); | |
529 | dev_err(&i2c->dev, | |
530 | "Failed to allocate regmap: %d\n", ret); | |
531 | goto err_out; | |
532 | } | |
533 | if (of_property_read_bool(i2c->dev.of_node, "interleave-mode")) | |
534 | max98926->interleave_mode = true; | |
535 | ||
536 | if (!of_property_read_u32(i2c->dev.of_node, "vmon-slot-no", &value)) { | |
537 | if (value > MAX98926_DAI_VMON_SLOT_1E_1F) { | |
538 | dev_err(&i2c->dev, "vmon slot number is wrong:\n"); | |
539 | return -EINVAL; | |
540 | } | |
541 | max98926->v_slot = value; | |
542 | } | |
543 | if (!of_property_read_u32(i2c->dev.of_node, "imon-slot-no", &value)) { | |
544 | if (value > MAX98926_DAI_IMON_SLOT_1E_1F) { | |
545 | dev_err(&i2c->dev, "imon slot number is wrong:\n"); | |
546 | return -EINVAL; | |
547 | } | |
548 | max98926->i_slot = value; | |
549 | } | |
550 | ret = regmap_read(max98926->regmap, | |
551 | MAX98926_VERSION, ®); | |
552 | if (ret < 0) { | |
553 | dev_err(&i2c->dev, "Failed to read: %x\n", reg); | |
554 | return ret; | |
555 | } | |
556 | ||
6f2b5d0d KM |
557 | ret = devm_snd_soc_register_component(&i2c->dev, |
558 | &soc_component_dev_max98926, | |
a2e2876a | 559 | max98926_dai, ARRAY_SIZE(max98926_dai)); |
560 | if (ret < 0) | |
561 | dev_err(&i2c->dev, | |
6f2b5d0d | 562 | "Failed to register component: %d\n", ret); |
a2e2876a | 563 | dev_info(&i2c->dev, "device version: %x\n", reg); |
564 | err_out: | |
565 | return ret; | |
566 | } | |
567 | ||
a2e2876a | 568 | static const struct i2c_device_id max98926_i2c_id[] = { |
569 | { "max98926", 0 }, | |
570 | { } | |
571 | }; | |
572 | MODULE_DEVICE_TABLE(i2c, max98926_i2c_id); | |
573 | ||
fff68ff6 | 574 | #ifdef CONFIG_OF |
a2e2876a | 575 | static const struct of_device_id max98926_of_match[] = { |
576 | { .compatible = "maxim,max98926", }, | |
577 | { } | |
578 | }; | |
579 | MODULE_DEVICE_TABLE(of, max98926_of_match); | |
fff68ff6 | 580 | #endif |
a2e2876a | 581 | |
582 | static struct i2c_driver max98926_i2c_driver = { | |
583 | .driver = { | |
584 | .name = "max98926", | |
585 | .of_match_table = of_match_ptr(max98926_of_match), | |
a2e2876a | 586 | }, |
587 | .probe = max98926_i2c_probe, | |
a2e2876a | 588 | .id_table = max98926_i2c_id, |
589 | }; | |
590 | ||
591 | module_i2c_driver(max98926_i2c_driver) | |
592 | MODULE_DESCRIPTION("ALSA SoC MAX98926 driver"); | |
593 | MODULE_AUTHOR("Anish kumar <anish.kumar@maximintegrated.com>"); | |
594 | MODULE_LICENSE("GPL"); |