1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // MAX9867 ALSA SoC codec driver |
4 | // |
5 | // Copyright 2013-2015 Maxim Integrated Products |
6 | // Copyright 2018 Ladislav Michl <ladis@linux-mips.org> |
7 | // |
8 | |
9 | #include <linux/clk.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/module.h> |
13 | #include <linux/regmap.h> |
14 | #include <sound/pcm_params.h> |
15 | #include <sound/soc.h> |
16 | #include <sound/tlv.h> |
17 | #include "max9867.h" |
18 | |
19 | struct max9867_priv { |
20 | struct clk *mclk; |
21 | struct regmap *regmap; |
22 | const struct snd_pcm_hw_constraint_list *constraints; |
23 | unsigned int sysclk, pclk; |
24 | bool provider, dsp_a; |
25 | unsigned int adc_dac_active; |
26 | }; |
27 | |
28 | static const char *const max9867_spmode[] = { |
29 | "Stereo Diff" , "Mono Diff" , |
30 | "Stereo Cap" , "Mono Cap" , |
31 | "Stereo Single" , "Mono Single" , |
32 | "Stereo Single Fast" , "Mono Single Fast" |
33 | }; |
34 | static const char *const max9867_filter_text[] = {"IIR" , "FIR" }; |
35 | |
36 | static const char *const max9867_adc_dac_filter_text[] = { |
37 | "Disabled" , |
38 | "Elliptical/16/256" , |
39 | "Butterworth/16/500" , |
40 | "Elliptical/8/256" , |
41 | "Butterworth/8/500" , |
42 | "Butterworth/8-24" |
43 | }; |
44 | |
45 | enum max9867_adc_dac { |
46 | MAX9867_ADC_LEFT, |
47 | MAX9867_ADC_RIGHT, |
48 | MAX9867_DAC_LEFT, |
49 | MAX9867_DAC_RIGHT, |
50 | }; |
51 | |
52 | static int max9867_adc_dac_event(struct snd_soc_dapm_widget *w, |
53 | struct snd_kcontrol *kcontrol, int event) |
54 | { |
55 | struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm); |
56 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
57 | enum max9867_adc_dac adc_dac; |
58 | |
59 | if (!snd_soc_dapm_widget_name_cmp(widget: w, s: "ADCL" )) |
60 | adc_dac = MAX9867_ADC_LEFT; |
61 | else if (!snd_soc_dapm_widget_name_cmp(widget: w, s: "ADCR" )) |
62 | adc_dac = MAX9867_ADC_RIGHT; |
63 | else if (!snd_soc_dapm_widget_name_cmp(widget: w, s: "DACL" )) |
64 | adc_dac = MAX9867_DAC_LEFT; |
65 | else if (!snd_soc_dapm_widget_name_cmp(widget: w, s: "DACR" )) |
66 | adc_dac = MAX9867_DAC_RIGHT; |
67 | else |
68 | return 0; |
69 | |
70 | if (SND_SOC_DAPM_EVENT_ON(event)) |
71 | max9867->adc_dac_active |= BIT(adc_dac); |
72 | else if (SND_SOC_DAPM_EVENT_OFF(event)) |
73 | max9867->adc_dac_active &= ~BIT(adc_dac); |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | static int max9867_filter_get(struct snd_kcontrol *kcontrol, |
79 | struct snd_ctl_elem_value *ucontrol) |
80 | { |
81 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
82 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
83 | unsigned int reg; |
84 | int ret; |
85 | |
86 | ret = regmap_read(map: max9867->regmap, MAX9867_CODECFLTR, val: ®); |
87 | if (ret) |
88 | return -EINVAL; |
89 | |
90 | if (reg & MAX9867_CODECFLTR_MODE) |
91 | ucontrol->value.enumerated.item[0] = 1; |
92 | else |
93 | ucontrol->value.enumerated.item[0] = 0; |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | static int max9867_filter_set(struct snd_kcontrol *kcontrol, |
99 | struct snd_ctl_elem_value *ucontrol) |
100 | { |
101 | struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); |
102 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
103 | unsigned int reg, mode = ucontrol->value.enumerated.item[0]; |
104 | int ret; |
105 | |
106 | if (mode > 1) |
107 | return -EINVAL; |
108 | |
109 | /* don't allow change if ADC/DAC active */ |
110 | if (max9867->adc_dac_active) |
111 | return -EBUSY; |
112 | |
113 | /* read current filter mode */ |
114 | ret = regmap_read(map: max9867->regmap, MAX9867_CODECFLTR, val: ®); |
115 | if (ret) |
116 | return -EINVAL; |
117 | |
118 | if (mode) |
119 | mode = MAX9867_CODECFLTR_MODE; |
120 | |
121 | /* check if change is needed */ |
122 | if ((reg & MAX9867_CODECFLTR_MODE) == mode) |
123 | return 0; |
124 | |
125 | /* shutdown codec before switching filter mode */ |
126 | regmap_update_bits(map: max9867->regmap, MAX9867_PWRMAN, |
127 | MAX9867_PWRMAN_SHDN, val: 0); |
128 | |
129 | /* switch filter mode */ |
130 | regmap_update_bits(map: max9867->regmap, MAX9867_CODECFLTR, |
131 | MAX9867_CODECFLTR_MODE, val: mode); |
132 | |
133 | /* out of shutdown now */ |
134 | regmap_update_bits(map: max9867->regmap, MAX9867_PWRMAN, |
135 | MAX9867_PWRMAN_SHDN, MAX9867_PWRMAN_SHDN); |
136 | |
137 | return 0; |
138 | } |
139 | |
140 | static SOC_ENUM_SINGLE_EXT_DECL(max9867_filter, max9867_filter_text); |
141 | static SOC_ENUM_SINGLE_DECL(max9867_dac_filter, MAX9867_CODECFLTR, 0, |
142 | max9867_adc_dac_filter_text); |
143 | static SOC_ENUM_SINGLE_DECL(max9867_adc_filter, MAX9867_CODECFLTR, 4, |
144 | max9867_adc_dac_filter_text); |
145 | static SOC_ENUM_SINGLE_DECL(max9867_spkmode, MAX9867_MODECONFIG, 0, |
146 | max9867_spmode); |
147 | static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_master_tlv, |
148 | 0, 2, TLV_DB_SCALE_ITEM(-8600, 200, 1), |
149 | 3, 17, TLV_DB_SCALE_ITEM(-7800, 400, 0), |
150 | 18, 25, TLV_DB_SCALE_ITEM(-2000, 200, 0), |
151 | 26, 34, TLV_DB_SCALE_ITEM( -500, 100, 0), |
152 | 35, 40, TLV_DB_SCALE_ITEM( 350, 50, 0), |
153 | ); |
154 | static DECLARE_TLV_DB_SCALE(max9867_mic_tlv, 0, 100, 0); |
155 | static DECLARE_TLV_DB_SCALE(max9867_line_tlv, -600, 200, 0); |
156 | static DECLARE_TLV_DB_SCALE(max9867_adc_tlv, -1200, 100, 0); |
157 | static DECLARE_TLV_DB_SCALE(max9867_dac_tlv, -1500, 100, 0); |
158 | static DECLARE_TLV_DB_SCALE(max9867_dacboost_tlv, 0, 600, 0); |
159 | static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max9867_micboost_tlv, |
160 | 0, 2, TLV_DB_SCALE_ITEM(-2000, 2000, 1), |
161 | 3, 3, TLV_DB_SCALE_ITEM(3000, 0, 0), |
162 | ); |
163 | |
164 | static const struct snd_kcontrol_new max9867_snd_controls[] = { |
165 | SOC_DOUBLE_R_TLV("Master Playback Volume" , MAX9867_LEFTVOL, |
166 | MAX9867_RIGHTVOL, 0, 40, 1, max9867_master_tlv), |
167 | SOC_DOUBLE_R_TLV("Line Capture Volume" , MAX9867_LEFTLINELVL, |
168 | MAX9867_RIGHTLINELVL, 0, 15, 1, max9867_line_tlv), |
169 | SOC_DOUBLE_R_TLV("Mic Capture Volume" , MAX9867_LEFTMICGAIN, |
170 | MAX9867_RIGHTMICGAIN, 0, 20, 1, max9867_mic_tlv), |
171 | SOC_DOUBLE_R_TLV("Mic Boost Capture Volume" , MAX9867_LEFTMICGAIN, |
172 | MAX9867_RIGHTMICGAIN, 5, 3, 0, max9867_micboost_tlv), |
173 | SOC_SINGLE("Digital Sidetone Volume" , MAX9867_SIDETONE, 0, 31, 1), |
174 | SOC_SINGLE_TLV("Digital Playback Volume" , MAX9867_DACLEVEL, 0, 15, 1, |
175 | max9867_dac_tlv), |
176 | SOC_SINGLE_TLV("Digital Boost Playback Volume" , MAX9867_DACLEVEL, 4, 3, 0, |
177 | max9867_dacboost_tlv), |
178 | SOC_DOUBLE_TLV("Digital Capture Volume" , MAX9867_ADCLEVEL, 4, 0, 15, 1, |
179 | max9867_adc_tlv), |
180 | SOC_ENUM("Speaker Mode" , max9867_spkmode), |
181 | SOC_SINGLE("Volume Smoothing Switch" , MAX9867_MODECONFIG, 6, 1, 0), |
182 | SOC_SINGLE("Line ZC Switch" , MAX9867_MODECONFIG, 5, 1, 0), |
183 | SOC_ENUM_EXT("DSP Filter" , max9867_filter, max9867_filter_get, max9867_filter_set), |
184 | SOC_ENUM("ADC Filter" , max9867_adc_filter), |
185 | SOC_ENUM("DAC Filter" , max9867_dac_filter), |
186 | SOC_SINGLE("Mono Playback Switch" , MAX9867_IFC1B, 3, 1, 0), |
187 | }; |
188 | |
189 | /* Input mixer */ |
190 | static const struct snd_kcontrol_new max9867_input_mixer_controls[] = { |
191 | SOC_DAPM_DOUBLE("Line Capture Switch" , MAX9867_INPUTCONFIG, 7, 5, 1, 0), |
192 | SOC_DAPM_DOUBLE("Mic Capture Switch" , MAX9867_INPUTCONFIG, 6, 4, 1, 0), |
193 | }; |
194 | |
195 | /* Output mixer */ |
196 | static const struct snd_kcontrol_new max9867_output_mixer_controls[] = { |
197 | SOC_DAPM_DOUBLE_R("Line Bypass Switch" , |
198 | MAX9867_LEFTLINELVL, MAX9867_RIGHTLINELVL, 6, 1, 1), |
199 | }; |
200 | |
201 | /* Sidetone mixer */ |
202 | static const struct snd_kcontrol_new max9867_sidetone_mixer_controls[] = { |
203 | SOC_DAPM_DOUBLE("Sidetone Switch" , MAX9867_SIDETONE, 6, 7, 1, 0), |
204 | }; |
205 | |
206 | /* Line out switch */ |
207 | static const struct snd_kcontrol_new max9867_line_out_control = |
208 | SOC_DAPM_DOUBLE_R("Switch" , |
209 | MAX9867_LEFTVOL, MAX9867_RIGHTVOL, 6, 1, 1); |
210 | |
211 | /* DMIC mux */ |
212 | static const char *const dmic_mux_text[] = { |
213 | "ADC" , "DMIC" |
214 | }; |
215 | static SOC_ENUM_SINGLE_DECL(left_dmic_mux_enum, |
216 | MAX9867_MICCONFIG, 5, dmic_mux_text); |
217 | static SOC_ENUM_SINGLE_DECL(right_dmic_mux_enum, |
218 | MAX9867_MICCONFIG, 4, dmic_mux_text); |
219 | static const struct snd_kcontrol_new max9867_left_dmic_mux = |
220 | SOC_DAPM_ENUM("DMICL Mux" , left_dmic_mux_enum); |
221 | static const struct snd_kcontrol_new max9867_right_dmic_mux = |
222 | SOC_DAPM_ENUM("DMICR Mux" , right_dmic_mux_enum); |
223 | |
224 | static const struct snd_soc_dapm_widget max9867_dapm_widgets[] = { |
225 | SND_SOC_DAPM_INPUT("MICL" ), |
226 | SND_SOC_DAPM_INPUT("MICR" ), |
227 | SND_SOC_DAPM_INPUT("DMICL" ), |
228 | SND_SOC_DAPM_INPUT("DMICR" ), |
229 | SND_SOC_DAPM_INPUT("LINL" ), |
230 | SND_SOC_DAPM_INPUT("LINR" ), |
231 | |
232 | SND_SOC_DAPM_PGA("Left Line Input" , SND_SOC_NOPM, 0, 0, NULL, 0), |
233 | SND_SOC_DAPM_PGA("Right Line Input" , SND_SOC_NOPM, 0, 0, NULL, 0), |
234 | SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer" , SND_SOC_NOPM, 0, 0, |
235 | max9867_input_mixer_controls, |
236 | ARRAY_SIZE(max9867_input_mixer_controls)), |
237 | SND_SOC_DAPM_MUX("DMICL Mux" , SND_SOC_NOPM, 0, 0, |
238 | &max9867_left_dmic_mux), |
239 | SND_SOC_DAPM_MUX("DMICR Mux" , SND_SOC_NOPM, 0, 0, |
240 | &max9867_right_dmic_mux), |
241 | SND_SOC_DAPM_ADC_E("ADCL" , "HiFi Capture" , SND_SOC_NOPM, 0, 0, |
242 | max9867_adc_dac_event, |
243 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
244 | SND_SOC_DAPM_ADC_E("ADCR" , "HiFi Capture" , SND_SOC_NOPM, 0, 0, |
245 | max9867_adc_dac_event, |
246 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
247 | |
248 | SND_SOC_DAPM_MIXER("Digital" , SND_SOC_NOPM, 0, 0, |
249 | max9867_sidetone_mixer_controls, |
250 | ARRAY_SIZE(max9867_sidetone_mixer_controls)), |
251 | SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer" , SND_SOC_NOPM, 0, 0, |
252 | max9867_output_mixer_controls, |
253 | ARRAY_SIZE(max9867_output_mixer_controls)), |
254 | SND_SOC_DAPM_DAC_E("DACL" , "HiFi Playback" , SND_SOC_NOPM, 0, 0, |
255 | max9867_adc_dac_event, |
256 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
257 | SND_SOC_DAPM_DAC_E("DACR" , "HiFi Playback" , SND_SOC_NOPM, 0, 0, |
258 | max9867_adc_dac_event, |
259 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
260 | SND_SOC_DAPM_SWITCH("Master Playback" , SND_SOC_NOPM, 0, 0, |
261 | &max9867_line_out_control), |
262 | SND_SOC_DAPM_OUTPUT("LOUT" ), |
263 | SND_SOC_DAPM_OUTPUT("ROUT" ), |
264 | }; |
265 | |
266 | static const struct snd_soc_dapm_route max9867_audio_map[] = { |
267 | {"Left Line Input" , NULL, "LINL" }, |
268 | {"Right Line Input" , NULL, "LINR" }, |
269 | {"Input Mixer" , "Mic Capture Switch" , "MICL" }, |
270 | {"Input Mixer" , "Mic Capture Switch" , "MICR" }, |
271 | {"Input Mixer" , "Line Capture Switch" , "Left Line Input" }, |
272 | {"Input Mixer" , "Line Capture Switch" , "Right Line Input" }, |
273 | {"DMICL Mux" , "DMIC" , "DMICL" }, |
274 | {"DMICR Mux" , "DMIC" , "DMICR" }, |
275 | {"DMICL Mux" , "ADC" , "Input Mixer" }, |
276 | {"DMICR Mux" , "ADC" , "Input Mixer" }, |
277 | {"ADCL" , NULL, "DMICL Mux" }, |
278 | {"ADCR" , NULL, "DMICR Mux" }, |
279 | |
280 | {"Digital" , "Sidetone Switch" , "ADCL" }, |
281 | {"Digital" , "Sidetone Switch" , "ADCR" }, |
282 | {"DACL" , NULL, "Digital" }, |
283 | {"DACR" , NULL, "Digital" }, |
284 | |
285 | {"Output Mixer" , "Line Bypass Switch" , "Left Line Input" }, |
286 | {"Output Mixer" , "Line Bypass Switch" , "Right Line Input" }, |
287 | {"Output Mixer" , NULL, "DACL" }, |
288 | {"Output Mixer" , NULL, "DACR" }, |
289 | {"Master Playback" , "Switch" , "Output Mixer" }, |
290 | {"LOUT" , NULL, "Master Playback" }, |
291 | {"ROUT" , NULL, "Master Playback" }, |
292 | }; |
293 | |
294 | static const unsigned int max9867_rates_44k1[] = { |
295 | 11025, 22050, 44100, |
296 | }; |
297 | |
298 | static const struct snd_pcm_hw_constraint_list max9867_constraints_44k1 = { |
299 | .list = max9867_rates_44k1, |
300 | .count = ARRAY_SIZE(max9867_rates_44k1), |
301 | }; |
302 | |
303 | static const unsigned int max9867_rates_48k[] = { |
304 | 8000, 16000, 32000, 48000, |
305 | }; |
306 | |
307 | static const struct snd_pcm_hw_constraint_list max9867_constraints_48k = { |
308 | .list = max9867_rates_48k, |
309 | .count = ARRAY_SIZE(max9867_rates_48k), |
310 | }; |
311 | |
312 | static int max9867_startup(struct snd_pcm_substream *substream, |
313 | struct snd_soc_dai *dai) |
314 | { |
315 | struct max9867_priv *max9867 = |
316 | snd_soc_component_get_drvdata(c: dai->component); |
317 | |
318 | if (max9867->constraints) |
319 | snd_pcm_hw_constraint_list(runtime: substream->runtime, cond: 0, |
320 | SNDRV_PCM_HW_PARAM_RATE, l: max9867->constraints); |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | static int max9867_dai_hw_params(struct snd_pcm_substream *substream, |
326 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
327 | { |
328 | int value, freq = 0; |
329 | unsigned long int rate, ratio; |
330 | struct snd_soc_component *component = dai->component; |
331 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
332 | unsigned int ni = DIV_ROUND_CLOSEST_ULL(96ULL * 0x10000 * params_rate(params), |
333 | max9867->pclk); |
334 | |
335 | /* set up the ni value */ |
336 | regmap_update_bits(map: max9867->regmap, MAX9867_AUDIOCLKHIGH, |
337 | MAX9867_NI_HIGH_MASK, val: (0xFF00 & ni) >> 8); |
338 | regmap_update_bits(map: max9867->regmap, MAX9867_AUDIOCLKLOW, |
339 | MAX9867_NI_LOW_MASK, val: 0x00FF & ni); |
340 | if (max9867->provider) { |
341 | if (max9867->dsp_a) { |
342 | value = MAX9867_IFC1B_48X; |
343 | } else { |
344 | rate = params_rate(p: params) * 2 * params_width(p: params); |
345 | ratio = max9867->pclk / rate; |
346 | switch (params_width(p: params)) { |
347 | case 8: |
348 | case 16: |
349 | switch (ratio) { |
350 | case 2: |
351 | value = MAX9867_IFC1B_PCLK_2; |
352 | break; |
353 | case 4: |
354 | value = MAX9867_IFC1B_PCLK_4; |
355 | break; |
356 | case 8: |
357 | value = MAX9867_IFC1B_PCLK_8; |
358 | break; |
359 | case 16: |
360 | value = MAX9867_IFC1B_PCLK_16; |
361 | break; |
362 | default: |
363 | return -EINVAL; |
364 | } |
365 | break; |
366 | case 24: |
367 | value = MAX9867_IFC1B_48X; |
368 | break; |
369 | case 32: |
370 | value = MAX9867_IFC1B_64X; |
371 | break; |
372 | default: |
373 | return -EINVAL; |
374 | } |
375 | } |
376 | regmap_update_bits(map: max9867->regmap, MAX9867_IFC1B, |
377 | MAX9867_IFC1B_BCLK_MASK, val: value); |
378 | |
379 | /* Exact integer mode available for 8kHz and 16kHz sample rates |
380 | * and certain PCLK (prescaled MCLK) values. |
381 | */ |
382 | if (params_rate(p: params) == 8000 || |
383 | params_rate(p: params) == 16000) { |
384 | switch (max9867->pclk) { |
385 | case 12000000: |
386 | freq = 0x08; |
387 | break; |
388 | case 13000000: |
389 | freq = 0x0A; |
390 | break; |
391 | case 16000000: |
392 | freq = 0x0C; |
393 | break; |
394 | case 19200000: |
395 | freq = 0x0E; |
396 | break; |
397 | } |
398 | } |
399 | if (freq && params_rate(p: params) == 16000) |
400 | freq++; |
401 | |
402 | /* If exact integer mode not available, the freq value |
403 | * remains zero, i.e. normal mode is used. |
404 | */ |
405 | regmap_update_bits(map: max9867->regmap, MAX9867_SYSCLK, |
406 | MAX9867_FREQ_MASK, val: freq); |
407 | } else { |
408 | /* |
409 | * digital pll locks on to any externally supplied LRCLK signal |
410 | * and also enable rapid lock mode. |
411 | */ |
412 | regmap_update_bits(map: max9867->regmap, MAX9867_AUDIOCLKLOW, |
413 | MAX9867_RAPID_LOCK, MAX9867_RAPID_LOCK); |
414 | regmap_update_bits(map: max9867->regmap, MAX9867_AUDIOCLKHIGH, |
415 | MAX9867_PLL, MAX9867_PLL); |
416 | } |
417 | return 0; |
418 | } |
419 | |
420 | static int max9867_mute(struct snd_soc_dai *dai, int mute, int direction) |
421 | { |
422 | struct snd_soc_component *component = dai->component; |
423 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
424 | |
425 | return regmap_update_bits(map: max9867->regmap, MAX9867_DACLEVEL, |
426 | mask: 1 << 6, val: !!mute << 6); |
427 | } |
428 | |
429 | static int max9867_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
430 | int clk_id, unsigned int freq, int dir) |
431 | { |
432 | struct snd_soc_component *component = codec_dai->component; |
433 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
434 | int value = 0; |
435 | |
436 | /* Set the prescaler based on the master clock frequency*/ |
437 | if (freq >= 10000000 && freq <= 20000000) { |
438 | value |= MAX9867_PSCLK_10_20; |
439 | max9867->pclk = freq; |
440 | } else if (freq >= 20000000 && freq <= 40000000) { |
441 | value |= MAX9867_PSCLK_20_40; |
442 | max9867->pclk = freq / 2; |
443 | } else if (freq >= 40000000 && freq <= 60000000) { |
444 | value |= MAX9867_PSCLK_40_60; |
445 | max9867->pclk = freq / 4; |
446 | } else { |
447 | dev_err(component->dev, |
448 | "Invalid clock frequency %uHz (required 10-60MHz)\n" , |
449 | freq); |
450 | return -EINVAL; |
451 | } |
452 | if (freq % 48000 == 0) |
453 | max9867->constraints = &max9867_constraints_48k; |
454 | else if (freq % 44100 == 0) |
455 | max9867->constraints = &max9867_constraints_44k1; |
456 | else |
457 | dev_warn(component->dev, |
458 | "Unable to set exact rate with %uHz clock frequency\n" , |
459 | freq); |
460 | max9867->sysclk = freq; |
461 | value = value << MAX9867_PSCLK_SHIFT; |
462 | regmap_update_bits(map: max9867->regmap, MAX9867_SYSCLK, |
463 | MAX9867_PSCLK_MASK, val: value); |
464 | return 0; |
465 | } |
466 | |
467 | static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai, |
468 | unsigned int fmt) |
469 | { |
470 | struct snd_soc_component *component = codec_dai->component; |
471 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
472 | u8 iface1A, iface1B; |
473 | |
474 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
475 | case SND_SOC_DAIFMT_CBP_CFP: |
476 | max9867->provider = true; |
477 | iface1A = MAX9867_MASTER; |
478 | iface1B = MAX9867_IFC1B_48X; |
479 | break; |
480 | case SND_SOC_DAIFMT_CBC_CFC: |
481 | max9867->provider = false; |
482 | iface1A = iface1B = 0; |
483 | break; |
484 | default: |
485 | return -EINVAL; |
486 | } |
487 | |
488 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
489 | case SND_SOC_DAIFMT_I2S: |
490 | max9867->dsp_a = false; |
491 | iface1A |= MAX9867_I2S_DLY; |
492 | break; |
493 | case SND_SOC_DAIFMT_DSP_A: |
494 | max9867->dsp_a = true; |
495 | iface1A |= MAX9867_TDM_MODE | MAX9867_SDOUT_HIZ; |
496 | break; |
497 | default: |
498 | return -EINVAL; |
499 | } |
500 | |
501 | /* Clock inversion bits, BCI and WCI */ |
502 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
503 | case SND_SOC_DAIFMT_NB_NF: |
504 | break; |
505 | case SND_SOC_DAIFMT_IB_IF: |
506 | iface1A |= MAX9867_WCI_MODE | MAX9867_BCI_MODE; |
507 | break; |
508 | case SND_SOC_DAIFMT_IB_NF: |
509 | iface1A |= MAX9867_BCI_MODE; |
510 | break; |
511 | case SND_SOC_DAIFMT_NB_IF: |
512 | iface1A |= MAX9867_WCI_MODE; |
513 | break; |
514 | default: |
515 | return -EINVAL; |
516 | } |
517 | |
518 | regmap_write(map: max9867->regmap, MAX9867_IFC1A, val: iface1A); |
519 | regmap_update_bits(map: max9867->regmap, MAX9867_IFC1B, |
520 | MAX9867_IFC1B_BCLK_MASK, val: iface1B); |
521 | |
522 | return 0; |
523 | } |
524 | |
525 | static const struct snd_soc_dai_ops max9867_dai_ops = { |
526 | .set_sysclk = max9867_set_dai_sysclk, |
527 | .set_fmt = max9867_dai_set_fmt, |
528 | .mute_stream = max9867_mute, |
529 | .startup = max9867_startup, |
530 | .hw_params = max9867_dai_hw_params, |
531 | .no_capture_mute = 1, |
532 | }; |
533 | |
534 | static struct snd_soc_dai_driver max9867_dai[] = { |
535 | { |
536 | .name = "max9867-aif1" , |
537 | .playback = { |
538 | .stream_name = "HiFi Playback" , |
539 | .channels_min = 2, |
540 | .channels_max = 2, |
541 | .rates = SNDRV_PCM_RATE_8000_48000, |
542 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
543 | }, |
544 | .capture = { |
545 | .stream_name = "HiFi Capture" , |
546 | .channels_min = 2, |
547 | .channels_max = 2, |
548 | .rates = SNDRV_PCM_RATE_8000_48000, |
549 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
550 | }, |
551 | .ops = &max9867_dai_ops, |
552 | .symmetric_rate = 1, |
553 | } |
554 | }; |
555 | |
556 | #ifdef CONFIG_PM |
557 | static int max9867_suspend(struct snd_soc_component *component) |
558 | { |
559 | snd_soc_component_force_bias_level(component, level: SND_SOC_BIAS_OFF); |
560 | |
561 | return 0; |
562 | } |
563 | |
564 | static int max9867_resume(struct snd_soc_component *component) |
565 | { |
566 | snd_soc_component_force_bias_level(component, level: SND_SOC_BIAS_STANDBY); |
567 | |
568 | return 0; |
569 | } |
570 | #else |
571 | #define max9867_suspend NULL |
572 | #define max9867_resume NULL |
573 | #endif |
574 | |
575 | static int max9867_set_bias_level(struct snd_soc_component *component, |
576 | enum snd_soc_bias_level level) |
577 | { |
578 | int err; |
579 | struct max9867_priv *max9867 = snd_soc_component_get_drvdata(c: component); |
580 | |
581 | switch (level) { |
582 | case SND_SOC_BIAS_ON: |
583 | err = clk_prepare_enable(clk: max9867->mclk); |
584 | if (err) |
585 | return err; |
586 | break; |
587 | case SND_SOC_BIAS_STANDBY: |
588 | if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { |
589 | err = regcache_sync(map: max9867->regmap); |
590 | if (err) |
591 | return err; |
592 | |
593 | err = regmap_write(map: max9867->regmap, |
594 | MAX9867_PWRMAN, val: 0xff); |
595 | if (err) |
596 | return err; |
597 | } |
598 | break; |
599 | case SND_SOC_BIAS_OFF: |
600 | err = regmap_write(map: max9867->regmap, MAX9867_PWRMAN, val: 0); |
601 | if (err) |
602 | return err; |
603 | |
604 | regcache_mark_dirty(map: max9867->regmap); |
605 | clk_disable_unprepare(clk: max9867->mclk); |
606 | break; |
607 | default: |
608 | break; |
609 | } |
610 | |
611 | return 0; |
612 | } |
613 | |
614 | static const struct snd_soc_component_driver max9867_component = { |
615 | .controls = max9867_snd_controls, |
616 | .num_controls = ARRAY_SIZE(max9867_snd_controls), |
617 | .dapm_routes = max9867_audio_map, |
618 | .num_dapm_routes = ARRAY_SIZE(max9867_audio_map), |
619 | .dapm_widgets = max9867_dapm_widgets, |
620 | .num_dapm_widgets = ARRAY_SIZE(max9867_dapm_widgets), |
621 | .suspend = max9867_suspend, |
622 | .resume = max9867_resume, |
623 | .set_bias_level = max9867_set_bias_level, |
624 | .idle_bias_on = 1, |
625 | .use_pmdown_time = 1, |
626 | .endianness = 1, |
627 | }; |
628 | |
629 | static bool max9867_volatile_register(struct device *dev, unsigned int reg) |
630 | { |
631 | switch (reg) { |
632 | case MAX9867_STATUS: |
633 | case MAX9867_JACKSTATUS: |
634 | case MAX9867_AUXHIGH: |
635 | case MAX9867_AUXLOW: |
636 | return true; |
637 | default: |
638 | return false; |
639 | } |
640 | } |
641 | |
642 | static const struct regmap_config max9867_regmap = { |
643 | .reg_bits = 8, |
644 | .val_bits = 8, |
645 | .max_register = MAX9867_REVISION, |
646 | .volatile_reg = max9867_volatile_register, |
647 | .cache_type = REGCACHE_RBTREE, |
648 | }; |
649 | |
650 | static int max9867_i2c_probe(struct i2c_client *i2c) |
651 | { |
652 | struct max9867_priv *max9867; |
653 | int ret, reg; |
654 | |
655 | max9867 = devm_kzalloc(dev: &i2c->dev, size: sizeof(*max9867), GFP_KERNEL); |
656 | if (!max9867) |
657 | return -ENOMEM; |
658 | |
659 | i2c_set_clientdata(client: i2c, data: max9867); |
660 | max9867->regmap = devm_regmap_init_i2c(i2c, &max9867_regmap); |
661 | if (IS_ERR(ptr: max9867->regmap)) { |
662 | ret = PTR_ERR(ptr: max9867->regmap); |
663 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n" , ret); |
664 | return ret; |
665 | } |
666 | ret = regmap_read(map: max9867->regmap, MAX9867_REVISION, val: ®); |
667 | if (ret < 0) { |
668 | dev_err(&i2c->dev, "Failed to read: %d\n" , ret); |
669 | return ret; |
670 | } |
671 | dev_info(&i2c->dev, "device revision: %x\n" , reg); |
672 | ret = devm_snd_soc_register_component(dev: &i2c->dev, component_driver: &max9867_component, |
673 | dai_drv: max9867_dai, ARRAY_SIZE(max9867_dai)); |
674 | if (ret < 0) { |
675 | dev_err(&i2c->dev, "Failed to register component: %d\n" , ret); |
676 | return ret; |
677 | } |
678 | |
679 | max9867->mclk = devm_clk_get(dev: &i2c->dev, NULL); |
680 | if (IS_ERR(ptr: max9867->mclk)) |
681 | return PTR_ERR(ptr: max9867->mclk); |
682 | |
683 | return 0; |
684 | } |
685 | |
686 | static const struct i2c_device_id max9867_i2c_id[] = { |
687 | { "max9867" , 0 }, |
688 | { } |
689 | }; |
690 | MODULE_DEVICE_TABLE(i2c, max9867_i2c_id); |
691 | |
692 | #ifdef CONFIG_OF |
693 | static const struct of_device_id max9867_of_match[] = { |
694 | { .compatible = "maxim,max9867" , }, |
695 | { } |
696 | }; |
697 | MODULE_DEVICE_TABLE(of, max9867_of_match); |
698 | #endif |
699 | |
700 | static struct i2c_driver max9867_i2c_driver = { |
701 | .driver = { |
702 | .name = "max9867" , |
703 | .of_match_table = of_match_ptr(max9867_of_match), |
704 | }, |
705 | .probe = max9867_i2c_probe, |
706 | .id_table = max9867_i2c_id, |
707 | }; |
708 | |
709 | module_i2c_driver(max9867_i2c_driver); |
710 | |
711 | MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>" ); |
712 | MODULE_DESCRIPTION("ASoC MAX9867 driver" ); |
713 | MODULE_LICENSE("GPL" ); |
714 | |