1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * wm8978.c -- WM8978 ALSA SoC Audio Codec driver |
4 | * |
5 | * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> |
6 | * Copyright (C) 2007 Carlos Munoz <carlos@kenati.com> |
7 | * Copyright 2006-2009 Wolfson Microelectronics PLC. |
8 | * Based on wm8974 and wm8990 by Liam Girdwood <lrg@slimlogic.co.uk> |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/moduleparam.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/init.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> |
18 | #include <linux/regmap.h> |
19 | #include <linux/slab.h> |
20 | #include <sound/core.h> |
21 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> |
23 | #include <sound/soc.h> |
24 | #include <sound/initval.h> |
25 | #include <sound/tlv.h> |
26 | #include <asm/div64.h> |
27 | |
28 | #include "wm8978.h" |
29 | |
30 | static const struct reg_default wm8978_reg_defaults[] = { |
31 | { 1, 0x0000 }, |
32 | { 2, 0x0000 }, |
33 | { 3, 0x0000 }, |
34 | { 4, 0x0050 }, |
35 | { 5, 0x0000 }, |
36 | { 6, 0x0140 }, |
37 | { 7, 0x0000 }, |
38 | { 8, 0x0000 }, |
39 | { 9, 0x0000 }, |
40 | { 10, 0x0000 }, |
41 | { 11, 0x00ff }, |
42 | { 12, 0x00ff }, |
43 | { 13, 0x0000 }, |
44 | { 14, 0x0100 }, |
45 | { 15, 0x00ff }, |
46 | { 16, 0x00ff }, |
47 | { 17, 0x0000 }, |
48 | { 18, 0x012c }, |
49 | { 19, 0x002c }, |
50 | { 20, 0x002c }, |
51 | { 21, 0x002c }, |
52 | { 22, 0x002c }, |
53 | { 23, 0x0000 }, |
54 | { 24, 0x0032 }, |
55 | { 25, 0x0000 }, |
56 | { 26, 0x0000 }, |
57 | { 27, 0x0000 }, |
58 | { 28, 0x0000 }, |
59 | { 29, 0x0000 }, |
60 | { 30, 0x0000 }, |
61 | { 31, 0x0000 }, |
62 | { 32, 0x0038 }, |
63 | { 33, 0x000b }, |
64 | { 34, 0x0032 }, |
65 | { 35, 0x0000 }, |
66 | { 36, 0x0008 }, |
67 | { 37, 0x000c }, |
68 | { 38, 0x0093 }, |
69 | { 39, 0x00e9 }, |
70 | { 40, 0x0000 }, |
71 | { 41, 0x0000 }, |
72 | { 42, 0x0000 }, |
73 | { 43, 0x0000 }, |
74 | { 44, 0x0033 }, |
75 | { 45, 0x0010 }, |
76 | { 46, 0x0010 }, |
77 | { 47, 0x0100 }, |
78 | { 48, 0x0100 }, |
79 | { 49, 0x0002 }, |
80 | { 50, 0x0001 }, |
81 | { 51, 0x0001 }, |
82 | { 52, 0x0039 }, |
83 | { 53, 0x0039 }, |
84 | { 54, 0x0039 }, |
85 | { 55, 0x0039 }, |
86 | { 56, 0x0001 }, |
87 | { 57, 0x0001 }, |
88 | }; |
89 | |
90 | static bool wm8978_volatile(struct device *dev, unsigned int reg) |
91 | { |
92 | return reg == WM8978_RESET; |
93 | } |
94 | |
95 | /* codec private data */ |
96 | struct wm8978_priv { |
97 | struct regmap *regmap; |
98 | unsigned int f_pllout; |
99 | unsigned int f_mclk; |
100 | unsigned int f_256fs; |
101 | unsigned int f_opclk; |
102 | int mclk_idx; |
103 | enum wm8978_sysclk_src sysclk; |
104 | }; |
105 | |
106 | static const char *wm8978_companding[] = {"Off" , "NC" , "u-law" , "A-law" }; |
107 | static const char *wm8978_eqmode[] = {"Capture" , "Playback" }; |
108 | static const char *wm8978_bw[] = {"Narrow" , "Wide" }; |
109 | static const char *wm8978_eq1[] = {"80Hz" , "105Hz" , "135Hz" , "175Hz" }; |
110 | static const char *wm8978_eq2[] = {"230Hz" , "300Hz" , "385Hz" , "500Hz" }; |
111 | static const char *wm8978_eq3[] = {"650Hz" , "850Hz" , "1.1kHz" , "1.4kHz" }; |
112 | static const char *wm8978_eq4[] = {"1.8kHz" , "2.4kHz" , "3.2kHz" , "4.1kHz" }; |
113 | static const char *wm8978_eq5[] = {"5.3kHz" , "6.9kHz" , "9kHz" , "11.7kHz" }; |
114 | static const char *wm8978_alc3[] = {"ALC" , "Limiter" }; |
115 | static const char *wm8978_alc1[] = {"Off" , "Right" , "Left" , "Both" }; |
116 | |
117 | static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, |
118 | wm8978_companding); |
119 | static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, |
120 | wm8978_companding); |
121 | static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); |
122 | static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); |
123 | static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); |
124 | static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); |
125 | static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); |
126 | static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); |
127 | static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); |
128 | static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); |
129 | static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); |
130 | static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); |
131 | static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); |
132 | |
133 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); |
134 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
135 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); |
136 | static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); |
137 | static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); |
138 | static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0); |
139 | |
140 | static const struct snd_kcontrol_new wm8978_snd_controls[] = { |
141 | |
142 | SOC_SINGLE("Digital Loopback Switch" , |
143 | WM8978_COMPANDING_CONTROL, 0, 1, 0), |
144 | |
145 | SOC_ENUM("ADC Companding" , adc_compand), |
146 | SOC_ENUM("DAC Companding" , dac_compand), |
147 | |
148 | SOC_DOUBLE("DAC Inversion Switch" , WM8978_DAC_CONTROL, 0, 1, 1, 0), |
149 | |
150 | SOC_DOUBLE_R_TLV("PCM Volume" , |
151 | WM8978_LEFT_DAC_DIGITAL_VOLUME, WM8978_RIGHT_DAC_DIGITAL_VOLUME, |
152 | 0, 255, 0, digital_tlv), |
153 | |
154 | SOC_SINGLE("High Pass Filter Switch" , WM8978_ADC_CONTROL, 8, 1, 0), |
155 | SOC_SINGLE("High Pass Cut Off" , WM8978_ADC_CONTROL, 4, 7, 0), |
156 | SOC_DOUBLE("ADC Inversion Switch" , WM8978_ADC_CONTROL, 0, 1, 1, 0), |
157 | |
158 | SOC_DOUBLE_R_TLV("ADC Volume" , |
159 | WM8978_LEFT_ADC_DIGITAL_VOLUME, WM8978_RIGHT_ADC_DIGITAL_VOLUME, |
160 | 0, 255, 0, digital_tlv), |
161 | |
162 | SOC_ENUM("Equaliser Function" , eqmode), |
163 | SOC_ENUM("EQ1 Cut Off" , eq1), |
164 | SOC_SINGLE_TLV("EQ1 Volume" , WM8978_EQ1, 0, 24, 1, eq_tlv), |
165 | |
166 | SOC_ENUM("Equaliser EQ2 Bandwidth" , eq2bw), |
167 | SOC_ENUM("EQ2 Cut Off" , eq2), |
168 | SOC_SINGLE_TLV("EQ2 Volume" , WM8978_EQ2, 0, 24, 1, eq_tlv), |
169 | |
170 | SOC_ENUM("Equaliser EQ3 Bandwidth" , eq3bw), |
171 | SOC_ENUM("EQ3 Cut Off" , eq3), |
172 | SOC_SINGLE_TLV("EQ3 Volume" , WM8978_EQ3, 0, 24, 1, eq_tlv), |
173 | |
174 | SOC_ENUM("Equaliser EQ4 Bandwidth" , eq4bw), |
175 | SOC_ENUM("EQ4 Cut Off" , eq4), |
176 | SOC_SINGLE_TLV("EQ4 Volume" , WM8978_EQ4, 0, 24, 1, eq_tlv), |
177 | |
178 | SOC_ENUM("EQ5 Cut Off" , eq5), |
179 | SOC_SINGLE_TLV("EQ5 Volume" , WM8978_EQ5, 0, 24, 1, eq_tlv), |
180 | |
181 | SOC_SINGLE("DAC Playback Limiter Switch" , |
182 | WM8978_DAC_LIMITER_1, 8, 1, 0), |
183 | SOC_SINGLE("DAC Playback Limiter Decay" , |
184 | WM8978_DAC_LIMITER_1, 4, 15, 0), |
185 | SOC_SINGLE("DAC Playback Limiter Attack" , |
186 | WM8978_DAC_LIMITER_1, 0, 15, 0), |
187 | |
188 | SOC_SINGLE("DAC Playback Limiter Threshold" , |
189 | WM8978_DAC_LIMITER_2, 4, 7, 0), |
190 | SOC_SINGLE_TLV("DAC Playback Limiter Volume" , |
191 | WM8978_DAC_LIMITER_2, 0, 12, 0, limiter_tlv), |
192 | |
193 | SOC_ENUM("ALC Enable Switch" , alc1), |
194 | SOC_SINGLE("ALC Capture Min Gain" , WM8978_ALC_CONTROL_1, 0, 7, 0), |
195 | SOC_SINGLE("ALC Capture Max Gain" , WM8978_ALC_CONTROL_1, 3, 7, 0), |
196 | |
197 | SOC_SINGLE("ALC Capture Hold" , WM8978_ALC_CONTROL_2, 4, 10, 0), |
198 | SOC_SINGLE("ALC Capture Target" , WM8978_ALC_CONTROL_2, 0, 15, 0), |
199 | |
200 | SOC_ENUM("ALC Capture Mode" , alc3), |
201 | SOC_SINGLE("ALC Capture Decay" , WM8978_ALC_CONTROL_3, 4, 10, 0), |
202 | SOC_SINGLE("ALC Capture Attack" , WM8978_ALC_CONTROL_3, 0, 10, 0), |
203 | |
204 | SOC_SINGLE("ALC Capture Noise Gate Switch" , WM8978_NOISE_GATE, 3, 1, 0), |
205 | SOC_SINGLE("ALC Capture Noise Gate Threshold" , |
206 | WM8978_NOISE_GATE, 0, 7, 0), |
207 | |
208 | SOC_DOUBLE_R("Capture PGA ZC Switch" , |
209 | WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL, |
210 | 7, 1, 0), |
211 | |
212 | /* OUT1 - Headphones */ |
213 | SOC_DOUBLE_R("Headphone Playback ZC Switch" , |
214 | WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 7, 1, 0), |
215 | |
216 | SOC_DOUBLE_R_TLV("Headphone Playback Volume" , |
217 | WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, |
218 | 0, 63, 0, spk_tlv), |
219 | |
220 | /* OUT2 - Speakers */ |
221 | SOC_DOUBLE_R("Speaker Playback ZC Switch" , |
222 | WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 7, 1, 0), |
223 | |
224 | SOC_DOUBLE_R_TLV("Speaker Playback Volume" , |
225 | WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, |
226 | 0, 63, 0, spk_tlv), |
227 | |
228 | /* OUT3/4 - Line Output */ |
229 | SOC_DOUBLE_R("Line Playback Switch" , |
230 | WM8978_OUT3_MIXER_CONTROL, WM8978_OUT4_MIXER_CONTROL, 6, 1, 1), |
231 | |
232 | /* Mixer #3: Boost (Input) mixer */ |
233 | SOC_DOUBLE_R("PGA Boost (+20dB)" , |
234 | WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, |
235 | 8, 1, 0), |
236 | SOC_DOUBLE_R_TLV("L2/R2 Boost Volume" , |
237 | WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, |
238 | 4, 7, 0, boost_tlv), |
239 | SOC_DOUBLE_R_TLV("Aux Boost Volume" , |
240 | WM8978_LEFT_ADC_BOOST_CONTROL, WM8978_RIGHT_ADC_BOOST_CONTROL, |
241 | 0, 7, 0, boost_tlv), |
242 | |
243 | /* Input PGA volume */ |
244 | SOC_DOUBLE_R_TLV("Input PGA Volume" , |
245 | WM8978_LEFT_INP_PGA_CONTROL, WM8978_RIGHT_INP_PGA_CONTROL, |
246 | 0, 63, 0, inpga_tlv), |
247 | |
248 | /* Headphone */ |
249 | SOC_DOUBLE_R("Headphone Switch" , |
250 | WM8978_LOUT1_HP_CONTROL, WM8978_ROUT1_HP_CONTROL, 6, 1, 1), |
251 | |
252 | /* Speaker */ |
253 | SOC_DOUBLE_R("Speaker Switch" , |
254 | WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1), |
255 | |
256 | /* DAC / ADC oversampling */ |
257 | SOC_SINGLE("DAC 128x Oversampling Switch" , WM8978_DAC_CONTROL, |
258 | 5, 1, 0), |
259 | SOC_SINGLE("ADC 128x Oversampling Switch" , WM8978_ADC_CONTROL, |
260 | 5, 1, 0), |
261 | }; |
262 | |
263 | /* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */ |
264 | static const struct snd_kcontrol_new wm8978_left_out_mixer[] = { |
265 | SOC_DAPM_SINGLE("Line Bypass Switch" , WM8978_LEFT_MIXER_CONTROL, 1, 1, 0), |
266 | SOC_DAPM_SINGLE("Aux Playback Switch" , WM8978_LEFT_MIXER_CONTROL, 5, 1, 0), |
267 | SOC_DAPM_SINGLE("PCM Playback Switch" , WM8978_LEFT_MIXER_CONTROL, 0, 1, 0), |
268 | }; |
269 | |
270 | static const struct snd_kcontrol_new wm8978_right_out_mixer[] = { |
271 | SOC_DAPM_SINGLE("Line Bypass Switch" , WM8978_RIGHT_MIXER_CONTROL, 1, 1, 0), |
272 | SOC_DAPM_SINGLE("Aux Playback Switch" , WM8978_RIGHT_MIXER_CONTROL, 5, 1, 0), |
273 | SOC_DAPM_SINGLE("PCM Playback Switch" , WM8978_RIGHT_MIXER_CONTROL, 0, 1, 0), |
274 | }; |
275 | |
276 | /* OUT3/OUT4 Mixer not implemented */ |
277 | |
278 | /* Mixer #2: Input PGA Mute */ |
279 | static const struct snd_kcontrol_new wm8978_left_input_mixer[] = { |
280 | SOC_DAPM_SINGLE("L2 Switch" , WM8978_INPUT_CONTROL, 2, 1, 0), |
281 | SOC_DAPM_SINGLE("MicN Switch" , WM8978_INPUT_CONTROL, 1, 1, 0), |
282 | SOC_DAPM_SINGLE("MicP Switch" , WM8978_INPUT_CONTROL, 0, 1, 0), |
283 | }; |
284 | static const struct snd_kcontrol_new wm8978_right_input_mixer[] = { |
285 | SOC_DAPM_SINGLE("R2 Switch" , WM8978_INPUT_CONTROL, 6, 1, 0), |
286 | SOC_DAPM_SINGLE("MicN Switch" , WM8978_INPUT_CONTROL, 5, 1, 0), |
287 | SOC_DAPM_SINGLE("MicP Switch" , WM8978_INPUT_CONTROL, 4, 1, 0), |
288 | }; |
289 | |
290 | static const struct snd_soc_dapm_widget wm8978_dapm_widgets[] = { |
291 | SND_SOC_DAPM_DAC("Left DAC" , "Left HiFi Playback" , |
292 | WM8978_POWER_MANAGEMENT_3, 0, 0), |
293 | SND_SOC_DAPM_DAC("Right DAC" , "Right HiFi Playback" , |
294 | WM8978_POWER_MANAGEMENT_3, 1, 0), |
295 | SND_SOC_DAPM_ADC("Left ADC" , "Left HiFi Capture" , |
296 | WM8978_POWER_MANAGEMENT_2, 0, 0), |
297 | SND_SOC_DAPM_ADC("Right ADC" , "Right HiFi Capture" , |
298 | WM8978_POWER_MANAGEMENT_2, 1, 0), |
299 | |
300 | /* Mixer #1: OUT1,2 */ |
301 | SOC_MIXER_ARRAY("Left Output Mixer" , WM8978_POWER_MANAGEMENT_3, |
302 | 2, 0, wm8978_left_out_mixer), |
303 | SOC_MIXER_ARRAY("Right Output Mixer" , WM8978_POWER_MANAGEMENT_3, |
304 | 3, 0, wm8978_right_out_mixer), |
305 | |
306 | SOC_MIXER_ARRAY("Left Input Mixer" , WM8978_POWER_MANAGEMENT_2, |
307 | 2, 0, wm8978_left_input_mixer), |
308 | SOC_MIXER_ARRAY("Right Input Mixer" , WM8978_POWER_MANAGEMENT_2, |
309 | 3, 0, wm8978_right_input_mixer), |
310 | |
311 | SND_SOC_DAPM_PGA("Left Boost Mixer" , WM8978_POWER_MANAGEMENT_2, |
312 | 4, 0, NULL, 0), |
313 | SND_SOC_DAPM_PGA("Right Boost Mixer" , WM8978_POWER_MANAGEMENT_2, |
314 | 5, 0, NULL, 0), |
315 | |
316 | SND_SOC_DAPM_PGA("Left Capture PGA" , WM8978_LEFT_INP_PGA_CONTROL, |
317 | 6, 1, NULL, 0), |
318 | SND_SOC_DAPM_PGA("Right Capture PGA" , WM8978_RIGHT_INP_PGA_CONTROL, |
319 | 6, 1, NULL, 0), |
320 | |
321 | SND_SOC_DAPM_PGA("Left Headphone Out" , WM8978_POWER_MANAGEMENT_2, |
322 | 7, 0, NULL, 0), |
323 | SND_SOC_DAPM_PGA("Right Headphone Out" , WM8978_POWER_MANAGEMENT_2, |
324 | 8, 0, NULL, 0), |
325 | |
326 | SND_SOC_DAPM_PGA("Left Speaker Out" , WM8978_POWER_MANAGEMENT_3, |
327 | 6, 0, NULL, 0), |
328 | SND_SOC_DAPM_PGA("Right Speaker Out" , WM8978_POWER_MANAGEMENT_3, |
329 | 5, 0, NULL, 0), |
330 | |
331 | SND_SOC_DAPM_MIXER("OUT4 VMID" , WM8978_POWER_MANAGEMENT_3, |
332 | 8, 0, NULL, 0), |
333 | |
334 | SND_SOC_DAPM_MICBIAS("Mic Bias" , WM8978_POWER_MANAGEMENT_1, 4, 0), |
335 | |
336 | SND_SOC_DAPM_INPUT("LMICN" ), |
337 | SND_SOC_DAPM_INPUT("LMICP" ), |
338 | SND_SOC_DAPM_INPUT("RMICN" ), |
339 | SND_SOC_DAPM_INPUT("RMICP" ), |
340 | SND_SOC_DAPM_INPUT("LAUX" ), |
341 | SND_SOC_DAPM_INPUT("RAUX" ), |
342 | SND_SOC_DAPM_INPUT("L2" ), |
343 | SND_SOC_DAPM_INPUT("R2" ), |
344 | SND_SOC_DAPM_OUTPUT("LHP" ), |
345 | SND_SOC_DAPM_OUTPUT("RHP" ), |
346 | SND_SOC_DAPM_OUTPUT("LSPK" ), |
347 | SND_SOC_DAPM_OUTPUT("RSPK" ), |
348 | }; |
349 | |
350 | static const struct snd_soc_dapm_route wm8978_dapm_routes[] = { |
351 | /* Output mixer */ |
352 | {"Right Output Mixer" , "PCM Playback Switch" , "Right DAC" }, |
353 | {"Right Output Mixer" , "Aux Playback Switch" , "RAUX" }, |
354 | {"Right Output Mixer" , "Line Bypass Switch" , "Right Boost Mixer" }, |
355 | |
356 | {"Left Output Mixer" , "PCM Playback Switch" , "Left DAC" }, |
357 | {"Left Output Mixer" , "Aux Playback Switch" , "LAUX" }, |
358 | {"Left Output Mixer" , "Line Bypass Switch" , "Left Boost Mixer" }, |
359 | |
360 | /* Outputs */ |
361 | {"Right Headphone Out" , NULL, "Right Output Mixer" }, |
362 | {"RHP" , NULL, "Right Headphone Out" }, |
363 | |
364 | {"Left Headphone Out" , NULL, "Left Output Mixer" }, |
365 | {"LHP" , NULL, "Left Headphone Out" }, |
366 | |
367 | {"Right Speaker Out" , NULL, "Right Output Mixer" }, |
368 | {"RSPK" , NULL, "Right Speaker Out" }, |
369 | |
370 | {"Left Speaker Out" , NULL, "Left Output Mixer" }, |
371 | {"LSPK" , NULL, "Left Speaker Out" }, |
372 | |
373 | /* Boost Mixer */ |
374 | {"Right ADC" , NULL, "Right Boost Mixer" }, |
375 | |
376 | {"Right Boost Mixer" , NULL, "RAUX" }, |
377 | {"Right Boost Mixer" , NULL, "Right Capture PGA" }, |
378 | {"Right Boost Mixer" , NULL, "R2" }, |
379 | |
380 | {"Left ADC" , NULL, "Left Boost Mixer" }, |
381 | |
382 | {"Left Boost Mixer" , NULL, "LAUX" }, |
383 | {"Left Boost Mixer" , NULL, "Left Capture PGA" }, |
384 | {"Left Boost Mixer" , NULL, "L2" }, |
385 | |
386 | /* Input PGA */ |
387 | {"Right Capture PGA" , NULL, "Right Input Mixer" }, |
388 | {"Left Capture PGA" , NULL, "Left Input Mixer" }, |
389 | |
390 | {"Right Input Mixer" , "R2 Switch" , "R2" }, |
391 | {"Right Input Mixer" , "MicN Switch" , "RMICN" }, |
392 | {"Right Input Mixer" , "MicP Switch" , "RMICP" }, |
393 | |
394 | {"Left Input Mixer" , "L2 Switch" , "L2" }, |
395 | {"Left Input Mixer" , "MicN Switch" , "LMICN" }, |
396 | {"Left Input Mixer" , "MicP Switch" , "LMICP" }, |
397 | }; |
398 | |
399 | /* PLL divisors */ |
400 | struct wm8978_pll_div { |
401 | u32 k; |
402 | u8 n; |
403 | u8 div2; |
404 | }; |
405 | |
406 | #define FIXED_PLL_SIZE (1 << 24) |
407 | |
408 | static void pll_factors(struct snd_soc_component *component, |
409 | struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source) |
410 | { |
411 | u64 k_part; |
412 | unsigned int k, n_div, n_mod; |
413 | |
414 | n_div = target / source; |
415 | if (n_div < 6) { |
416 | source >>= 1; |
417 | pll_div->div2 = 1; |
418 | n_div = target / source; |
419 | } else { |
420 | pll_div->div2 = 0; |
421 | } |
422 | |
423 | if (n_div < 6 || n_div > 12) |
424 | dev_warn(component->dev, |
425 | "WM8978 N value exceeds recommended range! N = %u\n" , |
426 | n_div); |
427 | |
428 | pll_div->n = n_div; |
429 | n_mod = target - source * n_div; |
430 | k_part = FIXED_PLL_SIZE * (long long)n_mod + source / 2; |
431 | |
432 | do_div(k_part, source); |
433 | |
434 | k = k_part & 0xFFFFFFFF; |
435 | |
436 | pll_div->k = k; |
437 | } |
438 | |
439 | /* MCLK dividers */ |
440 | static const int mclk_numerator[] = {1, 3, 2, 3, 4, 6, 8, 12}; |
441 | static const int mclk_denominator[] = {1, 2, 1, 1, 1, 1, 1, 1}; |
442 | |
443 | /* |
444 | * find index >= idx, such that, for a given f_out, |
445 | * 3 * f_mclk / 4 <= f_PLLOUT < 13 * f_mclk / 4 |
446 | * f_out can be f_256fs or f_opclk, currently only used for f_256fs. Can be |
447 | * generalised for f_opclk with suitable coefficient arrays, but currently |
448 | * the OPCLK divisor is calculated directly, not iteratively. |
449 | */ |
450 | static int wm8978_enum_mclk(unsigned int f_out, unsigned int f_mclk, |
451 | unsigned int *f_pllout) |
452 | { |
453 | int i; |
454 | |
455 | for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { |
456 | unsigned int f_pllout_x4 = 4 * f_out * mclk_numerator[i] / |
457 | mclk_denominator[i]; |
458 | if (3 * f_mclk <= f_pllout_x4 && f_pllout_x4 < 13 * f_mclk) { |
459 | *f_pllout = f_pllout_x4 / 4; |
460 | return i; |
461 | } |
462 | } |
463 | |
464 | return -EINVAL; |
465 | } |
466 | |
467 | /* |
468 | * Calculate internal frequencies and dividers, according to Figure 40 |
469 | * "PLL and Clock Select Circuit" in WM8978 datasheet Rev. 2.6 |
470 | */ |
471 | static int wm8978_configure_pll(struct snd_soc_component *component) |
472 | { |
473 | struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(c: component); |
474 | struct wm8978_pll_div pll_div; |
475 | unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk, |
476 | f_256fs = wm8978->f_256fs; |
477 | unsigned int f2; |
478 | |
479 | if (!f_mclk) |
480 | return -EINVAL; |
481 | |
482 | if (f_opclk) { |
483 | unsigned int opclk_div; |
484 | /* Cannot set up MCLK divider now, do later */ |
485 | wm8978->mclk_idx = -1; |
486 | |
487 | /* |
488 | * The user needs OPCLK. Choose OPCLKDIV to put |
489 | * 6 <= R = f2 / f1 < 13, 1 <= OPCLKDIV <= 4. |
490 | * f_opclk = f_mclk * prescale * R / 4 / OPCLKDIV, where |
491 | * prescale = 1, or prescale = 2. Prescale is calculated inside |
492 | * pll_factors(). We have to select f_PLLOUT, such that |
493 | * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be |
494 | * f_mclk * 3 / 16 <= f_opclk < f_mclk * 13 / 4. |
495 | */ |
496 | if (16 * f_opclk < 3 * f_mclk || 4 * f_opclk >= 13 * f_mclk) |
497 | return -EINVAL; |
498 | |
499 | if (4 * f_opclk < 3 * f_mclk) |
500 | /* Have to use OPCLKDIV */ |
501 | opclk_div = DIV_ROUND_UP(3 * f_mclk / 4, f_opclk); |
502 | else |
503 | opclk_div = 1; |
504 | |
505 | dev_dbg(component->dev, "%s: OPCLKDIV=%d\n" , __func__, opclk_div); |
506 | |
507 | snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, mask: 0x30, |
508 | val: (opclk_div - 1) << 4); |
509 | |
510 | wm8978->f_pllout = f_opclk * opclk_div; |
511 | } else if (f_256fs) { |
512 | /* |
513 | * Not using OPCLK, but PLL is used for the codec, choose R: |
514 | * 6 <= R = f2 / f1 < 13, to put 1 <= MCLKDIV <= 12. |
515 | * f_256fs = f_mclk * prescale * R / 4 / MCLKDIV, where |
516 | * prescale = 1, or prescale = 2. Prescale is calculated inside |
517 | * pll_factors(). We have to select f_PLLOUT, such that |
518 | * f_mclk * 3 / 4 <= f_PLLOUT < f_mclk * 13 / 4. Must be |
519 | * f_mclk * 3 / 48 <= f_256fs < f_mclk * 13 / 4. This means MCLK |
520 | * must be 3.781MHz <= f_MCLK <= 32.768MHz |
521 | */ |
522 | int idx = wm8978_enum_mclk(f_out: f_256fs, f_mclk, f_pllout: &wm8978->f_pllout); |
523 | if (idx < 0) |
524 | return idx; |
525 | |
526 | wm8978->mclk_idx = idx; |
527 | } else { |
528 | return -EINVAL; |
529 | } |
530 | |
531 | f2 = wm8978->f_pllout * 4; |
532 | |
533 | dev_dbg(component->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n" , __func__, |
534 | wm8978->f_mclk, wm8978->f_pllout); |
535 | |
536 | pll_factors(component, pll_div: &pll_div, target: f2, source: wm8978->f_mclk); |
537 | |
538 | dev_dbg(component->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n" , |
539 | __func__, pll_div.n, pll_div.k, pll_div.div2); |
540 | |
541 | /* Turn PLL off for configuration... */ |
542 | snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, mask: 0x20, val: 0); |
543 | |
544 | snd_soc_component_write(component, WM8978_PLL_N, val: (pll_div.div2 << 4) | pll_div.n); |
545 | snd_soc_component_write(component, WM8978_PLL_K1, val: pll_div.k >> 18); |
546 | snd_soc_component_write(component, WM8978_PLL_K2, val: (pll_div.k >> 9) & 0x1ff); |
547 | snd_soc_component_write(component, WM8978_PLL_K3, val: pll_div.k & 0x1ff); |
548 | |
549 | /* ...and on again */ |
550 | snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, mask: 0x20, val: 0x20); |
551 | |
552 | if (f_opclk) |
553 | /* Output PLL (OPCLK) to GPIO1 */ |
554 | snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, mask: 7, val: 4); |
555 | |
556 | return 0; |
557 | } |
558 | |
559 | /* |
560 | * Configure WM8978 clock dividers. |
561 | */ |
562 | static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
563 | int div_id, int div) |
564 | { |
565 | struct snd_soc_component *component = codec_dai->component; |
566 | struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(c: component); |
567 | int ret = 0; |
568 | |
569 | switch (div_id) { |
570 | case WM8978_OPCLKRATE: |
571 | wm8978->f_opclk = div; |
572 | |
573 | if (wm8978->f_mclk) |
574 | /* |
575 | * We know the MCLK frequency, the user has requested |
576 | * OPCLK, configure the PLL based on that and start it |
577 | * and OPCLK immediately. We will configure PLL to match |
578 | * user-requested OPCLK frquency as good as possible. |
579 | * In fact, it is likely, that matching the sampling |
580 | * rate, when it becomes known, is more important, and |
581 | * we will not be reconfiguring PLL then, because we |
582 | * must not interrupt OPCLK. But it should be fine, |
583 | * because typically the user will request OPCLK to run |
584 | * at 256fs or 512fs, and for these cases we will also |
585 | * find an exact MCLK divider configuration - it will |
586 | * be equal to or double the OPCLK divisor. |
587 | */ |
588 | ret = wm8978_configure_pll(component); |
589 | break; |
590 | case WM8978_BCLKDIV: |
591 | if (div & ~0x1c) |
592 | return -EINVAL; |
593 | snd_soc_component_update_bits(component, WM8978_CLOCKING, mask: 0x1c, val: div); |
594 | break; |
595 | default: |
596 | return -EINVAL; |
597 | } |
598 | |
599 | dev_dbg(component->dev, "%s: ID %d, value %u\n" , __func__, div_id, div); |
600 | |
601 | return ret; |
602 | } |
603 | |
604 | /* |
605 | * @freq: when .set_pll() us not used, freq is codec MCLK input frequency |
606 | */ |
607 | static int wm8978_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, |
608 | unsigned int freq, int dir) |
609 | { |
610 | struct snd_soc_component *component = codec_dai->component; |
611 | struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(c: component); |
612 | int ret = 0; |
613 | |
614 | dev_dbg(component->dev, "%s: ID %d, freq %u\n" , __func__, clk_id, freq); |
615 | |
616 | if (freq) { |
617 | wm8978->f_mclk = freq; |
618 | |
619 | /* Even if MCLK is used for system clock, might have to drive OPCLK */ |
620 | if (wm8978->f_opclk) |
621 | ret = wm8978_configure_pll(component); |
622 | |
623 | /* Our sysclk is fixed to 256 * fs, will configure in .hw_params() */ |
624 | |
625 | if (!ret) |
626 | wm8978->sysclk = clk_id; |
627 | } |
628 | |
629 | if (wm8978->sysclk == WM8978_PLL && (!freq || clk_id == WM8978_MCLK)) { |
630 | /* Clock CODEC directly from MCLK */ |
631 | snd_soc_component_update_bits(component, WM8978_CLOCKING, mask: 0x100, val: 0); |
632 | |
633 | /* GPIO1 into default mode as input - before configuring PLL */ |
634 | snd_soc_component_update_bits(component, WM8978_GPIO_CONTROL, mask: 7, val: 0); |
635 | |
636 | /* Turn off PLL */ |
637 | snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, mask: 0x20, val: 0); |
638 | wm8978->sysclk = WM8978_MCLK; |
639 | wm8978->f_pllout = 0; |
640 | wm8978->f_opclk = 0; |
641 | } |
642 | |
643 | return ret; |
644 | } |
645 | |
646 | /* |
647 | * Set ADC and Voice DAC format. |
648 | */ |
649 | static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) |
650 | { |
651 | struct snd_soc_component *component = codec_dai->component; |
652 | /* |
653 | * BCLK polarity mask = 0x100, LRC clock polarity mask = 0x80, |
654 | * Data Format mask = 0x18: all will be calculated anew |
655 | */ |
656 | u16 iface = snd_soc_component_read(component, WM8978_AUDIO_INTERFACE) & ~0x198; |
657 | u16 clk = snd_soc_component_read(component, WM8978_CLOCKING); |
658 | |
659 | dev_dbg(component->dev, "%s\n" , __func__); |
660 | |
661 | /* set master/slave audio interface */ |
662 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
663 | case SND_SOC_DAIFMT_CBM_CFM: |
664 | clk |= 1; |
665 | break; |
666 | case SND_SOC_DAIFMT_CBS_CFS: |
667 | clk &= ~1; |
668 | break; |
669 | default: |
670 | return -EINVAL; |
671 | } |
672 | |
673 | /* interface format */ |
674 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
675 | case SND_SOC_DAIFMT_I2S: |
676 | iface |= 0x10; |
677 | break; |
678 | case SND_SOC_DAIFMT_RIGHT_J: |
679 | break; |
680 | case SND_SOC_DAIFMT_LEFT_J: |
681 | iface |= 0x8; |
682 | break; |
683 | case SND_SOC_DAIFMT_DSP_A: |
684 | iface |= 0x18; |
685 | break; |
686 | default: |
687 | return -EINVAL; |
688 | } |
689 | |
690 | /* clock inversion */ |
691 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
692 | case SND_SOC_DAIFMT_NB_NF: |
693 | break; |
694 | case SND_SOC_DAIFMT_IB_IF: |
695 | iface |= 0x180; |
696 | break; |
697 | case SND_SOC_DAIFMT_IB_NF: |
698 | iface |= 0x100; |
699 | break; |
700 | case SND_SOC_DAIFMT_NB_IF: |
701 | iface |= 0x80; |
702 | break; |
703 | default: |
704 | return -EINVAL; |
705 | } |
706 | |
707 | snd_soc_component_write(component, WM8978_AUDIO_INTERFACE, val: iface); |
708 | snd_soc_component_write(component, WM8978_CLOCKING, val: clk); |
709 | |
710 | return 0; |
711 | } |
712 | |
713 | /* |
714 | * Set PCM DAI bit size and sample rate. |
715 | */ |
716 | static int wm8978_hw_params(struct snd_pcm_substream *substream, |
717 | struct snd_pcm_hw_params *params, |
718 | struct snd_soc_dai *dai) |
719 | { |
720 | struct snd_soc_component *component = dai->component; |
721 | struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(c: component); |
722 | /* Word length mask = 0x60 */ |
723 | u16 iface_ctl = snd_soc_component_read(component, WM8978_AUDIO_INTERFACE) & ~0x60; |
724 | /* Sampling rate mask = 0xe (for filters) */ |
725 | u16 add_ctl = snd_soc_component_read(component, WM8978_ADDITIONAL_CONTROL) & ~0xe; |
726 | u16 clking = snd_soc_component_read(component, WM8978_CLOCKING); |
727 | enum wm8978_sysclk_src current_clk_id = (clking & 0x100) ? |
728 | WM8978_PLL : WM8978_MCLK; |
729 | unsigned int f_sel, diff, diff_best = INT_MAX; |
730 | int i, best = 0; |
731 | |
732 | if (!wm8978->f_mclk) |
733 | return -EINVAL; |
734 | |
735 | /* bit size */ |
736 | switch (params_width(p: params)) { |
737 | case 16: |
738 | break; |
739 | case 20: |
740 | iface_ctl |= 0x20; |
741 | break; |
742 | case 24: |
743 | iface_ctl |= 0x40; |
744 | break; |
745 | case 32: |
746 | iface_ctl |= 0x60; |
747 | break; |
748 | } |
749 | |
750 | /* filter coefficient */ |
751 | switch (params_rate(p: params)) { |
752 | case 8000: |
753 | add_ctl |= 0x5 << 1; |
754 | break; |
755 | case 11025: |
756 | add_ctl |= 0x4 << 1; |
757 | break; |
758 | case 16000: |
759 | add_ctl |= 0x3 << 1; |
760 | break; |
761 | case 22050: |
762 | add_ctl |= 0x2 << 1; |
763 | break; |
764 | case 32000: |
765 | add_ctl |= 0x1 << 1; |
766 | break; |
767 | case 44100: |
768 | case 48000: |
769 | break; |
770 | } |
771 | |
772 | /* Sampling rate is known now, can configure the MCLK divider */ |
773 | wm8978->f_256fs = params_rate(p: params) * 256; |
774 | |
775 | if (wm8978->sysclk == WM8978_MCLK) { |
776 | wm8978->mclk_idx = -1; |
777 | f_sel = wm8978->f_mclk; |
778 | } else { |
779 | if (!wm8978->f_opclk) { |
780 | /* We only enter here, if OPCLK is not used */ |
781 | int ret = wm8978_configure_pll(component); |
782 | if (ret < 0) |
783 | return ret; |
784 | } |
785 | f_sel = wm8978->f_pllout; |
786 | } |
787 | |
788 | if (wm8978->mclk_idx < 0) { |
789 | /* Either MCLK is used directly, or OPCLK is used */ |
790 | if (f_sel < wm8978->f_256fs || f_sel > 12 * wm8978->f_256fs) |
791 | return -EINVAL; |
792 | |
793 | for (i = 0; i < ARRAY_SIZE(mclk_numerator); i++) { |
794 | diff = abs(wm8978->f_256fs * 3 - |
795 | f_sel * 3 * mclk_denominator[i] / mclk_numerator[i]); |
796 | |
797 | if (diff < diff_best) { |
798 | diff_best = diff; |
799 | best = i; |
800 | } |
801 | |
802 | if (!diff) |
803 | break; |
804 | } |
805 | } else { |
806 | /* OPCLK not used, codec driven by PLL */ |
807 | best = wm8978->mclk_idx; |
808 | diff = 0; |
809 | } |
810 | |
811 | if (diff) |
812 | dev_warn(component->dev, "Imprecise sampling rate: %uHz%s\n" , |
813 | f_sel * mclk_denominator[best] / mclk_numerator[best] / 256, |
814 | wm8978->sysclk == WM8978_MCLK ? |
815 | ", consider using PLL" : "" ); |
816 | |
817 | dev_dbg(component->dev, "%s: width %d, rate %u, MCLK divisor #%d\n" , __func__, |
818 | params_width(params), params_rate(params), best); |
819 | |
820 | /* MCLK divisor mask = 0xe0 */ |
821 | snd_soc_component_update_bits(component, WM8978_CLOCKING, mask: 0xe0, val: best << 5); |
822 | |
823 | snd_soc_component_write(component, WM8978_AUDIO_INTERFACE, val: iface_ctl); |
824 | snd_soc_component_write(component, WM8978_ADDITIONAL_CONTROL, val: add_ctl); |
825 | |
826 | if (wm8978->sysclk != current_clk_id) { |
827 | if (wm8978->sysclk == WM8978_PLL) |
828 | /* Run CODEC from PLL instead of MCLK */ |
829 | snd_soc_component_update_bits(component, WM8978_CLOCKING, |
830 | mask: 0x100, val: 0x100); |
831 | else |
832 | /* Clock CODEC directly from MCLK */ |
833 | snd_soc_component_update_bits(component, WM8978_CLOCKING, mask: 0x100, val: 0); |
834 | } |
835 | |
836 | return 0; |
837 | } |
838 | |
839 | static int wm8978_mute(struct snd_soc_dai *dai, int mute, int direction) |
840 | { |
841 | struct snd_soc_component *component = dai->component; |
842 | |
843 | dev_dbg(component->dev, "%s: %d\n" , __func__, mute); |
844 | |
845 | if (mute) |
846 | snd_soc_component_update_bits(component, WM8978_DAC_CONTROL, mask: 0x40, val: 0x40); |
847 | else |
848 | snd_soc_component_update_bits(component, WM8978_DAC_CONTROL, mask: 0x40, val: 0); |
849 | |
850 | return 0; |
851 | } |
852 | |
853 | static int wm8978_set_bias_level(struct snd_soc_component *component, |
854 | enum snd_soc_bias_level level) |
855 | { |
856 | u16 power1 = snd_soc_component_read(component, WM8978_POWER_MANAGEMENT_1) & ~3; |
857 | |
858 | switch (level) { |
859 | case SND_SOC_BIAS_ON: |
860 | case SND_SOC_BIAS_PREPARE: |
861 | power1 |= 1; /* VMID 75k */ |
862 | snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, val: power1); |
863 | break; |
864 | case SND_SOC_BIAS_STANDBY: |
865 | /* bit 3: enable bias, bit 2: enable I/O tie off buffer */ |
866 | power1 |= 0xc; |
867 | |
868 | if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { |
869 | /* Initial cap charge at VMID 5k */ |
870 | snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, |
871 | val: power1 | 0x3); |
872 | mdelay(100); |
873 | } |
874 | |
875 | power1 |= 0x2; /* VMID 500k */ |
876 | snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, val: power1); |
877 | break; |
878 | case SND_SOC_BIAS_OFF: |
879 | /* Preserve PLL - OPCLK may be used by someone */ |
880 | snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, mask: ~0x20, val: 0); |
881 | snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_2, val: 0); |
882 | snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_3, val: 0); |
883 | break; |
884 | } |
885 | |
886 | dev_dbg(component->dev, "%s: %d, %x\n" , __func__, level, power1); |
887 | |
888 | return 0; |
889 | } |
890 | |
891 | #define WM8978_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
892 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
893 | |
894 | static const struct snd_soc_dai_ops wm8978_dai_ops = { |
895 | .hw_params = wm8978_hw_params, |
896 | .mute_stream = wm8978_mute, |
897 | .set_fmt = wm8978_set_dai_fmt, |
898 | .set_clkdiv = wm8978_set_dai_clkdiv, |
899 | .set_sysclk = wm8978_set_dai_sysclk, |
900 | .no_capture_mute = 1, |
901 | }; |
902 | |
903 | /* Also supports 12kHz */ |
904 | static struct snd_soc_dai_driver wm8978_dai = { |
905 | .name = "wm8978-hifi" , |
906 | .playback = { |
907 | .stream_name = "Playback" , |
908 | .channels_min = 1, |
909 | .channels_max = 2, |
910 | .rates = SNDRV_PCM_RATE_8000_48000, |
911 | .formats = WM8978_FORMATS, |
912 | }, |
913 | .capture = { |
914 | .stream_name = "Capture" , |
915 | .channels_min = 1, |
916 | .channels_max = 2, |
917 | .rates = SNDRV_PCM_RATE_8000_48000, |
918 | .formats = WM8978_FORMATS, |
919 | }, |
920 | .ops = &wm8978_dai_ops, |
921 | .symmetric_rate = 1, |
922 | }; |
923 | |
924 | static int wm8978_suspend(struct snd_soc_component *component) |
925 | { |
926 | struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(c: component); |
927 | |
928 | snd_soc_component_force_bias_level(component, level: SND_SOC_BIAS_OFF); |
929 | /* Also switch PLL off */ |
930 | snd_soc_component_write(component, WM8978_POWER_MANAGEMENT_1, val: 0); |
931 | |
932 | regcache_mark_dirty(map: wm8978->regmap); |
933 | |
934 | return 0; |
935 | } |
936 | |
937 | static int wm8978_resume(struct snd_soc_component *component) |
938 | { |
939 | struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(c: component); |
940 | |
941 | /* Sync reg_cache with the hardware */ |
942 | regcache_sync(map: wm8978->regmap); |
943 | |
944 | snd_soc_component_force_bias_level(component, level: SND_SOC_BIAS_STANDBY); |
945 | |
946 | if (wm8978->f_pllout) |
947 | /* Switch PLL on */ |
948 | snd_soc_component_update_bits(component, WM8978_POWER_MANAGEMENT_1, mask: 0x20, val: 0x20); |
949 | |
950 | return 0; |
951 | } |
952 | |
953 | /* |
954 | * These registers contain an "update" bit - bit 8. This means, for example, |
955 | * that one can write new DAC digital volume for both channels, but only when |
956 | * the update bit is set, will also the volume be updated - simultaneously for |
957 | * both channels. |
958 | */ |
959 | static const int update_reg[] = { |
960 | WM8978_LEFT_DAC_DIGITAL_VOLUME, |
961 | WM8978_RIGHT_DAC_DIGITAL_VOLUME, |
962 | WM8978_LEFT_ADC_DIGITAL_VOLUME, |
963 | WM8978_RIGHT_ADC_DIGITAL_VOLUME, |
964 | WM8978_LEFT_INP_PGA_CONTROL, |
965 | WM8978_RIGHT_INP_PGA_CONTROL, |
966 | WM8978_LOUT1_HP_CONTROL, |
967 | WM8978_ROUT1_HP_CONTROL, |
968 | WM8978_LOUT2_SPK_CONTROL, |
969 | WM8978_ROUT2_SPK_CONTROL, |
970 | }; |
971 | |
972 | static int wm8978_probe(struct snd_soc_component *component) |
973 | { |
974 | struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(c: component); |
975 | int i; |
976 | |
977 | /* |
978 | * Set default system clock to PLL, it is more precise, this is also the |
979 | * default hardware setting |
980 | */ |
981 | wm8978->sysclk = WM8978_PLL; |
982 | |
983 | /* |
984 | * Set the update bit in all registers, that have one. This way all |
985 | * writes to those registers will also cause the update bit to be |
986 | * written. |
987 | */ |
988 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) |
989 | snd_soc_component_update_bits(component, reg: update_reg[i], mask: 0x100, val: 0x100); |
990 | |
991 | return 0; |
992 | } |
993 | |
994 | static const struct snd_soc_component_driver soc_component_dev_wm8978 = { |
995 | .probe = wm8978_probe, |
996 | .suspend = wm8978_suspend, |
997 | .resume = wm8978_resume, |
998 | .set_bias_level = wm8978_set_bias_level, |
999 | .controls = wm8978_snd_controls, |
1000 | .num_controls = ARRAY_SIZE(wm8978_snd_controls), |
1001 | .dapm_widgets = wm8978_dapm_widgets, |
1002 | .num_dapm_widgets = ARRAY_SIZE(wm8978_dapm_widgets), |
1003 | .dapm_routes = wm8978_dapm_routes, |
1004 | .num_dapm_routes = ARRAY_SIZE(wm8978_dapm_routes), |
1005 | .idle_bias_on = 1, |
1006 | .use_pmdown_time = 1, |
1007 | .endianness = 1, |
1008 | }; |
1009 | |
1010 | static const struct regmap_config wm8978_regmap_config = { |
1011 | .reg_bits = 7, |
1012 | .val_bits = 9, |
1013 | |
1014 | .max_register = WM8978_MAX_REGISTER, |
1015 | .volatile_reg = wm8978_volatile, |
1016 | |
1017 | .cache_type = REGCACHE_MAPLE, |
1018 | .reg_defaults = wm8978_reg_defaults, |
1019 | .num_reg_defaults = ARRAY_SIZE(wm8978_reg_defaults), |
1020 | }; |
1021 | |
1022 | static int wm8978_i2c_probe(struct i2c_client *i2c) |
1023 | { |
1024 | struct wm8978_priv *wm8978; |
1025 | int ret; |
1026 | |
1027 | wm8978 = devm_kzalloc(dev: &i2c->dev, size: sizeof(struct wm8978_priv), |
1028 | GFP_KERNEL); |
1029 | if (wm8978 == NULL) |
1030 | return -ENOMEM; |
1031 | |
1032 | wm8978->regmap = devm_regmap_init_i2c(i2c, &wm8978_regmap_config); |
1033 | if (IS_ERR(ptr: wm8978->regmap)) { |
1034 | ret = PTR_ERR(ptr: wm8978->regmap); |
1035 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n" , ret); |
1036 | return ret; |
1037 | } |
1038 | |
1039 | i2c_set_clientdata(client: i2c, data: wm8978); |
1040 | |
1041 | /* Reset the codec */ |
1042 | ret = regmap_write(map: wm8978->regmap, WM8978_RESET, val: 0); |
1043 | if (ret != 0) { |
1044 | dev_err(&i2c->dev, "Failed to issue reset: %d\n" , ret); |
1045 | return ret; |
1046 | } |
1047 | |
1048 | ret = devm_snd_soc_register_component(dev: &i2c->dev, |
1049 | component_driver: &soc_component_dev_wm8978, dai_drv: &wm8978_dai, num_dai: 1); |
1050 | if (ret != 0) { |
1051 | dev_err(&i2c->dev, "Failed to register CODEC: %d\n" , ret); |
1052 | return ret; |
1053 | } |
1054 | |
1055 | return 0; |
1056 | } |
1057 | |
1058 | static const struct i2c_device_id wm8978_i2c_id[] = { |
1059 | { "wm8978" , 0 }, |
1060 | { } |
1061 | }; |
1062 | MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id); |
1063 | |
1064 | static const struct of_device_id wm8978_of_match[] = { |
1065 | { .compatible = "wlf,wm8978" , }, |
1066 | { } |
1067 | }; |
1068 | MODULE_DEVICE_TABLE(of, wm8978_of_match); |
1069 | |
1070 | static struct i2c_driver wm8978_i2c_driver = { |
1071 | .driver = { |
1072 | .name = "wm8978" , |
1073 | .of_match_table = wm8978_of_match, |
1074 | }, |
1075 | .probe = wm8978_i2c_probe, |
1076 | .id_table = wm8978_i2c_id, |
1077 | }; |
1078 | |
1079 | module_i2c_driver(wm8978_i2c_driver); |
1080 | |
1081 | MODULE_DESCRIPTION("ASoC WM8978 codec driver" ); |
1082 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>" ); |
1083 | MODULE_LICENSE("GPL" ); |
1084 | |