1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * rt715.c -- rt715 ALSA SoC audio driver |
4 | * |
5 | * Copyright(c) 2019 Realtek Semiconductor Corp. |
6 | * |
7 | * ALC715 ASoC Codec Driver based Intel Dummy SdW codec driver |
8 | * |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/init.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/i2c.h> |
16 | #include <linux/pm_runtime.h> |
17 | #include <linux/pm.h> |
18 | #include <linux/soundwire/sdw.h> |
19 | #include <linux/regmap.h> |
20 | #include <linux/slab.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/regulator/consumer.h> |
23 | #include <sound/core.h> |
24 | #include <sound/pcm.h> |
25 | #include <sound/pcm_params.h> |
26 | #include <sound/sdw.h> |
27 | #include <sound/soc.h> |
28 | #include <sound/soc-dapm.h> |
29 | #include <sound/initval.h> |
30 | #include <sound/tlv.h> |
31 | #include <sound/hda_verbs.h> |
32 | |
33 | #include "rt715.h" |
34 | |
35 | static int rt715_index_write(struct regmap *regmap, unsigned int reg, |
36 | unsigned int value) |
37 | { |
38 | int ret; |
39 | unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 8) | reg; |
40 | |
41 | ret = regmap_write(map: regmap, reg: addr, val: value); |
42 | if (ret < 0) { |
43 | pr_err("%s: Failed to set private value: %08x <= %04x %d\n" , |
44 | __func__, addr, value, ret); |
45 | } |
46 | |
47 | return ret; |
48 | } |
49 | |
50 | static int rt715_index_write_nid(struct regmap *regmap, |
51 | unsigned int nid, unsigned int reg, unsigned int value) |
52 | { |
53 | int ret; |
54 | unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; |
55 | |
56 | ret = regmap_write(map: regmap, reg: addr, val: value); |
57 | if (ret < 0) |
58 | pr_err("%s: Failed to set private value: %06x <= %04x ret=%d\n" , |
59 | __func__, addr, value, ret); |
60 | |
61 | return ret; |
62 | } |
63 | |
64 | static int rt715_index_read_nid(struct regmap *regmap, |
65 | unsigned int nid, unsigned int reg, unsigned int *value) |
66 | { |
67 | int ret; |
68 | unsigned int addr = ((RT715_PRIV_INDEX_W_H_2 | nid) << 8) | reg; |
69 | |
70 | *value = 0; |
71 | ret = regmap_read(map: regmap, reg: addr, val: value); |
72 | if (ret < 0) |
73 | pr_err("%s: Failed to get private value: %06x => %04x ret=%d\n" , |
74 | __func__, addr, *value, ret); |
75 | |
76 | return ret; |
77 | } |
78 | |
79 | static int rt715_index_update_bits(struct regmap *regmap, unsigned int nid, |
80 | unsigned int reg, unsigned int mask, unsigned int val) |
81 | { |
82 | unsigned int tmp, orig; |
83 | int ret; |
84 | |
85 | ret = rt715_index_read_nid(regmap, nid, reg, value: &orig); |
86 | if (ret < 0) |
87 | return ret; |
88 | |
89 | tmp = orig & ~mask; |
90 | tmp |= val & mask; |
91 | |
92 | return rt715_index_write_nid(regmap, nid, reg, value: tmp); |
93 | } |
94 | |
95 | static void rt715_reset(struct regmap *regmap) |
96 | { |
97 | regmap_write(map: regmap, RT715_FUNC_RESET, val: 0); |
98 | rt715_index_update_bits(regmap, RT715_VENDOR_REGISTERS, |
99 | RT715_VD_CLEAR_CTRL, RT715_CLEAR_HIDDEN_REG, |
100 | RT715_CLEAR_HIDDEN_REG); |
101 | } |
102 | |
103 | |
104 | static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, |
105 | unsigned int addr_l, unsigned int val_h, |
106 | unsigned int *r_val, unsigned int *l_val) |
107 | { |
108 | int ret; |
109 | /* R Channel */ |
110 | *r_val = val_h << 8; |
111 | ret = regmap_read(map: rt715->regmap, reg: addr_l, val: r_val); |
112 | if (ret < 0) |
113 | pr_err("Failed to get R channel gain.\n" ); |
114 | |
115 | /* L Channel */ |
116 | val_h |= 0x20; |
117 | *l_val = val_h << 8; |
118 | ret = regmap_read(map: rt715->regmap, reg: addr_h, val: l_val); |
119 | if (ret < 0) |
120 | pr_err("Failed to get L channel gain.\n" ); |
121 | } |
122 | |
123 | /* For Verb-Set Amplifier Gain (Verb ID = 3h) */ |
124 | static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, |
125 | struct snd_ctl_elem_value *ucontrol) |
126 | { |
127 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
128 | struct snd_soc_dapm_context *dapm = |
129 | snd_soc_component_get_dapm(component); |
130 | struct soc_mixer_control *mc = |
131 | (struct soc_mixer_control *)kcontrol->private_value; |
132 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
133 | unsigned int addr_h, addr_l, val_h, val_ll, val_lr; |
134 | unsigned int read_ll, read_rl, i; |
135 | unsigned int k_vol_changed = 0; |
136 | |
137 | for (i = 0; i < 2; i++) { |
138 | if (ucontrol->value.integer.value[i] != rt715->kctl_2ch_vol_ori[i]) { |
139 | k_vol_changed = 1; |
140 | break; |
141 | } |
142 | } |
143 | |
144 | /* Can't use update bit function, so read the original value first */ |
145 | addr_h = mc->reg; |
146 | addr_l = mc->rreg; |
147 | |
148 | if (mc->shift == RT715_DIR_OUT_SFT) /* output */ |
149 | val_h = 0x80; |
150 | else /* input */ |
151 | val_h = 0x0; |
152 | |
153 | rt715_get_gain(rt715, addr_h, addr_l, val_h, r_val: &read_rl, l_val: &read_ll); |
154 | |
155 | if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) |
156 | regmap_write(map: rt715->regmap, |
157 | RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); |
158 | |
159 | /* L Channel */ |
160 | rt715->kctl_2ch_vol_ori[0] = ucontrol->value.integer.value[0]; |
161 | /* for gain */ |
162 | val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); |
163 | if (val_ll > mc->max) |
164 | val_ll = mc->max; |
165 | /* keep mute status */ |
166 | val_ll |= read_ll & 0x80; |
167 | |
168 | /* R Channel */ |
169 | rt715->kctl_2ch_vol_ori[1] = ucontrol->value.integer.value[1]; |
170 | /* for gain */ |
171 | val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); |
172 | if (val_lr > mc->max) |
173 | val_lr = mc->max; |
174 | /* keep mute status */ |
175 | val_lr |= read_rl & 0x80; |
176 | |
177 | for (i = 0; i < 3; i++) { /* retry 3 times at most */ |
178 | |
179 | if (val_ll == val_lr) { |
180 | /* Set both L/R channels at the same time */ |
181 | val_h = (1 << mc->shift) | (3 << 4); |
182 | regmap_write(map: rt715->regmap, reg: addr_h, |
183 | val: (val_h << 8) | val_ll); |
184 | regmap_write(map: rt715->regmap, reg: addr_l, |
185 | val: (val_h << 8) | val_ll); |
186 | } else { |
187 | /* Lch*/ |
188 | val_h = (1 << mc->shift) | (1 << 5); |
189 | regmap_write(map: rt715->regmap, reg: addr_h, |
190 | val: (val_h << 8) | val_ll); |
191 | /* Rch */ |
192 | val_h = (1 << mc->shift) | (1 << 4); |
193 | regmap_write(map: rt715->regmap, reg: addr_l, |
194 | val: (val_h << 8) | val_lr); |
195 | } |
196 | /* check result */ |
197 | if (mc->shift == RT715_DIR_OUT_SFT) /* output */ |
198 | val_h = 0x80; |
199 | else /* input */ |
200 | val_h = 0x0; |
201 | |
202 | rt715_get_gain(rt715, addr_h, addr_l, val_h, |
203 | r_val: &read_rl, l_val: &read_ll); |
204 | if (read_rl == val_lr && read_ll == val_ll) |
205 | break; |
206 | } |
207 | |
208 | /* D0:power on state, D3: power saving mode */ |
209 | if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) |
210 | regmap_write(map: rt715->regmap, |
211 | RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); |
212 | return k_vol_changed; |
213 | } |
214 | |
215 | static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol, |
216 | struct snd_ctl_elem_value *ucontrol) |
217 | { |
218 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
219 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
220 | struct soc_mixer_control *mc = |
221 | (struct soc_mixer_control *)kcontrol->private_value; |
222 | unsigned int addr_h, addr_l, val_h; |
223 | unsigned int read_ll, read_rl; |
224 | |
225 | addr_h = mc->reg; |
226 | addr_l = mc->rreg; |
227 | if (mc->shift == RT715_DIR_OUT_SFT) /* output */ |
228 | val_h = 0x80; |
229 | else /* input */ |
230 | val_h = 0x0; |
231 | |
232 | rt715_get_gain(rt715, addr_h, addr_l, val_h, r_val: &read_rl, l_val: &read_ll); |
233 | |
234 | if (mc->invert) { |
235 | /* for mute status */ |
236 | read_ll = !(read_ll & 0x80); |
237 | read_rl = !(read_rl & 0x80); |
238 | } else { |
239 | /* for gain */ |
240 | read_ll = read_ll & 0x7f; |
241 | read_rl = read_rl & 0x7f; |
242 | } |
243 | ucontrol->value.integer.value[0] = read_ll; |
244 | ucontrol->value.integer.value[1] = read_rl; |
245 | |
246 | return 0; |
247 | } |
248 | |
249 | static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol, |
250 | struct snd_ctl_elem_value *ucontrol) |
251 | { |
252 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
253 | struct snd_soc_dapm_context *dapm = |
254 | snd_soc_component_get_dapm(component); |
255 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
256 | static const unsigned int capture_reg_H[] = { |
257 | RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, |
258 | RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; |
259 | static const unsigned int capture_reg_L[] = { |
260 | RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, |
261 | RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L }; |
262 | unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr; |
263 | unsigned int k_shift = RT715_DIR_IN_SFT, k_changed = 0; |
264 | unsigned int read_ll, read_rl, i, j, loop_cnt = 4; |
265 | |
266 | for (i = 0; i < 8; i++) { |
267 | if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_switch_ori[i]) |
268 | k_changed = 1; |
269 | } |
270 | |
271 | for (j = 0; j < loop_cnt; j++) { |
272 | /* Can't use update bit function, so read the original value first */ |
273 | addr_h = capture_reg_H[j]; |
274 | addr_l = capture_reg_L[j]; |
275 | rt715_get_gain(rt715, addr_h, addr_l, val_h, r_val: &read_rl, l_val: &read_ll); |
276 | |
277 | if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) |
278 | regmap_write(map: rt715->regmap, |
279 | RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); |
280 | |
281 | /* L Channel */ |
282 | /* for mute */ |
283 | rt715->kctl_8ch_switch_ori[j * 2] = |
284 | ucontrol->value.integer.value[j * 2]; |
285 | val_ll = (!ucontrol->value.integer.value[j * 2]) << 7; |
286 | /* keep gain */ |
287 | val_ll |= read_ll & 0x7f; |
288 | |
289 | /* R Channel */ |
290 | /* for mute */ |
291 | rt715->kctl_8ch_switch_ori[j * 2 + 1] = |
292 | ucontrol->value.integer.value[j * 2 + 1]; |
293 | val_lr = (!ucontrol->value.integer.value[j * 2 + 1]) << 7; |
294 | /* keep gain */ |
295 | val_lr |= read_rl & 0x7f; |
296 | |
297 | for (i = 0; i < 3; i++) { /* retry 3 times at most */ |
298 | |
299 | if (val_ll == val_lr) { |
300 | /* Set both L/R channels at the same time */ |
301 | val_h = (1 << k_shift) | (3 << 4); |
302 | regmap_write(map: rt715->regmap, reg: addr_h, |
303 | val: (val_h << 8) | val_ll); |
304 | regmap_write(map: rt715->regmap, reg: addr_l, |
305 | val: (val_h << 8) | val_ll); |
306 | } else { |
307 | /* Lch*/ |
308 | val_h = (1 << k_shift) | (1 << 5); |
309 | regmap_write(map: rt715->regmap, reg: addr_h, |
310 | val: (val_h << 8) | val_ll); |
311 | /* Rch */ |
312 | val_h = (1 << k_shift) | (1 << 4); |
313 | regmap_write(map: rt715->regmap, reg: addr_l, |
314 | val: (val_h << 8) | val_lr); |
315 | } |
316 | val_h = 0x0; |
317 | rt715_get_gain(rt715, addr_h, addr_l, val_h, |
318 | r_val: &read_rl, l_val: &read_ll); |
319 | if (read_rl == val_lr && read_ll == val_ll) |
320 | break; |
321 | } |
322 | } |
323 | |
324 | /* D0:power on state, D3: power saving mode */ |
325 | if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) |
326 | regmap_write(map: rt715->regmap, |
327 | RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); |
328 | return k_changed; |
329 | } |
330 | |
331 | static int rt715_set_main_switch_get(struct snd_kcontrol *kcontrol, |
332 | struct snd_ctl_elem_value *ucontrol) |
333 | { |
334 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
335 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
336 | static const unsigned int capture_reg_H[] = { |
337 | RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, |
338 | RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; |
339 | static const unsigned int capture_reg_L[] = { |
340 | RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, |
341 | RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L }; |
342 | unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4; |
343 | unsigned int read_ll, read_rl; |
344 | |
345 | for (i = 0; i < loop_cnt; i++) { |
346 | addr_h = capture_reg_H[i]; |
347 | addr_l = capture_reg_L[i]; |
348 | rt715_get_gain(rt715, addr_h, addr_l, val_h, r_val: &read_rl, l_val: &read_ll); |
349 | |
350 | ucontrol->value.integer.value[i * 2] = !(read_ll & 0x80); |
351 | ucontrol->value.integer.value[i * 2 + 1] = !(read_rl & 0x80); |
352 | } |
353 | |
354 | return 0; |
355 | } |
356 | |
357 | static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol, |
358 | struct snd_ctl_elem_value *ucontrol) |
359 | { |
360 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
361 | struct snd_soc_dapm_context *dapm = |
362 | snd_soc_component_get_dapm(component); |
363 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
364 | static const unsigned int capture_reg_H[] = { |
365 | RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, |
366 | RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; |
367 | static const unsigned int capture_reg_L[] = { |
368 | RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, |
369 | RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L}; |
370 | unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr; |
371 | unsigned int read_ll, read_rl, i, j, loop_cnt = 4, k_changed = 0; |
372 | unsigned int k_shift = RT715_DIR_IN_SFT, k_max = 0x3f; |
373 | |
374 | for (i = 0; i < 8; i++) { |
375 | if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_vol_ori[i]) |
376 | k_changed = 1; |
377 | } |
378 | |
379 | for (j = 0; j < loop_cnt; j++) { |
380 | addr_h = capture_reg_H[j]; |
381 | addr_l = capture_reg_L[j]; |
382 | rt715_get_gain(rt715, addr_h, addr_l, val_h, r_val: &read_rl, l_val: &read_ll); |
383 | |
384 | if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) |
385 | regmap_write(map: rt715->regmap, |
386 | RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); |
387 | |
388 | /* L Channel */ |
389 | /* for gain */ |
390 | rt715->kctl_8ch_vol_ori[j * 2] = ucontrol->value.integer.value[j * 2]; |
391 | val_ll = ((ucontrol->value.integer.value[j * 2]) & 0x7f); |
392 | if (val_ll > k_max) |
393 | val_ll = k_max; |
394 | /* keep mute status */ |
395 | val_ll |= read_ll & 0x80; |
396 | |
397 | /* R Channel */ |
398 | /* for gain */ |
399 | rt715->kctl_8ch_vol_ori[j * 2 + 1] = |
400 | ucontrol->value.integer.value[j * 2 + 1]; |
401 | val_lr = ((ucontrol->value.integer.value[j * 2 + 1]) & 0x7f); |
402 | if (val_lr > k_max) |
403 | val_lr = k_max; |
404 | /* keep mute status */ |
405 | val_lr |= read_rl & 0x80; |
406 | |
407 | for (i = 0; i < 3; i++) { /* retry 3 times at most */ |
408 | if (val_ll == val_lr) { |
409 | /* Set both L/R channels at the same time */ |
410 | val_h = (1 << k_shift) | (3 << 4); |
411 | regmap_write(map: rt715->regmap, reg: addr_h, |
412 | val: (val_h << 8) | val_ll); |
413 | regmap_write(map: rt715->regmap, reg: addr_l, |
414 | val: (val_h << 8) | val_ll); |
415 | } else { |
416 | /* Lch*/ |
417 | val_h = (1 << k_shift) | (1 << 5); |
418 | regmap_write(map: rt715->regmap, reg: addr_h, |
419 | val: (val_h << 8) | val_ll); |
420 | /* Rch */ |
421 | val_h = (1 << k_shift) | (1 << 4); |
422 | regmap_write(map: rt715->regmap, reg: addr_l, |
423 | val: (val_h << 8) | val_lr); |
424 | } |
425 | val_h = 0x0; |
426 | rt715_get_gain(rt715, addr_h, addr_l, val_h, |
427 | r_val: &read_rl, l_val: &read_ll); |
428 | if (read_rl == val_lr && read_ll == val_ll) |
429 | break; |
430 | } |
431 | } |
432 | |
433 | /* D0:power on state, D3: power saving mode */ |
434 | if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) |
435 | regmap_write(map: rt715->regmap, |
436 | RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); |
437 | return k_changed; |
438 | } |
439 | |
440 | static int rt715_set_main_vol_get(struct snd_kcontrol *kcontrol, |
441 | struct snd_ctl_elem_value *ucontrol) |
442 | { |
443 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); |
444 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
445 | static const unsigned int capture_reg_H[] = { |
446 | RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_LINE_ADC_H, |
447 | RT715_SET_GAIN_MIX_ADC_H, RT715_SET_GAIN_MIX_ADC2_H }; |
448 | static const unsigned int capture_reg_L[] = { |
449 | RT715_SET_GAIN_MIC_ADC_L, RT715_SET_GAIN_LINE_ADC_L, |
450 | RT715_SET_GAIN_MIX_ADC_L, RT715_SET_GAIN_MIX_ADC2_L }; |
451 | unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4; |
452 | unsigned int read_ll, read_rl; |
453 | |
454 | for (i = 0; i < loop_cnt; i++) { |
455 | addr_h = capture_reg_H[i]; |
456 | addr_l = capture_reg_L[i]; |
457 | rt715_get_gain(rt715, addr_h, addr_l, val_h, r_val: &read_rl, l_val: &read_ll); |
458 | |
459 | ucontrol->value.integer.value[i * 2] = read_ll & 0x7f; |
460 | ucontrol->value.integer.value[i * 2 + 1] = read_rl & 0x7f; |
461 | } |
462 | |
463 | return 0; |
464 | } |
465 | |
466 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); |
467 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); |
468 | |
469 | static int rt715_switch_info(struct snd_kcontrol *kcontrol, |
470 | struct snd_ctl_elem_info *uinfo) |
471 | { |
472 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
473 | uinfo->count = 8; |
474 | uinfo->value.integer.min = 0; |
475 | uinfo->value.integer.max = 1; |
476 | return 0; |
477 | } |
478 | |
479 | static int rt715_vol_info(struct snd_kcontrol *kcontrol, |
480 | struct snd_ctl_elem_info *uinfo) |
481 | { |
482 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
483 | uinfo->count = 8; |
484 | uinfo->value.integer.min = 0; |
485 | uinfo->value.integer.max = 0x3f; |
486 | return 0; |
487 | } |
488 | |
489 | #define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ |
490 | xhandler_get, xhandler_put) \ |
491 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
492 | .info = snd_soc_info_volsw, \ |
493 | .get = xhandler_get, .put = xhandler_put, \ |
494 | .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ |
495 | xmax, xinvert) } |
496 | |
497 | #define RT715_MAIN_SWITCH_EXT(xname, xhandler_get, xhandler_put) \ |
498 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
499 | .info = rt715_switch_info, \ |
500 | .get = xhandler_get, .put = xhandler_put, \ |
501 | } |
502 | |
503 | #define RT715_MAIN_VOL_EXT_TLV(xname, xhandler_get, xhandler_put, tlv_array) \ |
504 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
505 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
506 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
507 | .tlv.p = (tlv_array), \ |
508 | .info = rt715_vol_info, \ |
509 | .get = xhandler_get, .put = xhandler_put, \ |
510 | } |
511 | |
512 | static const struct snd_kcontrol_new rt715_snd_controls[] = { |
513 | /* Capture switch */ |
514 | RT715_MAIN_SWITCH_EXT("Capture Switch" , |
515 | rt715_set_main_switch_get, rt715_set_main_switch_put), |
516 | /* Volume Control */ |
517 | RT715_MAIN_VOL_EXT_TLV("Capture Volume" , |
518 | rt715_set_main_vol_get, rt715_set_main_vol_put, in_vol_tlv), |
519 | /* MIC Boost Control */ |
520 | SOC_DOUBLE_R_EXT_TLV("DMIC1 Boost" , RT715_SET_GAIN_DMIC1_H, |
521 | RT715_SET_GAIN_DMIC1_L, RT715_DIR_IN_SFT, 3, 0, |
522 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
523 | mic_vol_tlv), |
524 | SOC_DOUBLE_R_EXT_TLV("DMIC2 Boost" , RT715_SET_GAIN_DMIC2_H, |
525 | RT715_SET_GAIN_DMIC2_L, RT715_DIR_IN_SFT, 3, 0, |
526 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
527 | mic_vol_tlv), |
528 | SOC_DOUBLE_R_EXT_TLV("DMIC3 Boost" , RT715_SET_GAIN_DMIC3_H, |
529 | RT715_SET_GAIN_DMIC3_L, RT715_DIR_IN_SFT, 3, 0, |
530 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
531 | mic_vol_tlv), |
532 | SOC_DOUBLE_R_EXT_TLV("DMIC4 Boost" , RT715_SET_GAIN_DMIC4_H, |
533 | RT715_SET_GAIN_DMIC4_L, RT715_DIR_IN_SFT, 3, 0, |
534 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
535 | mic_vol_tlv), |
536 | SOC_DOUBLE_R_EXT_TLV("MIC1 Boost" , RT715_SET_GAIN_MIC1_H, |
537 | RT715_SET_GAIN_MIC1_L, RT715_DIR_IN_SFT, 3, 0, |
538 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
539 | mic_vol_tlv), |
540 | SOC_DOUBLE_R_EXT_TLV("MIC2 Boost" , RT715_SET_GAIN_MIC2_H, |
541 | RT715_SET_GAIN_MIC2_L, RT715_DIR_IN_SFT, 3, 0, |
542 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
543 | mic_vol_tlv), |
544 | SOC_DOUBLE_R_EXT_TLV("LINE1 Boost" , RT715_SET_GAIN_LINE1_H, |
545 | RT715_SET_GAIN_LINE1_L, RT715_DIR_IN_SFT, 3, 0, |
546 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
547 | mic_vol_tlv), |
548 | SOC_DOUBLE_R_EXT_TLV("LINE2 Boost" , RT715_SET_GAIN_LINE2_H, |
549 | RT715_SET_GAIN_LINE2_L, RT715_DIR_IN_SFT, 3, 0, |
550 | rt715_set_amp_gain_get, rt715_set_amp_gain_put, |
551 | mic_vol_tlv), |
552 | }; |
553 | |
554 | static int rt715_mux_get(struct snd_kcontrol *kcontrol, |
555 | struct snd_ctl_elem_value *ucontrol) |
556 | { |
557 | struct snd_soc_component *component = |
558 | snd_soc_dapm_kcontrol_component(kcontrol); |
559 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
560 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
561 | unsigned int reg, val; |
562 | int ret; |
563 | |
564 | /* nid = e->reg, vid = 0xf01 */ |
565 | reg = RT715_VERB_SET_CONNECT_SEL | e->reg; |
566 | ret = regmap_read(map: rt715->regmap, reg, val: &val); |
567 | if (ret < 0) { |
568 | dev_err(component->dev, "%s: sdw read failed: %d\n" , |
569 | __func__, ret); |
570 | return ret; |
571 | } |
572 | |
573 | /* |
574 | * The first two indices of ADC Mux 24/25 are routed to the same |
575 | * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2. |
576 | * To have a unique set of inputs, we skip the index1 of the muxes. |
577 | */ |
578 | if ((e->reg == RT715_MUX_IN3 || e->reg == RT715_MUX_IN4) && (val > 0)) |
579 | val -= 1; |
580 | ucontrol->value.enumerated.item[0] = val; |
581 | |
582 | return 0; |
583 | } |
584 | |
585 | static int rt715_mux_put(struct snd_kcontrol *kcontrol, |
586 | struct snd_ctl_elem_value *ucontrol) |
587 | { |
588 | struct snd_soc_component *component = |
589 | snd_soc_dapm_kcontrol_component(kcontrol); |
590 | struct snd_soc_dapm_context *dapm = |
591 | snd_soc_dapm_kcontrol_dapm(kcontrol); |
592 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
593 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
594 | unsigned int *item = ucontrol->value.enumerated.item; |
595 | unsigned int val, val2 = 0, change, reg; |
596 | int ret; |
597 | |
598 | if (item[0] >= e->items) |
599 | return -EINVAL; |
600 | |
601 | /* Verb ID = 0x701h, nid = e->reg */ |
602 | val = snd_soc_enum_item_to_val(e, item: item[0]) << e->shift_l; |
603 | |
604 | reg = RT715_VERB_SET_CONNECT_SEL | e->reg; |
605 | ret = regmap_read(map: rt715->regmap, reg, val: &val2); |
606 | if (ret < 0) { |
607 | dev_err(component->dev, "%s: sdw read failed: %d\n" , |
608 | __func__, ret); |
609 | return ret; |
610 | } |
611 | |
612 | if (val == val2) |
613 | change = 0; |
614 | else |
615 | change = 1; |
616 | |
617 | if (change) { |
618 | reg = RT715_VERB_SET_CONNECT_SEL | e->reg; |
619 | regmap_write(map: rt715->regmap, reg, val); |
620 | } |
621 | |
622 | snd_soc_dapm_mux_update_power(dapm, kcontrol, |
623 | mux: item[0], e, NULL); |
624 | |
625 | return change; |
626 | } |
627 | |
628 | static const char * const adc_22_23_mux_text[] = { |
629 | "MIC1" , |
630 | "MIC2" , |
631 | "LINE1" , |
632 | "LINE2" , |
633 | "DMIC1" , |
634 | "DMIC2" , |
635 | "DMIC3" , |
636 | "DMIC4" , |
637 | }; |
638 | |
639 | /* |
640 | * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and |
641 | * 1 will be connected to the same dmic source, therefore we skip index 1 to |
642 | * avoid misunderstanding on usage of dapm routing. |
643 | */ |
644 | static const unsigned int rt715_adc_24_25_values[] = { |
645 | 0, |
646 | 2, |
647 | 3, |
648 | 4, |
649 | 5, |
650 | }; |
651 | |
652 | static const char * const adc_24_mux_text[] = { |
653 | "MIC2" , |
654 | "DMIC1" , |
655 | "DMIC2" , |
656 | "DMIC3" , |
657 | "DMIC4" , |
658 | }; |
659 | |
660 | static const char * const adc_25_mux_text[] = { |
661 | "MIC1" , |
662 | "DMIC1" , |
663 | "DMIC2" , |
664 | "DMIC3" , |
665 | "DMIC4" , |
666 | }; |
667 | |
668 | static SOC_ENUM_SINGLE_DECL( |
669 | rt715_adc22_enum, RT715_MUX_IN1, 0, adc_22_23_mux_text); |
670 | |
671 | static SOC_ENUM_SINGLE_DECL( |
672 | rt715_adc23_enum, RT715_MUX_IN2, 0, adc_22_23_mux_text); |
673 | |
674 | static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum, |
675 | RT715_MUX_IN3, 0, 0xf, |
676 | adc_24_mux_text, rt715_adc_24_25_values); |
677 | |
678 | static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum, |
679 | RT715_MUX_IN4, 0, 0xf, |
680 | adc_25_mux_text, rt715_adc_24_25_values); |
681 | |
682 | static const struct snd_kcontrol_new rt715_adc22_mux = |
683 | SOC_DAPM_ENUM_EXT("ADC 22 Mux" , rt715_adc22_enum, |
684 | rt715_mux_get, rt715_mux_put); |
685 | |
686 | static const struct snd_kcontrol_new rt715_adc23_mux = |
687 | SOC_DAPM_ENUM_EXT("ADC 23 Mux" , rt715_adc23_enum, |
688 | rt715_mux_get, rt715_mux_put); |
689 | |
690 | static const struct snd_kcontrol_new rt715_adc24_mux = |
691 | SOC_DAPM_ENUM_EXT("ADC 24 Mux" , rt715_adc24_enum, |
692 | rt715_mux_get, rt715_mux_put); |
693 | |
694 | static const struct snd_kcontrol_new rt715_adc25_mux = |
695 | SOC_DAPM_ENUM_EXT("ADC 25 Mux" , rt715_adc25_enum, |
696 | rt715_mux_get, rt715_mux_put); |
697 | |
698 | static const struct snd_soc_dapm_widget rt715_dapm_widgets[] = { |
699 | SND_SOC_DAPM_INPUT("DMIC1" ), |
700 | SND_SOC_DAPM_INPUT("DMIC2" ), |
701 | SND_SOC_DAPM_INPUT("DMIC3" ), |
702 | SND_SOC_DAPM_INPUT("DMIC4" ), |
703 | SND_SOC_DAPM_INPUT("MIC1" ), |
704 | SND_SOC_DAPM_INPUT("MIC2" ), |
705 | SND_SOC_DAPM_INPUT("LINE1" ), |
706 | SND_SOC_DAPM_INPUT("LINE2" ), |
707 | SND_SOC_DAPM_ADC("ADC 07" , NULL, RT715_SET_STREAMID_MIC_ADC, 4, 0), |
708 | SND_SOC_DAPM_ADC("ADC 08" , NULL, RT715_SET_STREAMID_LINE_ADC, 4, 0), |
709 | SND_SOC_DAPM_ADC("ADC 09" , NULL, RT715_SET_STREAMID_MIX_ADC, 4, 0), |
710 | SND_SOC_DAPM_ADC("ADC 27" , NULL, RT715_SET_STREAMID_MIX_ADC2, 4, 0), |
711 | SND_SOC_DAPM_MUX("ADC 22 Mux" , SND_SOC_NOPM, 0, 0, |
712 | &rt715_adc22_mux), |
713 | SND_SOC_DAPM_MUX("ADC 23 Mux" , SND_SOC_NOPM, 0, 0, |
714 | &rt715_adc23_mux), |
715 | SND_SOC_DAPM_MUX("ADC 24 Mux" , SND_SOC_NOPM, 0, 0, |
716 | &rt715_adc24_mux), |
717 | SND_SOC_DAPM_MUX("ADC 25 Mux" , SND_SOC_NOPM, 0, 0, |
718 | &rt715_adc25_mux), |
719 | SND_SOC_DAPM_AIF_OUT("DP4TX" , "DP4 Capture" , 0, SND_SOC_NOPM, 0, 0), |
720 | SND_SOC_DAPM_AIF_OUT("DP6TX" , "DP6 Capture" , 0, SND_SOC_NOPM, 0, 0), |
721 | }; |
722 | |
723 | static const struct snd_soc_dapm_route rt715_audio_map[] = { |
724 | {"DP6TX" , NULL, "ADC 09" }, |
725 | {"DP6TX" , NULL, "ADC 08" }, |
726 | {"DP4TX" , NULL, "ADC 07" }, |
727 | {"DP4TX" , NULL, "ADC 27" }, |
728 | {"ADC 09" , NULL, "ADC 22 Mux" }, |
729 | {"ADC 08" , NULL, "ADC 23 Mux" }, |
730 | {"ADC 07" , NULL, "ADC 24 Mux" }, |
731 | {"ADC 27" , NULL, "ADC 25 Mux" }, |
732 | {"ADC 22 Mux" , "MIC1" , "MIC1" }, |
733 | {"ADC 22 Mux" , "MIC2" , "MIC2" }, |
734 | {"ADC 22 Mux" , "LINE1" , "LINE1" }, |
735 | {"ADC 22 Mux" , "LINE2" , "LINE2" }, |
736 | {"ADC 22 Mux" , "DMIC1" , "DMIC1" }, |
737 | {"ADC 22 Mux" , "DMIC2" , "DMIC2" }, |
738 | {"ADC 22 Mux" , "DMIC3" , "DMIC3" }, |
739 | {"ADC 22 Mux" , "DMIC4" , "DMIC4" }, |
740 | {"ADC 23 Mux" , "MIC1" , "MIC1" }, |
741 | {"ADC 23 Mux" , "MIC2" , "MIC2" }, |
742 | {"ADC 23 Mux" , "LINE1" , "LINE1" }, |
743 | {"ADC 23 Mux" , "LINE2" , "LINE2" }, |
744 | {"ADC 23 Mux" , "DMIC1" , "DMIC1" }, |
745 | {"ADC 23 Mux" , "DMIC2" , "DMIC2" }, |
746 | {"ADC 23 Mux" , "DMIC3" , "DMIC3" }, |
747 | {"ADC 23 Mux" , "DMIC4" , "DMIC4" }, |
748 | {"ADC 24 Mux" , "MIC2" , "MIC2" }, |
749 | {"ADC 24 Mux" , "DMIC1" , "DMIC1" }, |
750 | {"ADC 24 Mux" , "DMIC2" , "DMIC2" }, |
751 | {"ADC 24 Mux" , "DMIC3" , "DMIC3" }, |
752 | {"ADC 24 Mux" , "DMIC4" , "DMIC4" }, |
753 | {"ADC 25 Mux" , "MIC1" , "MIC1" }, |
754 | {"ADC 25 Mux" , "DMIC1" , "DMIC1" }, |
755 | {"ADC 25 Mux" , "DMIC2" , "DMIC2" }, |
756 | {"ADC 25 Mux" , "DMIC3" , "DMIC3" }, |
757 | {"ADC 25 Mux" , "DMIC4" , "DMIC4" }, |
758 | }; |
759 | |
760 | static int rt715_set_bias_level(struct snd_soc_component *component, |
761 | enum snd_soc_bias_level level) |
762 | { |
763 | struct snd_soc_dapm_context *dapm = |
764 | snd_soc_component_get_dapm(component); |
765 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
766 | |
767 | switch (level) { |
768 | case SND_SOC_BIAS_PREPARE: |
769 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { |
770 | regmap_write(map: rt715->regmap, |
771 | RT715_SET_AUDIO_POWER_STATE, |
772 | AC_PWRST_D0); |
773 | msleep(RT715_POWER_UP_DELAY_MS); |
774 | } |
775 | break; |
776 | |
777 | case SND_SOC_BIAS_STANDBY: |
778 | regmap_write(map: rt715->regmap, |
779 | RT715_SET_AUDIO_POWER_STATE, |
780 | AC_PWRST_D3); |
781 | break; |
782 | |
783 | default: |
784 | break; |
785 | } |
786 | dapm->bias_level = level; |
787 | return 0; |
788 | } |
789 | |
790 | static int rt715_probe(struct snd_soc_component *component) |
791 | { |
792 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
793 | int ret; |
794 | |
795 | if (!rt715->first_hw_init) |
796 | return 0; |
797 | |
798 | ret = pm_runtime_resume(dev: component->dev); |
799 | if (ret < 0 && ret != -EACCES) |
800 | return ret; |
801 | |
802 | return 0; |
803 | } |
804 | |
805 | static const struct snd_soc_component_driver soc_codec_dev_rt715 = { |
806 | .probe = rt715_probe, |
807 | .set_bias_level = rt715_set_bias_level, |
808 | .controls = rt715_snd_controls, |
809 | .num_controls = ARRAY_SIZE(rt715_snd_controls), |
810 | .dapm_widgets = rt715_dapm_widgets, |
811 | .num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets), |
812 | .dapm_routes = rt715_audio_map, |
813 | .num_dapm_routes = ARRAY_SIZE(rt715_audio_map), |
814 | .endianness = 1, |
815 | }; |
816 | |
817 | static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, |
818 | int direction) |
819 | { |
820 | |
821 | snd_soc_dai_dma_data_set(dai, stream: direction, data: sdw_stream); |
822 | |
823 | return 0; |
824 | } |
825 | |
826 | static void rt715_shutdown(struct snd_pcm_substream *substream, |
827 | struct snd_soc_dai *dai) |
828 | |
829 | { |
830 | snd_soc_dai_set_dma_data(dai, substream, NULL); |
831 | } |
832 | |
833 | static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, |
834 | struct snd_pcm_hw_params *params, |
835 | struct snd_soc_dai *dai) |
836 | { |
837 | struct snd_soc_component *component = dai->component; |
838 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
839 | struct sdw_stream_config stream_config = {0}; |
840 | struct sdw_port_config port_config = {0}; |
841 | struct sdw_stream_runtime *sdw_stream; |
842 | int retval; |
843 | unsigned int val = 0; |
844 | |
845 | sdw_stream = snd_soc_dai_get_dma_data(dai, substream); |
846 | |
847 | if (!sdw_stream) |
848 | return -EINVAL; |
849 | |
850 | if (!rt715->slave) |
851 | return -EINVAL; |
852 | |
853 | snd_sdw_params_to_config(substream, params, stream_config: &stream_config, port_config: &port_config); |
854 | |
855 | switch (dai->id) { |
856 | case RT715_AIF1: |
857 | port_config.num = 6; |
858 | rt715_index_write(regmap: rt715->regmap, RT715_SDW_INPUT_SEL, value: 0xa500); |
859 | break; |
860 | case RT715_AIF2: |
861 | port_config.num = 4; |
862 | rt715_index_write(regmap: rt715->regmap, RT715_SDW_INPUT_SEL, value: 0xa000); |
863 | break; |
864 | default: |
865 | dev_err(component->dev, "%s: Invalid DAI id %d\n" , __func__, dai->id); |
866 | return -EINVAL; |
867 | } |
868 | |
869 | retval = sdw_stream_add_slave(slave: rt715->slave, stream_config: &stream_config, |
870 | port_config: &port_config, num_ports: 1, stream: sdw_stream); |
871 | if (retval) { |
872 | dev_err(dai->dev, "%s: Unable to configure port\n" , __func__); |
873 | return retval; |
874 | } |
875 | |
876 | switch (params_rate(p: params)) { |
877 | /* bit 14 0:48K 1:44.1K */ |
878 | /* bit 15 Stream Type 0:PCM 1:Non-PCM, should always be PCM */ |
879 | case 44100: |
880 | val |= 0x40 << 8; |
881 | break; |
882 | case 48000: |
883 | val |= 0x0 << 8; |
884 | break; |
885 | default: |
886 | dev_err(component->dev, "%s: Unsupported sample rate %d\n" , |
887 | __func__, params_rate(params)); |
888 | return -EINVAL; |
889 | } |
890 | |
891 | if (params_channels(p: params) <= 16) { |
892 | /* bit 3:0 Number of Channel */ |
893 | val |= (params_channels(p: params) - 1); |
894 | } else { |
895 | dev_err(component->dev, "%s: Unsupported channels %d\n" , |
896 | __func__, params_channels(params)); |
897 | return -EINVAL; |
898 | } |
899 | |
900 | switch (params_width(p: params)) { |
901 | /* bit 6:4 Bits per Sample */ |
902 | case 8: |
903 | break; |
904 | case 16: |
905 | val |= (0x1 << 4); |
906 | break; |
907 | case 20: |
908 | val |= (0x2 << 4); |
909 | break; |
910 | case 24: |
911 | val |= (0x3 << 4); |
912 | break; |
913 | case 32: |
914 | val |= (0x4 << 4); |
915 | break; |
916 | default: |
917 | return -EINVAL; |
918 | } |
919 | |
920 | regmap_write(map: rt715->regmap, RT715_MIC_ADC_FORMAT_H, val); |
921 | regmap_write(map: rt715->regmap, RT715_MIC_LINE_FORMAT_H, val); |
922 | regmap_write(map: rt715->regmap, RT715_MIX_ADC_FORMAT_H, val); |
923 | regmap_write(map: rt715->regmap, RT715_MIX_ADC2_FORMAT_H, val); |
924 | |
925 | return retval; |
926 | } |
927 | |
928 | static int rt715_pcm_hw_free(struct snd_pcm_substream *substream, |
929 | struct snd_soc_dai *dai) |
930 | { |
931 | struct snd_soc_component *component = dai->component; |
932 | struct rt715_priv *rt715 = snd_soc_component_get_drvdata(c: component); |
933 | struct sdw_stream_runtime *sdw_stream = |
934 | snd_soc_dai_get_dma_data(dai, substream); |
935 | |
936 | if (!rt715->slave) |
937 | return -EINVAL; |
938 | |
939 | sdw_stream_remove_slave(slave: rt715->slave, stream: sdw_stream); |
940 | return 0; |
941 | } |
942 | |
943 | #define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
944 | #define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
945 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) |
946 | |
947 | static const struct snd_soc_dai_ops rt715_ops = { |
948 | .hw_params = rt715_pcm_hw_params, |
949 | .hw_free = rt715_pcm_hw_free, |
950 | .set_stream = rt715_set_sdw_stream, |
951 | .shutdown = rt715_shutdown, |
952 | }; |
953 | |
954 | static struct snd_soc_dai_driver rt715_dai[] = { |
955 | { |
956 | .name = "rt715-aif1" , |
957 | .id = RT715_AIF1, |
958 | .capture = { |
959 | .stream_name = "DP6 Capture" , |
960 | .channels_min = 1, |
961 | .channels_max = 2, |
962 | .rates = RT715_STEREO_RATES, |
963 | .formats = RT715_FORMATS, |
964 | }, |
965 | .ops = &rt715_ops, |
966 | }, |
967 | { |
968 | .name = "rt715-aif2" , |
969 | .id = RT715_AIF2, |
970 | .capture = { |
971 | .stream_name = "DP4 Capture" , |
972 | .channels_min = 1, |
973 | .channels_max = 2, |
974 | .rates = RT715_STEREO_RATES, |
975 | .formats = RT715_FORMATS, |
976 | }, |
977 | .ops = &rt715_ops, |
978 | }, |
979 | }; |
980 | |
981 | /* Bus clock frequency */ |
982 | #define RT715_CLK_FREQ_9600000HZ 9600000 |
983 | #define RT715_CLK_FREQ_12000000HZ 12000000 |
984 | #define RT715_CLK_FREQ_6000000HZ 6000000 |
985 | #define RT715_CLK_FREQ_4800000HZ 4800000 |
986 | #define RT715_CLK_FREQ_2400000HZ 2400000 |
987 | #define RT715_CLK_FREQ_12288000HZ 12288000 |
988 | |
989 | int rt715_clock_config(struct device *dev) |
990 | { |
991 | struct rt715_priv *rt715 = dev_get_drvdata(dev); |
992 | unsigned int clk_freq, value; |
993 | |
994 | clk_freq = (rt715->params.curr_dr_freq >> 1); |
995 | |
996 | switch (clk_freq) { |
997 | case RT715_CLK_FREQ_12000000HZ: |
998 | value = 0x0; |
999 | break; |
1000 | case RT715_CLK_FREQ_6000000HZ: |
1001 | value = 0x1; |
1002 | break; |
1003 | case RT715_CLK_FREQ_9600000HZ: |
1004 | value = 0x2; |
1005 | break; |
1006 | case RT715_CLK_FREQ_4800000HZ: |
1007 | value = 0x3; |
1008 | break; |
1009 | case RT715_CLK_FREQ_2400000HZ: |
1010 | value = 0x4; |
1011 | break; |
1012 | case RT715_CLK_FREQ_12288000HZ: |
1013 | value = 0x5; |
1014 | break; |
1015 | default: |
1016 | return -EINVAL; |
1017 | } |
1018 | |
1019 | regmap_write(map: rt715->regmap, reg: 0xe0, val: value); |
1020 | regmap_write(map: rt715->regmap, reg: 0xf0, val: value); |
1021 | |
1022 | return 0; |
1023 | } |
1024 | |
1025 | int rt715_init(struct device *dev, struct regmap *sdw_regmap, |
1026 | struct regmap *regmap, struct sdw_slave *slave) |
1027 | { |
1028 | struct rt715_priv *rt715; |
1029 | int ret; |
1030 | |
1031 | rt715 = devm_kzalloc(dev, size: sizeof(*rt715), GFP_KERNEL); |
1032 | if (!rt715) |
1033 | return -ENOMEM; |
1034 | |
1035 | dev_set_drvdata(dev, data: rt715); |
1036 | rt715->slave = slave; |
1037 | rt715->regmap = regmap; |
1038 | rt715->sdw_regmap = sdw_regmap; |
1039 | |
1040 | regcache_cache_only(map: rt715->regmap, enable: true); |
1041 | |
1042 | /* |
1043 | * Mark hw_init to false |
1044 | * HW init will be performed when device reports present |
1045 | */ |
1046 | rt715->hw_init = false; |
1047 | rt715->first_hw_init = false; |
1048 | |
1049 | ret = devm_snd_soc_register_component(dev, |
1050 | component_driver: &soc_codec_dev_rt715, |
1051 | dai_drv: rt715_dai, |
1052 | ARRAY_SIZE(rt715_dai)); |
1053 | if (ret < 0) |
1054 | return ret; |
1055 | |
1056 | /* set autosuspend parameters */ |
1057 | pm_runtime_set_autosuspend_delay(dev, delay: 3000); |
1058 | pm_runtime_use_autosuspend(dev); |
1059 | |
1060 | /* make sure the device does not suspend immediately */ |
1061 | pm_runtime_mark_last_busy(dev); |
1062 | |
1063 | pm_runtime_enable(dev); |
1064 | |
1065 | /* important note: the device is NOT tagged as 'active' and will remain |
1066 | * 'suspended' until the hardware is enumerated/initialized. This is required |
1067 | * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently |
1068 | * fail with -EACCESS because of race conditions between card creation and enumeration |
1069 | */ |
1070 | |
1071 | return 0; |
1072 | } |
1073 | |
1074 | int rt715_io_init(struct device *dev, struct sdw_slave *slave) |
1075 | { |
1076 | struct rt715_priv *rt715 = dev_get_drvdata(dev); |
1077 | |
1078 | if (rt715->hw_init) |
1079 | return 0; |
1080 | |
1081 | regcache_cache_only(map: rt715->regmap, enable: false); |
1082 | |
1083 | /* |
1084 | * PM runtime status is marked as 'active' only when a Slave reports as Attached |
1085 | */ |
1086 | if (!rt715->first_hw_init) |
1087 | /* update count of parent 'active' children */ |
1088 | pm_runtime_set_active(dev: &slave->dev); |
1089 | |
1090 | pm_runtime_get_noresume(dev: &slave->dev); |
1091 | |
1092 | rt715_reset(regmap: rt715->regmap); |
1093 | |
1094 | /* Mute nid=08h/09h */ |
1095 | regmap_write(map: rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, val: 0xb080); |
1096 | regmap_write(map: rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, val: 0xb080); |
1097 | /* Mute nid=07h/27h */ |
1098 | regmap_write(map: rt715->regmap, RT715_SET_GAIN_MIC_ADC_H, val: 0xb080); |
1099 | regmap_write(map: rt715->regmap, RT715_SET_GAIN_MIX_ADC2_H, val: 0xb080); |
1100 | |
1101 | /* Set Pin Widget */ |
1102 | regmap_write(map: rt715->regmap, RT715_SET_PIN_DMIC1, val: 0x20); |
1103 | regmap_write(map: rt715->regmap, RT715_SET_PIN_DMIC2, val: 0x20); |
1104 | regmap_write(map: rt715->regmap, RT715_SET_PIN_DMIC3, val: 0x20); |
1105 | regmap_write(map: rt715->regmap, RT715_SET_PIN_DMIC4, val: 0x20); |
1106 | /* Set Converter Stream */ |
1107 | regmap_write(map: rt715->regmap, RT715_SET_STREAMID_LINE_ADC, val: 0x10); |
1108 | regmap_write(map: rt715->regmap, RT715_SET_STREAMID_MIX_ADC, val: 0x10); |
1109 | regmap_write(map: rt715->regmap, RT715_SET_STREAMID_MIC_ADC, val: 0x10); |
1110 | regmap_write(map: rt715->regmap, RT715_SET_STREAMID_MIX_ADC2, val: 0x10); |
1111 | /* Set Configuration Default */ |
1112 | regmap_write(map: rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT1, val: 0xd0); |
1113 | regmap_write(map: rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT2, val: 0x11); |
1114 | regmap_write(map: rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT3, val: 0xa1); |
1115 | regmap_write(map: rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT4, val: 0x81); |
1116 | regmap_write(map: rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT1, val: 0xd1); |
1117 | regmap_write(map: rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT2, val: 0x11); |
1118 | regmap_write(map: rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT3, val: 0xa1); |
1119 | regmap_write(map: rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT4, val: 0x81); |
1120 | regmap_write(map: rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT1, val: 0xd0); |
1121 | regmap_write(map: rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT2, val: 0x11); |
1122 | regmap_write(map: rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT3, val: 0xa1); |
1123 | regmap_write(map: rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT4, val: 0x81); |
1124 | regmap_write(map: rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT1, val: 0xd1); |
1125 | regmap_write(map: rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT2, val: 0x11); |
1126 | regmap_write(map: rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT3, val: 0xa1); |
1127 | regmap_write(map: rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT4, val: 0x81); |
1128 | |
1129 | /* Finish Initial Settings, set power to D3 */ |
1130 | regmap_write(map: rt715->regmap, RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); |
1131 | |
1132 | if (rt715->first_hw_init) |
1133 | regcache_mark_dirty(map: rt715->regmap); |
1134 | else |
1135 | rt715->first_hw_init = true; |
1136 | |
1137 | /* Mark Slave initialization complete */ |
1138 | rt715->hw_init = true; |
1139 | |
1140 | pm_runtime_mark_last_busy(dev: &slave->dev); |
1141 | pm_runtime_put_autosuspend(dev: &slave->dev); |
1142 | |
1143 | return 0; |
1144 | } |
1145 | |
1146 | MODULE_DESCRIPTION("ASoC rt715 driver" ); |
1147 | MODULE_DESCRIPTION("ASoC rt715 driver SDW" ); |
1148 | MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>" ); |
1149 | MODULE_LICENSE("GPL v2" ); |
1150 | |