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