1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // nau8822.c -- NAU8822 ALSA Soc Audio driver |
4 | // |
5 | // Copyright 2017 Nuvoton Technology Crop. |
6 | // |
7 | // Author: David Lin <ctlin0@nuvoton.com> |
8 | // Co-author: John Hsu <kchsu0@nuvoton.com> |
9 | // Co-author: Seven Li <wtli@nuvoton.com> |
10 | // |
11 | // Based on WM8974.c |
12 | |
13 | #include <linux/module.h> |
14 | #include <linux/moduleparam.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/pm.h> |
19 | #include <linux/i2c.h> |
20 | #include <linux/regmap.h> |
21 | #include <linux/slab.h> |
22 | #include <sound/core.h> |
23 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> |
25 | #include <sound/soc.h> |
26 | #include <sound/initval.h> |
27 | #include <sound/tlv.h> |
28 | #include <asm/div64.h> |
29 | #include "nau8822.h" |
30 | |
31 | #define NAU_PLL_FREQ_MAX 100000000 |
32 | #define NAU_PLL_FREQ_MIN 90000000 |
33 | #define NAU_PLL_REF_MAX 33000000 |
34 | #define NAU_PLL_REF_MIN 8000000 |
35 | #define NAU_PLL_OPTOP_MIN 6 |
36 | |
37 | static const int nau8822_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 }; |
38 | |
39 | static const struct reg_default nau8822_reg_defaults[] = { |
40 | { NAU8822_REG_POWER_MANAGEMENT_1, 0x0000 }, |
41 | { NAU8822_REG_POWER_MANAGEMENT_2, 0x0000 }, |
42 | { NAU8822_REG_POWER_MANAGEMENT_3, 0x0000 }, |
43 | { NAU8822_REG_AUDIO_INTERFACE, 0x0050 }, |
44 | { NAU8822_REG_COMPANDING_CONTROL, 0x0000 }, |
45 | { NAU8822_REG_CLOCKING, 0x0140 }, |
46 | { NAU8822_REG_ADDITIONAL_CONTROL, 0x0000 }, |
47 | { NAU8822_REG_GPIO_CONTROL, 0x0000 }, |
48 | { NAU8822_REG_JACK_DETECT_CONTROL_1, 0x0000 }, |
49 | { NAU8822_REG_DAC_CONTROL, 0x0000 }, |
50 | { NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, 0x00ff }, |
51 | { NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0x00ff }, |
52 | { NAU8822_REG_JACK_DETECT_CONTROL_2, 0x0000 }, |
53 | { NAU8822_REG_ADC_CONTROL, 0x0100 }, |
54 | { NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, 0x00ff }, |
55 | { NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0x00ff }, |
56 | { NAU8822_REG_EQ1, 0x012c }, |
57 | { NAU8822_REG_EQ2, 0x002c }, |
58 | { NAU8822_REG_EQ3, 0x002c }, |
59 | { NAU8822_REG_EQ4, 0x002c }, |
60 | { NAU8822_REG_EQ5, 0x002c }, |
61 | { NAU8822_REG_DAC_LIMITER_1, 0x0032 }, |
62 | { NAU8822_REG_DAC_LIMITER_2, 0x0000 }, |
63 | { NAU8822_REG_NOTCH_FILTER_1, 0x0000 }, |
64 | { NAU8822_REG_NOTCH_FILTER_2, 0x0000 }, |
65 | { NAU8822_REG_NOTCH_FILTER_3, 0x0000 }, |
66 | { NAU8822_REG_NOTCH_FILTER_4, 0x0000 }, |
67 | { NAU8822_REG_ALC_CONTROL_1, 0x0038 }, |
68 | { NAU8822_REG_ALC_CONTROL_2, 0x000b }, |
69 | { NAU8822_REG_ALC_CONTROL_3, 0x0032 }, |
70 | { NAU8822_REG_NOISE_GATE, 0x0010 }, |
71 | { NAU8822_REG_PLL_N, 0x0008 }, |
72 | { NAU8822_REG_PLL_K1, 0x000c }, |
73 | { NAU8822_REG_PLL_K2, 0x0093 }, |
74 | { NAU8822_REG_PLL_K3, 0x00e9 }, |
75 | { NAU8822_REG_3D_CONTROL, 0x0000 }, |
76 | { NAU8822_REG_RIGHT_SPEAKER_CONTROL, 0x0000 }, |
77 | { NAU8822_REG_INPUT_CONTROL, 0x0033 }, |
78 | { NAU8822_REG_LEFT_INP_PGA_CONTROL, 0x0010 }, |
79 | { NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0x0010 }, |
80 | { NAU8822_REG_LEFT_ADC_BOOST_CONTROL, 0x0100 }, |
81 | { NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0x0100 }, |
82 | { NAU8822_REG_OUTPUT_CONTROL, 0x0002 }, |
83 | { NAU8822_REG_LEFT_MIXER_CONTROL, 0x0001 }, |
84 | { NAU8822_REG_RIGHT_MIXER_CONTROL, 0x0001 }, |
85 | { NAU8822_REG_LHP_VOLUME, 0x0039 }, |
86 | { NAU8822_REG_RHP_VOLUME, 0x0039 }, |
87 | { NAU8822_REG_LSPKOUT_VOLUME, 0x0039 }, |
88 | { NAU8822_REG_RSPKOUT_VOLUME, 0x0039 }, |
89 | { NAU8822_REG_AUX2_MIXER, 0x0001 }, |
90 | { NAU8822_REG_AUX1_MIXER, 0x0001 }, |
91 | { NAU8822_REG_POWER_MANAGEMENT_4, 0x0000 }, |
92 | { NAU8822_REG_LEFT_TIME_SLOT, 0x0000 }, |
93 | { NAU8822_REG_MISC, 0x0020 }, |
94 | { NAU8822_REG_RIGHT_TIME_SLOT, 0x0000 }, |
95 | { NAU8822_REG_DEVICE_REVISION, 0x007f }, |
96 | { NAU8822_REG_DEVICE_ID, 0x001a }, |
97 | { NAU8822_REG_DAC_DITHER, 0x0114 }, |
98 | { NAU8822_REG_ALC_ENHANCE_1, 0x0000 }, |
99 | { NAU8822_REG_ALC_ENHANCE_2, 0x0000 }, |
100 | { NAU8822_REG_192KHZ_SAMPLING, 0x0008 }, |
101 | { NAU8822_REG_MISC_CONTROL, 0x0000 }, |
102 | { NAU8822_REG_INPUT_TIEOFF, 0x0000 }, |
103 | { NAU8822_REG_POWER_REDUCTION, 0x0000 }, |
104 | { NAU8822_REG_AGC_PEAK2PEAK, 0x0000 }, |
105 | { NAU8822_REG_AGC_PEAK_DETECT, 0x0000 }, |
106 | { NAU8822_REG_AUTOMUTE_CONTROL, 0x0000 }, |
107 | { NAU8822_REG_OUTPUT_TIEOFF, 0x0000 }, |
108 | }; |
109 | |
110 | static bool nau8822_readable_reg(struct device *dev, unsigned int reg) |
111 | { |
112 | switch (reg) { |
113 | case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: |
114 | case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: |
115 | case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: |
116 | case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: |
117 | case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: |
118 | case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: |
119 | case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: |
120 | case NAU8822_REG_3D_CONTROL: |
121 | case NAU8822_REG_RIGHT_SPEAKER_CONTROL: |
122 | case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: |
123 | case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: |
124 | case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: |
125 | case NAU8822_REG_DAC_DITHER: |
126 | case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: |
127 | case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: |
128 | return true; |
129 | default: |
130 | return false; |
131 | } |
132 | } |
133 | |
134 | static bool nau8822_writeable_reg(struct device *dev, unsigned int reg) |
135 | { |
136 | switch (reg) { |
137 | case NAU8822_REG_RESET ... NAU8822_REG_JACK_DETECT_CONTROL_1: |
138 | case NAU8822_REG_DAC_CONTROL ... NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME: |
139 | case NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME: |
140 | case NAU8822_REG_EQ1 ... NAU8822_REG_EQ5: |
141 | case NAU8822_REG_DAC_LIMITER_1 ... NAU8822_REG_DAC_LIMITER_2: |
142 | case NAU8822_REG_NOTCH_FILTER_1 ... NAU8822_REG_NOTCH_FILTER_4: |
143 | case NAU8822_REG_ALC_CONTROL_1 ...NAU8822_REG_PLL_K3: |
144 | case NAU8822_REG_3D_CONTROL: |
145 | case NAU8822_REG_RIGHT_SPEAKER_CONTROL: |
146 | case NAU8822_REG_INPUT_CONTROL ... NAU8822_REG_LEFT_ADC_BOOST_CONTROL: |
147 | case NAU8822_REG_RIGHT_ADC_BOOST_CONTROL ... NAU8822_REG_AUX1_MIXER: |
148 | case NAU8822_REG_POWER_MANAGEMENT_4 ... NAU8822_REG_DEVICE_ID: |
149 | case NAU8822_REG_DAC_DITHER: |
150 | case NAU8822_REG_ALC_ENHANCE_1 ... NAU8822_REG_MISC_CONTROL: |
151 | case NAU8822_REG_INPUT_TIEOFF ... NAU8822_REG_OUTPUT_TIEOFF: |
152 | return true; |
153 | default: |
154 | return false; |
155 | } |
156 | } |
157 | |
158 | static bool nau8822_volatile(struct device *dev, unsigned int reg) |
159 | { |
160 | switch (reg) { |
161 | case NAU8822_REG_RESET: |
162 | case NAU8822_REG_DEVICE_REVISION: |
163 | case NAU8822_REG_DEVICE_ID: |
164 | case NAU8822_REG_AGC_PEAK2PEAK: |
165 | case NAU8822_REG_AGC_PEAK_DETECT: |
166 | case NAU8822_REG_AUTOMUTE_CONTROL: |
167 | return true; |
168 | default: |
169 | return false; |
170 | } |
171 | } |
172 | |
173 | /* The EQ parameters get function is to get the 5 band equalizer control. |
174 | * The regmap raw read can't work here because regmap doesn't provide |
175 | * value format for value width of 9 bits. Therefore, the driver reads data |
176 | * from cache and makes value format according to the endianness of |
177 | * bytes type control element. |
178 | */ |
179 | static int nau8822_eq_get(struct snd_kcontrol *kcontrol, |
180 | struct snd_ctl_elem_value *ucontrol) |
181 | { |
182 | struct snd_soc_component *component = |
183 | snd_soc_kcontrol_component(kcontrol); |
184 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; |
185 | int i, reg; |
186 | u16 reg_val, *val; |
187 | __be16 tmp; |
188 | |
189 | val = (u16 *)ucontrol->value.bytes.data; |
190 | reg = NAU8822_REG_EQ1; |
191 | for (i = 0; i < params->max / sizeof(u16); i++) { |
192 | reg_val = snd_soc_component_read(component, reg: reg + i); |
193 | /* conversion of 16-bit integers between native CPU format |
194 | * and big endian format |
195 | */ |
196 | tmp = cpu_to_be16(reg_val); |
197 | memcpy(val + i, &tmp, sizeof(tmp)); |
198 | } |
199 | |
200 | return 0; |
201 | } |
202 | |
203 | /* The EQ parameters put function is to make configuration of 5 band equalizer |
204 | * control. These configuration includes central frequency, equalizer gain, |
205 | * cut-off frequency, bandwidth control, and equalizer path. |
206 | * The regmap raw write can't work here because regmap doesn't provide |
207 | * register and value format for register with address 7 bits and value 9 bits. |
208 | * Therefore, the driver makes value format according to the endianness of |
209 | * bytes type control element and writes data to codec. |
210 | */ |
211 | static int nau8822_eq_put(struct snd_kcontrol *kcontrol, |
212 | struct snd_ctl_elem_value *ucontrol) |
213 | { |
214 | struct snd_soc_component *component = |
215 | snd_soc_kcontrol_component(kcontrol); |
216 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; |
217 | void *data; |
218 | u16 *val, value; |
219 | int i, reg, ret; |
220 | __be16 *tmp; |
221 | |
222 | data = kmemdup(p: ucontrol->value.bytes.data, |
223 | size: params->max, GFP_KERNEL | GFP_DMA); |
224 | if (!data) |
225 | return -ENOMEM; |
226 | |
227 | val = (u16 *)data; |
228 | reg = NAU8822_REG_EQ1; |
229 | for (i = 0; i < params->max / sizeof(u16); i++) { |
230 | /* conversion of 16-bit integers between native CPU format |
231 | * and big endian format |
232 | */ |
233 | tmp = (__be16 *)(val + i); |
234 | value = be16_to_cpup(p: tmp); |
235 | ret = snd_soc_component_write(component, reg: reg + i, val: value); |
236 | if (ret) { |
237 | dev_err(component->dev, |
238 | "EQ configuration fail, register: %x ret: %d\n" , |
239 | reg + i, ret); |
240 | kfree(objp: data); |
241 | return ret; |
242 | } |
243 | } |
244 | kfree(objp: data); |
245 | |
246 | return 0; |
247 | } |
248 | |
249 | static const char * const nau8822_companding[] = { |
250 | "Off" , "NC" , "u-law" , "A-law" }; |
251 | |
252 | static const struct soc_enum nau8822_companding_adc_enum = |
253 | SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_ADCCM_SFT, |
254 | ARRAY_SIZE(nau8822_companding), nau8822_companding); |
255 | |
256 | static const struct soc_enum nau8822_companding_dac_enum = |
257 | SOC_ENUM_SINGLE(NAU8822_REG_COMPANDING_CONTROL, NAU8822_DACCM_SFT, |
258 | ARRAY_SIZE(nau8822_companding), nau8822_companding); |
259 | |
260 | static const char * const nau8822_eqmode[] = {"Capture" , "Playback" }; |
261 | |
262 | static const struct soc_enum nau8822_eqmode_enum = |
263 | SOC_ENUM_SINGLE(NAU8822_REG_EQ1, NAU8822_EQM_SFT, |
264 | ARRAY_SIZE(nau8822_eqmode), nau8822_eqmode); |
265 | |
266 | static const char * const nau8822_alc1[] = {"Off" , "Right" , "Left" , "Both" }; |
267 | static const char * const nau8822_alc3[] = {"Normal" , "Limiter" }; |
268 | |
269 | static const struct soc_enum nau8822_alc_enable_enum = |
270 | SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_1, NAU8822_ALCEN_SFT, |
271 | ARRAY_SIZE(nau8822_alc1), nau8822_alc1); |
272 | |
273 | static const struct soc_enum nau8822_alc_mode_enum = |
274 | SOC_ENUM_SINGLE(NAU8822_REG_ALC_CONTROL_3, NAU8822_ALCM_SFT, |
275 | ARRAY_SIZE(nau8822_alc3), nau8822_alc3); |
276 | |
277 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); |
278 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); |
279 | static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); |
280 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); |
281 | static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); |
282 | static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0); |
283 | |
284 | static const struct snd_kcontrol_new nau8822_snd_controls[] = { |
285 | SOC_ENUM("ADC Companding" , nau8822_companding_adc_enum), |
286 | SOC_ENUM("DAC Companding" , nau8822_companding_dac_enum), |
287 | |
288 | SOC_ENUM("EQ Function" , nau8822_eqmode_enum), |
289 | SND_SOC_BYTES_EXT("EQ Parameters" , 10, |
290 | nau8822_eq_get, nau8822_eq_put), |
291 | |
292 | SOC_DOUBLE("DAC Inversion Switch" , |
293 | NAU8822_REG_DAC_CONTROL, 0, 1, 1, 0), |
294 | SOC_DOUBLE_R_TLV("PCM Volume" , |
295 | NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, |
296 | NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), |
297 | |
298 | SOC_SINGLE("High Pass Filter Switch" , |
299 | NAU8822_REG_ADC_CONTROL, 8, 1, 0), |
300 | SOC_SINGLE("High Pass Cut Off" , |
301 | NAU8822_REG_ADC_CONTROL, 4, 7, 0), |
302 | |
303 | SOC_DOUBLE("ADC Inversion Switch" , |
304 | NAU8822_REG_ADC_CONTROL, 0, 1, 1, 0), |
305 | SOC_DOUBLE_R_TLV("ADC Volume" , |
306 | NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, |
307 | NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, 0, 255, 0, digital_tlv), |
308 | |
309 | SOC_SINGLE("DAC Limiter Switch" , |
310 | NAU8822_REG_DAC_LIMITER_1, 8, 1, 0), |
311 | SOC_SINGLE("DAC Limiter Decay" , |
312 | NAU8822_REG_DAC_LIMITER_1, 4, 15, 0), |
313 | SOC_SINGLE("DAC Limiter Attack" , |
314 | NAU8822_REG_DAC_LIMITER_1, 0, 15, 0), |
315 | SOC_SINGLE("DAC Limiter Threshold" , |
316 | NAU8822_REG_DAC_LIMITER_2, 4, 7, 0), |
317 | SOC_SINGLE_TLV("DAC Limiter Volume" , |
318 | NAU8822_REG_DAC_LIMITER_2, 0, 12, 0, limiter_tlv), |
319 | |
320 | SOC_ENUM("ALC Mode" , nau8822_alc_mode_enum), |
321 | SOC_ENUM("ALC Enable Switch" , nau8822_alc_enable_enum), |
322 | SOC_SINGLE("ALC Min Gain" , |
323 | NAU8822_REG_ALC_CONTROL_1, 0, 7, 0), |
324 | SOC_SINGLE("ALC Max Gain" , |
325 | NAU8822_REG_ALC_CONTROL_1, 3, 7, 0), |
326 | SOC_SINGLE("ALC Hold" , |
327 | NAU8822_REG_ALC_CONTROL_2, 4, 10, 0), |
328 | SOC_SINGLE("ALC Target" , |
329 | NAU8822_REG_ALC_CONTROL_2, 0, 15, 0), |
330 | SOC_SINGLE("ALC Decay" , |
331 | NAU8822_REG_ALC_CONTROL_3, 4, 10, 0), |
332 | SOC_SINGLE("ALC Attack" , |
333 | NAU8822_REG_ALC_CONTROL_3, 0, 10, 0), |
334 | SOC_SINGLE("ALC Noise Gate Switch" , |
335 | NAU8822_REG_NOISE_GATE, 3, 1, 0), |
336 | SOC_SINGLE("ALC Noise Gate Threshold" , |
337 | NAU8822_REG_NOISE_GATE, 0, 7, 0), |
338 | |
339 | SOC_DOUBLE_R("PGA ZC Switch" , |
340 | NAU8822_REG_LEFT_INP_PGA_CONTROL, |
341 | NAU8822_REG_RIGHT_INP_PGA_CONTROL, |
342 | 7, 1, 0), |
343 | SOC_DOUBLE_R_TLV("PGA Volume" , |
344 | NAU8822_REG_LEFT_INP_PGA_CONTROL, |
345 | NAU8822_REG_RIGHT_INP_PGA_CONTROL, 0, 63, 0, inpga_tlv), |
346 | |
347 | SOC_DOUBLE_R("Headphone ZC Switch" , |
348 | NAU8822_REG_LHP_VOLUME, |
349 | NAU8822_REG_RHP_VOLUME, 7, 1, 0), |
350 | SOC_DOUBLE_R("Headphone Playback Switch" , |
351 | NAU8822_REG_LHP_VOLUME, |
352 | NAU8822_REG_RHP_VOLUME, 6, 1, 1), |
353 | SOC_DOUBLE_R_TLV("Headphone Volume" , |
354 | NAU8822_REG_LHP_VOLUME, |
355 | NAU8822_REG_RHP_VOLUME, 0, 63, 0, spk_tlv), |
356 | |
357 | SOC_DOUBLE_R("Speaker ZC Switch" , |
358 | NAU8822_REG_LSPKOUT_VOLUME, |
359 | NAU8822_REG_RSPKOUT_VOLUME, 7, 1, 0), |
360 | SOC_DOUBLE_R("Speaker Playback Switch" , |
361 | NAU8822_REG_LSPKOUT_VOLUME, |
362 | NAU8822_REG_RSPKOUT_VOLUME, 6, 1, 1), |
363 | SOC_DOUBLE_R_TLV("Speaker Volume" , |
364 | NAU8822_REG_LSPKOUT_VOLUME, |
365 | NAU8822_REG_RSPKOUT_VOLUME, 0, 63, 0, spk_tlv), |
366 | |
367 | SOC_DOUBLE_R("AUXOUT Playback Switch" , |
368 | NAU8822_REG_AUX2_MIXER, |
369 | NAU8822_REG_AUX1_MIXER, 6, 1, 1), |
370 | |
371 | SOC_DOUBLE_R_TLV("PGA Boost Volume" , |
372 | NAU8822_REG_LEFT_ADC_BOOST_CONTROL, |
373 | NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 8, 1, 0, pga_boost_tlv), |
374 | SOC_DOUBLE_R_TLV("L2/R2 Boost Volume" , |
375 | NAU8822_REG_LEFT_ADC_BOOST_CONTROL, |
376 | NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 4, 7, 0, boost_tlv), |
377 | SOC_DOUBLE_R_TLV("Aux Boost Volume" , |
378 | NAU8822_REG_LEFT_ADC_BOOST_CONTROL, |
379 | NAU8822_REG_RIGHT_ADC_BOOST_CONTROL, 0, 7, 0, boost_tlv), |
380 | |
381 | SOC_SINGLE("DAC 128x Oversampling Switch" , |
382 | NAU8822_REG_DAC_CONTROL, 5, 1, 0), |
383 | SOC_SINGLE("ADC 128x Oversampling Switch" , |
384 | NAU8822_REG_ADC_CONTROL, 5, 1, 0), |
385 | }; |
386 | |
387 | /* LMAIN and RMAIN Mixer */ |
388 | static const struct snd_kcontrol_new nau8822_left_out_mixer[] = { |
389 | SOC_DAPM_SINGLE("LINMIX Switch" , |
390 | NAU8822_REG_LEFT_MIXER_CONTROL, 1, 1, 0), |
391 | SOC_DAPM_SINGLE("LAUX Switch" , |
392 | NAU8822_REG_LEFT_MIXER_CONTROL, 5, 1, 0), |
393 | SOC_DAPM_SINGLE("LDAC Switch" , |
394 | NAU8822_REG_LEFT_MIXER_CONTROL, 0, 1, 0), |
395 | SOC_DAPM_SINGLE("RDAC Switch" , |
396 | NAU8822_REG_OUTPUT_CONTROL, 5, 1, 0), |
397 | }; |
398 | |
399 | static const struct snd_kcontrol_new nau8822_right_out_mixer[] = { |
400 | SOC_DAPM_SINGLE("RINMIX Switch" , |
401 | NAU8822_REG_RIGHT_MIXER_CONTROL, 1, 1, 0), |
402 | SOC_DAPM_SINGLE("RAUX Switch" , |
403 | NAU8822_REG_RIGHT_MIXER_CONTROL, 5, 1, 0), |
404 | SOC_DAPM_SINGLE("RDAC Switch" , |
405 | NAU8822_REG_RIGHT_MIXER_CONTROL, 0, 1, 0), |
406 | SOC_DAPM_SINGLE("LDAC Switch" , |
407 | NAU8822_REG_OUTPUT_CONTROL, 6, 1, 0), |
408 | }; |
409 | |
410 | /* AUX1 and AUX2 Mixer */ |
411 | static const struct snd_kcontrol_new nau8822_auxout1_mixer[] = { |
412 | SOC_DAPM_SINGLE("RDAC Switch" , NAU8822_REG_AUX1_MIXER, 0, 1, 0), |
413 | SOC_DAPM_SINGLE("RMIX Switch" , NAU8822_REG_AUX1_MIXER, 1, 1, 0), |
414 | SOC_DAPM_SINGLE("RINMIX Switch" , NAU8822_REG_AUX1_MIXER, 2, 1, 0), |
415 | SOC_DAPM_SINGLE("LDAC Switch" , NAU8822_REG_AUX1_MIXER, 3, 1, 0), |
416 | SOC_DAPM_SINGLE("LMIX Switch" , NAU8822_REG_AUX1_MIXER, 4, 1, 0), |
417 | }; |
418 | |
419 | static const struct snd_kcontrol_new nau8822_auxout2_mixer[] = { |
420 | SOC_DAPM_SINGLE("LDAC Switch" , NAU8822_REG_AUX2_MIXER, 0, 1, 0), |
421 | SOC_DAPM_SINGLE("LMIX Switch" , NAU8822_REG_AUX2_MIXER, 1, 1, 0), |
422 | SOC_DAPM_SINGLE("LINMIX Switch" , NAU8822_REG_AUX2_MIXER, 2, 1, 0), |
423 | SOC_DAPM_SINGLE("AUX1MIX Output Switch" , |
424 | NAU8822_REG_AUX2_MIXER, 3, 1, 0), |
425 | }; |
426 | |
427 | /* Input PGA */ |
428 | static const struct snd_kcontrol_new nau8822_left_input_mixer[] = { |
429 | SOC_DAPM_SINGLE("L2 Switch" , NAU8822_REG_INPUT_CONTROL, 2, 1, 0), |
430 | SOC_DAPM_SINGLE("MicN Switch" , NAU8822_REG_INPUT_CONTROL, 1, 1, 0), |
431 | SOC_DAPM_SINGLE("MicP Switch" , NAU8822_REG_INPUT_CONTROL, 0, 1, 0), |
432 | }; |
433 | static const struct snd_kcontrol_new nau8822_right_input_mixer[] = { |
434 | SOC_DAPM_SINGLE("R2 Switch" , NAU8822_REG_INPUT_CONTROL, 6, 1, 0), |
435 | SOC_DAPM_SINGLE("MicN Switch" , NAU8822_REG_INPUT_CONTROL, 5, 1, 0), |
436 | SOC_DAPM_SINGLE("MicP Switch" , NAU8822_REG_INPUT_CONTROL, 4, 1, 0), |
437 | }; |
438 | |
439 | /* Loopback Switch */ |
440 | static const struct snd_kcontrol_new nau8822_loopback = |
441 | SOC_DAPM_SINGLE("Switch" , NAU8822_REG_COMPANDING_CONTROL, |
442 | NAU8822_ADDAP_SFT, 1, 0); |
443 | |
444 | static int check_mclk_select_pll(struct snd_soc_dapm_widget *source, |
445 | struct snd_soc_dapm_widget *sink) |
446 | { |
447 | struct snd_soc_component *component = |
448 | snd_soc_dapm_to_component(dapm: source->dapm); |
449 | unsigned int value; |
450 | |
451 | value = snd_soc_component_read(component, NAU8822_REG_CLOCKING); |
452 | |
453 | return (value & NAU8822_CLKM_MASK); |
454 | } |
455 | |
456 | static const struct snd_soc_dapm_widget nau8822_dapm_widgets[] = { |
457 | SND_SOC_DAPM_DAC("Left DAC" , "Left HiFi Playback" , |
458 | NAU8822_REG_POWER_MANAGEMENT_3, 0, 0), |
459 | SND_SOC_DAPM_DAC("Right DAC" , "Right HiFi Playback" , |
460 | NAU8822_REG_POWER_MANAGEMENT_3, 1, 0), |
461 | SND_SOC_DAPM_ADC("Left ADC" , "Left HiFi Capture" , |
462 | NAU8822_REG_POWER_MANAGEMENT_2, 0, 0), |
463 | SND_SOC_DAPM_ADC("Right ADC" , "Right HiFi Capture" , |
464 | NAU8822_REG_POWER_MANAGEMENT_2, 1, 0), |
465 | |
466 | SOC_MIXER_ARRAY("Left Output Mixer" , |
467 | NAU8822_REG_POWER_MANAGEMENT_3, 2, 0, nau8822_left_out_mixer), |
468 | SOC_MIXER_ARRAY("Right Output Mixer" , |
469 | NAU8822_REG_POWER_MANAGEMENT_3, 3, 0, nau8822_right_out_mixer), |
470 | SOC_MIXER_ARRAY("AUX1 Output Mixer" , |
471 | NAU8822_REG_POWER_MANAGEMENT_1, 7, 0, nau8822_auxout1_mixer), |
472 | SOC_MIXER_ARRAY("AUX2 Output Mixer" , |
473 | NAU8822_REG_POWER_MANAGEMENT_1, 6, 0, nau8822_auxout2_mixer), |
474 | |
475 | SOC_MIXER_ARRAY("Left Input Mixer" , |
476 | NAU8822_REG_POWER_MANAGEMENT_2, |
477 | 2, 0, nau8822_left_input_mixer), |
478 | SOC_MIXER_ARRAY("Right Input Mixer" , |
479 | NAU8822_REG_POWER_MANAGEMENT_2, |
480 | 3, 0, nau8822_right_input_mixer), |
481 | |
482 | SND_SOC_DAPM_PGA("Left Boost Mixer" , |
483 | NAU8822_REG_POWER_MANAGEMENT_2, 4, 0, NULL, 0), |
484 | SND_SOC_DAPM_PGA("Right Boost Mixer" , |
485 | NAU8822_REG_POWER_MANAGEMENT_2, 5, 0, NULL, 0), |
486 | |
487 | SND_SOC_DAPM_PGA("Left Capture PGA" , |
488 | NAU8822_REG_LEFT_INP_PGA_CONTROL, 6, 1, NULL, 0), |
489 | SND_SOC_DAPM_PGA("Right Capture PGA" , |
490 | NAU8822_REG_RIGHT_INP_PGA_CONTROL, 6, 1, NULL, 0), |
491 | |
492 | SND_SOC_DAPM_PGA("Left Headphone Out" , |
493 | NAU8822_REG_POWER_MANAGEMENT_2, 7, 0, NULL, 0), |
494 | SND_SOC_DAPM_PGA("Right Headphone Out" , |
495 | NAU8822_REG_POWER_MANAGEMENT_2, 8, 0, NULL, 0), |
496 | |
497 | SND_SOC_DAPM_PGA("Left Speaker Out" , |
498 | NAU8822_REG_POWER_MANAGEMENT_3, 6, 0, NULL, 0), |
499 | SND_SOC_DAPM_PGA("Right Speaker Out" , |
500 | NAU8822_REG_POWER_MANAGEMENT_3, 5, 0, NULL, 0), |
501 | |
502 | SND_SOC_DAPM_PGA("AUX1 Out" , |
503 | NAU8822_REG_POWER_MANAGEMENT_3, 8, 0, NULL, 0), |
504 | SND_SOC_DAPM_PGA("AUX2 Out" , |
505 | NAU8822_REG_POWER_MANAGEMENT_3, 7, 0, NULL, 0), |
506 | |
507 | SND_SOC_DAPM_SUPPLY("Mic Bias" , |
508 | NAU8822_REG_POWER_MANAGEMENT_1, 4, 0, NULL, 0), |
509 | SND_SOC_DAPM_SUPPLY("PLL" , |
510 | NAU8822_REG_POWER_MANAGEMENT_1, 5, 0, NULL, 0), |
511 | |
512 | SND_SOC_DAPM_SWITCH("Digital Loopback" , SND_SOC_NOPM, 0, 0, |
513 | &nau8822_loopback), |
514 | |
515 | SND_SOC_DAPM_INPUT("LMICN" ), |
516 | SND_SOC_DAPM_INPUT("LMICP" ), |
517 | SND_SOC_DAPM_INPUT("RMICN" ), |
518 | SND_SOC_DAPM_INPUT("RMICP" ), |
519 | SND_SOC_DAPM_INPUT("LAUX" ), |
520 | SND_SOC_DAPM_INPUT("RAUX" ), |
521 | SND_SOC_DAPM_INPUT("L2" ), |
522 | SND_SOC_DAPM_INPUT("R2" ), |
523 | SND_SOC_DAPM_OUTPUT("LHP" ), |
524 | SND_SOC_DAPM_OUTPUT("RHP" ), |
525 | SND_SOC_DAPM_OUTPUT("LSPK" ), |
526 | SND_SOC_DAPM_OUTPUT("RSPK" ), |
527 | SND_SOC_DAPM_OUTPUT("AUXOUT1" ), |
528 | SND_SOC_DAPM_OUTPUT("AUXOUT2" ), |
529 | }; |
530 | |
531 | static const struct snd_soc_dapm_route nau8822_dapm_routes[] = { |
532 | {"Right DAC" , NULL, "PLL" , check_mclk_select_pll}, |
533 | {"Left DAC" , NULL, "PLL" , check_mclk_select_pll}, |
534 | |
535 | /* LMAIN and RMAIN Mixer */ |
536 | {"Right Output Mixer" , "LDAC Switch" , "Left DAC" }, |
537 | {"Right Output Mixer" , "RDAC Switch" , "Right DAC" }, |
538 | {"Right Output Mixer" , "RAUX Switch" , "RAUX" }, |
539 | {"Right Output Mixer" , "RINMIX Switch" , "Right Boost Mixer" }, |
540 | |
541 | {"Left Output Mixer" , "LDAC Switch" , "Left DAC" }, |
542 | {"Left Output Mixer" , "RDAC Switch" , "Right DAC" }, |
543 | {"Left Output Mixer" , "LAUX Switch" , "LAUX" }, |
544 | {"Left Output Mixer" , "LINMIX Switch" , "Left Boost Mixer" }, |
545 | |
546 | /* AUX1 and AUX2 Mixer */ |
547 | {"AUX1 Output Mixer" , "RDAC Switch" , "Right DAC" }, |
548 | {"AUX1 Output Mixer" , "RMIX Switch" , "Right Output Mixer" }, |
549 | {"AUX1 Output Mixer" , "RINMIX Switch" , "Right Boost Mixer" }, |
550 | {"AUX1 Output Mixer" , "LDAC Switch" , "Left DAC" }, |
551 | {"AUX1 Output Mixer" , "LMIX Switch" , "Left Output Mixer" }, |
552 | |
553 | {"AUX2 Output Mixer" , "LDAC Switch" , "Left DAC" }, |
554 | {"AUX2 Output Mixer" , "LMIX Switch" , "Left Output Mixer" }, |
555 | {"AUX2 Output Mixer" , "LINMIX Switch" , "Left Boost Mixer" }, |
556 | {"AUX2 Output Mixer" , "AUX1MIX Output Switch" , "AUX1 Output Mixer" }, |
557 | |
558 | /* Outputs */ |
559 | {"Right Headphone Out" , NULL, "Right Output Mixer" }, |
560 | {"RHP" , NULL, "Right Headphone Out" }, |
561 | |
562 | {"Left Headphone Out" , NULL, "Left Output Mixer" }, |
563 | {"LHP" , NULL, "Left Headphone Out" }, |
564 | |
565 | {"Right Speaker Out" , NULL, "Right Output Mixer" }, |
566 | {"RSPK" , NULL, "Right Speaker Out" }, |
567 | |
568 | {"Left Speaker Out" , NULL, "Left Output Mixer" }, |
569 | {"LSPK" , NULL, "Left Speaker Out" }, |
570 | |
571 | {"AUX1 Out" , NULL, "AUX1 Output Mixer" }, |
572 | {"AUX2 Out" , NULL, "AUX2 Output Mixer" }, |
573 | {"AUXOUT1" , NULL, "AUX1 Out" }, |
574 | {"AUXOUT2" , NULL, "AUX2 Out" }, |
575 | |
576 | /* Boost Mixer */ |
577 | {"Right ADC" , NULL, "PLL" , check_mclk_select_pll}, |
578 | {"Left ADC" , NULL, "PLL" , check_mclk_select_pll}, |
579 | |
580 | {"Right ADC" , NULL, "Right Boost Mixer" }, |
581 | |
582 | {"Right Boost Mixer" , NULL, "RAUX" }, |
583 | {"Right Boost Mixer" , NULL, "Right Capture PGA" }, |
584 | {"Right Boost Mixer" , NULL, "R2" }, |
585 | |
586 | {"Left ADC" , NULL, "Left Boost Mixer" }, |
587 | |
588 | {"Left Boost Mixer" , NULL, "LAUX" }, |
589 | {"Left Boost Mixer" , NULL, "Left Capture PGA" }, |
590 | {"Left Boost Mixer" , NULL, "L2" }, |
591 | |
592 | /* Input PGA */ |
593 | {"Right Capture PGA" , NULL, "Right Input Mixer" }, |
594 | {"Left Capture PGA" , NULL, "Left Input Mixer" }, |
595 | |
596 | /* Enable Microphone Power */ |
597 | {"Right Capture PGA" , NULL, "Mic Bias" }, |
598 | {"Left Capture PGA" , NULL, "Mic Bias" }, |
599 | |
600 | {"Right Input Mixer" , "R2 Switch" , "R2" }, |
601 | {"Right Input Mixer" , "MicN Switch" , "RMICN" }, |
602 | {"Right Input Mixer" , "MicP Switch" , "RMICP" }, |
603 | |
604 | {"Left Input Mixer" , "L2 Switch" , "L2" }, |
605 | {"Left Input Mixer" , "MicN Switch" , "LMICN" }, |
606 | {"Left Input Mixer" , "MicP Switch" , "LMICP" }, |
607 | |
608 | /* Digital Loopback */ |
609 | {"Digital Loopback" , "Switch" , "Left ADC" }, |
610 | {"Digital Loopback" , "Switch" , "Right ADC" }, |
611 | {"Left DAC" , NULL, "Digital Loopback" }, |
612 | {"Right DAC" , NULL, "Digital Loopback" }, |
613 | }; |
614 | |
615 | static int nau8822_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, |
616 | unsigned int freq, int dir) |
617 | { |
618 | struct snd_soc_component *component = dai->component; |
619 | struct nau8822 *nau8822 = snd_soc_component_get_drvdata(c: component); |
620 | |
621 | nau8822->div_id = clk_id; |
622 | nau8822->sysclk = freq; |
623 | dev_dbg(component->dev, "master sysclk %dHz, source %s\n" , freq, |
624 | clk_id == NAU8822_CLK_PLL ? "PLL" : "MCLK" ); |
625 | |
626 | return 0; |
627 | } |
628 | |
629 | static int nau8822_calc_pll(unsigned int pll_in, unsigned int fs, |
630 | struct nau8822_pll *pll_param) |
631 | { |
632 | u64 f2, f2_max, pll_ratio; |
633 | int i, scal_sel; |
634 | |
635 | if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN) |
636 | return -EINVAL; |
637 | f2_max = 0; |
638 | scal_sel = ARRAY_SIZE(nau8822_mclk_scaler); |
639 | |
640 | for (i = 0; i < scal_sel; i++) { |
641 | f2 = 256 * fs * 4 * nau8822_mclk_scaler[i] / 10; |
642 | if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && |
643 | f2_max < f2) { |
644 | f2_max = f2; |
645 | scal_sel = i; |
646 | } |
647 | } |
648 | |
649 | if (ARRAY_SIZE(nau8822_mclk_scaler) == scal_sel) |
650 | return -EINVAL; |
651 | pll_param->mclk_scaler = scal_sel; |
652 | f2 = f2_max; |
653 | |
654 | /* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional |
655 | * input; round up the 24+4bit. |
656 | */ |
657 | pll_ratio = div_u64(dividend: f2 << 28, divisor: pll_in); |
658 | pll_param->pre_factor = 0; |
659 | if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) { |
660 | pll_ratio <<= 1; |
661 | pll_param->pre_factor = 1; |
662 | } |
663 | pll_param->pll_int = (pll_ratio >> 28) & 0xF; |
664 | pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4); |
665 | |
666 | return 0; |
667 | } |
668 | |
669 | static int nau8822_config_clkdiv(struct snd_soc_dai *dai, int div, int rate) |
670 | { |
671 | struct snd_soc_component *component = dai->component; |
672 | struct nau8822 *nau8822 = snd_soc_component_get_drvdata(c: component); |
673 | struct nau8822_pll *pll = &nau8822->pll; |
674 | int i, sclk, imclk; |
675 | |
676 | switch (nau8822->div_id) { |
677 | case NAU8822_CLK_MCLK: |
678 | /* Configure the master clock prescaler div to make system |
679 | * clock to approximate the internal master clock (IMCLK); |
680 | * and large or equal to IMCLK. |
681 | */ |
682 | div = 0; |
683 | imclk = rate * 256; |
684 | for (i = 1; i < ARRAY_SIZE(nau8822_mclk_scaler); i++) { |
685 | sclk = (nau8822->sysclk * 10) / nau8822_mclk_scaler[i]; |
686 | if (sclk < imclk) |
687 | break; |
688 | div = i; |
689 | } |
690 | dev_dbg(component->dev, "master clock prescaler %x for fs %d\n" , |
691 | div, rate); |
692 | |
693 | /* master clock from MCLK and disable PLL */ |
694 | snd_soc_component_update_bits(component, |
695 | NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, |
696 | val: (div << NAU8822_MCLKSEL_SFT)); |
697 | snd_soc_component_update_bits(component, |
698 | NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, |
699 | NAU8822_CLKM_MCLK); |
700 | break; |
701 | |
702 | case NAU8822_CLK_PLL: |
703 | /* master clock from PLL and enable PLL */ |
704 | if (pll->mclk_scaler != div) { |
705 | dev_err(component->dev, |
706 | "master clock prescaler not meet PLL parameters\n" ); |
707 | return -EINVAL; |
708 | } |
709 | snd_soc_component_update_bits(component, |
710 | NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, |
711 | val: (div << NAU8822_MCLKSEL_SFT)); |
712 | snd_soc_component_update_bits(component, |
713 | NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, |
714 | NAU8822_CLKM_PLL); |
715 | break; |
716 | |
717 | default: |
718 | return -EINVAL; |
719 | } |
720 | |
721 | return 0; |
722 | } |
723 | |
724 | static int nau8822_set_pll(struct snd_soc_dai *dai, int pll_id, int source, |
725 | unsigned int freq_in, unsigned int freq_out) |
726 | { |
727 | struct snd_soc_component *component = dai->component; |
728 | struct nau8822 *nau8822 = snd_soc_component_get_drvdata(c: component); |
729 | struct nau8822_pll *pll_param = &nau8822->pll; |
730 | int ret, fs; |
731 | |
732 | if (freq_in == pll_param->freq_in && |
733 | freq_out == pll_param->freq_out) |
734 | return 0; |
735 | |
736 | if (freq_out == 0) { |
737 | dev_dbg(component->dev, "PLL disabled\n" ); |
738 | snd_soc_component_update_bits(component, |
739 | NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF); |
740 | return 0; |
741 | } |
742 | |
743 | fs = freq_out / 256; |
744 | |
745 | ret = nau8822_calc_pll(pll_in: freq_in, fs, pll_param); |
746 | if (ret < 0) { |
747 | dev_err(component->dev, "Unsupported input clock %d\n" , |
748 | freq_in); |
749 | return ret; |
750 | } |
751 | |
752 | dev_info(component->dev, |
753 | "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n" , |
754 | pll_param->pll_int, pll_param->pll_frac, |
755 | pll_param->mclk_scaler, pll_param->pre_factor); |
756 | |
757 | snd_soc_component_update_bits(component, |
758 | NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_OFF); |
759 | snd_soc_component_update_bits(component, |
760 | NAU8822_REG_PLL_N, NAU8822_PLLMCLK_DIV2 | NAU8822_PLLN_MASK, |
761 | val: (pll_param->pre_factor ? NAU8822_PLLMCLK_DIV2 : 0) | |
762 | pll_param->pll_int); |
763 | snd_soc_component_write(component, |
764 | NAU8822_REG_PLL_K1, val: (pll_param->pll_frac >> NAU8822_PLLK1_SFT) & |
765 | NAU8822_PLLK1_MASK); |
766 | snd_soc_component_write(component, |
767 | NAU8822_REG_PLL_K2, val: (pll_param->pll_frac >> NAU8822_PLLK2_SFT) & |
768 | NAU8822_PLLK2_MASK); |
769 | snd_soc_component_write(component, |
770 | NAU8822_REG_PLL_K3, val: pll_param->pll_frac & NAU8822_PLLK3_MASK); |
771 | snd_soc_component_update_bits(component, |
772 | NAU8822_REG_CLOCKING, NAU8822_MCLKSEL_MASK, |
773 | val: pll_param->mclk_scaler << NAU8822_MCLKSEL_SFT); |
774 | snd_soc_component_update_bits(component, |
775 | NAU8822_REG_CLOCKING, NAU8822_CLKM_MASK, NAU8822_CLKM_PLL); |
776 | snd_soc_component_update_bits(component, |
777 | NAU8822_REG_POWER_MANAGEMENT_1, NAU8822_PLL_EN_MASK, NAU8822_PLL_ON); |
778 | |
779 | pll_param->freq_in = freq_in; |
780 | pll_param->freq_out = freq_out; |
781 | |
782 | return 0; |
783 | } |
784 | |
785 | static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
786 | { |
787 | struct snd_soc_component *component = dai->component; |
788 | u16 ctrl1_val = 0, ctrl2_val = 0; |
789 | |
790 | dev_dbg(component->dev, "%s\n" , __func__); |
791 | |
792 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
793 | case SND_SOC_DAIFMT_CBM_CFM: |
794 | ctrl2_val |= 1; |
795 | break; |
796 | case SND_SOC_DAIFMT_CBS_CFS: |
797 | ctrl2_val &= ~1; |
798 | break; |
799 | default: |
800 | return -EINVAL; |
801 | } |
802 | |
803 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
804 | case SND_SOC_DAIFMT_I2S: |
805 | ctrl1_val |= 0x10; |
806 | break; |
807 | case SND_SOC_DAIFMT_RIGHT_J: |
808 | break; |
809 | case SND_SOC_DAIFMT_LEFT_J: |
810 | ctrl1_val |= 0x8; |
811 | break; |
812 | case SND_SOC_DAIFMT_DSP_A: |
813 | ctrl1_val |= 0x18; |
814 | break; |
815 | default: |
816 | return -EINVAL; |
817 | } |
818 | |
819 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
820 | case SND_SOC_DAIFMT_NB_NF: |
821 | break; |
822 | case SND_SOC_DAIFMT_IB_IF: |
823 | ctrl1_val |= 0x180; |
824 | break; |
825 | case SND_SOC_DAIFMT_IB_NF: |
826 | ctrl1_val |= 0x100; |
827 | break; |
828 | case SND_SOC_DAIFMT_NB_IF: |
829 | ctrl1_val |= 0x80; |
830 | break; |
831 | default: |
832 | return -EINVAL; |
833 | } |
834 | |
835 | snd_soc_component_update_bits(component, |
836 | NAU8822_REG_AUDIO_INTERFACE, |
837 | NAU8822_AIFMT_MASK | NAU8822_LRP_MASK | NAU8822_BCLKP_MASK, |
838 | val: ctrl1_val); |
839 | snd_soc_component_update_bits(component, |
840 | NAU8822_REG_CLOCKING, NAU8822_CLKIOEN_MASK, val: ctrl2_val); |
841 | |
842 | return 0; |
843 | } |
844 | |
845 | static int nau8822_hw_params(struct snd_pcm_substream *substream, |
846 | struct snd_pcm_hw_params *params, |
847 | struct snd_soc_dai *dai) |
848 | { |
849 | struct snd_soc_component *component = dai->component; |
850 | struct nau8822 *nau8822 = snd_soc_component_get_drvdata(c: component); |
851 | int val_len = 0, val_rate = 0; |
852 | unsigned int ctrl_val, bclk_fs, bclk_div; |
853 | |
854 | /* make BCLK and LRC divide configuration if the codec as master. */ |
855 | ctrl_val = snd_soc_component_read(component, NAU8822_REG_CLOCKING); |
856 | if (ctrl_val & NAU8822_CLK_MASTER) { |
857 | /* get the bclk and fs ratio */ |
858 | bclk_fs = snd_soc_params_to_bclk(parms: params) / params_rate(p: params); |
859 | if (bclk_fs <= 32) |
860 | bclk_div = NAU8822_BCLKDIV_8; |
861 | else if (bclk_fs <= 64) |
862 | bclk_div = NAU8822_BCLKDIV_4; |
863 | else if (bclk_fs <= 128) |
864 | bclk_div = NAU8822_BCLKDIV_2; |
865 | else |
866 | return -EINVAL; |
867 | snd_soc_component_update_bits(component, NAU8822_REG_CLOCKING, |
868 | NAU8822_BCLKSEL_MASK, val: bclk_div); |
869 | } |
870 | |
871 | switch (params_format(p: params)) { |
872 | case SNDRV_PCM_FORMAT_S16_LE: |
873 | break; |
874 | case SNDRV_PCM_FORMAT_S20_3LE: |
875 | val_len |= NAU8822_WLEN_20; |
876 | break; |
877 | case SNDRV_PCM_FORMAT_S24_LE: |
878 | val_len |= NAU8822_WLEN_24; |
879 | break; |
880 | case SNDRV_PCM_FORMAT_S32_LE: |
881 | val_len |= NAU8822_WLEN_32; |
882 | break; |
883 | default: |
884 | return -EINVAL; |
885 | } |
886 | |
887 | switch (params_rate(p: params)) { |
888 | case 8000: |
889 | val_rate |= NAU8822_SMPLR_8K; |
890 | break; |
891 | case 11025: |
892 | val_rate |= NAU8822_SMPLR_12K; |
893 | break; |
894 | case 16000: |
895 | val_rate |= NAU8822_SMPLR_16K; |
896 | break; |
897 | case 22050: |
898 | val_rate |= NAU8822_SMPLR_24K; |
899 | break; |
900 | case 32000: |
901 | val_rate |= NAU8822_SMPLR_32K; |
902 | break; |
903 | case 44100: |
904 | case 48000: |
905 | break; |
906 | default: |
907 | return -EINVAL; |
908 | } |
909 | |
910 | snd_soc_component_update_bits(component, |
911 | NAU8822_REG_AUDIO_INTERFACE, NAU8822_WLEN_MASK, val: val_len); |
912 | snd_soc_component_update_bits(component, |
913 | NAU8822_REG_ADDITIONAL_CONTROL, NAU8822_SMPLR_MASK, val: val_rate); |
914 | |
915 | /* If the master clock is from MCLK, provide the runtime FS for driver |
916 | * to get the master clock prescaler configuration. |
917 | */ |
918 | if (nau8822->div_id == NAU8822_CLK_MCLK) |
919 | nau8822_config_clkdiv(dai, div: 0, rate: params_rate(p: params)); |
920 | |
921 | return 0; |
922 | } |
923 | |
924 | static int nau8822_mute(struct snd_soc_dai *dai, int mute, int direction) |
925 | { |
926 | struct snd_soc_component *component = dai->component; |
927 | |
928 | dev_dbg(component->dev, "%s: %d\n" , __func__, mute); |
929 | |
930 | if (mute) |
931 | snd_soc_component_update_bits(component, |
932 | NAU8822_REG_DAC_CONTROL, mask: 0x40, val: 0x40); |
933 | else |
934 | snd_soc_component_update_bits(component, |
935 | NAU8822_REG_DAC_CONTROL, mask: 0x40, val: 0); |
936 | |
937 | return 0; |
938 | } |
939 | |
940 | static int nau8822_set_bias_level(struct snd_soc_component *component, |
941 | enum snd_soc_bias_level level) |
942 | { |
943 | switch (level) { |
944 | case SND_SOC_BIAS_ON: |
945 | case SND_SOC_BIAS_PREPARE: |
946 | snd_soc_component_update_bits(component, |
947 | NAU8822_REG_POWER_MANAGEMENT_1, |
948 | NAU8822_REFIMP_MASK, NAU8822_REFIMP_80K); |
949 | break; |
950 | |
951 | case SND_SOC_BIAS_STANDBY: |
952 | snd_soc_component_update_bits(component, |
953 | NAU8822_REG_POWER_MANAGEMENT_1, |
954 | NAU8822_IOBUF_EN | NAU8822_ABIAS_EN, |
955 | NAU8822_IOBUF_EN | NAU8822_ABIAS_EN); |
956 | |
957 | if (snd_soc_component_get_bias_level(component) == |
958 | SND_SOC_BIAS_OFF) { |
959 | snd_soc_component_update_bits(component, |
960 | NAU8822_REG_POWER_MANAGEMENT_1, |
961 | NAU8822_REFIMP_MASK, NAU8822_REFIMP_3K); |
962 | mdelay(100); |
963 | } |
964 | snd_soc_component_update_bits(component, |
965 | NAU8822_REG_POWER_MANAGEMENT_1, |
966 | NAU8822_REFIMP_MASK, NAU8822_REFIMP_300K); |
967 | break; |
968 | |
969 | case SND_SOC_BIAS_OFF: |
970 | snd_soc_component_write(component, |
971 | NAU8822_REG_POWER_MANAGEMENT_1, val: 0); |
972 | snd_soc_component_write(component, |
973 | NAU8822_REG_POWER_MANAGEMENT_2, val: 0); |
974 | snd_soc_component_write(component, |
975 | NAU8822_REG_POWER_MANAGEMENT_3, val: 0); |
976 | break; |
977 | } |
978 | |
979 | dev_dbg(component->dev, "%s: %d\n" , __func__, level); |
980 | |
981 | return 0; |
982 | } |
983 | |
984 | #define NAU8822_RATES (SNDRV_PCM_RATE_8000_48000) |
985 | |
986 | #define NAU8822_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
987 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
988 | |
989 | static const struct snd_soc_dai_ops nau8822_dai_ops = { |
990 | .hw_params = nau8822_hw_params, |
991 | .mute_stream = nau8822_mute, |
992 | .set_fmt = nau8822_set_dai_fmt, |
993 | .set_sysclk = nau8822_set_dai_sysclk, |
994 | .set_pll = nau8822_set_pll, |
995 | .no_capture_mute = 1, |
996 | }; |
997 | |
998 | static struct snd_soc_dai_driver nau8822_dai = { |
999 | .name = "nau8822-hifi" , |
1000 | .playback = { |
1001 | .stream_name = "Playback" , |
1002 | .channels_min = 1, |
1003 | .channels_max = 2, |
1004 | .rates = NAU8822_RATES, |
1005 | .formats = NAU8822_FORMATS, |
1006 | }, |
1007 | .capture = { |
1008 | .stream_name = "Capture" , |
1009 | .channels_min = 1, |
1010 | .channels_max = 2, |
1011 | .rates = NAU8822_RATES, |
1012 | .formats = NAU8822_FORMATS, |
1013 | }, |
1014 | .ops = &nau8822_dai_ops, |
1015 | .symmetric_rate = 1, |
1016 | }; |
1017 | |
1018 | static int nau8822_suspend(struct snd_soc_component *component) |
1019 | { |
1020 | struct nau8822 *nau8822 = snd_soc_component_get_drvdata(c: component); |
1021 | |
1022 | snd_soc_component_force_bias_level(component, level: SND_SOC_BIAS_OFF); |
1023 | |
1024 | regcache_mark_dirty(map: nau8822->regmap); |
1025 | |
1026 | return 0; |
1027 | } |
1028 | |
1029 | static int nau8822_resume(struct snd_soc_component *component) |
1030 | { |
1031 | struct nau8822 *nau8822 = snd_soc_component_get_drvdata(c: component); |
1032 | |
1033 | regcache_sync(map: nau8822->regmap); |
1034 | |
1035 | snd_soc_component_force_bias_level(component, level: SND_SOC_BIAS_STANDBY); |
1036 | |
1037 | return 0; |
1038 | } |
1039 | |
1040 | /* |
1041 | * These registers contain an "update" bit - bit 8. This means, for example, |
1042 | * that one can write new DAC digital volume for both channels, but only when |
1043 | * the update bit is set, will also the volume be updated - simultaneously for |
1044 | * both channels. |
1045 | */ |
1046 | static const int update_reg[] = { |
1047 | NAU8822_REG_LEFT_DAC_DIGITAL_VOLUME, |
1048 | NAU8822_REG_RIGHT_DAC_DIGITAL_VOLUME, |
1049 | NAU8822_REG_LEFT_ADC_DIGITAL_VOLUME, |
1050 | NAU8822_REG_RIGHT_ADC_DIGITAL_VOLUME, |
1051 | NAU8822_REG_LEFT_INP_PGA_CONTROL, |
1052 | NAU8822_REG_RIGHT_INP_PGA_CONTROL, |
1053 | NAU8822_REG_LHP_VOLUME, |
1054 | NAU8822_REG_RHP_VOLUME, |
1055 | NAU8822_REG_LSPKOUT_VOLUME, |
1056 | NAU8822_REG_RSPKOUT_VOLUME, |
1057 | }; |
1058 | |
1059 | static int nau8822_probe(struct snd_soc_component *component) |
1060 | { |
1061 | int i; |
1062 | struct device_node *of_node = component->dev->of_node; |
1063 | |
1064 | /* |
1065 | * Set the update bit in all registers, that have one. This way all |
1066 | * writes to those registers will also cause the update bit to be |
1067 | * written. |
1068 | */ |
1069 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) |
1070 | snd_soc_component_update_bits(component, |
1071 | reg: update_reg[i], mask: 0x100, val: 0x100); |
1072 | |
1073 | /* Check property to configure the two loudspeaker outputs as |
1074 | * a single Bridge Tied Load output |
1075 | */ |
1076 | if (of_property_read_bool(np: of_node, propname: "nuvoton,spk-btl" )) |
1077 | snd_soc_component_update_bits(component, |
1078 | NAU8822_REG_RIGHT_SPEAKER_CONTROL, |
1079 | NAU8822_RSUBBYP, NAU8822_RSUBBYP); |
1080 | |
1081 | return 0; |
1082 | } |
1083 | |
1084 | static const struct snd_soc_component_driver soc_component_dev_nau8822 = { |
1085 | .probe = nau8822_probe, |
1086 | .suspend = nau8822_suspend, |
1087 | .resume = nau8822_resume, |
1088 | .set_bias_level = nau8822_set_bias_level, |
1089 | .controls = nau8822_snd_controls, |
1090 | .num_controls = ARRAY_SIZE(nau8822_snd_controls), |
1091 | .dapm_widgets = nau8822_dapm_widgets, |
1092 | .num_dapm_widgets = ARRAY_SIZE(nau8822_dapm_widgets), |
1093 | .dapm_routes = nau8822_dapm_routes, |
1094 | .num_dapm_routes = ARRAY_SIZE(nau8822_dapm_routes), |
1095 | .idle_bias_on = 1, |
1096 | .use_pmdown_time = 1, |
1097 | .endianness = 1, |
1098 | }; |
1099 | |
1100 | static const struct regmap_config nau8822_regmap_config = { |
1101 | .reg_bits = 7, |
1102 | .val_bits = 9, |
1103 | |
1104 | .max_register = NAU8822_REG_MAX_REGISTER, |
1105 | .volatile_reg = nau8822_volatile, |
1106 | |
1107 | .readable_reg = nau8822_readable_reg, |
1108 | .writeable_reg = nau8822_writeable_reg, |
1109 | |
1110 | .cache_type = REGCACHE_RBTREE, |
1111 | .reg_defaults = nau8822_reg_defaults, |
1112 | .num_reg_defaults = ARRAY_SIZE(nau8822_reg_defaults), |
1113 | }; |
1114 | |
1115 | static int nau8822_i2c_probe(struct i2c_client *i2c) |
1116 | { |
1117 | struct device *dev = &i2c->dev; |
1118 | struct nau8822 *nau8822 = dev_get_platdata(dev); |
1119 | int ret; |
1120 | |
1121 | if (!nau8822) { |
1122 | nau8822 = devm_kzalloc(dev, size: sizeof(*nau8822), GFP_KERNEL); |
1123 | if (nau8822 == NULL) |
1124 | return -ENOMEM; |
1125 | } |
1126 | i2c_set_clientdata(client: i2c, data: nau8822); |
1127 | |
1128 | nau8822->regmap = devm_regmap_init_i2c(i2c, &nau8822_regmap_config); |
1129 | if (IS_ERR(ptr: nau8822->regmap)) { |
1130 | ret = PTR_ERR(ptr: nau8822->regmap); |
1131 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n" , ret); |
1132 | return ret; |
1133 | } |
1134 | nau8822->dev = dev; |
1135 | |
1136 | /* Reset the codec */ |
1137 | ret = regmap_write(map: nau8822->regmap, NAU8822_REG_RESET, val: 0x00); |
1138 | if (ret != 0) { |
1139 | dev_err(&i2c->dev, "Failed to issue reset: %d\n" , ret); |
1140 | return ret; |
1141 | } |
1142 | |
1143 | ret = devm_snd_soc_register_component(dev, component_driver: &soc_component_dev_nau8822, |
1144 | dai_drv: &nau8822_dai, num_dai: 1); |
1145 | if (ret != 0) { |
1146 | dev_err(&i2c->dev, "Failed to register CODEC: %d\n" , ret); |
1147 | return ret; |
1148 | } |
1149 | |
1150 | return 0; |
1151 | } |
1152 | |
1153 | static const struct i2c_device_id nau8822_i2c_id[] = { |
1154 | { "nau8822" , 0 }, |
1155 | { } |
1156 | }; |
1157 | MODULE_DEVICE_TABLE(i2c, nau8822_i2c_id); |
1158 | |
1159 | #ifdef CONFIG_OF |
1160 | static const struct of_device_id nau8822_of_match[] = { |
1161 | { .compatible = "nuvoton,nau8822" , }, |
1162 | { } |
1163 | }; |
1164 | MODULE_DEVICE_TABLE(of, nau8822_of_match); |
1165 | #endif |
1166 | |
1167 | static struct i2c_driver nau8822_i2c_driver = { |
1168 | .driver = { |
1169 | .name = "nau8822" , |
1170 | .of_match_table = of_match_ptr(nau8822_of_match), |
1171 | }, |
1172 | .probe = nau8822_i2c_probe, |
1173 | .id_table = nau8822_i2c_id, |
1174 | }; |
1175 | module_i2c_driver(nau8822_i2c_driver); |
1176 | |
1177 | MODULE_DESCRIPTION("ASoC NAU8822 codec driver" ); |
1178 | MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>" ); |
1179 | MODULE_LICENSE("GPL v2" ); |
1180 | |