blob: 76300dc6ad4ebda6ed7836e642a89c830bf03fcb [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
277/* Declare DMIC codec components */
278SND_SOC_DAILINK_DEF(dmic_codec,
279 DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
280
281/* Declare ACP CPU components */
282static struct snd_soc_dai_link_component dummy_codec[] = {
283 {
284 .name = "snd-soc-dummy",
285 .dai_name = "snd-soc-dummy-dai",
286 }
287};
288
289static struct snd_soc_dai_link_component platform_component[] = {
290 {
291 .name = "acp_asoc_renoir.0",
292 }
293};
294
295static struct snd_soc_dai_link_component sof_component[] = {
296 {
297 .name = "0000:04:00.5",
298 }
299};
300
301SND_SOC_DAILINK_DEF(i2s_sp,
302 DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
303SND_SOC_DAILINK_DEF(sof_sp,
304 DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
305SND_SOC_DAILINK_DEF(sof_dmic,
306 DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
307
308int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
309{
310 struct snd_soc_dai_link *links;
311 struct device *dev = card->dev;
312 struct acp_card_drvdata *drv_data = card->drvdata;
313 int i = 0, num_links = 0;
314
315 if (drv_data->hs_cpu_id)
316 num_links++;
317 if (drv_data->amp_cpu_id)
318 num_links++;
319 if (drv_data->dmic_cpu_id)
320 num_links++;
321
322 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
323 if (!links)
324 return -ENOMEM;
325
326 if (drv_data->hs_cpu_id == I2S_SP) {
327 links[i].name = "acp-headset-codec";
328 links[i].id = HEADSET_BE_ID;
329 links[i].cpus = sof_sp;
330 links[i].num_cpus = ARRAY_SIZE(sof_sp);
331 links[i].platforms = sof_component;
332 links[i].num_platforms = ARRAY_SIZE(sof_component);
333 links[i].dpcm_playback = 1;
334 links[i].dpcm_capture = 1;
335 links[i].nonatomic = true;
336 links[i].no_pcm = 1;
337 if (!drv_data->hs_codec_id) {
338 /* Use dummy codec if codec id not specified */
339 links[i].codecs = dummy_codec;
340 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
341 }
342 if (drv_data->hs_codec_id == RT5682) {
343 links[i].codecs = rt5682;
344 links[i].num_codecs = ARRAY_SIZE(rt5682);
345 links[i].init = acp_card_rt5682_init;
346 links[i].ops = &acp_card_rt5682_ops;
347 }
348 i++;
349 }
350
351 if (drv_data->amp_cpu_id == I2S_SP) {
352 links[i].name = "acp-amp-codec";
353 links[i].id = AMP_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].nonatomic = true;
360 links[i].no_pcm = 1;
361 if (!drv_data->amp_codec_id) {
362 /* Use dummy codec if codec id not specified */
363 links[i].codecs = dummy_codec;
364 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
365 }
366 if (drv_data->amp_codec_id == RT1019) {
367 links[i].codecs = rt1019;
368 links[i].num_codecs = ARRAY_SIZE(rt1019);
369 links[i].ops = &acp_card_rt1019_ops;
370 links[i].init = acp_card_rt1019_init;
371 card->codec_conf = rt1019_conf;
372 card->num_configs = ARRAY_SIZE(rt1019_conf);
373 }
374 i++;
375 }
376
377 if (drv_data->dmic_cpu_id == DMIC) {
378 links[i].name = "acp-dmic-codec";
379 links[i].id = DMIC_BE_ID;
380 links[i].codecs = dmic_codec;
381 links[i].num_codecs = ARRAY_SIZE(dmic_codec);
382 links[i].cpus = sof_dmic;
383 links[i].num_cpus = ARRAY_SIZE(sof_dmic);
384 links[i].platforms = sof_component;
385 links[i].num_platforms = ARRAY_SIZE(sof_component);
386 links[i].dpcm_capture = 1;
387 links[i].nonatomic = true;
388 links[i].no_pcm = 1;
389 }
390
391 card->dai_link = links;
392 card->num_links = num_links;
393
394 return 0;
395}
396EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, SND_SOC_AMD_MACH);
397
398int acp_legacy_dai_links_create(struct snd_soc_card *card)
399{
400 struct snd_soc_dai_link *links;
401 struct device *dev = card->dev;
402 struct acp_card_drvdata *drv_data = card->drvdata;
403 int i = 0, num_links = 0;
404
405 if (drv_data->hs_cpu_id)
406 num_links++;
407 if (drv_data->amp_cpu_id)
408 num_links++;
409 if (drv_data->dmic_cpu_id)
410 num_links++;
411
412 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
413
414 if (drv_data->hs_cpu_id == I2S_SP) {
415 links[i].name = "acp-headset-codec";
416 links[i].id = HEADSET_BE_ID;
417 links[i].cpus = i2s_sp;
418 links[i].num_cpus = ARRAY_SIZE(i2s_sp);
419 links[i].platforms = platform_component;
420 links[i].num_platforms = ARRAY_SIZE(platform_component);
421 links[i].dpcm_playback = 1;
422 links[i].dpcm_capture = 1;
423 if (!drv_data->hs_codec_id) {
424 /* Use dummy codec if codec id not specified */
425 links[i].codecs = dummy_codec;
426 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
427 }
428 if (drv_data->hs_codec_id == RT5682) {
429 links[i].codecs = rt5682;
430 links[i].num_codecs = ARRAY_SIZE(rt5682);
431 links[i].init = acp_card_rt5682_init;
432 links[i].ops = &acp_card_rt5682_ops;
433 }
434 i++;
435 }
436
437 if (drv_data->amp_cpu_id == I2S_SP) {
438 links[i].name = "acp-amp-codec";
439 links[i].id = AMP_BE_ID;
440 links[i].cpus = i2s_sp;
441 links[i].num_cpus = ARRAY_SIZE(i2s_sp);
442 links[i].platforms = platform_component;
443 links[i].num_platforms = ARRAY_SIZE(platform_component);
444 links[i].dpcm_playback = 1;
445 if (!drv_data->amp_codec_id) {
446 /* Use dummy codec if codec id not specified */
447 links[i].codecs = dummy_codec;
448 links[i].num_codecs = ARRAY_SIZE(dummy_codec);
449 }
450 if (drv_data->amp_codec_id == RT1019) {
451 links[i].codecs = rt1019;
452 links[i].num_codecs = ARRAY_SIZE(rt1019);
453 links[i].ops = &acp_card_rt1019_ops;
454 links[i].init = acp_card_rt1019_init;
455 card->codec_conf = rt1019_conf;
456 card->num_configs = ARRAY_SIZE(rt1019_conf);
457 }
458 }
459
460 card->dai_link = links;
461 card->num_links = num_links;
462
463 return 0;
464}
465EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, SND_SOC_AMD_MACH);
466
467MODULE_LICENSE("GPL v2");