1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com 4 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/platform_device.h> 11 12 #include <sound/core.h> 13 #include <sound/pcm.h> 14 #include <sound/pcm_params.h> 15 #include <sound/soc.h> 16 17 #include "davinci-mcasp.h" 18 19 /* 20 * Maximum number of configuration entries for prefixes: 21 * CPB: 2 (mcasp10 + codec) 22 * IVI: 3 (mcasp0 + 2x codec) 23 */ 24 #define J721E_CODEC_CONF_COUNT 5 25 26 #define J721E_AUDIO_DOMAIN_CPB 0 27 #define J721E_AUDIO_DOMAIN_IVI 1 28 29 #define J721E_CLK_PARENT_48000 0 30 #define J721E_CLK_PARENT_44100 1 31 32 #define J721E_MAX_CLK_HSDIV 128 33 #define PCM1368A_MAX_SYSCLK 36864000 34 35 #define J721E_DAI_FMT (SND_SOC_DAIFMT_RIGHT_J | \ 36 SND_SOC_DAIFMT_NB_NF | \ 37 SND_SOC_DAIFMT_CBS_CFS) 38 39 enum j721e_board_type { 40 J721E_BOARD_CPB = 1, 41 J721E_BOARD_CPB_IVI, 42 }; 43 44 struct j721e_audio_match_data { 45 enum j721e_board_type board_type; 46 int num_links; 47 unsigned int pll_rates[2]; 48 }; 49 50 static unsigned int ratios_for_pcm3168a[] = { 51 256, 52 512, 53 768, 54 }; 55 56 struct j721e_audio_clocks { 57 struct clk *target; 58 struct clk *parent[2]; 59 }; 60 61 struct j721e_audio_domain { 62 struct j721e_audio_clocks codec; 63 struct j721e_audio_clocks mcasp; 64 int parent_clk_id; 65 66 int active; 67 unsigned int active_link; 68 unsigned int rate; 69 }; 70 71 struct j721e_priv { 72 struct device *dev; 73 struct snd_soc_card card; 74 struct snd_soc_dai_link *dai_links; 75 struct snd_soc_codec_conf codec_conf[J721E_CODEC_CONF_COUNT]; 76 struct snd_interval rate_range; 77 const struct j721e_audio_match_data *match_data; 78 u32 pll_rates[2]; 79 unsigned int hsdiv_rates[2]; 80 81 struct j721e_audio_domain audio_domains[2]; 82 83 struct mutex mutex; 84 }; 85 86 static const struct snd_soc_dapm_widget j721e_cpb_dapm_widgets[] = { 87 SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL), 88 SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL), 89 SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL), 90 SND_SOC_DAPM_LINE("CPB Line Out", NULL), 91 SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL), 92 SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL), 93 SND_SOC_DAPM_LINE("CPB Line In", NULL), 94 }; 95 96 static const struct snd_soc_dapm_route j721e_cpb_dapm_routes[] = { 97 {"CPB Stereo HP 1", NULL, "codec-1 AOUT1L"}, 98 {"CPB Stereo HP 1", NULL, "codec-1 AOUT1R"}, 99 {"CPB Stereo HP 2", NULL, "codec-1 AOUT2L"}, 100 {"CPB Stereo HP 2", NULL, "codec-1 AOUT2R"}, 101 {"CPB Stereo HP 3", NULL, "codec-1 AOUT3L"}, 102 {"CPB Stereo HP 3", NULL, "codec-1 AOUT3R"}, 103 {"CPB Line Out", NULL, "codec-1 AOUT4L"}, 104 {"CPB Line Out", NULL, "codec-1 AOUT4R"}, 105 106 {"codec-1 AIN1L", NULL, "CPB Stereo Mic 1"}, 107 {"codec-1 AIN1R", NULL, "CPB Stereo Mic 1"}, 108 {"codec-1 AIN2L", NULL, "CPB Stereo Mic 2"}, 109 {"codec-1 AIN2R", NULL, "CPB Stereo Mic 2"}, 110 {"codec-1 AIN3L", NULL, "CPB Line In"}, 111 {"codec-1 AIN3R", NULL, "CPB Line In"}, 112 }; 113 114 static const struct snd_soc_dapm_widget j721e_ivi_codec_a_dapm_widgets[] = { 115 SND_SOC_DAPM_LINE("IVI A Line Out 1", NULL), 116 SND_SOC_DAPM_LINE("IVI A Line Out 2", NULL), 117 SND_SOC_DAPM_LINE("IVI A Line Out 3", NULL), 118 SND_SOC_DAPM_LINE("IVI A Line Out 4", NULL), 119 SND_SOC_DAPM_MIC("IVI A Stereo Mic 1", NULL), 120 SND_SOC_DAPM_MIC("IVI A Stereo Mic 2", NULL), 121 SND_SOC_DAPM_LINE("IVI A Line In", NULL), 122 }; 123 124 static const struct snd_soc_dapm_route j721e_codec_a_dapm_routes[] = { 125 {"IVI A Line Out 1", NULL, "codec-a AOUT1L"}, 126 {"IVI A Line Out 1", NULL, "codec-a AOUT1R"}, 127 {"IVI A Line Out 2", NULL, "codec-a AOUT2L"}, 128 {"IVI A Line Out 2", NULL, "codec-a AOUT2R"}, 129 {"IVI A Line Out 3", NULL, "codec-a AOUT3L"}, 130 {"IVI A Line Out 3", NULL, "codec-a AOUT3R"}, 131 {"IVI A Line Out 4", NULL, "codec-a AOUT4L"}, 132 {"IVI A Line Out 4", NULL, "codec-a AOUT4R"}, 133 134 {"codec-a AIN1L", NULL, "IVI A Stereo Mic 1"}, 135 {"codec-a AIN1R", NULL, "IVI A Stereo Mic 1"}, 136 {"codec-a AIN2L", NULL, "IVI A Stereo Mic 2"}, 137 {"codec-a AIN2R", NULL, "IVI A Stereo Mic 2"}, 138 {"codec-a AIN3L", NULL, "IVI A Line In"}, 139 {"codec-a AIN3R", NULL, "IVI A Line In"}, 140 }; 141 142 static const struct snd_soc_dapm_widget j721e_ivi_codec_b_dapm_widgets[] = { 143 SND_SOC_DAPM_LINE("IVI B Line Out 1", NULL), 144 SND_SOC_DAPM_LINE("IVI B Line Out 2", NULL), 145 SND_SOC_DAPM_LINE("IVI B Line Out 3", NULL), 146 SND_SOC_DAPM_LINE("IVI B Line Out 4", NULL), 147 SND_SOC_DAPM_MIC("IVI B Stereo Mic 1", NULL), 148 SND_SOC_DAPM_MIC("IVI B Stereo Mic 2", NULL), 149 SND_SOC_DAPM_LINE("IVI B Line In", NULL), 150 }; 151 152 static const struct snd_soc_dapm_route j721e_codec_b_dapm_routes[] = { 153 {"IVI B Line Out 1", NULL, "codec-b AOUT1L"}, 154 {"IVI B Line Out 1", NULL, "codec-b AOUT1R"}, 155 {"IVI B Line Out 2", NULL, "codec-b AOUT2L"}, 156 {"IVI B Line Out 2", NULL, "codec-b AOUT2R"}, 157 {"IVI B Line Out 3", NULL, "codec-b AOUT3L"}, 158 {"IVI B Line Out 3", NULL, "codec-b AOUT3R"}, 159 {"IVI B Line Out 4", NULL, "codec-b AOUT4L"}, 160 {"IVI B Line Out 4", NULL, "codec-b AOUT4R"}, 161 162 {"codec-b AIN1L", NULL, "IVI B Stereo Mic 1"}, 163 {"codec-b AIN1R", NULL, "IVI B Stereo Mic 1"}, 164 {"codec-b AIN2L", NULL, "IVI B Stereo Mic 2"}, 165 {"codec-b AIN2R", NULL, "IVI B Stereo Mic 2"}, 166 {"codec-b AIN3L", NULL, "IVI B Line In"}, 167 {"codec-b AIN3R", NULL, "IVI B Line In"}, 168 }; 169 170 static int j721e_configure_refclk(struct j721e_priv *priv, 171 unsigned int audio_domain, unsigned int rate) 172 { 173 struct j721e_audio_domain *domain = &priv->audio_domains[audio_domain]; 174 unsigned int scki; 175 int ret = -EINVAL; 176 int i, clk_id; 177 178 if (!(rate % 8000) && priv->pll_rates[J721E_CLK_PARENT_48000]) 179 clk_id = J721E_CLK_PARENT_48000; 180 else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_44100]) 181 clk_id = J721E_CLK_PARENT_44100; 182 else 183 return ret; 184 185 for (i = 0; i < ARRAY_SIZE(ratios_for_pcm3168a); i++) { 186 scki = ratios_for_pcm3168a[i] * rate; 187 188 if (priv->pll_rates[clk_id] / scki <= J721E_MAX_CLK_HSDIV) { 189 ret = 0; 190 break; 191 } 192 } 193 194 if (ret) { 195 dev_err(priv->dev, "No valid clock configuration for %u Hz\n", 196 rate); 197 return ret; 198 } 199 200 if (domain->parent_clk_id == -1 || priv->hsdiv_rates[domain->parent_clk_id] != scki) { 201 dev_dbg(priv->dev, 202 "%s configuration for %u Hz: %s, %dxFS (SCKI: %u Hz)\n", 203 audio_domain == J721E_AUDIO_DOMAIN_CPB ? "CPB" : "IVI", 204 rate, 205 clk_id == J721E_CLK_PARENT_48000 ? "PLL4" : "PLL15", 206 ratios_for_pcm3168a[i], scki); 207 208 if (domain->parent_clk_id != clk_id) { 209 ret = clk_set_parent(domain->codec.target, 210 domain->codec.parent[clk_id]); 211 if (ret) 212 return ret; 213 214 ret = clk_set_parent(domain->mcasp.target, 215 domain->mcasp.parent[clk_id]); 216 if (ret) 217 return ret; 218 219 domain->parent_clk_id = clk_id; 220 } 221 222 ret = clk_set_rate(domain->codec.target, scki); 223 if (ret) { 224 dev_err(priv->dev, "codec set rate failed for %u Hz\n", 225 scki); 226 return ret; 227 } 228 229 ret = clk_set_rate(domain->mcasp.target, scki); 230 if (!ret) { 231 priv->hsdiv_rates[domain->parent_clk_id] = scki; 232 } else { 233 dev_err(priv->dev, "mcasp set rate failed for %u Hz\n", 234 scki); 235 return ret; 236 } 237 } 238 239 return ret; 240 } 241 242 static int j721e_rule_rate(struct snd_pcm_hw_params *params, 243 struct snd_pcm_hw_rule *rule) 244 { 245 struct snd_interval *t = rule->private; 246 247 return snd_interval_refine(hw_param_interval(params, rule->var), t); 248 } 249 250 static int j721e_audio_startup(struct snd_pcm_substream *substream) 251 { 252 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 253 struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card); 254 unsigned int domain_id = rtd->dai_link->id; 255 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 256 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 257 struct snd_soc_dai *codec_dai; 258 unsigned int active_rate; 259 int ret = 0; 260 int i; 261 262 mutex_lock(&priv->mutex); 263 264 domain->active++; 265 266 if (priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].rate) 267 active_rate = priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].rate; 268 else 269 active_rate = priv->audio_domains[J721E_AUDIO_DOMAIN_IVI].rate; 270 271 if (active_rate) 272 ret = snd_pcm_hw_constraint_single(substream->runtime, 273 SNDRV_PCM_HW_PARAM_RATE, 274 active_rate); 275 else 276 ret = snd_pcm_hw_rule_add(substream->runtime, 0, 277 SNDRV_PCM_HW_PARAM_RATE, 278 j721e_rule_rate, &priv->rate_range, 279 SNDRV_PCM_HW_PARAM_RATE, -1); 280 281 282 if (ret) 283 goto out; 284 285 /* Reset TDM slots to 32 */ 286 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32); 287 if (ret && ret != -ENOTSUPP) 288 goto out; 289 290 for_each_rtd_codec_dais(rtd, i, codec_dai) { 291 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32); 292 if (ret && ret != -ENOTSUPP) 293 goto out; 294 } 295 296 if (ret == -ENOTSUPP) 297 ret = 0; 298 out: 299 if (ret) 300 domain->active--; 301 mutex_unlock(&priv->mutex); 302 303 return ret; 304 } 305 306 static int j721e_audio_hw_params(struct snd_pcm_substream *substream, 307 struct snd_pcm_hw_params *params) 308 { 309 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 310 struct snd_soc_card *card = rtd->card; 311 struct j721e_priv *priv = snd_soc_card_get_drvdata(card); 312 unsigned int domain_id = rtd->dai_link->id; 313 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 314 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 315 struct snd_soc_dai *codec_dai; 316 unsigned int sysclk_rate; 317 int slot_width = 32; 318 int ret; 319 int i; 320 321 mutex_lock(&priv->mutex); 322 323 if (domain->rate && domain->rate != params_rate(params)) { 324 ret = -EINVAL; 325 goto out; 326 } 327 328 if (params_width(params) == 16) 329 slot_width = 16; 330 331 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, slot_width); 332 if (ret && ret != -ENOTSUPP) 333 goto out; 334 335 for_each_rtd_codec_dais(rtd, i, codec_dai) { 336 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 337 slot_width); 338 if (ret && ret != -ENOTSUPP) 339 goto out; 340 } 341 342 ret = j721e_configure_refclk(priv, domain_id, params_rate(params)); 343 if (ret) 344 goto out; 345 346 sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id]; 347 for_each_rtd_codec_dais(rtd, i, codec_dai) { 348 ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate, 349 SND_SOC_CLOCK_IN); 350 if (ret && ret != -ENOTSUPP) { 351 dev_err(priv->dev, 352 "codec set_sysclk failed for %u Hz\n", 353 sysclk_rate); 354 goto out; 355 } 356 } 357 358 ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK, 359 sysclk_rate, SND_SOC_CLOCK_IN); 360 361 if (ret && ret != -ENOTSUPP) { 362 dev_err(priv->dev, "mcasp set_sysclk failed for %u Hz\n", 363 sysclk_rate); 364 } else { 365 domain->rate = params_rate(params); 366 ret = 0; 367 } 368 369 out: 370 mutex_unlock(&priv->mutex); 371 return ret; 372 } 373 374 static void j721e_audio_shutdown(struct snd_pcm_substream *substream) 375 { 376 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 377 struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card); 378 unsigned int domain_id = rtd->dai_link->id; 379 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 380 381 mutex_lock(&priv->mutex); 382 383 domain->active--; 384 if (!domain->active) { 385 domain->rate = 0; 386 domain->active_link = 0; 387 } 388 389 mutex_unlock(&priv->mutex); 390 } 391 392 static const struct snd_soc_ops j721e_audio_ops = { 393 .startup = j721e_audio_startup, 394 .hw_params = j721e_audio_hw_params, 395 .shutdown = j721e_audio_shutdown, 396 }; 397 398 static int j721e_audio_init(struct snd_soc_pcm_runtime *rtd) 399 { 400 struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card); 401 unsigned int domain_id = rtd->dai_link->id; 402 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 403 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 404 struct snd_soc_dai *codec_dai; 405 unsigned int sysclk_rate; 406 int i, ret; 407 408 /* Set up initial clock configuration */ 409 ret = j721e_configure_refclk(priv, domain_id, 48000); 410 if (ret) 411 return ret; 412 413 sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id]; 414 for_each_rtd_codec_dais(rtd, i, codec_dai) { 415 ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate, 416 SND_SOC_CLOCK_IN); 417 if (ret && ret != -ENOTSUPP) 418 return ret; 419 } 420 421 ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK, 422 sysclk_rate, SND_SOC_CLOCK_IN); 423 if (ret && ret != -ENOTSUPP) 424 return ret; 425 426 /* Set initial tdm slots */ 427 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32); 428 if (ret && ret != -ENOTSUPP) 429 return ret; 430 431 for_each_rtd_codec_dais(rtd, i, codec_dai) { 432 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32); 433 if (ret && ret != -ENOTSUPP) 434 return ret; 435 } 436 437 return 0; 438 } 439 440 static int j721e_audio_init_ivi(struct snd_soc_pcm_runtime *rtd) 441 { 442 struct snd_soc_dapm_context *dapm = &rtd->card->dapm; 443 444 snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_a_dapm_widgets, 445 ARRAY_SIZE(j721e_ivi_codec_a_dapm_widgets)); 446 snd_soc_dapm_add_routes(dapm, j721e_codec_a_dapm_routes, 447 ARRAY_SIZE(j721e_codec_a_dapm_routes)); 448 snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_b_dapm_widgets, 449 ARRAY_SIZE(j721e_ivi_codec_b_dapm_widgets)); 450 snd_soc_dapm_add_routes(dapm, j721e_codec_b_dapm_routes, 451 ARRAY_SIZE(j721e_codec_b_dapm_routes)); 452 453 return j721e_audio_init(rtd); 454 } 455 456 static int j721e_get_clocks(struct device *dev, 457 struct j721e_audio_clocks *clocks, char *prefix) 458 { 459 struct clk *parent; 460 char *clk_name; 461 int ret; 462 463 clocks->target = devm_clk_get(dev, prefix); 464 if (IS_ERR(clocks->target)) { 465 ret = PTR_ERR(clocks->target); 466 if (ret != -EPROBE_DEFER) 467 dev_err(dev, "failed to acquire %s: %d\n", 468 prefix, ret); 469 return ret; 470 } 471 472 clk_name = kasprintf(GFP_KERNEL, "%s-48000", prefix); 473 if (clk_name) { 474 parent = devm_clk_get(dev, clk_name); 475 kfree(clk_name); 476 if (IS_ERR(parent)) { 477 ret = PTR_ERR(parent); 478 if (ret == -EPROBE_DEFER) 479 return ret; 480 481 dev_dbg(dev, "no 48KHz parent for %s: %d\n", prefix, ret); 482 parent = NULL; 483 } 484 clocks->parent[J721E_CLK_PARENT_48000] = parent; 485 } else { 486 return -ENOMEM; 487 } 488 489 clk_name = kasprintf(GFP_KERNEL, "%s-44100", prefix); 490 if (clk_name) { 491 parent = devm_clk_get(dev, clk_name); 492 kfree(clk_name); 493 if (IS_ERR(parent)) { 494 ret = PTR_ERR(parent); 495 if (ret == -EPROBE_DEFER) 496 return ret; 497 498 dev_dbg(dev, "no 44.1KHz parent for %s: %d\n", prefix, ret); 499 parent = NULL; 500 } 501 clocks->parent[J721E_CLK_PARENT_44100] = parent; 502 } else { 503 return -ENOMEM; 504 } 505 506 if (!clocks->parent[J721E_CLK_PARENT_44100] && 507 !clocks->parent[J721E_CLK_PARENT_48000]) { 508 dev_err(dev, "At least one parent clock is needed for %s\n", 509 prefix); 510 return -EINVAL; 511 } 512 513 return 0; 514 } 515 516 static const struct j721e_audio_match_data j721e_cpb_data = { 517 .board_type = J721E_BOARD_CPB, 518 .num_links = 2, /* CPB pcm3168a */ 519 .pll_rates = { 520 [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */ 521 [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */ 522 }, 523 }; 524 525 static const struct j721e_audio_match_data j721e_cpb_ivi_data = { 526 .board_type = J721E_BOARD_CPB_IVI, 527 .num_links = 4, /* CPB pcm3168a + 2x pcm3168a on IVI */ 528 .pll_rates = { 529 [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */ 530 [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */ 531 }, 532 }; 533 534 static const struct j721e_audio_match_data j7200_cpb_data = { 535 .board_type = J721E_BOARD_CPB, 536 .num_links = 2, /* CPB pcm3168a */ 537 .pll_rates = { 538 [J721E_CLK_PARENT_48000] = 2359296000u, /* PLL4 */ 539 }, 540 }; 541 542 static const struct of_device_id j721e_audio_of_match[] = { 543 { 544 .compatible = "ti,j721e-cpb-audio", 545 .data = &j721e_cpb_data, 546 }, { 547 .compatible = "ti,j721e-cpb-ivi-audio", 548 .data = &j721e_cpb_ivi_data, 549 }, { 550 .compatible = "ti,j7200-cpb-audio", 551 .data = &j7200_cpb_data, 552 }, 553 { }, 554 }; 555 MODULE_DEVICE_TABLE(of, j721e_audio_of_match); 556 557 static int j721e_calculate_rate_range(struct j721e_priv *priv) 558 { 559 const struct j721e_audio_match_data *match_data = priv->match_data; 560 struct j721e_audio_clocks *domain_clocks; 561 unsigned int min_rate, max_rate, pll_rate; 562 struct clk *pll; 563 564 domain_clocks = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].mcasp; 565 566 pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_44100]); 567 if (IS_ERR_OR_NULL(pll)) { 568 priv->pll_rates[J721E_CLK_PARENT_44100] = 569 match_data->pll_rates[J721E_CLK_PARENT_44100]; 570 } else { 571 priv->pll_rates[J721E_CLK_PARENT_44100] = clk_get_rate(pll); 572 clk_put(pll); 573 } 574 575 pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_48000]); 576 if (IS_ERR_OR_NULL(pll)) { 577 priv->pll_rates[J721E_CLK_PARENT_48000] = 578 match_data->pll_rates[J721E_CLK_PARENT_48000]; 579 } else { 580 priv->pll_rates[J721E_CLK_PARENT_48000] = clk_get_rate(pll); 581 clk_put(pll); 582 } 583 584 if (!priv->pll_rates[J721E_CLK_PARENT_44100] && 585 !priv->pll_rates[J721E_CLK_PARENT_48000]) { 586 dev_err(priv->dev, "At least one PLL is needed\n"); 587 return -EINVAL; 588 } 589 590 if (priv->pll_rates[J721E_CLK_PARENT_44100]) 591 pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100]; 592 else 593 pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000]; 594 595 min_rate = pll_rate / J721E_MAX_CLK_HSDIV; 596 min_rate /= ratios_for_pcm3168a[ARRAY_SIZE(ratios_for_pcm3168a) - 1]; 597 598 if (priv->pll_rates[J721E_CLK_PARENT_48000]) 599 pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000]; 600 else 601 pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100]; 602 603 if (pll_rate > PCM1368A_MAX_SYSCLK) 604 pll_rate = PCM1368A_MAX_SYSCLK; 605 606 max_rate = pll_rate / ratios_for_pcm3168a[0]; 607 608 snd_interval_any(&priv->rate_range); 609 priv->rate_range.min = min_rate; 610 priv->rate_range.max = max_rate; 611 612 return 0; 613 } 614 615 static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx, 616 int *conf_idx) 617 { 618 struct device_node *node = priv->dev->of_node; 619 struct snd_soc_dai_link_component *compnent; 620 struct device_node *dai_node, *codec_node; 621 struct j721e_audio_domain *domain; 622 int comp_count, comp_idx; 623 int ret; 624 625 dai_node = of_parse_phandle(node, "ti,cpb-mcasp", 0); 626 if (!dai_node) { 627 dev_err(priv->dev, "CPB McASP node is not provided\n"); 628 return -EINVAL; 629 } 630 631 codec_node = of_parse_phandle(node, "ti,cpb-codec", 0); 632 if (!codec_node) { 633 dev_err(priv->dev, "CPB codec node is not provided\n"); 634 return -EINVAL; 635 } 636 637 domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB]; 638 ret = j721e_get_clocks(priv->dev, &domain->codec, "cpb-codec-scki"); 639 if (ret) 640 return ret; 641 642 ret = j721e_get_clocks(priv->dev, &domain->mcasp, "cpb-mcasp-auxclk"); 643 if (ret) 644 return ret; 645 646 /* 647 * Common Processor Board, two links 648 * Link 1: McASP10 -> pcm3168a_1 DAC 649 * Link 2: McASP10 <- pcm3168a_1 ADC 650 */ 651 comp_count = 6; 652 compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent), 653 GFP_KERNEL); 654 if (!compnent) 655 return -ENOMEM; 656 657 comp_idx = 0; 658 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 659 priv->dai_links[*link_idx].num_cpus = 1; 660 priv->dai_links[*link_idx].codecs = &compnent[comp_idx++]; 661 priv->dai_links[*link_idx].num_codecs = 1; 662 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 663 priv->dai_links[*link_idx].num_platforms = 1; 664 665 priv->dai_links[*link_idx].name = "CPB PCM3168A Playback"; 666 priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog"; 667 priv->dai_links[*link_idx].cpus->of_node = dai_node; 668 priv->dai_links[*link_idx].platforms->of_node = dai_node; 669 priv->dai_links[*link_idx].codecs->of_node = codec_node; 670 priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-dac"; 671 priv->dai_links[*link_idx].playback_only = 1; 672 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB; 673 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 674 priv->dai_links[*link_idx].init = j721e_audio_init; 675 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 676 (*link_idx)++; 677 678 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 679 priv->dai_links[*link_idx].num_cpus = 1; 680 priv->dai_links[*link_idx].codecs = &compnent[comp_idx++]; 681 priv->dai_links[*link_idx].num_codecs = 1; 682 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 683 priv->dai_links[*link_idx].num_platforms = 1; 684 685 priv->dai_links[*link_idx].name = "CPB PCM3168A Capture"; 686 priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog"; 687 priv->dai_links[*link_idx].cpus->of_node = dai_node; 688 priv->dai_links[*link_idx].platforms->of_node = dai_node; 689 priv->dai_links[*link_idx].codecs->of_node = codec_node; 690 priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-adc"; 691 priv->dai_links[*link_idx].capture_only = 1; 692 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB; 693 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 694 priv->dai_links[*link_idx].init = j721e_audio_init; 695 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 696 (*link_idx)++; 697 698 priv->codec_conf[*conf_idx].dlc.of_node = codec_node; 699 priv->codec_conf[*conf_idx].name_prefix = "codec-1"; 700 (*conf_idx)++; 701 priv->codec_conf[*conf_idx].dlc.of_node = dai_node; 702 priv->codec_conf[*conf_idx].name_prefix = "McASP10"; 703 (*conf_idx)++; 704 705 return 0; 706 } 707 708 static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx, 709 int *conf_idx) 710 { 711 struct device_node *node = priv->dev->of_node; 712 struct snd_soc_dai_link_component *compnent; 713 struct device_node *dai_node, *codeca_node, *codecb_node; 714 struct j721e_audio_domain *domain; 715 int comp_count, comp_idx; 716 int ret; 717 718 if (priv->match_data->board_type != J721E_BOARD_CPB_IVI) 719 return 0; 720 721 dai_node = of_parse_phandle(node, "ti,ivi-mcasp", 0); 722 if (!dai_node) { 723 dev_err(priv->dev, "IVI McASP node is not provided\n"); 724 return -EINVAL; 725 } 726 727 codeca_node = of_parse_phandle(node, "ti,ivi-codec-a", 0); 728 if (!codeca_node) { 729 dev_err(priv->dev, "IVI codec-a node is not provided\n"); 730 return -EINVAL; 731 } 732 733 codecb_node = of_parse_phandle(node, "ti,ivi-codec-b", 0); 734 if (!codecb_node) { 735 dev_warn(priv->dev, "IVI codec-b node is not provided\n"); 736 return 0; 737 } 738 739 domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_IVI]; 740 ret = j721e_get_clocks(priv->dev, &domain->codec, "ivi-codec-scki"); 741 if (ret) 742 return ret; 743 744 ret = j721e_get_clocks(priv->dev, &domain->mcasp, "ivi-mcasp-auxclk"); 745 if (ret) 746 return ret; 747 748 /* 749 * IVI extension, two links 750 * Link 1: McASP0 -> pcm3168a_a DAC 751 * \> pcm3168a_b DAC 752 * Link 2: McASP0 <- pcm3168a_a ADC 753 * \ pcm3168a_b ADC 754 */ 755 comp_count = 8; 756 compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent), 757 GFP_KERNEL); 758 if (!compnent) 759 return -ENOMEM; 760 761 comp_idx = 0; 762 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 763 priv->dai_links[*link_idx].num_cpus = 1; 764 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 765 priv->dai_links[*link_idx].num_platforms = 1; 766 priv->dai_links[*link_idx].codecs = &compnent[comp_idx]; 767 priv->dai_links[*link_idx].num_codecs = 2; 768 comp_idx += 2; 769 770 priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Playback"; 771 priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog"; 772 priv->dai_links[*link_idx].cpus->of_node = dai_node; 773 priv->dai_links[*link_idx].platforms->of_node = dai_node; 774 priv->dai_links[*link_idx].codecs[0].of_node = codeca_node; 775 priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-dac"; 776 priv->dai_links[*link_idx].codecs[1].of_node = codecb_node; 777 priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-dac"; 778 priv->dai_links[*link_idx].playback_only = 1; 779 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI; 780 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 781 priv->dai_links[*link_idx].init = j721e_audio_init_ivi; 782 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 783 (*link_idx)++; 784 785 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 786 priv->dai_links[*link_idx].num_cpus = 1; 787 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 788 priv->dai_links[*link_idx].num_platforms = 1; 789 priv->dai_links[*link_idx].codecs = &compnent[comp_idx]; 790 priv->dai_links[*link_idx].num_codecs = 2; 791 792 priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Capture"; 793 priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog"; 794 priv->dai_links[*link_idx].cpus->of_node = dai_node; 795 priv->dai_links[*link_idx].platforms->of_node = dai_node; 796 priv->dai_links[*link_idx].codecs[0].of_node = codeca_node; 797 priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-adc"; 798 priv->dai_links[*link_idx].codecs[1].of_node = codecb_node; 799 priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-adc"; 800 priv->dai_links[*link_idx].capture_only = 1; 801 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI; 802 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 803 priv->dai_links[*link_idx].init = j721e_audio_init; 804 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 805 (*link_idx)++; 806 807 priv->codec_conf[*conf_idx].dlc.of_node = codeca_node; 808 priv->codec_conf[*conf_idx].name_prefix = "codec-a"; 809 (*conf_idx)++; 810 811 priv->codec_conf[*conf_idx].dlc.of_node = codecb_node; 812 priv->codec_conf[*conf_idx].name_prefix = "codec-b"; 813 (*conf_idx)++; 814 815 priv->codec_conf[*conf_idx].dlc.of_node = dai_node; 816 priv->codec_conf[*conf_idx].name_prefix = "McASP0"; 817 (*conf_idx)++; 818 819 return 0; 820 } 821 822 static int j721e_soc_probe(struct platform_device *pdev) 823 { 824 struct device_node *node = pdev->dev.of_node; 825 struct snd_soc_card *card; 826 const struct of_device_id *match; 827 struct j721e_priv *priv; 828 int link_cnt, conf_cnt, ret; 829 830 if (!node) { 831 dev_err(&pdev->dev, "of node is missing.\n"); 832 return -ENODEV; 833 } 834 835 match = of_match_node(j721e_audio_of_match, node); 836 if (!match) { 837 dev_err(&pdev->dev, "No compatible match found\n"); 838 return -ENODEV; 839 } 840 841 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 842 if (!priv) 843 return -ENOMEM; 844 845 priv->match_data = match->data; 846 847 priv->dai_links = devm_kcalloc(&pdev->dev, priv->match_data->num_links, 848 sizeof(*priv->dai_links), GFP_KERNEL); 849 if (!priv->dai_links) 850 return -ENOMEM; 851 852 priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].parent_clk_id = -1; 853 priv->audio_domains[J721E_AUDIO_DOMAIN_IVI].parent_clk_id = -1; 854 priv->dev = &pdev->dev; 855 card = &priv->card; 856 card->dev = &pdev->dev; 857 card->owner = THIS_MODULE; 858 card->dapm_widgets = j721e_cpb_dapm_widgets; 859 card->num_dapm_widgets = ARRAY_SIZE(j721e_cpb_dapm_widgets); 860 card->dapm_routes = j721e_cpb_dapm_routes; 861 card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes); 862 card->fully_routed = 1; 863 864 if (snd_soc_of_parse_card_name(card, "model")) { 865 dev_err(&pdev->dev, "Card name is not provided\n"); 866 return -ENODEV; 867 } 868 869 link_cnt = 0; 870 conf_cnt = 0; 871 ret = j721e_soc_probe_cpb(priv, &link_cnt, &conf_cnt); 872 if (ret) 873 return ret; 874 875 ret = j721e_soc_probe_ivi(priv, &link_cnt, &conf_cnt); 876 if (ret) 877 return ret; 878 879 card->dai_link = priv->dai_links; 880 card->num_links = link_cnt; 881 882 card->codec_conf = priv->codec_conf; 883 card->num_configs = conf_cnt; 884 885 ret = j721e_calculate_rate_range(priv); 886 if (ret) 887 return ret; 888 889 snd_soc_card_set_drvdata(card, priv); 890 891 mutex_init(&priv->mutex); 892 ret = devm_snd_soc_register_card(&pdev->dev, card); 893 if (ret) 894 dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", 895 ret); 896 897 return ret; 898 } 899 900 static struct platform_driver j721e_soc_driver = { 901 .driver = { 902 .name = "j721e-audio", 903 .pm = &snd_soc_pm_ops, 904 .of_match_table = j721e_audio_of_match, 905 }, 906 .probe = j721e_soc_probe, 907 }; 908 909 module_platform_driver(j721e_soc_driver); 910 911 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); 912 MODULE_DESCRIPTION("ASoC machine driver for j721e Common Processor Board"); 913 MODULE_LICENSE("GPL v2"); 914