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