diff options
Diffstat (limited to 'sound/soc/codecs/es8328.c')
-rw-r--r-- | sound/soc/codecs/es8328.c | 756 |
1 files changed, 756 insertions, 0 deletions
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c new file mode 100644 index 000000000000..f27325155ace --- /dev/null +++ b/sound/soc/codecs/es8328.c | |||
@@ -0,0 +1,756 @@ | |||
1 | /* | ||
2 | * es8328.c -- ES8328 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2014 Sutajio Ko-Usagi PTE LTD | ||
5 | * | ||
6 | * Author: Sean Cross <xobs@kosagi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/of_device.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/regulator/consumer.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/tlv.h> | ||
27 | #include "es8328.h" | ||
28 | |||
29 | #define ES8328_SYSCLK_RATE_1X 11289600 | ||
30 | #define ES8328_SYSCLK_RATE_2X 22579200 | ||
31 | |||
32 | /* Run the codec at 22.5792 or 11.2896 MHz to support these rates */ | ||
33 | static struct { | ||
34 | int rate; | ||
35 | u8 ratio; | ||
36 | } mclk_ratios[] = { | ||
37 | { 8000, 9 }, | ||
38 | {11025, 7 }, | ||
39 | {22050, 4 }, | ||
40 | {44100, 2 }, | ||
41 | }; | ||
42 | |||
43 | /* regulator supplies for sgtl5000, VDDD is an optional external supply */ | ||
44 | enum sgtl5000_regulator_supplies { | ||
45 | DVDD, | ||
46 | AVDD, | ||
47 | PVDD, | ||
48 | HPVDD, | ||
49 | ES8328_SUPPLY_NUM | ||
50 | }; | ||
51 | |||
52 | /* vddd is optional supply */ | ||
53 | static const char * const supply_names[ES8328_SUPPLY_NUM] = { | ||
54 | "DVDD", | ||
55 | "AVDD", | ||
56 | "PVDD", | ||
57 | "HPVDD", | ||
58 | }; | ||
59 | |||
60 | #define ES8328_RATES (SNDRV_PCM_RATE_44100 | \ | ||
61 | SNDRV_PCM_RATE_22050 | \ | ||
62 | SNDRV_PCM_RATE_11025) | ||
63 | #define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) | ||
64 | |||
65 | struct es8328_priv { | ||
66 | struct regmap *regmap; | ||
67 | struct clk *clk; | ||
68 | int playback_fs; | ||
69 | bool deemph; | ||
70 | struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; | ||
71 | }; | ||
72 | |||
73 | /* | ||
74 | * ES8328 Controls | ||
75 | */ | ||
76 | |||
77 | static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert", | ||
78 | "L + R Invert"}; | ||
79 | static SOC_ENUM_SINGLE_DECL(adcpol, | ||
80 | ES8328_ADCCONTROL6, 6, adcpol_txt); | ||
81 | |||
82 | static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0); | ||
83 | static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0); | ||
84 | static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); | ||
85 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); | ||
86 | static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0); | ||
87 | |||
88 | static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; | ||
89 | |||
90 | static int es8328_set_deemph(struct snd_soc_codec *codec) | ||
91 | { | ||
92 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
93 | int val, i, best; | ||
94 | |||
95 | /* | ||
96 | * If we're using deemphasis select the nearest available sample | ||
97 | * rate. | ||
98 | */ | ||
99 | if (es8328->deemph) { | ||
100 | best = 1; | ||
101 | for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { | ||
102 | if (abs(deemph_settings[i] - es8328->playback_fs) < | ||
103 | abs(deemph_settings[best] - es8328->playback_fs)) | ||
104 | best = i; | ||
105 | } | ||
106 | |||
107 | val = best << 1; | ||
108 | } else { | ||
109 | val = 0; | ||
110 | } | ||
111 | |||
112 | dev_dbg(codec->dev, "Set deemphasis %d\n", val); | ||
113 | |||
114 | return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val); | ||
115 | } | ||
116 | |||
117 | static int es8328_get_deemph(struct snd_kcontrol *kcontrol, | ||
118 | struct snd_ctl_elem_value *ucontrol) | ||
119 | { | ||
120 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
121 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
122 | |||
123 | ucontrol->value.enumerated.item[0] = es8328->deemph; | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int es8328_put_deemph(struct snd_kcontrol *kcontrol, | ||
128 | struct snd_ctl_elem_value *ucontrol) | ||
129 | { | ||
130 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
131 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
132 | int deemph = ucontrol->value.enumerated.item[0]; | ||
133 | int ret; | ||
134 | |||
135 | if (deemph > 1) | ||
136 | return -EINVAL; | ||
137 | |||
138 | ret = es8328_set_deemph(codec); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | |||
142 | es8328->deemph = deemph; | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | |||
148 | |||
149 | static const struct snd_kcontrol_new es8328_snd_controls[] = { | ||
150 | SOC_DOUBLE_R_TLV("Capture Digital Volume", | ||
151 | ES8328_ADCCONTROL8, ES8328_ADCCONTROL9, | ||
152 | 0, 0xc0, 1, dac_adc_tlv), | ||
153 | SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0), | ||
154 | |||
155 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, | ||
156 | es8328_get_deemph, es8328_put_deemph), | ||
157 | |||
158 | SOC_ENUM("Capture Polarity", adcpol), | ||
159 | |||
160 | SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", | ||
161 | ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv), | ||
162 | SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", | ||
163 | ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv), | ||
164 | SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", | ||
165 | ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv), | ||
166 | SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", | ||
167 | ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv), | ||
168 | |||
169 | SOC_DOUBLE_R_TLV("PCM Volume", | ||
170 | ES8328_LDACVOL, ES8328_RDACVOL, | ||
171 | 0, ES8328_DACVOL_MAX, 1, dac_adc_tlv), | ||
172 | |||
173 | SOC_DOUBLE_R_TLV("Output 1 Playback Volume", | ||
174 | ES8328_LOUT1VOL, ES8328_ROUT1VOL, | ||
175 | 0, ES8328_OUT1VOL_MAX, 0, play_tlv), | ||
176 | |||
177 | SOC_DOUBLE_R_TLV("Output 2 Playback Volume", | ||
178 | ES8328_LOUT2VOL, ES8328_ROUT2VOL, | ||
179 | 0, ES8328_OUT2VOL_MAX, 0, play_tlv), | ||
180 | |||
181 | SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1, | ||
182 | 4, 0, 8, 0, mic_tlv), | ||
183 | }; | ||
184 | |||
185 | /* | ||
186 | * DAPM Controls | ||
187 | */ | ||
188 | |||
189 | static const char * const es8328_line_texts[] = { | ||
190 | "Line 1", "Line 2", "PGA", "Differential"}; | ||
191 | |||
192 | static const struct soc_enum es8328_lline_enum = | ||
193 | SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3, | ||
194 | ARRAY_SIZE(es8328_line_texts), | ||
195 | es8328_line_texts); | ||
196 | static const struct snd_kcontrol_new es8328_left_line_controls = | ||
197 | SOC_DAPM_ENUM("Route", es8328_lline_enum); | ||
198 | |||
199 | static const struct soc_enum es8328_rline_enum = | ||
200 | SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0, | ||
201 | ARRAY_SIZE(es8328_line_texts), | ||
202 | es8328_line_texts); | ||
203 | static const struct snd_kcontrol_new es8328_right_line_controls = | ||
204 | SOC_DAPM_ENUM("Route", es8328_lline_enum); | ||
205 | |||
206 | /* Left Mixer */ | ||
207 | static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { | ||
208 | SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0), | ||
209 | SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0), | ||
210 | SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0), | ||
211 | SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0), | ||
212 | }; | ||
213 | |||
214 | /* Right Mixer */ | ||
215 | static const struct snd_kcontrol_new es8328_right_mixer_controls[] = { | ||
216 | SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0), | ||
217 | SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0), | ||
218 | SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0), | ||
219 | SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0), | ||
220 | }; | ||
221 | |||
222 | static const char * const es8328_pga_sel[] = { | ||
223 | "Line 1", "Line 2", "Line 3", "Differential"}; | ||
224 | |||
225 | /* Left PGA Mux */ | ||
226 | static const struct soc_enum es8328_lpga_enum = | ||
227 | SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6, | ||
228 | ARRAY_SIZE(es8328_pga_sel), | ||
229 | es8328_pga_sel); | ||
230 | static const struct snd_kcontrol_new es8328_left_pga_controls = | ||
231 | SOC_DAPM_ENUM("Route", es8328_lpga_enum); | ||
232 | |||
233 | /* Right PGA Mux */ | ||
234 | static const struct soc_enum es8328_rpga_enum = | ||
235 | SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4, | ||
236 | ARRAY_SIZE(es8328_pga_sel), | ||
237 | es8328_pga_sel); | ||
238 | static const struct snd_kcontrol_new es8328_right_pga_controls = | ||
239 | SOC_DAPM_ENUM("Route", es8328_rpga_enum); | ||
240 | |||
241 | /* Differential Mux */ | ||
242 | static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"}; | ||
243 | static SOC_ENUM_SINGLE_DECL(diffmux, | ||
244 | ES8328_ADCCONTROL3, 7, es8328_diff_sel); | ||
245 | static const struct snd_kcontrol_new es8328_diffmux_controls = | ||
246 | SOC_DAPM_ENUM("Route", diffmux); | ||
247 | |||
248 | /* Mono ADC Mux */ | ||
249 | static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)", | ||
250 | "Mono (Right)", "Digital Mono"}; | ||
251 | static SOC_ENUM_SINGLE_DECL(monomux, | ||
252 | ES8328_ADCCONTROL3, 3, es8328_mono_mux); | ||
253 | static const struct snd_kcontrol_new es8328_monomux_controls = | ||
254 | SOC_DAPM_ENUM("Route", monomux); | ||
255 | |||
256 | static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = { | ||
257 | SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, | ||
258 | &es8328_diffmux_controls), | ||
259 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, | ||
260 | &es8328_monomux_controls), | ||
261 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, | ||
262 | &es8328_monomux_controls), | ||
263 | |||
264 | SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER, | ||
265 | ES8328_ADCPOWER_AINL_OFF, 1, | ||
266 | &es8328_left_pga_controls), | ||
267 | SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER, | ||
268 | ES8328_ADCPOWER_AINR_OFF, 1, | ||
269 | &es8328_right_pga_controls), | ||
270 | |||
271 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, | ||
272 | &es8328_left_line_controls), | ||
273 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, | ||
274 | &es8328_right_line_controls), | ||
275 | |||
276 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER, | ||
277 | ES8328_ADCPOWER_ADCR_OFF, 1), | ||
278 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER, | ||
279 | ES8328_ADCPOWER_ADCL_OFF, 1), | ||
280 | |||
281 | SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER, | ||
282 | ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0), | ||
283 | SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER, | ||
284 | ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0), | ||
285 | |||
286 | SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER, | ||
287 | ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0), | ||
288 | SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER, | ||
289 | ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0), | ||
290 | |||
291 | SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER, | ||
292 | ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0), | ||
293 | SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER, | ||
294 | ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0), | ||
295 | |||
296 | SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER, | ||
297 | ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0), | ||
298 | SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER, | ||
299 | ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0), | ||
300 | |||
301 | SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER, | ||
302 | ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0), | ||
303 | SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER, | ||
304 | ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0), | ||
305 | |||
306 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER, | ||
307 | ES8328_DACPOWER_RDAC_OFF, 1), | ||
308 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER, | ||
309 | ES8328_DACPOWER_LDAC_OFF, 1), | ||
310 | |||
311 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, | ||
312 | &es8328_left_mixer_controls[0], | ||
313 | ARRAY_SIZE(es8328_left_mixer_controls)), | ||
314 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, | ||
315 | &es8328_right_mixer_controls[0], | ||
316 | ARRAY_SIZE(es8328_right_mixer_controls)), | ||
317 | |||
318 | SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER, | ||
319 | ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0), | ||
320 | SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER, | ||
321 | ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0), | ||
322 | SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER, | ||
323 | ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0), | ||
324 | SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER, | ||
325 | ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0), | ||
326 | |||
327 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
328 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
329 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
330 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
331 | |||
332 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
333 | SND_SOC_DAPM_INPUT("LINPUT2"), | ||
334 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
335 | SND_SOC_DAPM_INPUT("RINPUT2"), | ||
336 | }; | ||
337 | |||
338 | static const struct snd_soc_dapm_route es8328_dapm_routes[] = { | ||
339 | |||
340 | { "Left Line Mux", "Line 1", "LINPUT1" }, | ||
341 | { "Left Line Mux", "Line 2", "LINPUT2" }, | ||
342 | { "Left Line Mux", "PGA", "Left PGA Mux" }, | ||
343 | { "Left Line Mux", "Differential", "Differential Mux" }, | ||
344 | |||
345 | { "Right Line Mux", "Line 1", "RINPUT1" }, | ||
346 | { "Right Line Mux", "Line 2", "RINPUT2" }, | ||
347 | { "Right Line Mux", "PGA", "Right PGA Mux" }, | ||
348 | { "Right Line Mux", "Differential", "Differential Mux" }, | ||
349 | |||
350 | { "Left PGA Mux", "Line 1", "LINPUT1" }, | ||
351 | { "Left PGA Mux", "Line 2", "LINPUT2" }, | ||
352 | { "Left PGA Mux", "Differential", "Differential Mux" }, | ||
353 | |||
354 | { "Right PGA Mux", "Line 1", "RINPUT1" }, | ||
355 | { "Right PGA Mux", "Line 2", "RINPUT2" }, | ||
356 | { "Right PGA Mux", "Differential", "Differential Mux" }, | ||
357 | |||
358 | { "Differential Mux", "Line 1", "LINPUT1" }, | ||
359 | { "Differential Mux", "Line 1", "RINPUT1" }, | ||
360 | { "Differential Mux", "Line 2", "LINPUT2" }, | ||
361 | { "Differential Mux", "Line 2", "RINPUT2" }, | ||
362 | |||
363 | { "Left ADC Mux", "Stereo", "Left PGA Mux" }, | ||
364 | { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, | ||
365 | { "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, | ||
366 | |||
367 | { "Right ADC Mux", "Stereo", "Right PGA Mux" }, | ||
368 | { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, | ||
369 | { "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, | ||
370 | |||
371 | { "Left ADC", NULL, "Left ADC Mux" }, | ||
372 | { "Right ADC", NULL, "Right ADC Mux" }, | ||
373 | |||
374 | { "ADC DIG", NULL, "ADC STM" }, | ||
375 | { "ADC DIG", NULL, "ADC Vref" }, | ||
376 | { "ADC DIG", NULL, "ADC DLL" }, | ||
377 | |||
378 | { "Left ADC", NULL, "ADC DIG" }, | ||
379 | { "Right ADC", NULL, "ADC DIG" }, | ||
380 | |||
381 | { "Mic Bias", NULL, "Mic Bias Gen" }, | ||
382 | |||
383 | { "Left Line Mux", "Line 1", "LINPUT1" }, | ||
384 | { "Left Line Mux", "Line 2", "LINPUT2" }, | ||
385 | { "Left Line Mux", "PGA", "Left PGA Mux" }, | ||
386 | { "Left Line Mux", "Differential", "Differential Mux" }, | ||
387 | |||
388 | { "Right Line Mux", "Line 1", "RINPUT1" }, | ||
389 | { "Right Line Mux", "Line 2", "RINPUT2" }, | ||
390 | { "Right Line Mux", "PGA", "Right PGA Mux" }, | ||
391 | { "Right Line Mux", "Differential", "Differential Mux" }, | ||
392 | |||
393 | { "Left Out 1", NULL, "Left DAC" }, | ||
394 | { "Right Out 1", NULL, "Right DAC" }, | ||
395 | { "Left Out 2", NULL, "Left DAC" }, | ||
396 | { "Right Out 2", NULL, "Right DAC" }, | ||
397 | |||
398 | { "Left Mixer", "Playback Switch", "Left DAC" }, | ||
399 | { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, | ||
400 | { "Left Mixer", "Right Playback Switch", "Right DAC" }, | ||
401 | { "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, | ||
402 | |||
403 | { "Right Mixer", "Left Playback Switch", "Left DAC" }, | ||
404 | { "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, | ||
405 | { "Right Mixer", "Playback Switch", "Right DAC" }, | ||
406 | { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, | ||
407 | |||
408 | { "DAC DIG", NULL, "DAC STM" }, | ||
409 | { "DAC DIG", NULL, "DAC Vref" }, | ||
410 | { "DAC DIG", NULL, "DAC DLL" }, | ||
411 | |||
412 | { "Left DAC", NULL, "DAC DIG" }, | ||
413 | { "Right DAC", NULL, "DAC DIG" }, | ||
414 | |||
415 | { "Left Out 1", NULL, "Left Mixer" }, | ||
416 | { "LOUT1", NULL, "Left Out 1" }, | ||
417 | { "Right Out 1", NULL, "Right Mixer" }, | ||
418 | { "ROUT1", NULL, "Right Out 1" }, | ||
419 | |||
420 | { "Left Out 2", NULL, "Left Mixer" }, | ||
421 | { "LOUT2", NULL, "Left Out 2" }, | ||
422 | { "Right Out 2", NULL, "Right Mixer" }, | ||
423 | { "ROUT2", NULL, "Right Out 2" }, | ||
424 | }; | ||
425 | |||
426 | static int es8328_mute(struct snd_soc_dai *dai, int mute) | ||
427 | { | ||
428 | return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3, | ||
429 | ES8328_DACCONTROL3_DACMUTE, | ||
430 | mute ? ES8328_DACCONTROL3_DACMUTE : 0); | ||
431 | } | ||
432 | |||
433 | static int es8328_hw_params(struct snd_pcm_substream *substream, | ||
434 | struct snd_pcm_hw_params *params, | ||
435 | struct snd_soc_dai *dai) | ||
436 | { | ||
437 | struct snd_soc_codec *codec = dai->codec; | ||
438 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
439 | int clk_rate; | ||
440 | int i; | ||
441 | int reg; | ||
442 | u8 ratio; | ||
443 | |||
444 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
445 | reg = ES8328_DACCONTROL2; | ||
446 | else | ||
447 | reg = ES8328_ADCCONTROL5; | ||
448 | |||
449 | clk_rate = clk_get_rate(es8328->clk); | ||
450 | |||
451 | if ((clk_rate != ES8328_SYSCLK_RATE_1X) && | ||
452 | (clk_rate != ES8328_SYSCLK_RATE_2X)) { | ||
453 | dev_err(codec->dev, | ||
454 | "%s: clock is running at %d Hz, not %d or %d Hz\n", | ||
455 | __func__, clk_rate, | ||
456 | ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X); | ||
457 | return -EINVAL; | ||
458 | } | ||
459 | |||
460 | /* find master mode MCLK to sampling frequency ratio */ | ||
461 | ratio = mclk_ratios[0].rate; | ||
462 | for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++) | ||
463 | if (params_rate(params) <= mclk_ratios[i].rate) | ||
464 | ratio = mclk_ratios[i].ratio; | ||
465 | |||
466 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
467 | es8328->playback_fs = params_rate(params); | ||
468 | es8328_set_deemph(codec); | ||
469 | } | ||
470 | |||
471 | return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio); | ||
472 | } | ||
473 | |||
474 | static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
475 | unsigned int fmt) | ||
476 | { | ||
477 | struct snd_soc_codec *codec = codec_dai->codec; | ||
478 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
479 | int clk_rate; | ||
480 | u8 mode = ES8328_DACCONTROL1_DACWL_16; | ||
481 | |||
482 | /* set master/slave audio interface */ | ||
483 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) | ||
484 | return -EINVAL; | ||
485 | |||
486 | /* interface format */ | ||
487 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
488 | case SND_SOC_DAIFMT_I2S: | ||
489 | mode |= ES8328_DACCONTROL1_DACFORMAT_I2S; | ||
490 | break; | ||
491 | case SND_SOC_DAIFMT_RIGHT_J: | ||
492 | mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST; | ||
493 | break; | ||
494 | case SND_SOC_DAIFMT_LEFT_J: | ||
495 | mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST; | ||
496 | break; | ||
497 | default: | ||
498 | return -EINVAL; | ||
499 | } | ||
500 | |||
501 | /* clock inversion */ | ||
502 | if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) | ||
503 | return -EINVAL; | ||
504 | |||
505 | snd_soc_write(codec, ES8328_DACCONTROL1, mode); | ||
506 | snd_soc_write(codec, ES8328_ADCCONTROL4, mode); | ||
507 | |||
508 | /* Master serial port mode, with BCLK generated automatically */ | ||
509 | clk_rate = clk_get_rate(es8328->clk); | ||
510 | if (clk_rate == ES8328_SYSCLK_RATE_1X) | ||
511 | snd_soc_write(codec, ES8328_MASTERMODE, | ||
512 | ES8328_MASTERMODE_MSC); | ||
513 | else | ||
514 | snd_soc_write(codec, ES8328_MASTERMODE, | ||
515 | ES8328_MASTERMODE_MCLKDIV2 | | ||
516 | ES8328_MASTERMODE_MSC); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int es8328_set_bias_level(struct snd_soc_codec *codec, | ||
522 | enum snd_soc_bias_level level) | ||
523 | { | ||
524 | switch (level) { | ||
525 | case SND_SOC_BIAS_ON: | ||
526 | break; | ||
527 | |||
528 | case SND_SOC_BIAS_PREPARE: | ||
529 | /* VREF, VMID=2x50k, digital enabled */ | ||
530 | snd_soc_write(codec, ES8328_CHIPPOWER, 0); | ||
531 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
532 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
533 | ES8328_CONTROL1_ENREF, | ||
534 | ES8328_CONTROL1_VMIDSEL_50k | | ||
535 | ES8328_CONTROL1_ENREF); | ||
536 | break; | ||
537 | |||
538 | case SND_SOC_BIAS_STANDBY: | ||
539 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
540 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
541 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
542 | ES8328_CONTROL1_ENREF, | ||
543 | ES8328_CONTROL1_VMIDSEL_5k | | ||
544 | ES8328_CONTROL1_ENREF); | ||
545 | |||
546 | /* Charge caps */ | ||
547 | msleep(100); | ||
548 | } | ||
549 | |||
550 | snd_soc_write(codec, ES8328_CONTROL2, | ||
551 | ES8328_CONTROL2_OVERCURRENT_ON | | ||
552 | ES8328_CONTROL2_THERMAL_SHUTDOWN_ON); | ||
553 | |||
554 | /* VREF, VMID=2*500k, digital stopped */ | ||
555 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
556 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
557 | ES8328_CONTROL1_ENREF, | ||
558 | ES8328_CONTROL1_VMIDSEL_500k | | ||
559 | ES8328_CONTROL1_ENREF); | ||
560 | break; | ||
561 | |||
562 | case SND_SOC_BIAS_OFF: | ||
563 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
564 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
565 | ES8328_CONTROL1_ENREF, | ||
566 | 0); | ||
567 | break; | ||
568 | } | ||
569 | codec->dapm.bias_level = level; | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static const struct snd_soc_dai_ops es8328_dai_ops = { | ||
574 | .hw_params = es8328_hw_params, | ||
575 | .digital_mute = es8328_mute, | ||
576 | .set_fmt = es8328_set_dai_fmt, | ||
577 | }; | ||
578 | |||
579 | static struct snd_soc_dai_driver es8328_dai = { | ||
580 | .name = "es8328-hifi-analog", | ||
581 | .playback = { | ||
582 | .stream_name = "Playback", | ||
583 | .channels_min = 2, | ||
584 | .channels_max = 2, | ||
585 | .rates = ES8328_RATES, | ||
586 | .formats = ES8328_FORMATS, | ||
587 | }, | ||
588 | .capture = { | ||
589 | .stream_name = "Capture", | ||
590 | .channels_min = 2, | ||
591 | .channels_max = 2, | ||
592 | .rates = ES8328_RATES, | ||
593 | .formats = ES8328_FORMATS, | ||
594 | }, | ||
595 | .ops = &es8328_dai_ops, | ||
596 | }; | ||
597 | |||
598 | static int es8328_suspend(struct snd_soc_codec *codec) | ||
599 | { | ||
600 | struct es8328_priv *es8328; | ||
601 | int ret; | ||
602 | |||
603 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
604 | |||
605 | clk_disable_unprepare(es8328->clk); | ||
606 | |||
607 | ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), | ||
608 | es8328->supplies); | ||
609 | if (ret) { | ||
610 | dev_err(codec->dev, "unable to disable regulators\n"); | ||
611 | return ret; | ||
612 | } | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int es8328_resume(struct snd_soc_codec *codec) | ||
617 | { | ||
618 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | ||
619 | struct es8328_priv *es8328; | ||
620 | int ret; | ||
621 | |||
622 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
623 | |||
624 | ret = clk_prepare_enable(es8328->clk); | ||
625 | if (ret) { | ||
626 | dev_err(codec->dev, "unable to enable clock\n"); | ||
627 | return ret; | ||
628 | } | ||
629 | |||
630 | ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), | ||
631 | es8328->supplies); | ||
632 | if (ret) { | ||
633 | dev_err(codec->dev, "unable to enable regulators\n"); | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | regcache_mark_dirty(regmap); | ||
638 | ret = regcache_sync(regmap); | ||
639 | if (ret) { | ||
640 | dev_err(codec->dev, "unable to sync regcache\n"); | ||
641 | return ret; | ||
642 | } | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int es8328_codec_probe(struct snd_soc_codec *codec) | ||
648 | { | ||
649 | struct es8328_priv *es8328; | ||
650 | int ret; | ||
651 | |||
652 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
653 | |||
654 | ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), | ||
655 | es8328->supplies); | ||
656 | if (ret) { | ||
657 | dev_err(codec->dev, "unable to enable regulators\n"); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | /* Setup clocks */ | ||
662 | es8328->clk = devm_clk_get(codec->dev, NULL); | ||
663 | if (IS_ERR(es8328->clk)) { | ||
664 | dev_err(codec->dev, "codec clock missing or invalid\n"); | ||
665 | ret = PTR_ERR(es8328->clk); | ||
666 | goto clk_fail; | ||
667 | } | ||
668 | |||
669 | ret = clk_prepare_enable(es8328->clk); | ||
670 | if (ret) { | ||
671 | dev_err(codec->dev, "unable to prepare codec clk\n"); | ||
672 | goto clk_fail; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | |||
677 | clk_fail: | ||
678 | regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), | ||
679 | es8328->supplies); | ||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static int es8328_remove(struct snd_soc_codec *codec) | ||
684 | { | ||
685 | struct es8328_priv *es8328; | ||
686 | |||
687 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
688 | |||
689 | if (es8328->clk) | ||
690 | clk_disable_unprepare(es8328->clk); | ||
691 | |||
692 | regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), | ||
693 | es8328->supplies); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | const struct regmap_config es8328_regmap_config = { | ||
699 | .reg_bits = 8, | ||
700 | .val_bits = 8, | ||
701 | .max_register = ES8328_REG_MAX, | ||
702 | .cache_type = REGCACHE_RBTREE, | ||
703 | }; | ||
704 | EXPORT_SYMBOL_GPL(es8328_regmap_config); | ||
705 | |||
706 | static struct snd_soc_codec_driver es8328_codec_driver = { | ||
707 | .probe = es8328_codec_probe, | ||
708 | .suspend = es8328_suspend, | ||
709 | .resume = es8328_resume, | ||
710 | .remove = es8328_remove, | ||
711 | .set_bias_level = es8328_set_bias_level, | ||
712 | .suspend_bias_off = true, | ||
713 | |||
714 | .controls = es8328_snd_controls, | ||
715 | .num_controls = ARRAY_SIZE(es8328_snd_controls), | ||
716 | .dapm_widgets = es8328_dapm_widgets, | ||
717 | .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets), | ||
718 | .dapm_routes = es8328_dapm_routes, | ||
719 | .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes), | ||
720 | }; | ||
721 | |||
722 | int es8328_probe(struct device *dev, struct regmap *regmap) | ||
723 | { | ||
724 | struct es8328_priv *es8328; | ||
725 | int ret; | ||
726 | int i; | ||
727 | |||
728 | if (IS_ERR(regmap)) | ||
729 | return PTR_ERR(regmap); | ||
730 | |||
731 | es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL); | ||
732 | if (es8328 == NULL) | ||
733 | return -ENOMEM; | ||
734 | |||
735 | es8328->regmap = regmap; | ||
736 | |||
737 | for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++) | ||
738 | es8328->supplies[i].supply = supply_names[i]; | ||
739 | |||
740 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies), | ||
741 | es8328->supplies); | ||
742 | if (ret) { | ||
743 | dev_err(dev, "unable to get regulators\n"); | ||
744 | return ret; | ||
745 | } | ||
746 | |||
747 | dev_set_drvdata(dev, es8328); | ||
748 | |||
749 | return snd_soc_register_codec(dev, | ||
750 | &es8328_codec_driver, &es8328_dai, 1); | ||
751 | } | ||
752 | EXPORT_SYMBOL_GPL(es8328_probe); | ||
753 | |||
754 | MODULE_DESCRIPTION("ASoC ES8328 driver"); | ||
755 | MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); | ||
756 | MODULE_LICENSE("GPL"); | ||