1 // 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 "../../codecs/rt5682s.h" 27 #include "acp-mach.h" 28 29 #define PCO_PLAT_CLK 48000000 30 #define RT5682_PLL_FREQ (48000 * 512) 31 #define DUAL_CHANNEL 2 32 #define FOUR_CHANNEL 4 33 34 static struct snd_soc_jack pco_jack; 35 36 static const unsigned int channels[] = { 37 DUAL_CHANNEL, 38 }; 39 40 static const unsigned int rates[] = { 41 48000, 42 }; 43 44 static const struct snd_pcm_hw_constraint_list constraints_rates = { 45 .count = ARRAY_SIZE(rates), 46 .list = rates, 47 .mask = 0, 48 }; 49 50 static const struct snd_pcm_hw_constraint_list constraints_channels = { 51 .count = ARRAY_SIZE(channels), 52 .list = channels, 53 .mask = 0, 54 }; 55 56 static int acp_clk_enable(struct acp_card_drvdata *drvdata) 57 { 58 clk_set_rate(drvdata->wclk, 48000); 59 clk_set_rate(drvdata->bclk, 48000 * 64); 60 61 return clk_prepare_enable(drvdata->wclk); 62 } 63 64 /* Declare RT5682 codec components */ 65 SND_SOC_DAILINK_DEF(rt5682, 66 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); 67 68 static const struct snd_soc_dapm_route rt5682_map[] = { 69 { "Headphone Jack", NULL, "HPOL" }, 70 { "Headphone Jack", NULL, "HPOR" }, 71 { "IN1P", NULL, "Headset Mic" }, 72 }; 73 74 int event_spkr_handler(struct snd_soc_dapm_widget *w, 75 struct snd_kcontrol *k, int event) 76 { 77 struct snd_soc_dapm_context *dapm = w->dapm; 78 struct snd_soc_card *card = dapm->card; 79 struct acp_card_drvdata *drvdata = snd_soc_card_get_drvdata(card); 80 81 if (!gpio_is_valid(drvdata->gpio_spkr_en)) 82 return 0; 83 84 switch (event) { 85 case SND_SOC_DAPM_POST_PMU: 86 gpio_set_value(drvdata->gpio_spkr_en, 1); 87 break; 88 case SND_SOC_DAPM_PRE_PMD: 89 gpio_set_value(drvdata->gpio_spkr_en, 0); 90 break; 91 default: 92 dev_warn(card->dev, "%s invalid setting\n", __func__); 93 break; 94 } 95 return 0; 96 } 97 EXPORT_SYMBOL_NS_GPL(event_spkr_handler, SND_SOC_AMD_MACH); 98 99 /* Define card ops for RT5682 CODEC */ 100 static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd) 101 { 102 struct snd_soc_card *card = rtd->card; 103 struct acp_card_drvdata *drvdata = card->drvdata; 104 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 105 struct snd_soc_component *component = codec_dai->component; 106 int ret; 107 108 dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); 109 110 if (drvdata->hs_codec_id != RT5682) 111 return -EINVAL; 112 113 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 114 | SND_SOC_DAIFMT_CBP_CFP); 115 if (ret < 0) { 116 dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); 117 return ret; 118 } 119 120 ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK, 121 PCO_PLAT_CLK, RT5682_PLL_FREQ); 122 if (ret < 0) { 123 dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret); 124 return ret; 125 } 126 127 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2, 128 RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); 129 if (ret < 0) { 130 dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret); 131 return ret; 132 } 133 134 /* Set tdm/i2s1 master bclk ratio */ 135 ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); 136 if (ret < 0) { 137 dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret); 138 return ret; 139 } 140 141 drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); 142 drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); 143 144 ret = snd_soc_card_jack_new(card, "Headset Jack", 145 SND_JACK_HEADSET | SND_JACK_LINEOUT | 146 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 147 SND_JACK_BTN_2 | SND_JACK_BTN_3, 148 &pco_jack, NULL, 0); 149 if (ret) { 150 dev_err(card->dev, "HP jack creation failed %d\n", ret); 151 return ret; 152 } 153 154 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 155 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 156 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 157 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 158 159 ret = snd_soc_component_set_jack(component, &pco_jack, NULL); 160 if (ret) { 161 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 162 return ret; 163 } 164 165 return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682_map, ARRAY_SIZE(rt5682_map)); 166 } 167 168 static int acp_card_hs_startup(struct snd_pcm_substream *substream) 169 { 170 struct snd_pcm_runtime *runtime = substream->runtime; 171 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 172 struct snd_soc_card *card = rtd->card; 173 struct acp_card_drvdata *drvdata = card->drvdata; 174 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 175 int ret; 176 177 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 178 | SND_SOC_DAIFMT_CBP_CFP); 179 if (ret < 0) { 180 dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); 181 return ret; 182 } 183 184 runtime->hw.channels_max = DUAL_CHANNEL; 185 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 186 &constraints_channels); 187 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 188 &constraints_rates); 189 190 ret = acp_clk_enable(drvdata); 191 if (ret < 0) 192 dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret); 193 194 return ret; 195 } 196 197 static void acp_card_shutdown(struct snd_pcm_substream *substream) 198 { 199 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 200 struct snd_soc_card *card = rtd->card; 201 struct acp_card_drvdata *drvdata = card->drvdata; 202 203 clk_disable_unprepare(drvdata->wclk); 204 } 205 206 static const struct snd_soc_ops acp_card_rt5682_ops = { 207 .startup = acp_card_hs_startup, 208 .shutdown = acp_card_shutdown, 209 }; 210 211 /* Define RT5682S CODEC component*/ 212 SND_SOC_DAILINK_DEF(rt5682s, 213 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RTL5682:00", "rt5682s-aif1"))); 214 215 static const struct snd_soc_dapm_route rt5682s_map[] = { 216 { "Headphone Jack", NULL, "HPOL" }, 217 { "Headphone Jack", NULL, "HPOR" }, 218 { "IN1P", NULL, "Headset Mic" }, 219 }; 220 221 static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) 222 { 223 struct snd_soc_card *card = rtd->card; 224 struct acp_card_drvdata *drvdata = card->drvdata; 225 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 226 struct snd_soc_component *component = codec_dai->component; 227 int ret; 228 229 dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); 230 231 if (drvdata->hs_codec_id != RT5682S) 232 return -EINVAL; 233 234 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 235 | SND_SOC_DAIFMT_CBP_CFP); 236 if (ret < 0) { 237 dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); 238 return ret; 239 } 240 241 ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK, 242 PCO_PLAT_CLK, RT5682_PLL_FREQ); 243 if (ret < 0) { 244 dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret); 245 return ret; 246 } 247 248 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2, 249 RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); 250 if (ret < 0) { 251 dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret); 252 return ret; 253 } 254 255 /* Set tdm/i2s1 master bclk ratio */ 256 ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); 257 if (ret < 0) { 258 dev_err(rtd->dev, "Failed to set rt5682 tdm bclk ratio: %d\n", ret); 259 return ret; 260 } 261 262 drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); 263 drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); 264 265 ret = snd_soc_card_jack_new(card, "Headset Jack", 266 SND_JACK_HEADSET | SND_JACK_LINEOUT | 267 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 268 SND_JACK_BTN_2 | SND_JACK_BTN_3, 269 &pco_jack, NULL, 0); 270 if (ret) { 271 dev_err(card->dev, "HP jack creation failed %d\n", ret); 272 return ret; 273 } 274 275 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 276 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 277 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 278 snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 279 280 ret = snd_soc_component_set_jack(component, &pco_jack, NULL); 281 if (ret) { 282 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 283 return ret; 284 } 285 286 return snd_soc_dapm_add_routes(&rtd->card->dapm, rt5682s_map, ARRAY_SIZE(rt5682s_map)); 287 } 288 289 static const struct snd_soc_ops acp_card_rt5682s_ops = { 290 .startup = acp_card_hs_startup, 291 .shutdown = acp_card_shutdown, 292 }; 293 294 static const unsigned int dmic_channels[] = { 295 DUAL_CHANNEL, FOUR_CHANNEL, 296 }; 297 298 static const struct snd_pcm_hw_constraint_list dmic_constraints_channels = { 299 .count = ARRAY_SIZE(dmic_channels), 300 .list = dmic_channels, 301 .mask = 0, 302 }; 303 304 static int acp_card_dmic_startup(struct snd_pcm_substream *substream) 305 { 306 struct snd_pcm_runtime *runtime = substream->runtime; 307 308 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 309 &dmic_constraints_channels); 310 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 311 &constraints_rates); 312 313 return 0; 314 } 315 316 static const struct snd_soc_ops acp_card_dmic_ops = { 317 .startup = acp_card_dmic_startup, 318 }; 319 320 /* Declare RT1019 codec components */ 321 SND_SOC_DAILINK_DEF(rt1019, 322 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1019:00", "rt1019-aif"), 323 COMP_CODEC("i2c-10EC1019:01", "rt1019-aif"))); 324 325 static const struct snd_soc_dapm_route rt1019_map_lr[] = { 326 { "Left Spk", NULL, "Left SPO" }, 327 { "Right Spk", NULL, "Right SPO" }, 328 }; 329 330 static struct snd_soc_codec_conf rt1019_conf[] = { 331 { 332 .dlc = COMP_CODEC_CONF("i2c-10EC1019:01"), 333 .name_prefix = "Left", 334 }, 335 { 336 .dlc = COMP_CODEC_CONF("i2c-10EC1019:00"), 337 .name_prefix = "Right", 338 }, 339 }; 340 341 static int acp_card_rt1019_init(struct snd_soc_pcm_runtime *rtd) 342 { 343 struct snd_soc_card *card = rtd->card; 344 struct acp_card_drvdata *drvdata = card->drvdata; 345 346 if (drvdata->amp_codec_id != RT1019) 347 return -EINVAL; 348 349 return snd_soc_dapm_add_routes(&rtd->card->dapm, rt1019_map_lr, 350 ARRAY_SIZE(rt1019_map_lr)); 351 } 352 353 static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream, 354 struct snd_pcm_hw_params *params) 355 { 356 struct snd_soc_pcm_runtime *rtd = substream->private_data; 357 struct snd_soc_card *card = rtd->card; 358 struct acp_card_drvdata *drvdata = card->drvdata; 359 struct snd_soc_dai *codec_dai; 360 int srate, i, ret = 0; 361 362 srate = params_rate(params); 363 364 if (drvdata->amp_codec_id != RT1019) 365 return -EINVAL; 366 367 for_each_rtd_codec_dais(rtd, i, codec_dai) { 368 if (strcmp(codec_dai->name, "rt1019-aif")) 369 continue; 370 371 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK, 372 64 * srate, 256 * srate); 373 if (ret < 0) 374 return ret; 375 376 ret = snd_soc_dai_set_sysclk(codec_dai, RT1019_SCLK_S_PLL, 377 256 * srate, SND_SOC_CLOCK_IN); 378 if (ret < 0) 379 return ret; 380 } 381 382 return 0; 383 } 384 385 static int acp_card_amp_startup(struct snd_pcm_substream *substream) 386 { 387 struct snd_pcm_runtime *runtime = substream->runtime; 388 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 389 struct snd_soc_card *card = rtd->card; 390 struct acp_card_drvdata *drvdata = card->drvdata; 391 int ret; 392 393 runtime->hw.channels_max = DUAL_CHANNEL; 394 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 395 &constraints_channels); 396 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 397 &constraints_rates); 398 399 ret = acp_clk_enable(drvdata); 400 if (ret < 0) 401 dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret); 402 403 return ret; 404 } 405 406 static const struct snd_soc_ops acp_card_rt1019_ops = { 407 .startup = acp_card_amp_startup, 408 .shutdown = acp_card_shutdown, 409 .hw_params = acp_card_rt1019_hw_params, 410 }; 411 412 /* Declare Maxim codec components */ 413 SND_SOC_DAILINK_DEF(max98360a, 414 DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi"))); 415 416 static const struct snd_soc_dapm_route max98360a_map[] = { 417 {"Spk", NULL, "Speaker"}, 418 }; 419 420 static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd) 421 { 422 struct snd_soc_card *card = rtd->card; 423 struct acp_card_drvdata *drvdata = card->drvdata; 424 425 if (drvdata->amp_codec_id != MAX98360A) 426 return -EINVAL; 427 428 return snd_soc_dapm_add_routes(&rtd->card->dapm, max98360a_map, 429 ARRAY_SIZE(max98360a_map)); 430 } 431 432 static const struct snd_soc_ops acp_card_maxim_ops = { 433 .startup = acp_card_amp_startup, 434 .shutdown = acp_card_shutdown, 435 }; 436 437 /* Declare DMIC codec components */ 438 SND_SOC_DAILINK_DEF(dmic_codec, 439 DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); 440 441 /* Declare ACP CPU components */ 442 static struct snd_soc_dai_link_component dummy_codec[] = { 443 { 444 .name = "snd-soc-dummy", 445 .dai_name = "snd-soc-dummy-dai", 446 } 447 }; 448 449 static struct snd_soc_dai_link_component platform_component[] = { 450 { 451 .name = "acp_asoc_renoir.0", 452 } 453 }; 454 455 static struct snd_soc_dai_link_component sof_component[] = { 456 { 457 .name = "0000:04:00.5", 458 } 459 }; 460 461 SND_SOC_DAILINK_DEF(i2s_sp, 462 DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp"))); 463 SND_SOC_DAILINK_DEF(sof_sp, 464 DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp"))); 465 SND_SOC_DAILINK_DEF(sof_dmic, 466 DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic"))); 467 SND_SOC_DAILINK_DEF(pdm_dmic, 468 DAILINK_COMP_ARRAY(COMP_CPU("acp-pdm-dmic"))); 469 470 int acp_sofdsp_dai_links_create(struct snd_soc_card *card) 471 { 472 struct snd_soc_dai_link *links; 473 struct device *dev = card->dev; 474 struct acp_card_drvdata *drv_data = card->drvdata; 475 int i = 0, num_links = 0; 476 477 if (drv_data->hs_cpu_id) 478 num_links++; 479 if (drv_data->amp_cpu_id) 480 num_links++; 481 if (drv_data->dmic_cpu_id) 482 num_links++; 483 484 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL); 485 if (!links) 486 return -ENOMEM; 487 488 if (drv_data->hs_cpu_id == I2S_SP) { 489 links[i].name = "acp-headset-codec"; 490 links[i].id = HEADSET_BE_ID; 491 links[i].cpus = sof_sp; 492 links[i].num_cpus = ARRAY_SIZE(sof_sp); 493 links[i].platforms = sof_component; 494 links[i].num_platforms = ARRAY_SIZE(sof_component); 495 links[i].dpcm_playback = 1; 496 links[i].dpcm_capture = 1; 497 links[i].nonatomic = true; 498 links[i].no_pcm = 1; 499 if (!drv_data->hs_codec_id) { 500 /* Use dummy codec if codec id not specified */ 501 links[i].codecs = dummy_codec; 502 links[i].num_codecs = ARRAY_SIZE(dummy_codec); 503 } 504 if (drv_data->hs_codec_id == RT5682) { 505 links[i].codecs = rt5682; 506 links[i].num_codecs = ARRAY_SIZE(rt5682); 507 links[i].init = acp_card_rt5682_init; 508 links[i].ops = &acp_card_rt5682_ops; 509 } 510 if (drv_data->hs_codec_id == RT5682S) { 511 links[i].codecs = rt5682s; 512 links[i].num_codecs = ARRAY_SIZE(rt5682s); 513 links[i].init = acp_card_rt5682s_init; 514 links[i].ops = &acp_card_rt5682s_ops; 515 } 516 i++; 517 } 518 519 if (drv_data->amp_cpu_id == I2S_SP) { 520 links[i].name = "acp-amp-codec"; 521 links[i].id = AMP_BE_ID; 522 links[i].cpus = sof_sp; 523 links[i].num_cpus = ARRAY_SIZE(sof_sp); 524 links[i].platforms = sof_component; 525 links[i].num_platforms = ARRAY_SIZE(sof_component); 526 links[i].dpcm_playback = 1; 527 links[i].nonatomic = true; 528 links[i].no_pcm = 1; 529 if (!drv_data->amp_codec_id) { 530 /* Use dummy codec if codec id not specified */ 531 links[i].codecs = dummy_codec; 532 links[i].num_codecs = ARRAY_SIZE(dummy_codec); 533 } 534 if (drv_data->amp_codec_id == RT1019) { 535 links[i].codecs = rt1019; 536 links[i].num_codecs = ARRAY_SIZE(rt1019); 537 links[i].ops = &acp_card_rt1019_ops; 538 links[i].init = acp_card_rt1019_init; 539 card->codec_conf = rt1019_conf; 540 card->num_configs = ARRAY_SIZE(rt1019_conf); 541 } 542 if (drv_data->amp_codec_id == MAX98360A) { 543 links[i].codecs = max98360a; 544 links[i].num_codecs = ARRAY_SIZE(max98360a); 545 links[i].ops = &acp_card_maxim_ops; 546 links[i].init = acp_card_maxim_init; 547 } 548 i++; 549 } 550 551 if (drv_data->dmic_cpu_id == DMIC) { 552 links[i].name = "acp-dmic-codec"; 553 links[i].id = DMIC_BE_ID; 554 links[i].codecs = dmic_codec; 555 links[i].num_codecs = ARRAY_SIZE(dmic_codec); 556 links[i].cpus = sof_dmic; 557 links[i].num_cpus = ARRAY_SIZE(sof_dmic); 558 links[i].platforms = sof_component; 559 links[i].num_platforms = ARRAY_SIZE(sof_component); 560 links[i].dpcm_capture = 1; 561 links[i].nonatomic = true; 562 links[i].no_pcm = 1; 563 } 564 565 card->dai_link = links; 566 card->num_links = num_links; 567 568 return 0; 569 } 570 EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, SND_SOC_AMD_MACH); 571 572 int acp_legacy_dai_links_create(struct snd_soc_card *card) 573 { 574 struct snd_soc_dai_link *links; 575 struct device *dev = card->dev; 576 struct acp_card_drvdata *drv_data = card->drvdata; 577 int i = 0, num_links = 0; 578 579 if (drv_data->hs_cpu_id) 580 num_links++; 581 if (drv_data->amp_cpu_id) 582 num_links++; 583 if (drv_data->dmic_cpu_id) 584 num_links++; 585 586 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL); 587 if (!links) 588 return -ENOMEM; 589 590 if (drv_data->hs_cpu_id == I2S_SP) { 591 links[i].name = "acp-headset-codec"; 592 links[i].id = HEADSET_BE_ID; 593 links[i].cpus = i2s_sp; 594 links[i].num_cpus = ARRAY_SIZE(i2s_sp); 595 links[i].platforms = platform_component; 596 links[i].num_platforms = ARRAY_SIZE(platform_component); 597 links[i].dpcm_playback = 1; 598 links[i].dpcm_capture = 1; 599 if (!drv_data->hs_codec_id) { 600 /* Use dummy codec if codec id not specified */ 601 links[i].codecs = dummy_codec; 602 links[i].num_codecs = ARRAY_SIZE(dummy_codec); 603 } 604 if (drv_data->hs_codec_id == RT5682) { 605 links[i].codecs = rt5682; 606 links[i].num_codecs = ARRAY_SIZE(rt5682); 607 links[i].init = acp_card_rt5682_init; 608 links[i].ops = &acp_card_rt5682_ops; 609 } 610 if (drv_data->hs_codec_id == RT5682S) { 611 links[i].codecs = rt5682s; 612 links[i].num_codecs = ARRAY_SIZE(rt5682s); 613 links[i].init = acp_card_rt5682s_init; 614 links[i].ops = &acp_card_rt5682s_ops; 615 } 616 i++; 617 } 618 619 if (drv_data->amp_cpu_id == I2S_SP) { 620 links[i].name = "acp-amp-codec"; 621 links[i].id = AMP_BE_ID; 622 links[i].cpus = i2s_sp; 623 links[i].num_cpus = ARRAY_SIZE(i2s_sp); 624 links[i].platforms = platform_component; 625 links[i].num_platforms = ARRAY_SIZE(platform_component); 626 links[i].dpcm_playback = 1; 627 if (!drv_data->amp_codec_id) { 628 /* Use dummy codec if codec id not specified */ 629 links[i].codecs = dummy_codec; 630 links[i].num_codecs = ARRAY_SIZE(dummy_codec); 631 } 632 if (drv_data->amp_codec_id == RT1019) { 633 links[i].codecs = rt1019; 634 links[i].num_codecs = ARRAY_SIZE(rt1019); 635 links[i].ops = &acp_card_rt1019_ops; 636 links[i].init = acp_card_rt1019_init; 637 card->codec_conf = rt1019_conf; 638 card->num_configs = ARRAY_SIZE(rt1019_conf); 639 } 640 if (drv_data->amp_codec_id == MAX98360A) { 641 links[i].codecs = max98360a; 642 links[i].num_codecs = ARRAY_SIZE(max98360a); 643 links[i].ops = &acp_card_maxim_ops; 644 links[i].init = acp_card_maxim_init; 645 } 646 i++; 647 } 648 649 if (drv_data->dmic_cpu_id == DMIC) { 650 links[i].name = "acp-dmic-codec"; 651 links[i].id = DMIC_BE_ID; 652 if (drv_data->dmic_codec_id == DMIC) { 653 links[i].codecs = dmic_codec; 654 links[i].num_codecs = ARRAY_SIZE(dmic_codec); 655 } else { 656 /* Use dummy codec if codec id not specified */ 657 links[i].codecs = dummy_codec; 658 links[i].num_codecs = ARRAY_SIZE(dummy_codec); 659 } 660 links[i].cpus = pdm_dmic; 661 links[i].num_cpus = ARRAY_SIZE(pdm_dmic); 662 links[i].platforms = platform_component; 663 links[i].num_platforms = ARRAY_SIZE(platform_component); 664 links[i].ops = &acp_card_dmic_ops; 665 links[i].dpcm_capture = 1; 666 } 667 668 card->dai_link = links; 669 card->num_links = num_links; 670 671 return 0; 672 } 673 EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, SND_SOC_AMD_MACH); 674 675 MODULE_LICENSE("GPL v2"); 676