diff options
author | Adam Thomson <Adam.Thomson.Opensource@diasemi.com> | 2015-09-29 11:44:01 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-10-02 13:11:27 -0400 |
commit | 6d817c0e9fd7536be76690bfdee88e8a81c16f7d (patch) | |
tree | 12d54c899e31db9ebacf2bf05b8f4fe24b3d8e38 /sound/soc/codecs/da7219.c | |
parent | c25c79b468a61ad8a54f764553056e2e2a427ea8 (diff) |
ASoC: codecs: Add da7219 codec driver
This adds support for the DA7219 audio codec with built-in advanced
accessory detect features.
Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/da7219.c')
-rw-r--r-- | sound/soc/codecs/da7219.c | 1940 |
1 files changed, 1940 insertions, 0 deletions
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c new file mode 100644 index 000000000000..76f8fc2c00fe --- /dev/null +++ b/sound/soc/codecs/da7219.c | |||
@@ -0,0 +1,1940 @@ | |||
1 | /* | ||
2 | * da7219.c - DA7219 ALSA SoC Codec Driver | ||
3 | * | ||
4 | * Copyright (c) 2015 Dialog Semiconductor | ||
5 | * | ||
6 | * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/of_device.h> | ||
17 | #include <linux/regmap.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/regulator/consumer.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | #include <asm/div64.h> | ||
30 | |||
31 | #include <sound/da7219.h> | ||
32 | #include "da7219.h" | ||
33 | #include "da7219-aad.h" | ||
34 | |||
35 | |||
36 | /* | ||
37 | * TLVs and Enums | ||
38 | */ | ||
39 | |||
40 | /* Input TLVs */ | ||
41 | static const DECLARE_TLV_DB_SCALE(da7219_mic_gain_tlv, -600, 600, 0); | ||
42 | static const DECLARE_TLV_DB_SCALE(da7219_mixin_gain_tlv, -450, 150, 0); | ||
43 | static const DECLARE_TLV_DB_SCALE(da7219_adc_dig_gain_tlv, -8325, 75, 0); | ||
44 | static const DECLARE_TLV_DB_SCALE(da7219_alc_threshold_tlv, -9450, 150, 0); | ||
45 | static const DECLARE_TLV_DB_SCALE(da7219_alc_gain_tlv, 0, 600, 0); | ||
46 | static const DECLARE_TLV_DB_SCALE(da7219_alc_ana_gain_tlv, 0, 600, 0); | ||
47 | static const DECLARE_TLV_DB_SCALE(da7219_sidetone_gain_tlv, -4200, 300, 0); | ||
48 | static const DECLARE_TLV_DB_SCALE(da7219_tonegen_gain_tlv, -4500, 300, 0); | ||
49 | |||
50 | /* Output TLVs */ | ||
51 | static const DECLARE_TLV_DB_SCALE(da7219_dac_eq_band_tlv, -1050, 150, 0); | ||
52 | |||
53 | static const DECLARE_TLV_DB_RANGE(da7219_dac_dig_gain_tlv, | ||
54 | 0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), | ||
55 | /* -77.25dB to 12dB */ | ||
56 | 0x08, 0x7f, TLV_DB_SCALE_ITEM(-7725, 75, 0) | ||
57 | ); | ||
58 | |||
59 | static const DECLARE_TLV_DB_SCALE(da7219_dac_ng_threshold_tlv, -10200, 600, 0); | ||
60 | static const DECLARE_TLV_DB_SCALE(da7219_hp_gain_tlv, -5700, 100, 0); | ||
61 | |||
62 | /* Input Enums */ | ||
63 | static const char * const da7219_alc_attack_rate_txt[] = { | ||
64 | "7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs", | ||
65 | "469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs", | ||
66 | "30024/fs" | ||
67 | }; | ||
68 | |||
69 | static const struct soc_enum da7219_alc_attack_rate = | ||
70 | SOC_ENUM_SINGLE(DA7219_ALC_CTRL2, DA7219_ALC_ATTACK_SHIFT, | ||
71 | DA7219_ALC_ATTACK_MAX, da7219_alc_attack_rate_txt); | ||
72 | |||
73 | static const char * const da7219_alc_release_rate_txt[] = { | ||
74 | "28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs", | ||
75 | "1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs" | ||
76 | }; | ||
77 | |||
78 | static const struct soc_enum da7219_alc_release_rate = | ||
79 | SOC_ENUM_SINGLE(DA7219_ALC_CTRL2, DA7219_ALC_RELEASE_SHIFT, | ||
80 | DA7219_ALC_RELEASE_MAX, da7219_alc_release_rate_txt); | ||
81 | |||
82 | static const char * const da7219_alc_hold_time_txt[] = { | ||
83 | "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs", | ||
84 | "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs", | ||
85 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" | ||
86 | }; | ||
87 | |||
88 | static const struct soc_enum da7219_alc_hold_time = | ||
89 | SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_HOLD_SHIFT, | ||
90 | DA7219_ALC_HOLD_MAX, da7219_alc_hold_time_txt); | ||
91 | |||
92 | static const char * const da7219_alc_env_rate_txt[] = { | ||
93 | "1/4", "1/16", "1/256", "1/65536" | ||
94 | }; | ||
95 | |||
96 | static const struct soc_enum da7219_alc_env_attack_rate = | ||
97 | SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_INTEG_ATTACK_SHIFT, | ||
98 | DA7219_ALC_INTEG_MAX, da7219_alc_env_rate_txt); | ||
99 | |||
100 | static const struct soc_enum da7219_alc_env_release_rate = | ||
101 | SOC_ENUM_SINGLE(DA7219_ALC_CTRL3, DA7219_ALC_INTEG_RELEASE_SHIFT, | ||
102 | DA7219_ALC_INTEG_MAX, da7219_alc_env_rate_txt); | ||
103 | |||
104 | static const char * const da7219_alc_anticlip_step_txt[] = { | ||
105 | "0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs" | ||
106 | }; | ||
107 | |||
108 | static const struct soc_enum da7219_alc_anticlip_step = | ||
109 | SOC_ENUM_SINGLE(DA7219_ALC_ANTICLIP_CTRL, | ||
110 | DA7219_ALC_ANTICLIP_STEP_SHIFT, | ||
111 | DA7219_ALC_ANTICLIP_STEP_MAX, | ||
112 | da7219_alc_anticlip_step_txt); | ||
113 | |||
114 | /* Input/Output Enums */ | ||
115 | static const char * const da7219_gain_ramp_rate_txt[] = { | ||
116 | "Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8", | ||
117 | "Nominal Rate / 16" | ||
118 | }; | ||
119 | |||
120 | static const struct soc_enum da7219_gain_ramp_rate = | ||
121 | SOC_ENUM_SINGLE(DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_SHIFT, | ||
122 | DA7219_GAIN_RAMP_RATE_MAX, da7219_gain_ramp_rate_txt); | ||
123 | |||
124 | static const char * const da7219_hpf_mode_txt[] = { | ||
125 | "Disabled", "Audio", "Voice" | ||
126 | }; | ||
127 | |||
128 | static const unsigned int da7219_hpf_mode_val[] = { | ||
129 | DA7219_HPF_DISABLED, DA7219_HPF_AUDIO_EN, DA7219_HPF_VOICE_EN, | ||
130 | }; | ||
131 | |||
132 | static const struct soc_enum da7219_adc_hpf_mode = | ||
133 | SOC_VALUE_ENUM_SINGLE(DA7219_ADC_FILTERS1, DA7219_HPF_MODE_SHIFT, | ||
134 | DA7219_HPF_MODE_MASK, DA7219_HPF_MODE_MAX, | ||
135 | da7219_hpf_mode_txt, da7219_hpf_mode_val); | ||
136 | |||
137 | static const struct soc_enum da7219_dac_hpf_mode = | ||
138 | SOC_VALUE_ENUM_SINGLE(DA7219_DAC_FILTERS1, DA7219_HPF_MODE_SHIFT, | ||
139 | DA7219_HPF_MODE_MASK, DA7219_HPF_MODE_MAX, | ||
140 | da7219_hpf_mode_txt, da7219_hpf_mode_val); | ||
141 | |||
142 | static const char * const da7219_audio_hpf_corner_txt[] = { | ||
143 | "2Hz", "4Hz", "8Hz", "16Hz" | ||
144 | }; | ||
145 | |||
146 | static const struct soc_enum da7219_adc_audio_hpf_corner = | ||
147 | SOC_ENUM_SINGLE(DA7219_ADC_FILTERS1, | ||
148 | DA7219_ADC_AUDIO_HPF_CORNER_SHIFT, | ||
149 | DA7219_AUDIO_HPF_CORNER_MAX, | ||
150 | da7219_audio_hpf_corner_txt); | ||
151 | |||
152 | static const struct soc_enum da7219_dac_audio_hpf_corner = | ||
153 | SOC_ENUM_SINGLE(DA7219_DAC_FILTERS1, | ||
154 | DA7219_DAC_AUDIO_HPF_CORNER_SHIFT, | ||
155 | DA7219_AUDIO_HPF_CORNER_MAX, | ||
156 | da7219_audio_hpf_corner_txt); | ||
157 | |||
158 | static const char * const da7219_voice_hpf_corner_txt[] = { | ||
159 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | ||
160 | }; | ||
161 | |||
162 | static const struct soc_enum da7219_adc_voice_hpf_corner = | ||
163 | SOC_ENUM_SINGLE(DA7219_ADC_FILTERS1, | ||
164 | DA7219_ADC_VOICE_HPF_CORNER_SHIFT, | ||
165 | DA7219_VOICE_HPF_CORNER_MAX, | ||
166 | da7219_voice_hpf_corner_txt); | ||
167 | |||
168 | static const struct soc_enum da7219_dac_voice_hpf_corner = | ||
169 | SOC_ENUM_SINGLE(DA7219_DAC_FILTERS1, | ||
170 | DA7219_DAC_VOICE_HPF_CORNER_SHIFT, | ||
171 | DA7219_VOICE_HPF_CORNER_MAX, | ||
172 | da7219_voice_hpf_corner_txt); | ||
173 | |||
174 | static const char * const da7219_tonegen_dtmf_key_txt[] = { | ||
175 | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", | ||
176 | "*", "#" | ||
177 | }; | ||
178 | |||
179 | static const struct soc_enum da7219_tonegen_dtmf_key = | ||
180 | SOC_ENUM_SINGLE(DA7219_TONE_GEN_CFG1, DA7219_DTMF_REG_SHIFT, | ||
181 | DA7219_DTMF_REG_MAX, da7219_tonegen_dtmf_key_txt); | ||
182 | |||
183 | static const char * const da7219_tonegen_swg_sel_txt[] = { | ||
184 | "Sum", "SWG1", "SWG2", "SWG1_1-Cos" | ||
185 | }; | ||
186 | |||
187 | static const struct soc_enum da7219_tonegen_swg_sel = | ||
188 | SOC_ENUM_SINGLE(DA7219_TONE_GEN_CFG2, DA7219_SWG_SEL_SHIFT, | ||
189 | DA7219_SWG_SEL_MAX, da7219_tonegen_swg_sel_txt); | ||
190 | |||
191 | /* Output Enums */ | ||
192 | static const char * const da7219_dac_softmute_rate_txt[] = { | ||
193 | "1 Sample", "2 Samples", "4 Samples", "8 Samples", "16 Samples", | ||
194 | "32 Samples", "64 Samples" | ||
195 | }; | ||
196 | |||
197 | static const struct soc_enum da7219_dac_softmute_rate = | ||
198 | SOC_ENUM_SINGLE(DA7219_DAC_FILTERS5, DA7219_DAC_SOFTMUTE_RATE_SHIFT, | ||
199 | DA7219_DAC_SOFTMUTE_RATE_MAX, | ||
200 | da7219_dac_softmute_rate_txt); | ||
201 | |||
202 | static const char * const da7219_dac_ng_setup_time_txt[] = { | ||
203 | "256 Samples", "512 Samples", "1024 Samples", "2048 Samples" | ||
204 | }; | ||
205 | |||
206 | static const struct soc_enum da7219_dac_ng_setup_time = | ||
207 | SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME, | ||
208 | DA7219_DAC_NG_SETUP_TIME_SHIFT, | ||
209 | DA7219_DAC_NG_SETUP_TIME_MAX, | ||
210 | da7219_dac_ng_setup_time_txt); | ||
211 | |||
212 | static const char * const da7219_dac_ng_rampup_txt[] = { | ||
213 | "0.22ms/dB", "0.0138ms/dB" | ||
214 | }; | ||
215 | |||
216 | static const struct soc_enum da7219_dac_ng_rampup_rate = | ||
217 | SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME, | ||
218 | DA7219_DAC_NG_RAMPUP_RATE_SHIFT, | ||
219 | DA7219_DAC_NG_RAMP_RATE_MAX, | ||
220 | da7219_dac_ng_rampup_txt); | ||
221 | |||
222 | static const char * const da7219_dac_ng_rampdown_txt[] = { | ||
223 | "0.88ms/dB", "14.08ms/dB" | ||
224 | }; | ||
225 | |||
226 | static const struct soc_enum da7219_dac_ng_rampdown_rate = | ||
227 | SOC_ENUM_SINGLE(DA7219_DAC_NG_SETUP_TIME, | ||
228 | DA7219_DAC_NG_RAMPDN_RATE_SHIFT, | ||
229 | DA7219_DAC_NG_RAMP_RATE_MAX, | ||
230 | da7219_dac_ng_rampdown_txt); | ||
231 | |||
232 | |||
233 | static const char * const da7219_cp_track_mode_txt[] = { | ||
234 | "Largest Volume", "DAC Volume", "Signal Magnitude" | ||
235 | }; | ||
236 | |||
237 | static const unsigned int da7219_cp_track_mode_val[] = { | ||
238 | DA7219_CP_MCHANGE_LARGEST_VOL, DA7219_CP_MCHANGE_DAC_VOL, | ||
239 | DA7219_CP_MCHANGE_SIG_MAG | ||
240 | }; | ||
241 | |||
242 | static const struct soc_enum da7219_cp_track_mode = | ||
243 | SOC_VALUE_ENUM_SINGLE(DA7219_CP_CTRL, DA7219_CP_MCHANGE_SHIFT, | ||
244 | DA7219_CP_MCHANGE_REL_MASK, DA7219_CP_MCHANGE_MAX, | ||
245 | da7219_cp_track_mode_txt, | ||
246 | da7219_cp_track_mode_val); | ||
247 | |||
248 | |||
249 | /* | ||
250 | * Control Functions | ||
251 | */ | ||
252 | |||
253 | /* Locked Kcontrol calls */ | ||
254 | static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol, | ||
255 | struct snd_ctl_elem_value *ucontrol) | ||
256 | { | ||
257 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
258 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
259 | int ret; | ||
260 | |||
261 | mutex_lock(&da7219->lock); | ||
262 | ret = snd_soc_get_volsw(kcontrol, ucontrol); | ||
263 | mutex_unlock(&da7219->lock); | ||
264 | |||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol, | ||
269 | struct snd_ctl_elem_value *ucontrol) | ||
270 | { | ||
271 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
272 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
273 | int ret; | ||
274 | |||
275 | mutex_lock(&da7219->lock); | ||
276 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | ||
277 | mutex_unlock(&da7219->lock); | ||
278 | |||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol, | ||
283 | struct snd_ctl_elem_value *ucontrol) | ||
284 | { | ||
285 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
286 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
287 | int ret; | ||
288 | |||
289 | mutex_lock(&da7219->lock); | ||
290 | ret = snd_soc_get_enum_double(kcontrol, ucontrol); | ||
291 | mutex_unlock(&da7219->lock); | ||
292 | |||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol, | ||
297 | struct snd_ctl_elem_value *ucontrol) | ||
298 | { | ||
299 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
300 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
301 | int ret; | ||
302 | |||
303 | mutex_lock(&da7219->lock); | ||
304 | ret = snd_soc_put_enum_double(kcontrol, ucontrol); | ||
305 | mutex_unlock(&da7219->lock); | ||
306 | |||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | /* ALC */ | ||
311 | static void da7219_alc_calib(struct snd_soc_codec *codec) | ||
312 | { | ||
313 | u8 mic_ctrl, mixin_ctrl, adc_ctrl, calib_ctrl; | ||
314 | |||
315 | /* Save current state of mic control register */ | ||
316 | mic_ctrl = snd_soc_read(codec, DA7219_MIC_1_CTRL); | ||
317 | |||
318 | /* Save current state of input mixer control register */ | ||
319 | mixin_ctrl = snd_soc_read(codec, DA7219_MIXIN_L_CTRL); | ||
320 | |||
321 | /* Save current state of input ADC control register */ | ||
322 | adc_ctrl = snd_soc_read(codec, DA7219_ADC_L_CTRL); | ||
323 | |||
324 | /* Enable then Mute MIC PGAs */ | ||
325 | snd_soc_update_bits(codec, DA7219_MIC_1_CTRL, DA7219_MIC_1_AMP_EN_MASK, | ||
326 | DA7219_MIC_1_AMP_EN_MASK); | ||
327 | snd_soc_update_bits(codec, DA7219_MIC_1_CTRL, | ||
328 | DA7219_MIC_1_AMP_MUTE_EN_MASK, | ||
329 | DA7219_MIC_1_AMP_MUTE_EN_MASK); | ||
330 | |||
331 | /* Enable input mixers unmuted */ | ||
332 | snd_soc_update_bits(codec, DA7219_MIXIN_L_CTRL, | ||
333 | DA7219_MIXIN_L_AMP_EN_MASK | | ||
334 | DA7219_MIXIN_L_AMP_MUTE_EN_MASK, | ||
335 | DA7219_MIXIN_L_AMP_EN_MASK); | ||
336 | |||
337 | /* Enable input filters unmuted */ | ||
338 | snd_soc_update_bits(codec, DA7219_ADC_L_CTRL, | ||
339 | DA7219_ADC_L_MUTE_EN_MASK | DA7219_ADC_L_EN_MASK, | ||
340 | DA7219_ADC_L_EN_MASK); | ||
341 | |||
342 | /* Perform auto calibration */ | ||
343 | snd_soc_update_bits(codec, DA7219_ALC_CTRL1, | ||
344 | DA7219_ALC_AUTO_CALIB_EN_MASK, | ||
345 | DA7219_ALC_AUTO_CALIB_EN_MASK); | ||
346 | do { | ||
347 | calib_ctrl = snd_soc_read(codec, DA7219_ALC_CTRL1); | ||
348 | } while (calib_ctrl & DA7219_ALC_AUTO_CALIB_EN_MASK); | ||
349 | |||
350 | /* If auto calibration fails, disable DC offset, hybrid ALC */ | ||
351 | if (calib_ctrl & DA7219_ALC_CALIB_OVERFLOW_MASK) { | ||
352 | dev_warn(codec->dev, | ||
353 | "ALC auto calibration failed with overflow\n"); | ||
354 | snd_soc_update_bits(codec, DA7219_ALC_CTRL1, | ||
355 | DA7219_ALC_OFFSET_EN_MASK | | ||
356 | DA7219_ALC_SYNC_MODE_MASK, 0); | ||
357 | } else { | ||
358 | /* Enable DC offset cancellation, hybrid mode */ | ||
359 | snd_soc_update_bits(codec, DA7219_ALC_CTRL1, | ||
360 | DA7219_ALC_OFFSET_EN_MASK | | ||
361 | DA7219_ALC_SYNC_MODE_MASK, | ||
362 | DA7219_ALC_OFFSET_EN_MASK | | ||
363 | DA7219_ALC_SYNC_MODE_MASK); | ||
364 | } | ||
365 | |||
366 | /* Restore input filter control register to original state */ | ||
367 | snd_soc_write(codec, DA7219_ADC_L_CTRL, adc_ctrl); | ||
368 | |||
369 | /* Restore input mixer control registers to original state */ | ||
370 | snd_soc_write(codec, DA7219_MIXIN_L_CTRL, mixin_ctrl); | ||
371 | |||
372 | /* Restore MIC control registers to original states */ | ||
373 | snd_soc_write(codec, DA7219_MIC_1_CTRL, mic_ctrl); | ||
374 | } | ||
375 | |||
376 | static int da7219_mixin_gain_put(struct snd_kcontrol *kcontrol, | ||
377 | struct snd_ctl_elem_value *ucontrol) | ||
378 | { | ||
379 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
380 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
381 | int ret; | ||
382 | |||
383 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | ||
384 | |||
385 | /* | ||
386 | * If ALC in operation and value of control has been updated, | ||
387 | * make sure calibrated offsets are updated. | ||
388 | */ | ||
389 | if ((ret == 1) && (da7219->alc_en)) | ||
390 | da7219_alc_calib(codec); | ||
391 | |||
392 | return ret; | ||
393 | } | ||
394 | |||
395 | static int da7219_alc_sw_put(struct snd_kcontrol *kcontrol, | ||
396 | struct snd_ctl_elem_value *ucontrol) | ||
397 | { | ||
398 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
399 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
400 | |||
401 | |||
402 | /* Force ALC offset calibration if enabling ALC */ | ||
403 | if ((ucontrol->value.integer.value[0]) && (!da7219->alc_en)) { | ||
404 | da7219_alc_calib(codec); | ||
405 | da7219->alc_en = false; | ||
406 | } else { | ||
407 | da7219->alc_en = false; | ||
408 | } | ||
409 | |||
410 | return snd_soc_put_volsw(kcontrol, ucontrol); | ||
411 | } | ||
412 | |||
413 | /* ToneGen */ | ||
414 | static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, | ||
415 | struct snd_ctl_elem_value *ucontrol) | ||
416 | { | ||
417 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
418 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
419 | struct soc_mixer_control *mixer_ctrl = | ||
420 | (struct soc_mixer_control *) kcontrol->private_value; | ||
421 | unsigned int reg = mixer_ctrl->reg; | ||
422 | u16 val; | ||
423 | int ret; | ||
424 | |||
425 | mutex_lock(&da7219->lock); | ||
426 | ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val)); | ||
427 | mutex_unlock(&da7219->lock); | ||
428 | |||
429 | if (ret) | ||
430 | return ret; | ||
431 | |||
432 | /* | ||
433 | * Frequency value spans two 8-bit registers, lower then upper byte. | ||
434 | * Therefore we need to convert to host endianness here. | ||
435 | */ | ||
436 | ucontrol->value.integer.value[0] = le16_to_cpu(val); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, | ||
442 | struct snd_ctl_elem_value *ucontrol) | ||
443 | { | ||
444 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
445 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
446 | struct soc_mixer_control *mixer_ctrl = | ||
447 | (struct soc_mixer_control *) kcontrol->private_value; | ||
448 | unsigned int reg = mixer_ctrl->reg; | ||
449 | u16 val; | ||
450 | int ret; | ||
451 | |||
452 | /* | ||
453 | * Frequency value spans two 8-bit registers, lower then upper byte. | ||
454 | * Therefore we need to convert to little endian here to align with | ||
455 | * HW registers. | ||
456 | */ | ||
457 | val = cpu_to_le16(ucontrol->value.integer.value[0]); | ||
458 | |||
459 | mutex_lock(&da7219->lock); | ||
460 | ret = regmap_raw_write(da7219->regmap, reg, &val, sizeof(val)); | ||
461 | mutex_unlock(&da7219->lock); | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | |||
467 | /* | ||
468 | * KControls | ||
469 | */ | ||
470 | |||
471 | static const struct snd_kcontrol_new da7219_snd_controls[] = { | ||
472 | /* Mics */ | ||
473 | SOC_SINGLE_TLV("Mic Volume", DA7219_MIC_1_GAIN, | ||
474 | DA7219_MIC_1_AMP_GAIN_SHIFT, DA7219_MIC_1_AMP_GAIN_MAX, | ||
475 | DA7219_NO_INVERT, da7219_mic_gain_tlv), | ||
476 | SOC_SINGLE("Mic Switch", DA7219_MIC_1_CTRL, | ||
477 | DA7219_MIC_1_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
478 | DA7219_INVERT), | ||
479 | |||
480 | /* Mixer Input */ | ||
481 | SOC_SINGLE_EXT_TLV("Mixin Volume", DA7219_MIXIN_L_GAIN, | ||
482 | DA7219_MIXIN_L_AMP_GAIN_SHIFT, | ||
483 | DA7219_MIXIN_L_AMP_GAIN_MAX, DA7219_NO_INVERT, | ||
484 | snd_soc_get_volsw, da7219_mixin_gain_put, | ||
485 | da7219_mixin_gain_tlv), | ||
486 | SOC_SINGLE("Mixin Switch", DA7219_MIXIN_L_CTRL, | ||
487 | DA7219_MIXIN_L_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
488 | DA7219_INVERT), | ||
489 | SOC_SINGLE("Mixin Gain Ramp Switch", DA7219_MIXIN_L_CTRL, | ||
490 | DA7219_MIXIN_L_AMP_RAMP_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
491 | DA7219_NO_INVERT), | ||
492 | SOC_SINGLE("Mixin ZC Gain Switch", DA7219_MIXIN_L_CTRL, | ||
493 | DA7219_MIXIN_L_AMP_ZC_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
494 | DA7219_NO_INVERT), | ||
495 | |||
496 | /* ADC */ | ||
497 | SOC_SINGLE_TLV("Capture Digital Volume", DA7219_ADC_L_GAIN, | ||
498 | DA7219_ADC_L_DIGITAL_GAIN_SHIFT, | ||
499 | DA7219_ADC_L_DIGITAL_GAIN_MAX, DA7219_NO_INVERT, | ||
500 | da7219_adc_dig_gain_tlv), | ||
501 | SOC_SINGLE("Capture Digital Switch", DA7219_ADC_L_CTRL, | ||
502 | DA7219_ADC_L_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
503 | DA7219_INVERT), | ||
504 | SOC_SINGLE("Capture Digital Gain Ramp Switch", DA7219_ADC_L_CTRL, | ||
505 | DA7219_ADC_L_RAMP_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
506 | DA7219_NO_INVERT), | ||
507 | |||
508 | /* ALC */ | ||
509 | SOC_ENUM("ALC Attack Rate", da7219_alc_attack_rate), | ||
510 | SOC_ENUM("ALC Release Rate", da7219_alc_release_rate), | ||
511 | SOC_ENUM("ALC Hold Time", da7219_alc_hold_time), | ||
512 | SOC_ENUM("ALC Envelope Attack Rate", da7219_alc_env_attack_rate), | ||
513 | SOC_ENUM("ALC Envelope Release Rate", da7219_alc_env_release_rate), | ||
514 | SOC_SINGLE_TLV("ALC Noise Threshold", DA7219_ALC_NOISE, | ||
515 | DA7219_ALC_NOISE_SHIFT, DA7219_ALC_THRESHOLD_MAX, | ||
516 | DA7219_INVERT, da7219_alc_threshold_tlv), | ||
517 | SOC_SINGLE_TLV("ALC Min Threshold", DA7219_ALC_TARGET_MIN, | ||
518 | DA7219_ALC_THRESHOLD_MIN_SHIFT, DA7219_ALC_THRESHOLD_MAX, | ||
519 | DA7219_INVERT, da7219_alc_threshold_tlv), | ||
520 | SOC_SINGLE_TLV("ALC Max Threshold", DA7219_ALC_TARGET_MAX, | ||
521 | DA7219_ALC_THRESHOLD_MAX_SHIFT, DA7219_ALC_THRESHOLD_MAX, | ||
522 | DA7219_INVERT, da7219_alc_threshold_tlv), | ||
523 | SOC_SINGLE_TLV("ALC Max Attenuation", DA7219_ALC_GAIN_LIMITS, | ||
524 | DA7219_ALC_ATTEN_MAX_SHIFT, DA7219_ALC_ATTEN_GAIN_MAX, | ||
525 | DA7219_NO_INVERT, da7219_alc_gain_tlv), | ||
526 | SOC_SINGLE_TLV("ALC Max Volume", DA7219_ALC_GAIN_LIMITS, | ||
527 | DA7219_ALC_GAIN_MAX_SHIFT, DA7219_ALC_ATTEN_GAIN_MAX, | ||
528 | DA7219_NO_INVERT, da7219_alc_gain_tlv), | ||
529 | SOC_SINGLE_RANGE_TLV("ALC Min Analog Volume", DA7219_ALC_ANA_GAIN_LIMITS, | ||
530 | DA7219_ALC_ANA_GAIN_MIN_SHIFT, | ||
531 | DA7219_ALC_ANA_GAIN_MIN, DA7219_ALC_ANA_GAIN_MAX, | ||
532 | DA7219_NO_INVERT, da7219_alc_ana_gain_tlv), | ||
533 | SOC_SINGLE_RANGE_TLV("ALC Max Analog Volume", DA7219_ALC_ANA_GAIN_LIMITS, | ||
534 | DA7219_ALC_ANA_GAIN_MAX_SHIFT, | ||
535 | DA7219_ALC_ANA_GAIN_MIN, DA7219_ALC_ANA_GAIN_MAX, | ||
536 | DA7219_NO_INVERT, da7219_alc_ana_gain_tlv), | ||
537 | SOC_ENUM("ALC Anticlip Step", da7219_alc_anticlip_step), | ||
538 | SOC_SINGLE("ALC Anticlip Switch", DA7219_ALC_ANTICLIP_CTRL, | ||
539 | DA7219_ALC_ANTIPCLIP_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
540 | DA7219_NO_INVERT), | ||
541 | SOC_SINGLE_EXT("ALC Switch", DA7219_ALC_CTRL1, DA7219_ALC_EN_SHIFT, | ||
542 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT, | ||
543 | snd_soc_get_volsw, da7219_alc_sw_put), | ||
544 | |||
545 | /* Input High-Pass Filters */ | ||
546 | SOC_ENUM("ADC HPF Mode", da7219_adc_hpf_mode), | ||
547 | SOC_ENUM("ADC HPF Corner Audio", da7219_adc_audio_hpf_corner), | ||
548 | SOC_ENUM("ADC HPF Corner Voice", da7219_adc_voice_hpf_corner), | ||
549 | |||
550 | /* Sidetone Filter */ | ||
551 | SOC_SINGLE_TLV("Sidetone Volume", DA7219_SIDETONE_GAIN, | ||
552 | DA7219_SIDETONE_GAIN_SHIFT, DA7219_SIDETONE_GAIN_MAX, | ||
553 | DA7219_NO_INVERT, da7219_sidetone_gain_tlv), | ||
554 | SOC_SINGLE("Sidetone Switch", DA7219_SIDETONE_CTRL, | ||
555 | DA7219_SIDETONE_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
556 | DA7219_INVERT), | ||
557 | |||
558 | /* Tone Generator */ | ||
559 | SOC_SINGLE_EXT_TLV("ToneGen Volume", DA7219_TONE_GEN_CFG2, | ||
560 | DA7219_TONE_GEN_GAIN_SHIFT, DA7219_TONE_GEN_GAIN_MAX, | ||
561 | DA7219_NO_INVERT, da7219_volsw_locked_get, | ||
562 | da7219_volsw_locked_put, da7219_tonegen_gain_tlv), | ||
563 | SOC_ENUM_EXT("ToneGen DTMF Key", da7219_tonegen_dtmf_key, | ||
564 | da7219_enum_locked_get, da7219_enum_locked_put), | ||
565 | SOC_SINGLE_EXT("ToneGen DTMF Switch", DA7219_TONE_GEN_CFG1, | ||
566 | DA7219_DTMF_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
567 | DA7219_NO_INVERT, da7219_volsw_locked_get, | ||
568 | da7219_volsw_locked_put), | ||
569 | SOC_ENUM_EXT("ToneGen Sinewave Gen Type", da7219_tonegen_swg_sel, | ||
570 | da7219_enum_locked_get, da7219_enum_locked_put), | ||
571 | SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7219_TONE_GEN_FREQ1_L, | ||
572 | DA7219_FREQ1_L_SHIFT, DA7219_FREQ_MAX, DA7219_NO_INVERT, | ||
573 | da7219_tonegen_freq_get, da7219_tonegen_freq_put), | ||
574 | SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7219_TONE_GEN_FREQ2_L, | ||
575 | DA7219_FREQ2_L_SHIFT, DA7219_FREQ_MAX, DA7219_NO_INVERT, | ||
576 | da7219_tonegen_freq_get, da7219_tonegen_freq_put), | ||
577 | SOC_SINGLE_EXT("ToneGen On Time", DA7219_TONE_GEN_ON_PER, | ||
578 | DA7219_BEEP_ON_PER_SHIFT, DA7219_BEEP_ON_OFF_MAX, | ||
579 | DA7219_NO_INVERT, da7219_volsw_locked_get, | ||
580 | da7219_volsw_locked_put), | ||
581 | SOC_SINGLE("ToneGen Off Time", DA7219_TONE_GEN_OFF_PER, | ||
582 | DA7219_BEEP_OFF_PER_SHIFT, DA7219_BEEP_ON_OFF_MAX, | ||
583 | DA7219_NO_INVERT), | ||
584 | |||
585 | /* Gain ramping */ | ||
586 | SOC_ENUM("Gain Ramp Rate", da7219_gain_ramp_rate), | ||
587 | |||
588 | /* DAC High-Pass Filter */ | ||
589 | SOC_ENUM_EXT("DAC HPF Mode", da7219_dac_hpf_mode, | ||
590 | da7219_enum_locked_get, da7219_enum_locked_put), | ||
591 | SOC_ENUM("DAC HPF Corner Audio", da7219_dac_audio_hpf_corner), | ||
592 | SOC_ENUM("DAC HPF Corner Voice", da7219_dac_voice_hpf_corner), | ||
593 | |||
594 | /* DAC 5-Band Equaliser */ | ||
595 | SOC_SINGLE_TLV("DAC EQ Band1 Volume", DA7219_DAC_FILTERS2, | ||
596 | DA7219_DAC_EQ_BAND1_SHIFT, DA7219_DAC_EQ_BAND_MAX, | ||
597 | DA7219_NO_INVERT, da7219_dac_eq_band_tlv), | ||
598 | SOC_SINGLE_TLV("DAC EQ Band2 Volume", DA7219_DAC_FILTERS2, | ||
599 | DA7219_DAC_EQ_BAND2_SHIFT, DA7219_DAC_EQ_BAND_MAX, | ||
600 | DA7219_NO_INVERT, da7219_dac_eq_band_tlv), | ||
601 | SOC_SINGLE_TLV("DAC EQ Band3 Volume", DA7219_DAC_FILTERS3, | ||
602 | DA7219_DAC_EQ_BAND3_SHIFT, DA7219_DAC_EQ_BAND_MAX, | ||
603 | DA7219_NO_INVERT, da7219_dac_eq_band_tlv), | ||
604 | SOC_SINGLE_TLV("DAC EQ Band4 Volume", DA7219_DAC_FILTERS3, | ||
605 | DA7219_DAC_EQ_BAND4_SHIFT, DA7219_DAC_EQ_BAND_MAX, | ||
606 | DA7219_NO_INVERT, da7219_dac_eq_band_tlv), | ||
607 | SOC_SINGLE_TLV("DAC EQ Band5 Volume", DA7219_DAC_FILTERS4, | ||
608 | DA7219_DAC_EQ_BAND5_SHIFT, DA7219_DAC_EQ_BAND_MAX, | ||
609 | DA7219_NO_INVERT, da7219_dac_eq_band_tlv), | ||
610 | SOC_SINGLE_EXT("DAC EQ Switch", DA7219_DAC_FILTERS4, | ||
611 | DA7219_DAC_EQ_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
612 | DA7219_NO_INVERT, da7219_volsw_locked_get, | ||
613 | da7219_volsw_locked_put), | ||
614 | |||
615 | /* DAC Softmute */ | ||
616 | SOC_ENUM("DAC Soft Mute Rate", da7219_dac_softmute_rate), | ||
617 | SOC_SINGLE_EXT("DAC Soft Mute Switch", DA7219_DAC_FILTERS5, | ||
618 | DA7219_DAC_SOFTMUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
619 | DA7219_NO_INVERT, da7219_volsw_locked_get, | ||
620 | da7219_volsw_locked_put), | ||
621 | |||
622 | /* DAC Noise Gate */ | ||
623 | SOC_ENUM("DAC NG Setup Time", da7219_dac_ng_setup_time), | ||
624 | SOC_ENUM("DAC NG Rampup Rate", da7219_dac_ng_rampup_rate), | ||
625 | SOC_ENUM("DAC NG Rampdown Rate", da7219_dac_ng_rampdown_rate), | ||
626 | SOC_SINGLE_TLV("DAC NG Off Threshold", DA7219_DAC_NG_OFF_THRESH, | ||
627 | DA7219_DAC_NG_OFF_THRESHOLD_SHIFT, | ||
628 | DA7219_DAC_NG_THRESHOLD_MAX, DA7219_NO_INVERT, | ||
629 | da7219_dac_ng_threshold_tlv), | ||
630 | SOC_SINGLE_TLV("DAC NG On Threshold", DA7219_DAC_NG_ON_THRESH, | ||
631 | DA7219_DAC_NG_ON_THRESHOLD_SHIFT, | ||
632 | DA7219_DAC_NG_THRESHOLD_MAX, DA7219_NO_INVERT, | ||
633 | da7219_dac_ng_threshold_tlv), | ||
634 | SOC_SINGLE("DAC NG Switch", DA7219_DAC_NG_CTRL, DA7219_DAC_NG_EN_SHIFT, | ||
635 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), | ||
636 | |||
637 | /* DACs */ | ||
638 | SOC_DOUBLE_R_EXT_TLV("Playback Digital Volume", DA7219_DAC_L_GAIN, | ||
639 | DA7219_DAC_R_GAIN, DA7219_DAC_L_DIGITAL_GAIN_SHIFT, | ||
640 | DA7219_DAC_DIGITAL_GAIN_MAX, DA7219_NO_INVERT, | ||
641 | da7219_volsw_locked_get, da7219_volsw_locked_put, | ||
642 | da7219_dac_dig_gain_tlv), | ||
643 | SOC_DOUBLE_R_EXT("Playback Digital Switch", DA7219_DAC_L_CTRL, | ||
644 | DA7219_DAC_R_CTRL, DA7219_DAC_L_MUTE_EN_SHIFT, | ||
645 | DA7219_SWITCH_EN_MAX, DA7219_INVERT, | ||
646 | da7219_volsw_locked_get, da7219_volsw_locked_put), | ||
647 | SOC_DOUBLE_R("Playback Digital Gain Ramp Switch", DA7219_DAC_L_CTRL, | ||
648 | DA7219_DAC_R_CTRL, DA7219_DAC_L_RAMP_EN_SHIFT, | ||
649 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), | ||
650 | |||
651 | /* CP */ | ||
652 | SOC_ENUM("Charge Pump Track Mode", da7219_cp_track_mode), | ||
653 | SOC_SINGLE("Charge Pump Threshold", DA7219_CP_VOL_THRESHOLD1, | ||
654 | DA7219_CP_THRESH_VDD2_SHIFT, DA7219_CP_THRESH_VDD2_MAX, | ||
655 | DA7219_NO_INVERT), | ||
656 | |||
657 | /* Headphones */ | ||
658 | SOC_DOUBLE_R_EXT_TLV("Headphone Volume", DA7219_HP_L_GAIN, | ||
659 | DA7219_HP_R_GAIN, DA7219_HP_L_AMP_GAIN_SHIFT, | ||
660 | DA7219_HP_AMP_GAIN_MAX, DA7219_NO_INVERT, | ||
661 | da7219_volsw_locked_get, da7219_volsw_locked_put, | ||
662 | da7219_hp_gain_tlv), | ||
663 | SOC_DOUBLE_R_EXT("Headphone Switch", DA7219_HP_L_CTRL, DA7219_HP_R_CTRL, | ||
664 | DA7219_HP_L_AMP_MUTE_EN_SHIFT, DA7219_SWITCH_EN_MAX, | ||
665 | DA7219_INVERT, da7219_volsw_locked_get, | ||
666 | da7219_volsw_locked_put), | ||
667 | SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7219_HP_L_CTRL, | ||
668 | DA7219_HP_R_CTRL, DA7219_HP_L_AMP_RAMP_EN_SHIFT, | ||
669 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), | ||
670 | SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7219_HP_L_CTRL, | ||
671 | DA7219_HP_R_CTRL, DA7219_HP_L_AMP_ZC_EN_SHIFT, | ||
672 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), | ||
673 | }; | ||
674 | |||
675 | |||
676 | /* | ||
677 | * DAPM Mux Controls | ||
678 | */ | ||
679 | |||
680 | static const char * const da7219_out_sel_txt[] = { | ||
681 | "ADC", "Tone Generator", "DAIL", "DAIR" | ||
682 | }; | ||
683 | |||
684 | static const struct soc_enum da7219_out_dail_sel = | ||
685 | SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAI, | ||
686 | DA7219_DAI_L_SRC_SHIFT, | ||
687 | DA7219_OUT_SRC_MAX, | ||
688 | da7219_out_sel_txt); | ||
689 | |||
690 | static const struct snd_kcontrol_new da7219_out_dail_sel_mux = | ||
691 | SOC_DAPM_ENUM("Out DAIL Mux", da7219_out_dail_sel); | ||
692 | |||
693 | static const struct soc_enum da7219_out_dair_sel = | ||
694 | SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAI, | ||
695 | DA7219_DAI_R_SRC_SHIFT, | ||
696 | DA7219_OUT_SRC_MAX, | ||
697 | da7219_out_sel_txt); | ||
698 | |||
699 | static const struct snd_kcontrol_new da7219_out_dair_sel_mux = | ||
700 | SOC_DAPM_ENUM("Out DAIR Mux", da7219_out_dair_sel); | ||
701 | |||
702 | static const struct soc_enum da7219_out_dacl_sel = | ||
703 | SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAC, | ||
704 | DA7219_DAC_L_SRC_SHIFT, | ||
705 | DA7219_OUT_SRC_MAX, | ||
706 | da7219_out_sel_txt); | ||
707 | |||
708 | static const struct snd_kcontrol_new da7219_out_dacl_sel_mux = | ||
709 | SOC_DAPM_ENUM("Out DACL Mux", da7219_out_dacl_sel); | ||
710 | |||
711 | static const struct soc_enum da7219_out_dacr_sel = | ||
712 | SOC_ENUM_SINGLE(DA7219_DIG_ROUTING_DAC, | ||
713 | DA7219_DAC_R_SRC_SHIFT, | ||
714 | DA7219_OUT_SRC_MAX, | ||
715 | da7219_out_sel_txt); | ||
716 | |||
717 | static const struct snd_kcontrol_new da7219_out_dacr_sel_mux = | ||
718 | SOC_DAPM_ENUM("Out DACR Mux", da7219_out_dacr_sel); | ||
719 | |||
720 | |||
721 | /* | ||
722 | * DAPM Mixer Controls | ||
723 | */ | ||
724 | |||
725 | static const struct snd_kcontrol_new da7219_mixin_controls[] = { | ||
726 | SOC_DAPM_SINGLE("Mic Switch", DA7219_MIXIN_L_SELECT, | ||
727 | DA7219_MIXIN_L_MIX_SELECT_SHIFT, | ||
728 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), | ||
729 | }; | ||
730 | |||
731 | static const struct snd_kcontrol_new da7219_mixout_l_controls[] = { | ||
732 | SOC_DAPM_SINGLE("DACL Switch", DA7219_MIXOUT_L_SELECT, | ||
733 | DA7219_MIXOUT_L_MIX_SELECT_SHIFT, | ||
734 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), | ||
735 | }; | ||
736 | |||
737 | static const struct snd_kcontrol_new da7219_mixout_r_controls[] = { | ||
738 | SOC_DAPM_SINGLE("DACR Switch", DA7219_MIXOUT_R_SELECT, | ||
739 | DA7219_MIXOUT_R_MIX_SELECT_SHIFT, | ||
740 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), | ||
741 | }; | ||
742 | |||
743 | #define DA7219_DMIX_ST_CTRLS(reg) \ | ||
744 | SOC_DAPM_SINGLE("Out FilterL Switch", reg, \ | ||
745 | DA7219_DMIX_ST_SRC_OUTFILT1L_SHIFT, \ | ||
746 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), \ | ||
747 | SOC_DAPM_SINGLE("Out FilterR Switch", reg, \ | ||
748 | DA7219_DMIX_ST_SRC_OUTFILT1R_SHIFT, \ | ||
749 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT), \ | ||
750 | SOC_DAPM_SINGLE("Sidetone Switch", reg, \ | ||
751 | DA7219_DMIX_ST_SRC_SIDETONE_SHIFT, \ | ||
752 | DA7219_SWITCH_EN_MAX, DA7219_NO_INVERT) \ | ||
753 | |||
754 | static const struct snd_kcontrol_new da7219_st_out_filtl_mix_controls[] = { | ||
755 | DA7219_DMIX_ST_CTRLS(DA7219_DROUTING_ST_OUTFILT_1L), | ||
756 | }; | ||
757 | |||
758 | static const struct snd_kcontrol_new da7219_st_out_filtr_mix_controls[] = { | ||
759 | DA7219_DMIX_ST_CTRLS(DA7219_DROUTING_ST_OUTFILT_1R), | ||
760 | }; | ||
761 | |||
762 | |||
763 | /* | ||
764 | * DAPM Events | ||
765 | */ | ||
766 | |||
767 | static int da7219_dai_event(struct snd_soc_dapm_widget *w, | ||
768 | struct snd_kcontrol *kcontrol, int event) | ||
769 | { | ||
770 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
771 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
772 | u8 pll_ctrl, pll_status; | ||
773 | int i = 0; | ||
774 | bool srm_lock = false; | ||
775 | |||
776 | switch (event) { | ||
777 | case SND_SOC_DAPM_PRE_PMU: | ||
778 | if (da7219->master) | ||
779 | /* Enable DAI clks for master mode */ | ||
780 | snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE, | ||
781 | DA7219_DAI_CLK_EN_MASK, | ||
782 | DA7219_DAI_CLK_EN_MASK); | ||
783 | |||
784 | /* PC synchronised to DAI */ | ||
785 | snd_soc_update_bits(codec, DA7219_PC_COUNT, | ||
786 | DA7219_PC_FREERUN_MASK, 0); | ||
787 | |||
788 | /* Slave mode, if SRM not enabled no need for status checks */ | ||
789 | pll_ctrl = snd_soc_read(codec, DA7219_PLL_CTRL); | ||
790 | if ((pll_ctrl & DA7219_PLL_MODE_MASK) != DA7219_PLL_MODE_SRM) | ||
791 | return 0; | ||
792 | |||
793 | /* Check SRM has locked */ | ||
794 | do { | ||
795 | pll_status = snd_soc_read(codec, DA7219_PLL_SRM_STS); | ||
796 | if (pll_status & DA7219_PLL_SRM_STS_SRM_LOCK) { | ||
797 | srm_lock = true; | ||
798 | } else { | ||
799 | ++i; | ||
800 | msleep(50); | ||
801 | } | ||
802 | } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); | ||
803 | |||
804 | if (!srm_lock) | ||
805 | dev_warn(codec->dev, "SRM failed to lock\n"); | ||
806 | |||
807 | return 0; | ||
808 | case SND_SOC_DAPM_POST_PMD: | ||
809 | /* PC free-running */ | ||
810 | snd_soc_update_bits(codec, DA7219_PC_COUNT, | ||
811 | DA7219_PC_FREERUN_MASK, | ||
812 | DA7219_PC_FREERUN_MASK); | ||
813 | |||
814 | /* Disable DAI clks if in master mode */ | ||
815 | if (da7219->master) | ||
816 | snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE, | ||
817 | DA7219_DAI_CLK_EN_MASK, 0); | ||
818 | return 0; | ||
819 | default: | ||
820 | return -EINVAL; | ||
821 | } | ||
822 | } | ||
823 | |||
824 | |||
825 | /* | ||
826 | * DAPM Widgets | ||
827 | */ | ||
828 | |||
829 | static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = { | ||
830 | /* Input Supplies */ | ||
831 | SND_SOC_DAPM_SUPPLY("Mic Bias", DA7219_MICBIAS_CTRL, | ||
832 | DA7219_MICBIAS1_EN_SHIFT, DA7219_NO_INVERT, | ||
833 | NULL, 0), | ||
834 | |||
835 | /* Inputs */ | ||
836 | SND_SOC_DAPM_INPUT("MIC"), | ||
837 | |||
838 | /* Input PGAs */ | ||
839 | SND_SOC_DAPM_PGA("Mic PGA", DA7219_MIC_1_CTRL, | ||
840 | DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT, | ||
841 | NULL, 0), | ||
842 | SND_SOC_DAPM_PGA("Mixin PGA", DA7219_MIXIN_L_CTRL, | ||
843 | DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT, | ||
844 | NULL, 0), | ||
845 | |||
846 | /* Input Filters */ | ||
847 | SND_SOC_DAPM_ADC("ADC", NULL, DA7219_ADC_L_CTRL, DA7219_ADC_L_EN_SHIFT, | ||
848 | DA7219_NO_INVERT), | ||
849 | |||
850 | /* Tone Generator */ | ||
851 | SND_SOC_DAPM_SIGGEN("TONE"), | ||
852 | SND_SOC_DAPM_PGA("Tone Generator", DA7219_TONE_GEN_CFG1, | ||
853 | DA7219_START_STOPN_SHIFT, DA7219_NO_INVERT, NULL, 0), | ||
854 | |||
855 | /* Sidetone Input */ | ||
856 | SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7219_SIDETONE_CTRL, | ||
857 | DA7219_SIDETONE_EN_SHIFT, DA7219_NO_INVERT), | ||
858 | |||
859 | /* Input Mixer Supply */ | ||
860 | SND_SOC_DAPM_SUPPLY("Mixer In Supply", DA7219_MIXIN_L_CTRL, | ||
861 | DA7219_MIXIN_L_MIX_EN_SHIFT, DA7219_NO_INVERT, | ||
862 | NULL, 0), | ||
863 | |||
864 | /* Input Mixer */ | ||
865 | SND_SOC_DAPM_MIXER("Mixer In", SND_SOC_NOPM, 0, 0, | ||
866 | da7219_mixin_controls, | ||
867 | ARRAY_SIZE(da7219_mixin_controls)), | ||
868 | |||
869 | /* Input Muxes */ | ||
870 | SND_SOC_DAPM_MUX("Out DAIL Mux", SND_SOC_NOPM, 0, 0, | ||
871 | &da7219_out_dail_sel_mux), | ||
872 | SND_SOC_DAPM_MUX("Out DAIR Mux", SND_SOC_NOPM, 0, 0, | ||
873 | &da7219_out_dair_sel_mux), | ||
874 | |||
875 | /* DAI Supply */ | ||
876 | SND_SOC_DAPM_SUPPLY("DAI", DA7219_DAI_CTRL, DA7219_DAI_EN_SHIFT, | ||
877 | DA7219_NO_INVERT, da7219_dai_event, | ||
878 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
879 | |||
880 | /* DAI */ | ||
881 | SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0), | ||
882 | SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0), | ||
883 | |||
884 | /* Output Muxes */ | ||
885 | SND_SOC_DAPM_MUX("Out DACL Mux", SND_SOC_NOPM, 0, 0, | ||
886 | &da7219_out_dacl_sel_mux), | ||
887 | SND_SOC_DAPM_MUX("Out DACR Mux", SND_SOC_NOPM, 0, 0, | ||
888 | &da7219_out_dacr_sel_mux), | ||
889 | |||
890 | /* Output Mixers */ | ||
891 | SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0, | ||
892 | da7219_mixout_l_controls, | ||
893 | ARRAY_SIZE(da7219_mixout_l_controls)), | ||
894 | SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0, | ||
895 | da7219_mixout_r_controls, | ||
896 | ARRAY_SIZE(da7219_mixout_r_controls)), | ||
897 | |||
898 | /* Sidetone Mixers */ | ||
899 | SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0, | ||
900 | da7219_st_out_filtl_mix_controls, | ||
901 | ARRAY_SIZE(da7219_st_out_filtl_mix_controls)), | ||
902 | SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0, | ||
903 | 0, da7219_st_out_filtr_mix_controls, | ||
904 | ARRAY_SIZE(da7219_st_out_filtr_mix_controls)), | ||
905 | |||
906 | /* DACs */ | ||
907 | SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT, | ||
908 | DA7219_NO_INVERT), | ||
909 | SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT, | ||
910 | DA7219_NO_INVERT), | ||
911 | |||
912 | /* Output PGAs */ | ||
913 | SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL, | ||
914 | DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT, | ||
915 | NULL, 0), | ||
916 | SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL, | ||
917 | DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT, | ||
918 | NULL, 0), | ||
919 | SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL, | ||
920 | DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), | ||
921 | SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL, | ||
922 | DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), | ||
923 | |||
924 | /* Output Supplies */ | ||
925 | SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT, | ||
926 | DA7219_NO_INVERT, NULL, 0), | ||
927 | |||
928 | /* Outputs */ | ||
929 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
930 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
931 | }; | ||
932 | |||
933 | |||
934 | /* | ||
935 | * DAPM Mux Routes | ||
936 | */ | ||
937 | |||
938 | #define DA7219_OUT_DAI_MUX_ROUTES(name) \ | ||
939 | {name, "ADC", "Mixer In"}, \ | ||
940 | {name, "Tone Generator", "Tone Generator"}, \ | ||
941 | {name, "DAIL", "DAIOUT"}, \ | ||
942 | {name, "DAIR", "DAIOUT"} | ||
943 | |||
944 | #define DA7219_OUT_DAC_MUX_ROUTES(name) \ | ||
945 | {name, "ADC", "Mixer In"}, \ | ||
946 | {name, "Tone Generator", "Tone Generator"}, \ | ||
947 | {name, "DAIL", "DAIIN"}, \ | ||
948 | {name, "DAIR", "DAIIN"} | ||
949 | |||
950 | /* | ||
951 | * DAPM Mixer Routes | ||
952 | */ | ||
953 | |||
954 | #define DA7219_DMIX_ST_ROUTES(name) \ | ||
955 | {name, "Out FilterL Switch", "Mixer Out FilterL"}, \ | ||
956 | {name, "Out FilterR Switch", "Mixer Out FilterR"}, \ | ||
957 | {name, "Sidetone Switch", "Sidetone Filter"} | ||
958 | |||
959 | |||
960 | /* | ||
961 | * DAPM audio route definition | ||
962 | */ | ||
963 | |||
964 | static const struct snd_soc_dapm_route da7219_audio_map[] = { | ||
965 | /* Input paths */ | ||
966 | {"MIC", NULL, "Mic Bias"}, | ||
967 | {"Mic PGA", NULL, "MIC"}, | ||
968 | {"Mixin PGA", NULL, "Mic PGA"}, | ||
969 | {"ADC", NULL, "Mixin PGA"}, | ||
970 | |||
971 | {"Sidetone Filter", NULL, "ADC"}, | ||
972 | {"Mixer In", NULL, "Mixer In Supply"}, | ||
973 | {"Mixer In", "Mic Switch", "ADC"}, | ||
974 | |||
975 | {"Tone Generator", NULL, "TONE"}, | ||
976 | |||
977 | DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"), | ||
978 | DA7219_OUT_DAI_MUX_ROUTES("Out DAIR Mux"), | ||
979 | |||
980 | {"DAIOUT", NULL, "Out DAIL Mux"}, | ||
981 | {"DAIOUT", NULL, "Out DAIR Mux"}, | ||
982 | {"DAIOUT", NULL, "DAI"}, | ||
983 | |||
984 | /* Output paths */ | ||
985 | {"DAIIN", NULL, "DAI"}, | ||
986 | |||
987 | DA7219_OUT_DAC_MUX_ROUTES("Out DACL Mux"), | ||
988 | DA7219_OUT_DAC_MUX_ROUTES("Out DACR Mux"), | ||
989 | |||
990 | {"Mixer Out FilterL", "DACL Switch", "Out DACL Mux"}, | ||
991 | {"Mixer Out FilterR", "DACR Switch", "Out DACR Mux"}, | ||
992 | |||
993 | DA7219_DMIX_ST_ROUTES("ST Mixer Out FilterL"), | ||
994 | DA7219_DMIX_ST_ROUTES("ST Mixer Out FilterR"), | ||
995 | |||
996 | {"DACL", NULL, "ST Mixer Out FilterL"}, | ||
997 | {"DACR", NULL, "ST Mixer Out FilterR"}, | ||
998 | |||
999 | {"Mixout Left PGA", NULL, "DACL"}, | ||
1000 | {"Mixout Right PGA", NULL, "DACR"}, | ||
1001 | |||
1002 | {"Headphone Left PGA", NULL, "Mixout Left PGA"}, | ||
1003 | {"Headphone Right PGA", NULL, "Mixout Right PGA"}, | ||
1004 | |||
1005 | {"HPL", NULL, "Headphone Left PGA"}, | ||
1006 | {"HPR", NULL, "Headphone Right PGA"}, | ||
1007 | |||
1008 | {"HPL", NULL, "Charge Pump"}, | ||
1009 | {"HPR", NULL, "Charge Pump"}, | ||
1010 | }; | ||
1011 | |||
1012 | |||
1013 | /* | ||
1014 | * DAI operations | ||
1015 | */ | ||
1016 | |||
1017 | static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
1018 | int clk_id, unsigned int freq, int dir) | ||
1019 | { | ||
1020 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1021 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1022 | int ret = 0; | ||
1023 | |||
1024 | if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) | ||
1025 | return 0; | ||
1026 | |||
1027 | if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) { | ||
1028 | dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", | ||
1029 | freq); | ||
1030 | return -EINVAL; | ||
1031 | } | ||
1032 | |||
1033 | switch (clk_id) { | ||
1034 | case DA7219_CLKSRC_MCLK_SQR: | ||
1035 | snd_soc_update_bits(codec, DA7219_PLL_CTRL, | ||
1036 | DA7219_PLL_MCLK_SQR_EN_MASK, | ||
1037 | DA7219_PLL_MCLK_SQR_EN_MASK); | ||
1038 | break; | ||
1039 | case DA7219_CLKSRC_MCLK: | ||
1040 | snd_soc_update_bits(codec, DA7219_PLL_CTRL, | ||
1041 | DA7219_PLL_MCLK_SQR_EN_MASK, 0); | ||
1042 | break; | ||
1043 | default: | ||
1044 | dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); | ||
1045 | return -EINVAL; | ||
1046 | } | ||
1047 | |||
1048 | da7219->clk_src = clk_id; | ||
1049 | |||
1050 | if (da7219->mclk) { | ||
1051 | freq = clk_round_rate(da7219->mclk, freq); | ||
1052 | ret = clk_set_rate(da7219->mclk, freq); | ||
1053 | if (ret) { | ||
1054 | dev_err(codec_dai->dev, "Failed to set clock rate %d\n", | ||
1055 | freq); | ||
1056 | return ret; | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | da7219->mclk_rate = freq; | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | ||
1066 | int source, unsigned int fref, unsigned int fout) | ||
1067 | { | ||
1068 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1069 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1070 | |||
1071 | u8 pll_ctrl, indiv_bits, indiv; | ||
1072 | u8 pll_frac_top, pll_frac_bot, pll_integer; | ||
1073 | u32 freq_ref; | ||
1074 | u64 frac_div; | ||
1075 | |||
1076 | /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ | ||
1077 | if (da7219->mclk_rate == 32768) { | ||
1078 | indiv_bits = DA7219_PLL_INDIV_2_5_MHZ; | ||
1079 | indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL; | ||
1080 | } else if (da7219->mclk_rate < 2000000) { | ||
1081 | dev_err(codec->dev, "PLL input clock %d below valid range\n", | ||
1082 | da7219->mclk_rate); | ||
1083 | return -EINVAL; | ||
1084 | } else if (da7219->mclk_rate <= 5000000) { | ||
1085 | indiv_bits = DA7219_PLL_INDIV_2_5_MHZ; | ||
1086 | indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL; | ||
1087 | } else if (da7219->mclk_rate <= 10000000) { | ||
1088 | indiv_bits = DA7219_PLL_INDIV_5_10_MHZ; | ||
1089 | indiv = DA7219_PLL_INDIV_5_10_MHZ_VAL; | ||
1090 | } else if (da7219->mclk_rate <= 20000000) { | ||
1091 | indiv_bits = DA7219_PLL_INDIV_10_20_MHZ; | ||
1092 | indiv = DA7219_PLL_INDIV_10_20_MHZ_VAL; | ||
1093 | } else if (da7219->mclk_rate <= 40000000) { | ||
1094 | indiv_bits = DA7219_PLL_INDIV_20_40_MHZ; | ||
1095 | indiv = DA7219_PLL_INDIV_20_40_MHZ_VAL; | ||
1096 | } else if (da7219->mclk_rate <= 54000000) { | ||
1097 | indiv_bits = DA7219_PLL_INDIV_40_54_MHZ; | ||
1098 | indiv = DA7219_PLL_INDIV_40_54_MHZ_VAL; | ||
1099 | } else { | ||
1100 | dev_err(codec->dev, "PLL input clock %d above valid range\n", | ||
1101 | da7219->mclk_rate); | ||
1102 | return -EINVAL; | ||
1103 | } | ||
1104 | freq_ref = (da7219->mclk_rate / indiv); | ||
1105 | pll_ctrl = indiv_bits; | ||
1106 | |||
1107 | /* Configure PLL */ | ||
1108 | switch (source) { | ||
1109 | case DA7219_SYSCLK_MCLK: | ||
1110 | pll_ctrl |= DA7219_PLL_MODE_BYPASS; | ||
1111 | snd_soc_update_bits(codec, DA7219_PLL_CTRL, | ||
1112 | DA7219_PLL_INDIV_MASK | | ||
1113 | DA7219_PLL_MODE_MASK, pll_ctrl); | ||
1114 | return 0; | ||
1115 | case DA7219_SYSCLK_PLL: | ||
1116 | pll_ctrl |= DA7219_PLL_MODE_NORMAL; | ||
1117 | break; | ||
1118 | case DA7219_SYSCLK_PLL_SRM: | ||
1119 | pll_ctrl |= DA7219_PLL_MODE_SRM; | ||
1120 | break; | ||
1121 | case DA7219_SYSCLK_PLL_32KHZ: | ||
1122 | pll_ctrl |= DA7219_PLL_MODE_32KHZ; | ||
1123 | break; | ||
1124 | default: | ||
1125 | dev_err(codec->dev, "Invalid PLL config\n"); | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | /* Calculate dividers for PLL */ | ||
1130 | pll_integer = fout / freq_ref; | ||
1131 | frac_div = (u64)(fout % freq_ref) * 8192ULL; | ||
1132 | do_div(frac_div, freq_ref); | ||
1133 | pll_frac_top = (frac_div >> DA7219_BYTE_SHIFT) & DA7219_BYTE_MASK; | ||
1134 | pll_frac_bot = (frac_div) & DA7219_BYTE_MASK; | ||
1135 | |||
1136 | /* Write PLL config & dividers */ | ||
1137 | snd_soc_write(codec, DA7219_PLL_FRAC_TOP, pll_frac_top); | ||
1138 | snd_soc_write(codec, DA7219_PLL_FRAC_BOT, pll_frac_bot); | ||
1139 | snd_soc_write(codec, DA7219_PLL_INTEGER, pll_integer); | ||
1140 | snd_soc_update_bits(codec, DA7219_PLL_CTRL, | ||
1141 | DA7219_PLL_INDIV_MASK | DA7219_PLL_MODE_MASK, | ||
1142 | pll_ctrl); | ||
1143 | |||
1144 | return 0; | ||
1145 | } | ||
1146 | |||
1147 | static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
1148 | { | ||
1149 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1150 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1151 | u8 dai_clk_mode = 0, dai_ctrl = 0; | ||
1152 | |||
1153 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1154 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1155 | da7219->master = true; | ||
1156 | break; | ||
1157 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1158 | da7219->master = false; | ||
1159 | break; | ||
1160 | default: | ||
1161 | return -EINVAL; | ||
1162 | } | ||
1163 | |||
1164 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1165 | case SND_SOC_DAIFMT_NB_NF: | ||
1166 | break; | ||
1167 | case SND_SOC_DAIFMT_NB_IF: | ||
1168 | dai_clk_mode |= DA7219_DAI_WCLK_POL_INV; | ||
1169 | break; | ||
1170 | case SND_SOC_DAIFMT_IB_NF: | ||
1171 | dai_clk_mode |= DA7219_DAI_CLK_POL_INV; | ||
1172 | break; | ||
1173 | case SND_SOC_DAIFMT_IB_IF: | ||
1174 | dai_clk_mode |= DA7219_DAI_WCLK_POL_INV | | ||
1175 | DA7219_DAI_CLK_POL_INV; | ||
1176 | break; | ||
1177 | default: | ||
1178 | return -EINVAL; | ||
1179 | } | ||
1180 | |||
1181 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1182 | case SND_SOC_DAIFMT_I2S: | ||
1183 | dai_ctrl |= DA7219_DAI_FORMAT_I2S; | ||
1184 | break; | ||
1185 | case SND_SOC_DAIFMT_LEFT_J: | ||
1186 | dai_ctrl |= DA7219_DAI_FORMAT_LEFT_J; | ||
1187 | break; | ||
1188 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1189 | dai_ctrl |= DA7219_DAI_FORMAT_RIGHT_J; | ||
1190 | break; | ||
1191 | case SND_SOC_DAIFMT_DSP_B: | ||
1192 | dai_ctrl |= DA7219_DAI_FORMAT_DSP; | ||
1193 | break; | ||
1194 | default: | ||
1195 | return -EINVAL; | ||
1196 | } | ||
1197 | |||
1198 | /* By default 64 BCLKs per WCLK is supported */ | ||
1199 | dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64; | ||
1200 | |||
1201 | snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE, | ||
1202 | DA7219_DAI_BCLKS_PER_WCLK_MASK | | ||
1203 | DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK, | ||
1204 | dai_clk_mode); | ||
1205 | snd_soc_update_bits(codec, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK, | ||
1206 | dai_ctrl); | ||
1207 | |||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, | ||
1212 | unsigned int tx_mask, unsigned int rx_mask, | ||
1213 | int slots, int slot_width) | ||
1214 | { | ||
1215 | struct snd_soc_codec *codec = dai->codec; | ||
1216 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1217 | u8 dai_bclks_per_wclk; | ||
1218 | u16 offset; | ||
1219 | u32 frame_size; | ||
1220 | |||
1221 | /* No channels enabled so disable TDM, revert to 64-bit frames */ | ||
1222 | if (!tx_mask) { | ||
1223 | snd_soc_update_bits(codec, DA7219_DAI_TDM_CTRL, | ||
1224 | DA7219_DAI_TDM_CH_EN_MASK | | ||
1225 | DA7219_DAI_TDM_MODE_EN_MASK, 0); | ||
1226 | snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE, | ||
1227 | DA7219_DAI_BCLKS_PER_WCLK_MASK, | ||
1228 | DA7219_DAI_BCLKS_PER_WCLK_64); | ||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | /* Check we have valid slots */ | ||
1233 | if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) { | ||
1234 | dev_err(codec->dev, "Invalid number of slots, max = %d\n", | ||
1235 | DA7219_DAI_TDM_MAX_SLOTS); | ||
1236 | return -EINVAL; | ||
1237 | } | ||
1238 | |||
1239 | /* Check we have a valid offset given */ | ||
1240 | if (rx_mask > DA7219_DAI_OFFSET_MAX) { | ||
1241 | dev_err(codec->dev, "Invalid slot offset, max = %d\n", | ||
1242 | DA7219_DAI_OFFSET_MAX); | ||
1243 | return -EINVAL; | ||
1244 | } | ||
1245 | |||
1246 | /* Calculate & validate frame size based on slot info provided. */ | ||
1247 | frame_size = slots * slot_width; | ||
1248 | switch (frame_size) { | ||
1249 | case 32: | ||
1250 | dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; | ||
1251 | break; | ||
1252 | case 64: | ||
1253 | dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; | ||
1254 | break; | ||
1255 | case 128: | ||
1256 | dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; | ||
1257 | break; | ||
1258 | case 256: | ||
1259 | dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; | ||
1260 | break; | ||
1261 | default: | ||
1262 | dev_err(codec->dev, "Invalid frame size %d\n", frame_size); | ||
1263 | return -EINVAL; | ||
1264 | } | ||
1265 | |||
1266 | snd_soc_update_bits(codec, DA7219_DAI_CLK_MODE, | ||
1267 | DA7219_DAI_BCLKS_PER_WCLK_MASK, | ||
1268 | dai_bclks_per_wclk); | ||
1269 | |||
1270 | offset = cpu_to_le16(rx_mask); | ||
1271 | regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER, | ||
1272 | &offset, sizeof(offset)); | ||
1273 | |||
1274 | snd_soc_update_bits(codec, DA7219_DAI_TDM_CTRL, | ||
1275 | DA7219_DAI_TDM_CH_EN_MASK | | ||
1276 | DA7219_DAI_TDM_MODE_EN_MASK, | ||
1277 | (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | | ||
1278 | DA7219_DAI_TDM_MODE_EN_MASK); | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | static int da7219_hw_params(struct snd_pcm_substream *substream, | ||
1284 | struct snd_pcm_hw_params *params, | ||
1285 | struct snd_soc_dai *dai) | ||
1286 | { | ||
1287 | struct snd_soc_codec *codec = dai->codec; | ||
1288 | u8 dai_ctrl = 0, fs; | ||
1289 | unsigned int channels; | ||
1290 | |||
1291 | switch (params_width(params)) { | ||
1292 | case 16: | ||
1293 | dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE; | ||
1294 | break; | ||
1295 | case 20: | ||
1296 | dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE; | ||
1297 | break; | ||
1298 | case 24: | ||
1299 | dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE; | ||
1300 | break; | ||
1301 | case 32: | ||
1302 | dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE; | ||
1303 | break; | ||
1304 | default: | ||
1305 | return -EINVAL; | ||
1306 | } | ||
1307 | |||
1308 | channels = params_channels(params); | ||
1309 | if ((channels < 1) | (channels > DA7219_DAI_CH_NUM_MAX)) { | ||
1310 | dev_err(codec->dev, | ||
1311 | "Invalid number of channels, only 1 to %d supported\n", | ||
1312 | DA7219_DAI_CH_NUM_MAX); | ||
1313 | return -EINVAL; | ||
1314 | } | ||
1315 | dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT; | ||
1316 | |||
1317 | switch (params_rate(params)) { | ||
1318 | case 8000: | ||
1319 | fs = DA7219_SR_8000; | ||
1320 | break; | ||
1321 | case 11025: | ||
1322 | fs = DA7219_SR_11025; | ||
1323 | break; | ||
1324 | case 12000: | ||
1325 | fs = DA7219_SR_12000; | ||
1326 | break; | ||
1327 | case 16000: | ||
1328 | fs = DA7219_SR_16000; | ||
1329 | break; | ||
1330 | case 22050: | ||
1331 | fs = DA7219_SR_22050; | ||
1332 | break; | ||
1333 | case 24000: | ||
1334 | fs = DA7219_SR_24000; | ||
1335 | break; | ||
1336 | case 32000: | ||
1337 | fs = DA7219_SR_32000; | ||
1338 | break; | ||
1339 | case 44100: | ||
1340 | fs = DA7219_SR_44100; | ||
1341 | break; | ||
1342 | case 48000: | ||
1343 | fs = DA7219_SR_48000; | ||
1344 | break; | ||
1345 | case 88200: | ||
1346 | fs = DA7219_SR_88200; | ||
1347 | break; | ||
1348 | case 96000: | ||
1349 | fs = DA7219_SR_96000; | ||
1350 | break; | ||
1351 | default: | ||
1352 | return -EINVAL; | ||
1353 | } | ||
1354 | |||
1355 | snd_soc_update_bits(codec, DA7219_DAI_CTRL, | ||
1356 | DA7219_DAI_WORD_LENGTH_MASK | | ||
1357 | DA7219_DAI_CH_NUM_MASK, | ||
1358 | dai_ctrl); | ||
1359 | snd_soc_write(codec, DA7219_SR, fs); | ||
1360 | |||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | static const struct snd_soc_dai_ops da7219_dai_ops = { | ||
1365 | .hw_params = da7219_hw_params, | ||
1366 | .set_sysclk = da7219_set_dai_sysclk, | ||
1367 | .set_pll = da7219_set_dai_pll, | ||
1368 | .set_fmt = da7219_set_dai_fmt, | ||
1369 | .set_tdm_slot = da7219_set_dai_tdm_slot, | ||
1370 | }; | ||
1371 | |||
1372 | #define DA7219_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1373 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
1374 | |||
1375 | static struct snd_soc_dai_driver da7219_dai = { | ||
1376 | .name = "da7219-hifi", | ||
1377 | .playback = { | ||
1378 | .stream_name = "Playback", | ||
1379 | .channels_min = 1, | ||
1380 | .channels_max = DA7219_DAI_CH_NUM_MAX, | ||
1381 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
1382 | .formats = DA7219_FORMATS, | ||
1383 | }, | ||
1384 | .capture = { | ||
1385 | .stream_name = "Capture", | ||
1386 | .channels_min = 1, | ||
1387 | .channels_max = DA7219_DAI_CH_NUM_MAX, | ||
1388 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
1389 | .formats = DA7219_FORMATS, | ||
1390 | }, | ||
1391 | .ops = &da7219_dai_ops, | ||
1392 | .symmetric_rates = 1, | ||
1393 | .symmetric_channels = 1, | ||
1394 | .symmetric_samplebits = 1, | ||
1395 | }; | ||
1396 | |||
1397 | |||
1398 | /* | ||
1399 | * DT | ||
1400 | */ | ||
1401 | |||
1402 | static const struct of_device_id da7219_of_match[] = { | ||
1403 | { .compatible = "dlg,da7219", }, | ||
1404 | { } | ||
1405 | }; | ||
1406 | MODULE_DEVICE_TABLE(of, da7219_of_match); | ||
1407 | |||
1408 | static enum da7219_ldo_lvl_sel da7219_of_ldo_lvl(struct snd_soc_codec *codec, | ||
1409 | u32 val) | ||
1410 | { | ||
1411 | switch (val) { | ||
1412 | case 1050: | ||
1413 | return DA7219_LDO_LVL_SEL_1_05V; | ||
1414 | case 1100: | ||
1415 | return DA7219_LDO_LVL_SEL_1_10V; | ||
1416 | case 1200: | ||
1417 | return DA7219_LDO_LVL_SEL_1_20V; | ||
1418 | case 1400: | ||
1419 | return DA7219_LDO_LVL_SEL_1_40V; | ||
1420 | default: | ||
1421 | dev_warn(codec->dev, "Invalid LDO level"); | ||
1422 | return DA7219_LDO_LVL_SEL_1_05V; | ||
1423 | } | ||
1424 | } | ||
1425 | |||
1426 | static enum da7219_micbias_voltage | ||
1427 | da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) | ||
1428 | { | ||
1429 | switch (val) { | ||
1430 | case 1800: | ||
1431 | return DA7219_MICBIAS_1_8V; | ||
1432 | case 2000: | ||
1433 | return DA7219_MICBIAS_2_0V; | ||
1434 | case 2200: | ||
1435 | return DA7219_MICBIAS_2_2V; | ||
1436 | case 2400: | ||
1437 | return DA7219_MICBIAS_2_4V; | ||
1438 | case 2600: | ||
1439 | return DA7219_MICBIAS_2_6V; | ||
1440 | default: | ||
1441 | dev_warn(codec->dev, "Invalid micbias level"); | ||
1442 | return DA7219_MICBIAS_2_2V; | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | static enum da7219_mic_amp_in_sel | ||
1447 | da7219_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str) | ||
1448 | { | ||
1449 | if (!strcmp(str, "diff")) { | ||
1450 | return DA7219_MIC_AMP_IN_SEL_DIFF; | ||
1451 | } else if (!strcmp(str, "se_p")) { | ||
1452 | return DA7219_MIC_AMP_IN_SEL_SE_P; | ||
1453 | } else if (!strcmp(str, "se_n")) { | ||
1454 | return DA7219_MIC_AMP_IN_SEL_SE_N; | ||
1455 | } else { | ||
1456 | dev_warn(codec->dev, "Invalid mic input type selection"); | ||
1457 | return DA7219_MIC_AMP_IN_SEL_DIFF; | ||
1458 | } | ||
1459 | } | ||
1460 | |||
1461 | static struct da7219_pdata *da7219_of_to_pdata(struct snd_soc_codec *codec) | ||
1462 | { | ||
1463 | struct device_node *np = codec->dev->of_node; | ||
1464 | struct da7219_pdata *pdata; | ||
1465 | const char *of_str; | ||
1466 | u32 of_val32; | ||
1467 | |||
1468 | pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL); | ||
1469 | if (!pdata) | ||
1470 | return NULL; | ||
1471 | |||
1472 | if (of_property_read_u32(np, "dlg,ldo-lvl", &of_val32) >= 0) | ||
1473 | pdata->ldo_lvl_sel = da7219_of_ldo_lvl(codec, of_val32); | ||
1474 | |||
1475 | if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0) | ||
1476 | pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32); | ||
1477 | else | ||
1478 | pdata->micbias_lvl = DA7219_MICBIAS_2_2V; | ||
1479 | |||
1480 | if (!of_property_read_string(np, "dlg,mic-amp-in-sel", &of_str)) | ||
1481 | pdata->mic_amp_in_sel = da7219_of_mic_amp_in_sel(codec, of_str); | ||
1482 | else | ||
1483 | pdata->mic_amp_in_sel = DA7219_MIC_AMP_IN_SEL_DIFF; | ||
1484 | |||
1485 | return pdata; | ||
1486 | } | ||
1487 | |||
1488 | |||
1489 | /* | ||
1490 | * Codec driver functions | ||
1491 | */ | ||
1492 | |||
1493 | static int da7219_set_bias_level(struct snd_soc_codec *codec, | ||
1494 | enum snd_soc_bias_level level) | ||
1495 | { | ||
1496 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1497 | |||
1498 | switch (level) { | ||
1499 | case SND_SOC_BIAS_ON: | ||
1500 | case SND_SOC_BIAS_PREPARE: | ||
1501 | break; | ||
1502 | case SND_SOC_BIAS_STANDBY: | ||
1503 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { | ||
1504 | /* MCLK */ | ||
1505 | clk_prepare_enable(da7219->mclk); | ||
1506 | |||
1507 | /* Master bias */ | ||
1508 | snd_soc_update_bits(codec, DA7219_REFERENCES, | ||
1509 | DA7219_BIAS_EN_MASK, | ||
1510 | DA7219_BIAS_EN_MASK); | ||
1511 | |||
1512 | /* Enable Internal Digital LDO */ | ||
1513 | snd_soc_update_bits(codec, DA7219_LDO_CTRL, | ||
1514 | DA7219_LDO_EN_MASK, | ||
1515 | DA7219_LDO_EN_MASK); | ||
1516 | } | ||
1517 | break; | ||
1518 | case SND_SOC_BIAS_OFF: | ||
1519 | /* Only disable if jack detection not active */ | ||
1520 | if (!da7219->aad->jack) { | ||
1521 | /* Bypass Internal Digital LDO */ | ||
1522 | snd_soc_update_bits(codec, DA7219_LDO_CTRL, | ||
1523 | DA7219_LDO_EN_MASK, 0); | ||
1524 | |||
1525 | /* Master bias */ | ||
1526 | snd_soc_update_bits(codec, DA7219_REFERENCES, | ||
1527 | DA7219_BIAS_EN_MASK, 0); | ||
1528 | } | ||
1529 | |||
1530 | /* MCLK */ | ||
1531 | clk_disable_unprepare(da7219->mclk); | ||
1532 | break; | ||
1533 | } | ||
1534 | |||
1535 | return 0; | ||
1536 | } | ||
1537 | |||
1538 | static const char *da7219_supply_names[DA7219_NUM_SUPPLIES] = { | ||
1539 | [DA7219_SUPPLY_VDD] = "VDD", | ||
1540 | [DA7219_SUPPLY_VDDMIC] = "VDDMIC", | ||
1541 | [DA7219_SUPPLY_VDDIO] = "VDDIO", | ||
1542 | }; | ||
1543 | |||
1544 | static int da7219_handle_supplies(struct snd_soc_codec *codec) | ||
1545 | { | ||
1546 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1547 | struct regulator *vddio; | ||
1548 | u8 io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_2_5V_3_6V; | ||
1549 | int i, ret; | ||
1550 | |||
1551 | /* Get required supplies */ | ||
1552 | for (i = 0; i < DA7219_NUM_SUPPLIES; ++i) | ||
1553 | da7219->supplies[i].supply = da7219_supply_names[i]; | ||
1554 | |||
1555 | ret = devm_regulator_bulk_get(codec->dev, DA7219_NUM_SUPPLIES, | ||
1556 | da7219->supplies); | ||
1557 | if (ret) | ||
1558 | return ret; | ||
1559 | |||
1560 | /* Determine VDDIO voltage provided */ | ||
1561 | vddio = da7219->supplies[DA7219_SUPPLY_VDDIO].consumer; | ||
1562 | ret = regulator_get_voltage(vddio); | ||
1563 | if (ret < 1200000) | ||
1564 | dev_warn(codec->dev, "Invalid VDDIO voltage\n"); | ||
1565 | else if (ret < 2800000) | ||
1566 | io_voltage_lvl = DA7219_IO_VOLTAGE_LEVEL_1_2V_2_8V; | ||
1567 | |||
1568 | /* Enable main supplies */ | ||
1569 | ret = regulator_bulk_enable(DA7219_NUM_SUPPLIES, da7219->supplies); | ||
1570 | |||
1571 | /* Ensure device in active mode */ | ||
1572 | snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, DA7219_SYSTEM_ACTIVE_MASK); | ||
1573 | |||
1574 | /* Update IO voltage level range */ | ||
1575 | snd_soc_write(codec, DA7219_IO_CTRL, io_voltage_lvl); | ||
1576 | |||
1577 | return ret; | ||
1578 | } | ||
1579 | |||
1580 | static void da7219_handle_pdata(struct snd_soc_codec *codec) | ||
1581 | { | ||
1582 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1583 | struct da7219_pdata *pdata = da7219->pdata; | ||
1584 | |||
1585 | if (pdata) { | ||
1586 | u8 micbias_lvl = 0; | ||
1587 | |||
1588 | /* Internal LDO */ | ||
1589 | switch (pdata->ldo_lvl_sel) { | ||
1590 | case DA7219_LDO_LVL_SEL_1_05V: | ||
1591 | case DA7219_LDO_LVL_SEL_1_10V: | ||
1592 | case DA7219_LDO_LVL_SEL_1_20V: | ||
1593 | case DA7219_LDO_LVL_SEL_1_40V: | ||
1594 | snd_soc_update_bits(codec, DA7219_LDO_CTRL, | ||
1595 | DA7219_LDO_LEVEL_SELECT_MASK, | ||
1596 | (pdata->ldo_lvl_sel << | ||
1597 | DA7219_LDO_LEVEL_SELECT_SHIFT)); | ||
1598 | break; | ||
1599 | } | ||
1600 | |||
1601 | /* Mic Bias voltages */ | ||
1602 | switch (pdata->micbias_lvl) { | ||
1603 | case DA7219_MICBIAS_1_8V: | ||
1604 | case DA7219_MICBIAS_2_0V: | ||
1605 | case DA7219_MICBIAS_2_2V: | ||
1606 | case DA7219_MICBIAS_2_4V: | ||
1607 | case DA7219_MICBIAS_2_6V: | ||
1608 | micbias_lvl |= (pdata->micbias_lvl << | ||
1609 | DA7219_MICBIAS1_LEVEL_SHIFT); | ||
1610 | break; | ||
1611 | } | ||
1612 | |||
1613 | snd_soc_write(codec, DA7219_MICBIAS_CTRL, micbias_lvl); | ||
1614 | |||
1615 | /* Mic */ | ||
1616 | switch (pdata->mic_amp_in_sel) { | ||
1617 | case DA7219_MIC_AMP_IN_SEL_DIFF: | ||
1618 | case DA7219_MIC_AMP_IN_SEL_SE_P: | ||
1619 | case DA7219_MIC_AMP_IN_SEL_SE_N: | ||
1620 | snd_soc_write(codec, DA7219_MIC_1_SELECT, | ||
1621 | pdata->mic_amp_in_sel); | ||
1622 | break; | ||
1623 | } | ||
1624 | } | ||
1625 | } | ||
1626 | |||
1627 | static int da7219_probe(struct snd_soc_codec *codec) | ||
1628 | { | ||
1629 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1630 | int ret; | ||
1631 | |||
1632 | mutex_init(&da7219->lock); | ||
1633 | |||
1634 | /* Regulator configuration */ | ||
1635 | ret = da7219_handle_supplies(codec); | ||
1636 | if (ret) | ||
1637 | return ret; | ||
1638 | |||
1639 | /* Handle DT/Platform data */ | ||
1640 | if (codec->dev->of_node) | ||
1641 | da7219->pdata = da7219_of_to_pdata(codec); | ||
1642 | else | ||
1643 | da7219->pdata = dev_get_platdata(codec->dev); | ||
1644 | |||
1645 | da7219_handle_pdata(codec); | ||
1646 | |||
1647 | /* Check if MCLK provided */ | ||
1648 | da7219->mclk = devm_clk_get(codec->dev, "mclk"); | ||
1649 | if (IS_ERR(da7219->mclk)) { | ||
1650 | if (PTR_ERR(da7219->mclk) != -ENOENT) | ||
1651 | return PTR_ERR(da7219->mclk); | ||
1652 | else | ||
1653 | da7219->mclk = NULL; | ||
1654 | } | ||
1655 | |||
1656 | /* Default PC counter to free-running */ | ||
1657 | snd_soc_update_bits(codec, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK, | ||
1658 | DA7219_PC_FREERUN_MASK); | ||
1659 | |||
1660 | /* Default gain ramping */ | ||
1661 | snd_soc_update_bits(codec, DA7219_MIXIN_L_CTRL, | ||
1662 | DA7219_MIXIN_L_AMP_RAMP_EN_MASK, | ||
1663 | DA7219_MIXIN_L_AMP_RAMP_EN_MASK); | ||
1664 | snd_soc_update_bits(codec, DA7219_ADC_L_CTRL, DA7219_ADC_L_RAMP_EN_MASK, | ||
1665 | DA7219_ADC_L_RAMP_EN_MASK); | ||
1666 | snd_soc_update_bits(codec, DA7219_DAC_L_CTRL, DA7219_DAC_L_RAMP_EN_MASK, | ||
1667 | DA7219_DAC_L_RAMP_EN_MASK); | ||
1668 | snd_soc_update_bits(codec, DA7219_DAC_R_CTRL, DA7219_DAC_R_RAMP_EN_MASK, | ||
1669 | DA7219_DAC_R_RAMP_EN_MASK); | ||
1670 | snd_soc_update_bits(codec, DA7219_HP_L_CTRL, | ||
1671 | DA7219_HP_L_AMP_RAMP_EN_MASK, | ||
1672 | DA7219_HP_L_AMP_RAMP_EN_MASK); | ||
1673 | snd_soc_update_bits(codec, DA7219_HP_R_CTRL, | ||
1674 | DA7219_HP_R_AMP_RAMP_EN_MASK, | ||
1675 | DA7219_HP_R_AMP_RAMP_EN_MASK); | ||
1676 | |||
1677 | /* Default infinite tone gen, start/stop by Kcontrol */ | ||
1678 | snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK); | ||
1679 | |||
1680 | /* Initialise AAD block */ | ||
1681 | return da7219_aad_init(codec); | ||
1682 | } | ||
1683 | |||
1684 | static int da7219_remove(struct snd_soc_codec *codec) | ||
1685 | { | ||
1686 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1687 | |||
1688 | da7219_aad_exit(codec); | ||
1689 | |||
1690 | /* Supplies */ | ||
1691 | return regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies); | ||
1692 | } | ||
1693 | |||
1694 | #ifdef CONFIG_PM | ||
1695 | static int da7219_suspend(struct snd_soc_codec *codec) | ||
1696 | { | ||
1697 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1698 | |||
1699 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1700 | |||
1701 | /* Put device into standby mode if jack detection disabled */ | ||
1702 | if (!da7219->aad->jack) | ||
1703 | snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, 0); | ||
1704 | |||
1705 | return 0; | ||
1706 | } | ||
1707 | |||
1708 | static int da7219_resume(struct snd_soc_codec *codec) | ||
1709 | { | ||
1710 | struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); | ||
1711 | |||
1712 | /* Put device into active mode if previously pushed to standby */ | ||
1713 | if (!da7219->aad->jack) | ||
1714 | snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, | ||
1715 | DA7219_SYSTEM_ACTIVE_MASK); | ||
1716 | |||
1717 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1718 | |||
1719 | return 0; | ||
1720 | } | ||
1721 | #else | ||
1722 | #define da7219_suspend NULL | ||
1723 | #define da7219_resume NULL | ||
1724 | #endif | ||
1725 | |||
1726 | static struct snd_soc_codec_driver soc_codec_dev_da7219 = { | ||
1727 | .probe = da7219_probe, | ||
1728 | .remove = da7219_remove, | ||
1729 | .suspend = da7219_suspend, | ||
1730 | .resume = da7219_resume, | ||
1731 | .set_bias_level = da7219_set_bias_level, | ||
1732 | |||
1733 | .controls = da7219_snd_controls, | ||
1734 | .num_controls = ARRAY_SIZE(da7219_snd_controls), | ||
1735 | |||
1736 | .dapm_widgets = da7219_dapm_widgets, | ||
1737 | .num_dapm_widgets = ARRAY_SIZE(da7219_dapm_widgets), | ||
1738 | .dapm_routes = da7219_audio_map, | ||
1739 | .num_dapm_routes = ARRAY_SIZE(da7219_audio_map), | ||
1740 | }; | ||
1741 | |||
1742 | |||
1743 | /* | ||
1744 | * Regmap configs | ||
1745 | */ | ||
1746 | |||
1747 | static struct reg_default da7219_reg_defaults[] = { | ||
1748 | { DA7219_MIC_1_SELECT, 0x00 }, | ||
1749 | { DA7219_CIF_TIMEOUT_CTRL, 0x01 }, | ||
1750 | { DA7219_SR_24_48, 0x00 }, | ||
1751 | { DA7219_SR, 0x0A }, | ||
1752 | { DA7219_CIF_I2C_ADDR_CFG, 0x02 }, | ||
1753 | { DA7219_PLL_CTRL, 0x10 }, | ||
1754 | { DA7219_PLL_FRAC_TOP, 0x00 }, | ||
1755 | { DA7219_PLL_FRAC_BOT, 0x00 }, | ||
1756 | { DA7219_PLL_INTEGER, 0x20 }, | ||
1757 | { DA7219_DIG_ROUTING_DAI, 0x10 }, | ||
1758 | { DA7219_DAI_CLK_MODE, 0x01 }, | ||
1759 | { DA7219_DAI_CTRL, 0x28 }, | ||
1760 | { DA7219_DAI_TDM_CTRL, 0x40 }, | ||
1761 | { DA7219_DIG_ROUTING_DAC, 0x32 }, | ||
1762 | { DA7219_DAI_OFFSET_LOWER, 0x00 }, | ||
1763 | { DA7219_DAI_OFFSET_UPPER, 0x00 }, | ||
1764 | { DA7219_REFERENCES, 0x00 }, | ||
1765 | { DA7219_MIXIN_L_SELECT, 0x00 }, | ||
1766 | { DA7219_MIXIN_L_GAIN, 0x03 }, | ||
1767 | { DA7219_ADC_L_GAIN, 0x6F }, | ||
1768 | { DA7219_ADC_FILTERS1, 0x80 }, | ||
1769 | { DA7219_MIC_1_GAIN, 0x01 }, | ||
1770 | { DA7219_SIDETONE_CTRL, 0x40 }, | ||
1771 | { DA7219_SIDETONE_GAIN, 0x0E }, | ||
1772 | { DA7219_DROUTING_ST_OUTFILT_1L, 0x01 }, | ||
1773 | { DA7219_DROUTING_ST_OUTFILT_1R, 0x02 }, | ||
1774 | { DA7219_DAC_FILTERS5, 0x00 }, | ||
1775 | { DA7219_DAC_FILTERS2, 0x88 }, | ||
1776 | { DA7219_DAC_FILTERS3, 0x88 }, | ||
1777 | { DA7219_DAC_FILTERS4, 0x08 }, | ||
1778 | { DA7219_DAC_FILTERS1, 0x80 }, | ||
1779 | { DA7219_DAC_L_GAIN, 0x6F }, | ||
1780 | { DA7219_DAC_R_GAIN, 0x6F }, | ||
1781 | { DA7219_CP_CTRL, 0x20 }, | ||
1782 | { DA7219_HP_L_GAIN, 0x39 }, | ||
1783 | { DA7219_HP_R_GAIN, 0x39 }, | ||
1784 | { DA7219_MIXOUT_L_SELECT, 0x00 }, | ||
1785 | { DA7219_MIXOUT_R_SELECT, 0x00 }, | ||
1786 | { DA7219_MICBIAS_CTRL, 0x03 }, | ||
1787 | { DA7219_MIC_1_CTRL, 0x40 }, | ||
1788 | { DA7219_MIXIN_L_CTRL, 0x40 }, | ||
1789 | { DA7219_ADC_L_CTRL, 0x40 }, | ||
1790 | { DA7219_DAC_L_CTRL, 0x40 }, | ||
1791 | { DA7219_DAC_R_CTRL, 0x40 }, | ||
1792 | { DA7219_HP_L_CTRL, 0x40 }, | ||
1793 | { DA7219_HP_R_CTRL, 0x40 }, | ||
1794 | { DA7219_MIXOUT_L_CTRL, 0x10 }, | ||
1795 | { DA7219_MIXOUT_R_CTRL, 0x10 }, | ||
1796 | { DA7219_CHIP_ID1, 0x23 }, | ||
1797 | { DA7219_CHIP_ID2, 0x93 }, | ||
1798 | { DA7219_CHIP_REVISION, 0x00 }, | ||
1799 | { DA7219_LDO_CTRL, 0x00 }, | ||
1800 | { DA7219_IO_CTRL, 0x00 }, | ||
1801 | { DA7219_GAIN_RAMP_CTRL, 0x00 }, | ||
1802 | { DA7219_PC_COUNT, 0x02 }, | ||
1803 | { DA7219_CP_VOL_THRESHOLD1, 0x0E }, | ||
1804 | { DA7219_DIG_CTRL, 0x00 }, | ||
1805 | { DA7219_ALC_CTRL2, 0x00 }, | ||
1806 | { DA7219_ALC_CTRL3, 0x00 }, | ||
1807 | { DA7219_ALC_NOISE, 0x3F }, | ||
1808 | { DA7219_ALC_TARGET_MIN, 0x3F }, | ||
1809 | { DA7219_ALC_TARGET_MAX, 0x00 }, | ||
1810 | { DA7219_ALC_GAIN_LIMITS, 0xFF }, | ||
1811 | { DA7219_ALC_ANA_GAIN_LIMITS, 0x71 }, | ||
1812 | { DA7219_ALC_ANTICLIP_CTRL, 0x00 }, | ||
1813 | { DA7219_ALC_ANTICLIP_LEVEL, 0x00 }, | ||
1814 | { DA7219_DAC_NG_SETUP_TIME, 0x00 }, | ||
1815 | { DA7219_DAC_NG_OFF_THRESH, 0x00 }, | ||
1816 | { DA7219_DAC_NG_ON_THRESH, 0x00 }, | ||
1817 | { DA7219_DAC_NG_CTRL, 0x00 }, | ||
1818 | { DA7219_TONE_GEN_CFG1, 0x00 }, | ||
1819 | { DA7219_TONE_GEN_CFG2, 0x00 }, | ||
1820 | { DA7219_TONE_GEN_CYCLES, 0x00 }, | ||
1821 | { DA7219_TONE_GEN_FREQ1_L, 0x55 }, | ||
1822 | { DA7219_TONE_GEN_FREQ1_U, 0x15 }, | ||
1823 | { DA7219_TONE_GEN_FREQ2_L, 0x00 }, | ||
1824 | { DA7219_TONE_GEN_FREQ2_U, 0x40 }, | ||
1825 | { DA7219_TONE_GEN_ON_PER, 0x02 }, | ||
1826 | { DA7219_TONE_GEN_OFF_PER, 0x01 }, | ||
1827 | { DA7219_ACCDET_IRQ_MASK_A, 0x00 }, | ||
1828 | { DA7219_ACCDET_IRQ_MASK_B, 0x00 }, | ||
1829 | { DA7219_ACCDET_CONFIG_1, 0xD6 }, | ||
1830 | { DA7219_ACCDET_CONFIG_2, 0x34 }, | ||
1831 | { DA7219_ACCDET_CONFIG_3, 0x0A }, | ||
1832 | { DA7219_ACCDET_CONFIG_4, 0x16 }, | ||
1833 | { DA7219_ACCDET_CONFIG_5, 0x21 }, | ||
1834 | { DA7219_ACCDET_CONFIG_6, 0x3E }, | ||
1835 | { DA7219_ACCDET_CONFIG_7, 0x01 }, | ||
1836 | { DA7219_SYSTEM_ACTIVE, 0x00 }, | ||
1837 | }; | ||
1838 | |||
1839 | static bool da7219_volatile_register(struct device *dev, unsigned int reg) | ||
1840 | { | ||
1841 | switch (reg) { | ||
1842 | case DA7219_MIC_1_GAIN_STATUS: | ||
1843 | case DA7219_MIXIN_L_GAIN_STATUS: | ||
1844 | case DA7219_ADC_L_GAIN_STATUS: | ||
1845 | case DA7219_DAC_L_GAIN_STATUS: | ||
1846 | case DA7219_DAC_R_GAIN_STATUS: | ||
1847 | case DA7219_HP_L_GAIN_STATUS: | ||
1848 | case DA7219_HP_R_GAIN_STATUS: | ||
1849 | case DA7219_CIF_CTRL: | ||
1850 | case DA7219_PLL_SRM_STS: | ||
1851 | case DA7219_ALC_CTRL1: | ||
1852 | case DA7219_SYSTEM_MODES_INPUT: | ||
1853 | case DA7219_SYSTEM_MODES_OUTPUT: | ||
1854 | case DA7219_ALC_OFFSET_AUTO_M_L: | ||
1855 | case DA7219_ALC_OFFSET_AUTO_U_L: | ||
1856 | case DA7219_TONE_GEN_CFG1: | ||
1857 | case DA7219_ACCDET_STATUS_A: | ||
1858 | case DA7219_ACCDET_STATUS_B: | ||
1859 | case DA7219_ACCDET_IRQ_EVENT_A: | ||
1860 | case DA7219_ACCDET_IRQ_EVENT_B: | ||
1861 | case DA7219_ACCDET_CONFIG_8: | ||
1862 | case DA7219_SYSTEM_STATUS: | ||
1863 | return 1; | ||
1864 | default: | ||
1865 | return 0; | ||
1866 | } | ||
1867 | } | ||
1868 | |||
1869 | static const struct regmap_config da7219_regmap_config = { | ||
1870 | .reg_bits = 8, | ||
1871 | .val_bits = 8, | ||
1872 | |||
1873 | .max_register = DA7219_SYSTEM_ACTIVE, | ||
1874 | .reg_defaults = da7219_reg_defaults, | ||
1875 | .num_reg_defaults = ARRAY_SIZE(da7219_reg_defaults), | ||
1876 | .volatile_reg = da7219_volatile_register, | ||
1877 | .cache_type = REGCACHE_RBTREE, | ||
1878 | }; | ||
1879 | |||
1880 | |||
1881 | /* | ||
1882 | * I2C layer | ||
1883 | */ | ||
1884 | |||
1885 | static int da7219_i2c_probe(struct i2c_client *i2c, | ||
1886 | const struct i2c_device_id *id) | ||
1887 | { | ||
1888 | struct da7219_priv *da7219; | ||
1889 | int ret; | ||
1890 | |||
1891 | da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv), | ||
1892 | GFP_KERNEL); | ||
1893 | if (!da7219) | ||
1894 | return -ENOMEM; | ||
1895 | |||
1896 | i2c_set_clientdata(i2c, da7219); | ||
1897 | |||
1898 | da7219->regmap = devm_regmap_init_i2c(i2c, &da7219_regmap_config); | ||
1899 | if (IS_ERR(da7219->regmap)) { | ||
1900 | ret = PTR_ERR(da7219->regmap); | ||
1901 | dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); | ||
1902 | return ret; | ||
1903 | } | ||
1904 | |||
1905 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219, | ||
1906 | &da7219_dai, 1); | ||
1907 | if (ret < 0) { | ||
1908 | dev_err(&i2c->dev, "Failed to register da7219 codec: %d\n", | ||
1909 | ret); | ||
1910 | } | ||
1911 | return ret; | ||
1912 | } | ||
1913 | |||
1914 | static int da7219_i2c_remove(struct i2c_client *client) | ||
1915 | { | ||
1916 | snd_soc_unregister_codec(&client->dev); | ||
1917 | return 0; | ||
1918 | } | ||
1919 | |||
1920 | static const struct i2c_device_id da7219_i2c_id[] = { | ||
1921 | { "da7219", }, | ||
1922 | { } | ||
1923 | }; | ||
1924 | MODULE_DEVICE_TABLE(i2c, da7219_i2c_id); | ||
1925 | |||
1926 | static struct i2c_driver da7219_i2c_driver = { | ||
1927 | .driver = { | ||
1928 | .name = "da7219", | ||
1929 | .of_match_table = da7219_of_match, | ||
1930 | }, | ||
1931 | .probe = da7219_i2c_probe, | ||
1932 | .remove = da7219_i2c_remove, | ||
1933 | .id_table = da7219_i2c_id, | ||
1934 | }; | ||
1935 | |||
1936 | module_i2c_driver(da7219_i2c_driver); | ||
1937 | |||
1938 | MODULE_DESCRIPTION("ASoC DA7219 Codec Driver"); | ||
1939 | MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); | ||
1940 | MODULE_LICENSE("GPL"); | ||