blob: 24d1075eb62e0d8d2f11a721a6f31fef1d65f6d4 [file] [log] [blame]
Ajit Kumar Pandeyd4c750f2021-10-19 12:39:34 +05301// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2021 Advanced Micro Devices, Inc.
7//
8// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
9// Vijendar Mukunda <Vijendar.Mukunda@amd.com>
10//
11
12/*
13 * Machine Driver Interface for ACP HW block
14 */
15
16#include <sound/core.h>
17#include <sound/jack.h>
18#include <sound/pcm_params.h>
19#include <sound/soc-dapm.h>
20#include <sound/soc.h>
21#include <linux/input.h>
22#include <linux/module.h>
23
24#include "../../codecs/rt5682.h"
25#include "../../codecs/rt1019.h"
26#include "acp-mach.h"
27
28#define PCO_PLAT_CLK 48000000
29#define RT5682_PLL_FREQ (48000 * 512)
30#define DUAL_CHANNEL 2
31#define FOUR_CHANNEL 4
32
33static struct snd_soc_jack pco_jack;
34
35static const unsigned int channels[] = {
36 DUAL_CHANNEL,
37};
38
39static const unsigned int rates[] = {
40 48000,
41};
42
43static const struct snd_pcm_hw_constraint_list constraints_rates = {
44 .count = ARRAY_SIZE(rates),
45 .list = rates,
46 .mask = 0,
47};
48
49static const struct snd_pcm_hw_constraint_list constraints_channels = {
50 .count = ARRAY_SIZE(channels),
51 .list = channels,
52 .mask = 0,
53};
54
55static int acp_clk_enable(struct acp_card_drvdata *drvdata)
56{
57 clk_set_rate(drvdata->wclk, 48000);
58 clk_set_rate(drvdata->bclk, 48000 * 64);
59
60 return clk_prepare_enable(drvdata->wclk);
61}
62
63/* Declare RT5682 codec components */
64SND_SOC_DAILINK_DEF(rt5682,
65 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1")));
66
67static const struct snd_soc_dapm_route rt5682_map[] = {
68 { "Headphone Jack", NULL, "HPOL" },
69 { "Headphone Jack", NULL, "HPOR" },
70 { "IN1P", NULL, "Headset Mic" },
71};
72
73/* Define card ops for RT5682 CODEC */
74static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
75{
76 struct snd_soc_card *card = rtd->card;
77 struct acp_card_drvdata *drvdata = card->drvdata;
78 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
79 struct snd_soc_component *component = codec_dai->component;
80 int ret;
81
82 dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
83
84 if (drvdata->hs_codec_id != RT5682)
85 return -EINVAL;
86
87 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
88 | SND_SOC_DAIFMT_CBP_CFP);
89 if (ret < 0) {
90 dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
91 return ret;
92 }
93
94 ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK,
95 PCO_PLAT_CLK, RT5682_PLL_FREQ);
96 if (ret < 0) {
97 dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret);
98 return ret;
99 }
100
101 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2,
102 RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
103 if (ret < 0) {
104 dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret);
105 return ret;
106 }
107
108 /* Set tdm/i2s1 master bclk ratio */
109 ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64);
110 if (ret < 0) {
111 dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret);
112 return ret;
113 }
114
115 drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk");
116 drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk");
117
118 ret = snd_soc_card_jack_new(card, "Headset Jack",
119 SND_JACK_HEADSET | SND_JACK_LINEOUT |
120 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
121 SND_JACK_BTN_2 | SND_JACK_BTN_3,
122 &pco_jack, NULL, 0);
123 if (ret) {
124 dev_err(card->dev, "HP jack creation failed %d\n", ret);
125 return ret;
126 }
127
128 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
129 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
130 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
131 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
132
133 ret = snd_soc_component_set_jack(component, &pco_jack, NULL);
134 if (ret) {
135 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
136 return ret;
137 }
138
139 return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682_map, ARRAY_SIZE(rt5682_map));
140}
141
142static int acp_card_hs_startup(struct snd_pcm_substream *substream)
143{
144 struct snd_pcm_runtime *runtime = substream->runtime;
145 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
146 struct snd_soc_card *card = rtd->card;
147 struct acp_card_drvdata *drvdata = card->drvdata;
148 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
149 int ret;
150
151 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
152 | SND_SOC_DAIFMT_CBP_CFP);
153 if (ret < 0) {
154 dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
155 return ret;
156 }
157
158 runtime->hw.channels_max = DUAL_CHANNEL;
159 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
160 &constraints_channels);
161 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
162 &constraints_rates);
163
164 ret = acp_clk_enable(drvdata);
165 if (ret < 0)
166 dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret);
167
168 return ret;
169}
170
171static void acp_card_shutdown(struct snd_pcm_substream *substream)
172{
173 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
174 struct snd_soc_card *card = rtd->card;
175 struct acp_card_drvdata *drvdata = card->drvdata;
176
177 clk_disable_unprepare(drvdata->wclk);
178}
179
180static const struct snd_soc_ops acp_card_rt5682_ops = {
181 .startup = acp_card_hs_startup,
182 .shutdown = acp_card_shutdown,
183};
184
185/* Declare RT1019 codec components */
186SND_SOC_DAILINK_DEF(rt1019,
187 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"),
188 COMP_CODEC("i2c-10EC1019:02", "rt1019-aif")));
189
190static const struct snd_soc_dapm_route rt1019_map_lr[] = {
191 { "Left Spk", NULL, "Left SPO" },
192 { "Right Spk", NULL, "Right SPO" },
193};
194
195static struct snd_soc_codec_conf rt1019_conf[] = {
196 {
197 .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
198 .name_prefix = "Left",
199 },
200 {
201 .dlc = COMP_CODEC_CONF("i2c-10EC1019:02"),
202 .name_prefix = "Right",
203 },
204};
205
206static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd)
207{
208 struct snd_soc_card *card = rtd->card;
209 struct acp_card_drvdata *drvdata = card->drvdata;
210
211 if (drvdata->amp_codec_id != RT1019)
212 return -EINVAL;
213
214 return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr,
215 ARRAY_SIZE(rt1019_map_lr));
216}
217
218static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
219 struct snd_pcm_hw_params *params)
220{
221 struct snd_soc_pcm_runtime *rtd = substream->private_data;
222 struct snd_soc_card *card = rtd->card;
223 struct acp_card_drvdata *drvdata = card->drvdata;
224 struct snd_soc_dai *codec_dai;
225 int srate, i, ret = 0;
226
227 srate = params_rate(params);
228
229 if (drvdata->amp_codec_id != RT1019)
230 return -EINVAL;
231
232 for_each_rtd_codec_dais(rtd, i, codec_dai) {
233 if (strcmp(codec_dai->name, "rt1019-aif"))
234 continue;
235
236 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
237 64 * srate, 256 * srate);
238 if (ret < 0)
239 return ret;
240
241 ret = snd_soc_dai_set_sysclk(codec_dai, RT1019_SCLK_S_PLL,
242 256 * srate, SND_SOC_CLOCK_IN);
243 if (ret < 0)
244 return ret;
245 }
246
247 return 0;
248}
249
250static int acp_card_amp_startup(struct snd_pcm_substream *substream)
251{
252 struct snd_pcm_runtime *runtime = substream->runtime;
253 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
254 struct snd_soc_card *card = rtd->card;
255 struct acp_card_drvdata *drvdata = card->drvdata;
256 int ret;
257
258 runtime->hw.channels_max = DUAL_CHANNEL;
259 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
260 &constraints_channels);
261 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
262 &constraints_rates);
263
264 ret = acp_clk_enable(drvdata);
265 if (ret < 0)
266 dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret);
267
268 return ret;
269}
270
271static const struct snd_soc_ops acp_card_rt1019_ops = {
272 .startup = acp_card_amp_startup,
273 .shutdown = acp_card_shutdown,
274 .hw_params = acp_card_rt1019_hw_params,
275};
276
Ajit Kumar Pandeycabc3ac2021-10-19 12:39:37 +0530277/* Declare Maxim codec components */
278SND_SOC_DAILINK_DEF(max98360a,
279 DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi")));
280
281static const struct snd_soc_dapm_route max98360a_map[] = {
282 {"Spk", NULL, "Speaker"},
283};
284
285static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
286{
287 struct snd_soc_card *card = rtd->card;
288 struct acp_card_drvdata *drvdata = card->drvdata;
289
290 if (drvdata->amp_codec_id != MAX98360A)
291 return -EINVAL;
292
293 return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map,
294 ARRAY_SIZE(max98360a_map));
295}
296
297static const struct snd_soc_ops acp_card_maxim_ops = {
298 .startup = acp_card_amp_startup,
299 .shutdown = acp_card_shutdown,
300};
301
Ajit Kumar Pandeyd4c750f2021-10-19 12:39:34 +0530302/* Declare DMIC codec components */
303SND_SOC_DAILINK_DEF(dmic_codec,
304 DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
305
306/* Declare ACP CPU components */
307static struct snd_soc_dai_link_component dummy_codec[] = {
308 {
309 .name = "snd-soc-dummy",
310 .dai_name = "snd-soc-dummy-dai",
311 }
312};
313
314static struct snd_soc_dai_link_component platform_component[] = {
315 {
316 .name = "acp_asoc_renoir.0",
317 }
318};
319
320static struct snd_soc_dai_link_component sof_component[] = {
321 {
322 .name = "0000:04:00.5",
323 }
324};
325
326SND_SOC_DAILINK_DEF(i2s_sp,
327 DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
328SND_SOC_DAILINK_DEF(sof_sp,
329 DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
330SND_SOC_DAILINK_DEF(sof_dmic,
331 DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
332
333int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
334{
335 struct snd_soc_dai_link *links;
336 struct device *dev = card->dev;
337 struct acp_card_drvdata *drv_data = card->drvdata;
338 int i = 0, num_links = 0;
339
340 if (drv_data->hs_cpu_id)
341 num_links++;
342 if (drv_data->amp_cpu_id)
343 num_links++;
344 if (drv_data->dmic_cpu_id)
345 num_links++;
346
347 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
348 if (!links)
349 return -ENOMEM;
350
351 if (drv_data->hs_cpu_id == I2S_SP) {
352 links[i].name = "acp-headset-codec";
353 links[i].id = HEADSET_BE_ID;
354 links[i].cpus = sof_sp;
355 links[i].num_cpus = ARRAY_SIZE(sof_sp);
356 links[i].platforms = sof_component;
357 links[i].num_platforms = ARRAY_SIZE(sof_component);
358 links[i].dpcm_playback = 1;
359 links[i].dpcm_capture = 1;
360 links[i].nonatomic = true;
361 links[i].no_pcm = 1;
362 if (!drv_data->hs_codec_id) {
363 /* Use dummy codec if codec id not specified */
364 links[i].codecs = dummy_codec;
365 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
366 }
367 if (drv_data->hs_codec_id == RT5682) {
368 links[i].codecs = rt5682;
369 links[i].num_codecs = ARRAY_SIZE(rt5682);
370 links[i].init = acp_card_rt5682_init;
371 links[i].ops = &acp_card_rt5682_ops;
372 }
373 i++;
374 }
375
376 if (drv_data->amp_cpu_id == I2S_SP) {
377 links[i].name = "acp-amp-codec";
378 links[i].id = AMP_BE_ID;
379 links[i].cpus = sof_sp;
380 links[i].num_cpus = ARRAY_SIZE(sof_sp);
381 links[i].platforms = sof_component;
382 links[i].num_platforms = ARRAY_SIZE(sof_component);
383 links[i].dpcm_playback = 1;
384 links[i].nonatomic = true;
385 links[i].no_pcm = 1;
386 if (!drv_data->amp_codec_id) {
387 /* Use dummy codec if codec id not specified */
388 links[i].codecs = dummy_codec;
389 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
390 }
391 if (drv_data->amp_codec_id == RT1019) {
392 links[i].codecs = rt1019;
393 links[i].num_codecs = ARRAY_SIZE(rt1019);
394 links[i].ops = &acp_card_rt1019_ops;
395 links[i].init = acp_card_rt1019_init;
396 card->codec_conf = rt1019_conf;
397 card->num_configs = ARRAY_SIZE(rt1019_conf);
398 }
Ajit Kumar Pandeycabc3ac2021-10-19 12:39:37 +0530399 if (drv_data->amp_codec_id == MAX98360A) {
400 links[i].codecs = max98360a;
401 links[i].num_codecs = ARRAY_SIZE(max98360a);
402 links[i].ops = &acp_card_maxim_ops;
403 links[i].init = acp_card_maxim_init;
404 }
Ajit Kumar Pandeyd4c750f2021-10-19 12:39:34 +0530405 i++;
406 }
407
408 if (drv_data->dmic_cpu_id == DMIC) {
409 links[i].name = "acp-dmic-codec";
410 links[i].id = DMIC_BE_ID;
411 links[i].codecs = dmic_codec;
412 links[i].num_codecs = ARRAY_SIZE(dmic_codec);
413 links[i].cpus = sof_dmic;
414 links[i].num_cpus = ARRAY_SIZE(sof_dmic);
415 links[i].platforms = sof_component;
416 links[i].num_platforms = ARRAY_SIZE(sof_component);
417 links[i].dpcm_capture = 1;
418 links[i].nonatomic = true;
419 links[i].no_pcm = 1;
420 }
421
422 card->dai_link = links;
423 card->num_links = num_links;
424
425 return 0;
426}
427EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, SND_SOC_AMD_MACH);
428
429int acp_legacy_dai_links_create(struct snd_soc_card *card)
430{
431 struct snd_soc_dai_link *links;
432 struct device *dev = card->dev;
433 struct acp_card_drvdata *drv_data = card->drvdata;
434 int i = 0, num_links = 0;
435
436 if (drv_data->hs_cpu_id)
437 num_links++;
438 if (drv_data->amp_cpu_id)
439 num_links++;
440 if (drv_data->dmic_cpu_id)
441 num_links++;
442
443 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
444
445 if (drv_data->hs_cpu_id == I2S_SP) {
446 links[i].name = "acp-headset-codec";
447 links[i].id = HEADSET_BE_ID;
448 links[i].cpus = i2s_sp;
449 links[i].num_cpus = ARRAY_SIZE(i2s_sp);
450 links[i].platforms = platform_component;
451 links[i].num_platforms = ARRAY_SIZE(platform_component);
452 links[i].dpcm_playback = 1;
453 links[i].dpcm_capture = 1;
454 if (!drv_data->hs_codec_id) {
455 /* Use dummy codec if codec id not specified */
456 links[i].codecs = dummy_codec;
457 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
458 }
459 if (drv_data->hs_codec_id == RT5682) {
460 links[i].codecs = rt5682;
461 links[i].num_codecs = ARRAY_SIZE(rt5682);
462 links[i].init = acp_card_rt5682_init;
463 links[i].ops = &acp_card_rt5682_ops;
464 }
465 i++;
466 }
467
468 if (drv_data->amp_cpu_id == I2S_SP) {
469 links[i].name = "acp-amp-codec";
470 links[i].id = AMP_BE_ID;
471 links[i].cpus = i2s_sp;
472 links[i].num_cpus = ARRAY_SIZE(i2s_sp);
473 links[i].platforms = platform_component;
474 links[i].num_platforms = ARRAY_SIZE(platform_component);
475 links[i].dpcm_playback = 1;
476 if (!drv_data->amp_codec_id) {
477 /* Use dummy codec if codec id not specified */
478 links[i].codecs = dummy_codec;
479 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
480 }
481 if (drv_data->amp_codec_id == RT1019) {
482 links[i].codecs = rt1019;
483 links[i].num_codecs = ARRAY_SIZE(rt1019);
484 links[i].ops = &acp_card_rt1019_ops;
485 links[i].init = acp_card_rt1019_init;
486 card->codec_conf = rt1019_conf;
487 card->num_configs = ARRAY_SIZE(rt1019_conf);
488 }
Ajit Kumar Pandeycabc3ac2021-10-19 12:39:37 +0530489 if (drv_data->amp_codec_id == MAX98360A) {
490 links[i].codecs = max98360a;
491 links[i].num_codecs = ARRAY_SIZE(max98360a);
492 links[i].ops = &acp_card_maxim_ops;
493 links[i].init = acp_card_maxim_init;
494 }
Ajit Kumar Pandeyd4c750f2021-10-19 12:39:34 +0530495 }
496
497 card->dai_link = links;
498 card->num_links = num_links;
499
500 return 0;
501}
502EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, SND_SOC_AMD_MACH);
503
504MODULE_LICENSE("GPL v2");