1 | // SPDX-License-Identifier: MIT |
2 | // |
3 | // Machine driver for AMD ACP Audio engine using DA7219, RT5682 & MAX98357 codec |
4 | // |
5 | //Copyright 2017-2021 Advanced Micro Devices, Inc. |
6 | |
7 | #include <sound/core.h> |
8 | #include <sound/soc.h> |
9 | #include <sound/pcm.h> |
10 | #include <sound/pcm_params.h> |
11 | #include <sound/soc-dapm.h> |
12 | #include <sound/jack.h> |
13 | #include <linux/clk.h> |
14 | #include <linux/gpio.h> |
15 | #include <linux/module.h> |
16 | #include <linux/regulator/machine.h> |
17 | #include <linux/regulator/driver.h> |
18 | #include <linux/i2c.h> |
19 | #include <linux/input.h> |
20 | #include <linux/acpi.h> |
21 | |
22 | #include "acp.h" |
23 | #include "../codecs/da7219.h" |
24 | #include "../codecs/rt5682.h" |
25 | |
26 | #define CZ_PLAT_CLK 48000000 |
27 | #define DUAL_CHANNEL 2 |
28 | #define RT5682_PLL_FREQ (48000 * 512) |
29 | |
30 | static struct snd_soc_jack cz_jack; |
31 | static struct snd_soc_jack_pin cz_jack_pins[] = { |
32 | { |
33 | .pin = "Headphone Jack" , |
34 | .mask = SND_JACK_HEADPHONE, |
35 | }, |
36 | { |
37 | .pin = "Headset Mic" , |
38 | .mask = SND_JACK_MICROPHONE, |
39 | }, |
40 | { |
41 | .pin = "Line Out" , |
42 | .mask = SND_JACK_LINEOUT, |
43 | }, |
44 | }; |
45 | |
46 | static struct clk *da7219_dai_wclk; |
47 | static struct clk *da7219_dai_bclk; |
48 | static struct clk *rt5682_dai_wclk; |
49 | static struct clk *rt5682_dai_bclk; |
50 | |
51 | void *acp_soc_is_rltk_max(struct device *dev); |
52 | |
53 | static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) |
54 | { |
55 | int ret; |
56 | struct snd_soc_card *card = rtd->card; |
57 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
58 | struct snd_soc_component *component = codec_dai->component; |
59 | |
60 | dev_info(rtd->dev, "codec dai name = %s\n" , codec_dai->name); |
61 | |
62 | ret = snd_soc_dai_set_sysclk(dai: codec_dai, clk_id: DA7219_CLKSRC_MCLK, |
63 | CZ_PLAT_CLK, SND_SOC_CLOCK_IN); |
64 | if (ret < 0) { |
65 | dev_err(rtd->dev, "can't set codec sysclk: %d\n" , ret); |
66 | return ret; |
67 | } |
68 | |
69 | ret = snd_soc_dai_set_pll(dai: codec_dai, pll_id: 0, source: DA7219_SYSCLK_PLL, |
70 | CZ_PLAT_CLK, DA7219_PLL_FREQ_OUT_98304); |
71 | if (ret < 0) { |
72 | dev_err(rtd->dev, "can't set codec pll: %d\n" , ret); |
73 | return ret; |
74 | } |
75 | |
76 | da7219_dai_wclk = devm_clk_get(dev: component->dev, id: "da7219-dai-wclk" ); |
77 | if (IS_ERR(ptr: da7219_dai_wclk)) |
78 | return PTR_ERR(ptr: da7219_dai_wclk); |
79 | |
80 | da7219_dai_bclk = devm_clk_get(dev: component->dev, id: "da7219-dai-bclk" ); |
81 | if (IS_ERR(ptr: da7219_dai_bclk)) |
82 | return PTR_ERR(ptr: da7219_dai_bclk); |
83 | |
84 | ret = snd_soc_card_jack_new_pins(card, id: "Headset Jack" , |
85 | type: SND_JACK_HEADSET | SND_JACK_LINEOUT | |
86 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | |
87 | SND_JACK_BTN_2 | SND_JACK_BTN_3, |
88 | jack: &cz_jack, |
89 | pins: cz_jack_pins, |
90 | ARRAY_SIZE(cz_jack_pins)); |
91 | if (ret) { |
92 | dev_err(card->dev, "HP jack creation failed %d\n" , ret); |
93 | return ret; |
94 | } |
95 | |
96 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_0, KEY_PLAYPAUSE); |
97 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_1, KEY_VOLUMEUP); |
98 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_2, KEY_VOLUMEDOWN); |
99 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_3, KEY_VOICECOMMAND); |
100 | |
101 | snd_soc_component_set_jack(component, jack: &cz_jack, NULL); |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | static int da7219_clk_enable(struct snd_pcm_substream *substream) |
107 | { |
108 | int ret = 0; |
109 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
110 | |
111 | /* |
112 | * Set wclk to 48000 because the rate constraint of this driver is |
113 | * 48000. ADAU7002 spec: "The ADAU7002 requires a BCLK rate that is |
114 | * minimum of 64x the LRCLK sample rate." DA7219 is the only clk |
115 | * source so for all codecs we have to limit bclk to 64X lrclk. |
116 | */ |
117 | clk_set_rate(clk: da7219_dai_wclk, rate: 48000); |
118 | clk_set_rate(clk: da7219_dai_bclk, rate: 48000 * 64); |
119 | ret = clk_prepare_enable(clk: da7219_dai_bclk); |
120 | if (ret < 0) { |
121 | dev_err(rtd->dev, "can't enable master clock %d\n" , ret); |
122 | return ret; |
123 | } |
124 | |
125 | return ret; |
126 | } |
127 | |
128 | static void da7219_clk_disable(void) |
129 | { |
130 | clk_disable_unprepare(clk: da7219_dai_bclk); |
131 | } |
132 | |
133 | static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd) |
134 | { |
135 | int ret; |
136 | struct snd_soc_card *card = rtd->card; |
137 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
138 | struct snd_soc_component *component = codec_dai->component; |
139 | |
140 | dev_info(codec_dai->dev, "codec dai name = %s\n" , codec_dai->name); |
141 | |
142 | /* Set codec sysclk */ |
143 | ret = snd_soc_dai_set_sysclk(dai: codec_dai, clk_id: RT5682_SCLK_S_PLL2, |
144 | RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); |
145 | if (ret < 0) { |
146 | dev_err(codec_dai->dev, |
147 | "Failed to set rt5682 SYSCLK: %d\n" , ret); |
148 | return ret; |
149 | } |
150 | /* set codec PLL */ |
151 | ret = snd_soc_dai_set_pll(dai: codec_dai, pll_id: RT5682_PLL2, source: RT5682_PLL2_S_MCLK, |
152 | CZ_PLAT_CLK, RT5682_PLL_FREQ); |
153 | if (ret < 0) { |
154 | dev_err(codec_dai->dev, "can't set rt5682 PLL: %d\n" , ret); |
155 | return ret; |
156 | } |
157 | |
158 | rt5682_dai_wclk = devm_clk_get(dev: component->dev, id: "rt5682-dai-wclk" ); |
159 | if (IS_ERR(ptr: rt5682_dai_wclk)) |
160 | return PTR_ERR(ptr: rt5682_dai_wclk); |
161 | |
162 | rt5682_dai_bclk = devm_clk_get(dev: component->dev, id: "rt5682-dai-bclk" ); |
163 | if (IS_ERR(ptr: rt5682_dai_bclk)) |
164 | return PTR_ERR(ptr: rt5682_dai_bclk); |
165 | |
166 | ret = snd_soc_card_jack_new_pins(card, id: "Headset Jack" , |
167 | type: SND_JACK_HEADSET | SND_JACK_LINEOUT | |
168 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | |
169 | SND_JACK_BTN_2 | SND_JACK_BTN_3, |
170 | jack: &cz_jack, |
171 | pins: cz_jack_pins, |
172 | ARRAY_SIZE(cz_jack_pins)); |
173 | if (ret) { |
174 | dev_err(card->dev, "HP jack creation failed %d\n" , ret); |
175 | return ret; |
176 | } |
177 | |
178 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_0, KEY_PLAYPAUSE); |
179 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_1, KEY_VOLUMEUP); |
180 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_2, KEY_VOLUMEDOWN); |
181 | snd_jack_set_key(jack: cz_jack.jack, type: SND_JACK_BTN_3, KEY_VOICECOMMAND); |
182 | |
183 | ret = snd_soc_component_set_jack(component, jack: &cz_jack, NULL); |
184 | if (ret) { |
185 | dev_err(rtd->dev, "Headset Jack call-back failed: %d\n" , ret); |
186 | return ret; |
187 | } |
188 | return 0; |
189 | } |
190 | |
191 | static int rt5682_clk_enable(struct snd_pcm_substream *substream) |
192 | { |
193 | int ret; |
194 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
195 | |
196 | /* |
197 | * Set wclk to 48000 because the rate constraint of this driver is |
198 | * 48000. ADAU7002 spec: "The ADAU7002 requires a BCLK rate that is |
199 | * minimum of 64x the LRCLK sample rate." RT5682 is the only clk |
200 | * source so for all codecs we have to limit bclk to 64X lrclk. |
201 | */ |
202 | ret = clk_set_rate(clk: rt5682_dai_wclk, rate: 48000); |
203 | if (ret) { |
204 | dev_err(rtd->dev, "Error setting wclk rate: %d\n" , ret); |
205 | return ret; |
206 | } |
207 | ret = clk_set_rate(clk: rt5682_dai_bclk, rate: 48000 * 64); |
208 | if (ret) { |
209 | dev_err(rtd->dev, "Error setting bclk rate: %d\n" , ret); |
210 | return ret; |
211 | } |
212 | ret = clk_prepare_enable(clk: rt5682_dai_wclk); |
213 | if (ret < 0) { |
214 | dev_err(rtd->dev, "can't enable wclk %d\n" , ret); |
215 | return ret; |
216 | } |
217 | return ret; |
218 | } |
219 | |
220 | static void rt5682_clk_disable(void) |
221 | { |
222 | clk_disable_unprepare(clk: rt5682_dai_wclk); |
223 | } |
224 | |
225 | static const unsigned int channels[] = { |
226 | DUAL_CHANNEL, |
227 | }; |
228 | |
229 | static const unsigned int rates[] = { |
230 | 48000, |
231 | }; |
232 | |
233 | static const struct snd_pcm_hw_constraint_list constraints_rates = { |
234 | .count = ARRAY_SIZE(rates), |
235 | .list = rates, |
236 | .mask = 0, |
237 | }; |
238 | |
239 | static const struct snd_pcm_hw_constraint_list constraints_channels = { |
240 | .count = ARRAY_SIZE(channels), |
241 | .list = channels, |
242 | .mask = 0, |
243 | }; |
244 | |
245 | static int cz_da7219_play_startup(struct snd_pcm_substream *substream) |
246 | { |
247 | struct snd_pcm_runtime *runtime = substream->runtime; |
248 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
249 | struct snd_soc_card *card = rtd->card; |
250 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
251 | |
252 | /* |
253 | * On this platform for PCM device we support stereo |
254 | */ |
255 | |
256 | runtime->hw.channels_max = DUAL_CHANNEL; |
257 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
258 | l: &constraints_channels); |
259 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
260 | l: &constraints_rates); |
261 | |
262 | machine->play_i2s_instance = I2S_SP_INSTANCE; |
263 | return da7219_clk_enable(substream); |
264 | } |
265 | |
266 | static int cz_da7219_cap_startup(struct snd_pcm_substream *substream) |
267 | { |
268 | struct snd_pcm_runtime *runtime = substream->runtime; |
269 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
270 | struct snd_soc_card *card = rtd->card; |
271 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
272 | |
273 | /* |
274 | * On this platform for PCM device we support stereo |
275 | */ |
276 | |
277 | runtime->hw.channels_max = DUAL_CHANNEL; |
278 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
279 | l: &constraints_channels); |
280 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
281 | l: &constraints_rates); |
282 | |
283 | machine->cap_i2s_instance = I2S_SP_INSTANCE; |
284 | machine->capture_channel = CAP_CHANNEL1; |
285 | return da7219_clk_enable(substream); |
286 | } |
287 | |
288 | static int cz_max_startup(struct snd_pcm_substream *substream) |
289 | { |
290 | struct snd_pcm_runtime *runtime = substream->runtime; |
291 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
292 | struct snd_soc_card *card = rtd->card; |
293 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
294 | |
295 | /* |
296 | * On this platform for PCM device we support stereo |
297 | */ |
298 | |
299 | runtime->hw.channels_max = DUAL_CHANNEL; |
300 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
301 | l: &constraints_channels); |
302 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
303 | l: &constraints_rates); |
304 | |
305 | machine->play_i2s_instance = I2S_BT_INSTANCE; |
306 | return da7219_clk_enable(substream); |
307 | } |
308 | |
309 | static int cz_dmic0_startup(struct snd_pcm_substream *substream) |
310 | { |
311 | struct snd_pcm_runtime *runtime = substream->runtime; |
312 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
313 | struct snd_soc_card *card = rtd->card; |
314 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
315 | |
316 | /* |
317 | * On this platform for PCM device we support stereo |
318 | */ |
319 | |
320 | runtime->hw.channels_max = DUAL_CHANNEL; |
321 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
322 | l: &constraints_channels); |
323 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
324 | l: &constraints_rates); |
325 | |
326 | machine->cap_i2s_instance = I2S_BT_INSTANCE; |
327 | return da7219_clk_enable(substream); |
328 | } |
329 | |
330 | static int cz_dmic1_startup(struct snd_pcm_substream *substream) |
331 | { |
332 | struct snd_pcm_runtime *runtime = substream->runtime; |
333 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
334 | struct snd_soc_card *card = rtd->card; |
335 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
336 | |
337 | /* |
338 | * On this platform for PCM device we support stereo |
339 | */ |
340 | |
341 | runtime->hw.channels_max = DUAL_CHANNEL; |
342 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
343 | l: &constraints_channels); |
344 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
345 | l: &constraints_rates); |
346 | |
347 | machine->cap_i2s_instance = I2S_SP_INSTANCE; |
348 | machine->capture_channel = CAP_CHANNEL0; |
349 | return da7219_clk_enable(substream); |
350 | } |
351 | |
352 | static void cz_da7219_shutdown(struct snd_pcm_substream *substream) |
353 | { |
354 | da7219_clk_disable(); |
355 | } |
356 | |
357 | static int cz_rt5682_play_startup(struct snd_pcm_substream *substream) |
358 | { |
359 | struct snd_pcm_runtime *runtime = substream->runtime; |
360 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
361 | struct snd_soc_card *card = rtd->card; |
362 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
363 | |
364 | /* |
365 | * On this platform for PCM device we support stereo |
366 | */ |
367 | |
368 | runtime->hw.channels_max = DUAL_CHANNEL; |
369 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
370 | l: &constraints_channels); |
371 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
372 | l: &constraints_rates); |
373 | |
374 | machine->play_i2s_instance = I2S_SP_INSTANCE; |
375 | return rt5682_clk_enable(substream); |
376 | } |
377 | |
378 | static int cz_rt5682_cap_startup(struct snd_pcm_substream *substream) |
379 | { |
380 | struct snd_pcm_runtime *runtime = substream->runtime; |
381 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
382 | struct snd_soc_card *card = rtd->card; |
383 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
384 | |
385 | /* |
386 | * On this platform for PCM device we support stereo |
387 | */ |
388 | |
389 | runtime->hw.channels_max = DUAL_CHANNEL; |
390 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
391 | l: &constraints_channels); |
392 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
393 | l: &constraints_rates); |
394 | |
395 | machine->cap_i2s_instance = I2S_SP_INSTANCE; |
396 | machine->capture_channel = CAP_CHANNEL1; |
397 | return rt5682_clk_enable(substream); |
398 | } |
399 | |
400 | static int cz_rt5682_max_startup(struct snd_pcm_substream *substream) |
401 | { |
402 | struct snd_pcm_runtime *runtime = substream->runtime; |
403 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
404 | struct snd_soc_card *card = rtd->card; |
405 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
406 | |
407 | /* |
408 | * On this platform for PCM device we support stereo |
409 | */ |
410 | |
411 | runtime->hw.channels_max = DUAL_CHANNEL; |
412 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
413 | l: &constraints_channels); |
414 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
415 | l: &constraints_rates); |
416 | |
417 | machine->play_i2s_instance = I2S_BT_INSTANCE; |
418 | return rt5682_clk_enable(substream); |
419 | } |
420 | |
421 | static int cz_rt5682_dmic0_startup(struct snd_pcm_substream *substream) |
422 | { |
423 | struct snd_pcm_runtime *runtime = substream->runtime; |
424 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
425 | struct snd_soc_card *card = rtd->card; |
426 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
427 | |
428 | /* |
429 | * On this platform for PCM device we support stereo |
430 | */ |
431 | |
432 | runtime->hw.channels_max = DUAL_CHANNEL; |
433 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
434 | l: &constraints_channels); |
435 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
436 | l: &constraints_rates); |
437 | |
438 | machine->cap_i2s_instance = I2S_BT_INSTANCE; |
439 | return rt5682_clk_enable(substream); |
440 | } |
441 | |
442 | static int cz_rt5682_dmic1_startup(struct snd_pcm_substream *substream) |
443 | { |
444 | struct snd_pcm_runtime *runtime = substream->runtime; |
445 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
446 | struct snd_soc_card *card = rtd->card; |
447 | struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); |
448 | |
449 | /* |
450 | * On this platform for PCM device we support stereo |
451 | */ |
452 | |
453 | runtime->hw.channels_max = DUAL_CHANNEL; |
454 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
455 | l: &constraints_channels); |
456 | snd_pcm_hw_constraint_list(runtime, cond: 0, SNDRV_PCM_HW_PARAM_RATE, |
457 | l: &constraints_rates); |
458 | |
459 | machine->cap_i2s_instance = I2S_SP_INSTANCE; |
460 | machine->capture_channel = CAP_CHANNEL0; |
461 | return rt5682_clk_enable(substream); |
462 | } |
463 | |
464 | static void cz_rt5682_shutdown(struct snd_pcm_substream *substream) |
465 | { |
466 | rt5682_clk_disable(); |
467 | } |
468 | |
469 | static const struct snd_soc_ops cz_da7219_play_ops = { |
470 | .startup = cz_da7219_play_startup, |
471 | .shutdown = cz_da7219_shutdown, |
472 | }; |
473 | |
474 | static const struct snd_soc_ops cz_da7219_cap_ops = { |
475 | .startup = cz_da7219_cap_startup, |
476 | .shutdown = cz_da7219_shutdown, |
477 | }; |
478 | |
479 | static const struct snd_soc_ops cz_max_play_ops = { |
480 | .startup = cz_max_startup, |
481 | .shutdown = cz_da7219_shutdown, |
482 | }; |
483 | |
484 | static const struct snd_soc_ops cz_dmic0_cap_ops = { |
485 | .startup = cz_dmic0_startup, |
486 | .shutdown = cz_da7219_shutdown, |
487 | }; |
488 | |
489 | static const struct snd_soc_ops cz_dmic1_cap_ops = { |
490 | .startup = cz_dmic1_startup, |
491 | .shutdown = cz_da7219_shutdown, |
492 | }; |
493 | |
494 | static const struct snd_soc_ops cz_rt5682_play_ops = { |
495 | .startup = cz_rt5682_play_startup, |
496 | .shutdown = cz_rt5682_shutdown, |
497 | }; |
498 | |
499 | static const struct snd_soc_ops cz_rt5682_cap_ops = { |
500 | .startup = cz_rt5682_cap_startup, |
501 | .shutdown = cz_rt5682_shutdown, |
502 | }; |
503 | |
504 | static const struct snd_soc_ops cz_rt5682_max_play_ops = { |
505 | .startup = cz_rt5682_max_startup, |
506 | .shutdown = cz_rt5682_shutdown, |
507 | }; |
508 | |
509 | static const struct snd_soc_ops cz_rt5682_dmic0_cap_ops = { |
510 | .startup = cz_rt5682_dmic0_startup, |
511 | .shutdown = cz_rt5682_shutdown, |
512 | }; |
513 | |
514 | static const struct snd_soc_ops cz_rt5682_dmic1_cap_ops = { |
515 | .startup = cz_rt5682_dmic1_startup, |
516 | .shutdown = cz_rt5682_shutdown, |
517 | }; |
518 | |
519 | SND_SOC_DAILINK_DEF(designware1, |
520 | DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto" ))); |
521 | SND_SOC_DAILINK_DEF(designware2, |
522 | DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto" ))); |
523 | SND_SOC_DAILINK_DEF(designware3, |
524 | DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.3.auto" ))); |
525 | |
526 | SND_SOC_DAILINK_DEF(dlgs, |
527 | DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00" , "da7219-hifi" ))); |
528 | SND_SOC_DAILINK_DEF(rt5682, |
529 | DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00" , "rt5682-aif1" ))); |
530 | SND_SOC_DAILINK_DEF(mx, |
531 | DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00" , "HiFi" ))); |
532 | SND_SOC_DAILINK_DEF(adau, |
533 | DAILINK_COMP_ARRAY(COMP_CODEC("ADAU7002:00" , "adau7002-hifi" ))); |
534 | |
535 | SND_SOC_DAILINK_DEF(platform, |
536 | DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.0.auto" ))); |
537 | |
538 | static struct snd_soc_dai_link cz_dai_7219_98357[] = { |
539 | { |
540 | .name = "amd-da7219-play" , |
541 | .stream_name = "Playback" , |
542 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
543 | | SND_SOC_DAIFMT_CBP_CFP, |
544 | .init = cz_da7219_init, |
545 | .dpcm_playback = 1, |
546 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
547 | .ops = &cz_da7219_play_ops, |
548 | SND_SOC_DAILINK_REG(designware1, dlgs, platform), |
549 | }, |
550 | { |
551 | .name = "amd-da7219-cap" , |
552 | .stream_name = "Capture" , |
553 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
554 | | SND_SOC_DAIFMT_CBP_CFP, |
555 | .dpcm_capture = 1, |
556 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
557 | .ops = &cz_da7219_cap_ops, |
558 | SND_SOC_DAILINK_REG(designware2, dlgs, platform), |
559 | }, |
560 | { |
561 | .name = "amd-max98357-play" , |
562 | .stream_name = "HiFi Playback" , |
563 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
564 | | SND_SOC_DAIFMT_CBP_CFP, |
565 | .dpcm_playback = 1, |
566 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
567 | .ops = &cz_max_play_ops, |
568 | SND_SOC_DAILINK_REG(designware3, mx, platform), |
569 | }, |
570 | { |
571 | /* C panel DMIC */ |
572 | .name = "dmic0" , |
573 | .stream_name = "DMIC0 Capture" , |
574 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
575 | | SND_SOC_DAIFMT_CBP_CFP, |
576 | .dpcm_capture = 1, |
577 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
578 | .ops = &cz_dmic0_cap_ops, |
579 | SND_SOC_DAILINK_REG(designware3, adau, platform), |
580 | }, |
581 | { |
582 | /* A/B panel DMIC */ |
583 | .name = "dmic1" , |
584 | .stream_name = "DMIC1 Capture" , |
585 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
586 | | SND_SOC_DAIFMT_CBP_CFP, |
587 | .dpcm_capture = 1, |
588 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
589 | .ops = &cz_dmic1_cap_ops, |
590 | SND_SOC_DAILINK_REG(designware2, adau, platform), |
591 | }, |
592 | }; |
593 | |
594 | static struct snd_soc_dai_link cz_dai_5682_98357[] = { |
595 | { |
596 | .name = "amd-rt5682-play" , |
597 | .stream_name = "Playback" , |
598 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
599 | | SND_SOC_DAIFMT_CBP_CFP, |
600 | .init = cz_rt5682_init, |
601 | .dpcm_playback = 1, |
602 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
603 | .ops = &cz_rt5682_play_ops, |
604 | SND_SOC_DAILINK_REG(designware1, rt5682, platform), |
605 | }, |
606 | { |
607 | .name = "amd-rt5682-cap" , |
608 | .stream_name = "Capture" , |
609 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
610 | | SND_SOC_DAIFMT_CBP_CFP, |
611 | .dpcm_capture = 1, |
612 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
613 | .ops = &cz_rt5682_cap_ops, |
614 | SND_SOC_DAILINK_REG(designware2, rt5682, platform), |
615 | }, |
616 | { |
617 | .name = "amd-max98357-play" , |
618 | .stream_name = "HiFi Playback" , |
619 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
620 | | SND_SOC_DAIFMT_CBP_CFP, |
621 | .dpcm_playback = 1, |
622 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
623 | .ops = &cz_rt5682_max_play_ops, |
624 | SND_SOC_DAILINK_REG(designware3, mx, platform), |
625 | }, |
626 | { |
627 | /* C panel DMIC */ |
628 | .name = "dmic0" , |
629 | .stream_name = "DMIC0 Capture" , |
630 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
631 | | SND_SOC_DAIFMT_CBP_CFP, |
632 | .dpcm_capture = 1, |
633 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
634 | .ops = &cz_rt5682_dmic0_cap_ops, |
635 | SND_SOC_DAILINK_REG(designware3, adau, platform), |
636 | }, |
637 | { |
638 | /* A/B panel DMIC */ |
639 | .name = "dmic1" , |
640 | .stream_name = "DMIC1 Capture" , |
641 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
642 | | SND_SOC_DAIFMT_CBP_CFP, |
643 | .dpcm_capture = 1, |
644 | .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, |
645 | .ops = &cz_rt5682_dmic1_cap_ops, |
646 | SND_SOC_DAILINK_REG(designware2, adau, platform), |
647 | }, |
648 | }; |
649 | |
650 | static const struct snd_soc_dapm_widget cz_widgets[] = { |
651 | SND_SOC_DAPM_HP("Headphones" , NULL), |
652 | SND_SOC_DAPM_SPK("Speakers" , NULL), |
653 | SND_SOC_DAPM_LINE("Line Out" , NULL), |
654 | SND_SOC_DAPM_MIC("Headset Mic" , NULL), |
655 | SND_SOC_DAPM_MIC("Int Mic" , NULL), |
656 | }; |
657 | |
658 | static const struct snd_soc_dapm_route cz_audio_route[] = { |
659 | {"Headphones" , NULL, "HPL" }, |
660 | {"Headphones" , NULL, "HPR" }, |
661 | {"MIC" , NULL, "Headset Mic" }, |
662 | {"Speakers" , NULL, "Speaker" }, |
663 | {"PDM_DAT" , NULL, "Int Mic" }, |
664 | }; |
665 | |
666 | static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = { |
667 | {"Headphones" , NULL, "HPOL" }, |
668 | {"Headphones" , NULL, "HPOR" }, |
669 | {"IN1P" , NULL, "Headset Mic" }, |
670 | {"Speakers" , NULL, "Speaker" }, |
671 | {"PDM_DAT" , NULL, "Int Mic" }, |
672 | }; |
673 | |
674 | static const struct snd_kcontrol_new cz_mc_controls[] = { |
675 | SOC_DAPM_PIN_SWITCH("Headphones" ), |
676 | SOC_DAPM_PIN_SWITCH("Speakers" ), |
677 | SOC_DAPM_PIN_SWITCH("Line Out" ), |
678 | SOC_DAPM_PIN_SWITCH("Headset Mic" ), |
679 | SOC_DAPM_PIN_SWITCH("Int Mic" ), |
680 | }; |
681 | |
682 | static struct snd_soc_card cz_card = { |
683 | .name = "acpd7219m98357" , |
684 | .owner = THIS_MODULE, |
685 | .dai_link = cz_dai_7219_98357, |
686 | .num_links = ARRAY_SIZE(cz_dai_7219_98357), |
687 | .dapm_widgets = cz_widgets, |
688 | .num_dapm_widgets = ARRAY_SIZE(cz_widgets), |
689 | .dapm_routes = cz_audio_route, |
690 | .num_dapm_routes = ARRAY_SIZE(cz_audio_route), |
691 | .controls = cz_mc_controls, |
692 | .num_controls = ARRAY_SIZE(cz_mc_controls), |
693 | }; |
694 | |
695 | static struct snd_soc_card cz_rt5682_card = { |
696 | .name = "acpr5682m98357" , |
697 | .owner = THIS_MODULE, |
698 | .dai_link = cz_dai_5682_98357, |
699 | .num_links = ARRAY_SIZE(cz_dai_5682_98357), |
700 | .dapm_widgets = cz_widgets, |
701 | .num_dapm_widgets = ARRAY_SIZE(cz_widgets), |
702 | .dapm_routes = cz_rt5682_audio_route, |
703 | .controls = cz_mc_controls, |
704 | .num_controls = ARRAY_SIZE(cz_mc_controls), |
705 | }; |
706 | |
707 | void *acp_soc_is_rltk_max(struct device *dev) |
708 | { |
709 | const struct acpi_device_id *match; |
710 | |
711 | match = acpi_match_device(ids: dev->driver->acpi_match_table, dev); |
712 | if (!match) |
713 | return NULL; |
714 | return (void *)match->driver_data; |
715 | } |
716 | |
717 | static struct regulator_consumer_supply acp_da7219_supplies[] = { |
718 | REGULATOR_SUPPLY("VDD" , "i2c-DLGS7219:00" ), |
719 | REGULATOR_SUPPLY("VDDMIC" , "i2c-DLGS7219:00" ), |
720 | REGULATOR_SUPPLY("VDDIO" , "i2c-DLGS7219:00" ), |
721 | REGULATOR_SUPPLY("IOVDD" , "ADAU7002:00" ), |
722 | }; |
723 | |
724 | static struct regulator_init_data acp_da7219_data = { |
725 | .constraints = { |
726 | .always_on = 1, |
727 | }, |
728 | .num_consumer_supplies = ARRAY_SIZE(acp_da7219_supplies), |
729 | .consumer_supplies = acp_da7219_supplies, |
730 | }; |
731 | |
732 | static struct regulator_config acp_da7219_cfg = { |
733 | .init_data = &acp_da7219_data, |
734 | }; |
735 | |
736 | static struct regulator_ops acp_da7219_ops = { |
737 | }; |
738 | |
739 | static const struct regulator_desc acp_da7219_desc = { |
740 | .name = "reg-fixed-1.8V" , |
741 | .type = REGULATOR_VOLTAGE, |
742 | .owner = THIS_MODULE, |
743 | .ops = &acp_da7219_ops, |
744 | .fixed_uV = 1800000, /* 1.8V */ |
745 | .n_voltages = 1, |
746 | }; |
747 | |
748 | static int cz_probe(struct platform_device *pdev) |
749 | { |
750 | int ret; |
751 | struct snd_soc_card *card; |
752 | struct acp_platform_info *machine; |
753 | struct regulator_dev *rdev; |
754 | struct device *dev = &pdev->dev; |
755 | |
756 | card = (struct snd_soc_card *)acp_soc_is_rltk_max(dev); |
757 | if (!card) |
758 | return -ENODEV; |
759 | if (!strcmp(card->name, "acpd7219m98357" )) { |
760 | acp_da7219_cfg.dev = &pdev->dev; |
761 | rdev = devm_regulator_register(dev: &pdev->dev, regulator_desc: &acp_da7219_desc, |
762 | config: &acp_da7219_cfg); |
763 | if (IS_ERR(ptr: rdev)) { |
764 | dev_err(&pdev->dev, "Failed to register regulator: %d\n" , |
765 | (int)PTR_ERR(rdev)); |
766 | return -EINVAL; |
767 | } |
768 | } |
769 | |
770 | machine = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct acp_platform_info), |
771 | GFP_KERNEL); |
772 | if (!machine) |
773 | return -ENOMEM; |
774 | card->dev = &pdev->dev; |
775 | platform_set_drvdata(pdev, data: card); |
776 | snd_soc_card_set_drvdata(card, data: machine); |
777 | ret = devm_snd_soc_register_card(dev: &pdev->dev, card); |
778 | if (ret) { |
779 | return dev_err_probe(dev: &pdev->dev, err: ret, |
780 | fmt: "devm_snd_soc_register_card(%s) failed\n" , |
781 | card->name); |
782 | } |
783 | acp_bt_uart_enable = !device_property_read_bool(dev: &pdev->dev, |
784 | propname: "bt-pad-enable" ); |
785 | return 0; |
786 | } |
787 | |
788 | #ifdef CONFIG_ACPI |
789 | static const struct acpi_device_id cz_audio_acpi_match[] = { |
790 | { "AMD7219" , (unsigned long)&cz_card }, |
791 | { "AMDI5682" , (unsigned long)&cz_rt5682_card}, |
792 | {}, |
793 | }; |
794 | MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match); |
795 | #endif |
796 | |
797 | static struct platform_driver cz_pcm_driver = { |
798 | .driver = { |
799 | .name = "cz-da7219-max98357a" , |
800 | .acpi_match_table = ACPI_PTR(cz_audio_acpi_match), |
801 | .pm = &snd_soc_pm_ops, |
802 | }, |
803 | .probe = cz_probe, |
804 | }; |
805 | |
806 | module_platform_driver(cz_pcm_driver); |
807 | |
808 | MODULE_AUTHOR("akshu.agrawal@amd.com" ); |
809 | MODULE_AUTHOR("Vijendar.Mukunda@amd.com" ); |
810 | MODULE_DESCRIPTION("DA7219, RT5682 & MAX98357A audio support" ); |
811 | MODULE_LICENSE("GPL v2" ); |
812 | |