j721e-evm.c (26847B)
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 26enum 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 42enum j721e_board_type { 43 J721E_BOARD_CPB = 1, 44 J721E_BOARD_CPB_IVI, 45}; 46 47struct j721e_audio_match_data { 48 enum j721e_board_type board_type; 49 int num_links; 50 unsigned int pll_rates[2]; 51}; 52 53static unsigned int ratios_for_pcm3168a[] = { 54 256, 55 512, 56 768, 57}; 58 59struct j721e_audio_clocks { 60 struct clk *target; 61 struct clk *parent[2]; 62}; 63 64struct 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 74struct 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 89static 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 99static 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 117static 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 127static 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 145static 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 155static 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 173static 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 244static 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 252static 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; 301out: 302 if (ret) 303 domain->active--; 304 mutex_unlock(&priv->mutex); 305 306 return ret; 307} 308 309static 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 372out: 373 mutex_unlock(&priv->mutex); 374 return ret; 375} 376 377static 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 395static 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 401static 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 443static 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 459static 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 return dev_err_probe(dev, PTR_ERR(clocks->target), 469 "failed to acquire %s\n", prefix); 470 471 clk_name = kasprintf(GFP_KERNEL, "%s-48000", prefix); 472 if (clk_name) { 473 parent = devm_clk_get(dev, clk_name); 474 kfree(clk_name); 475 if (IS_ERR(parent)) { 476 ret = PTR_ERR(parent); 477 if (ret == -EPROBE_DEFER) 478 return ret; 479 480 dev_dbg(dev, "no 48KHz parent for %s: %d\n", prefix, ret); 481 parent = NULL; 482 } 483 clocks->parent[J721E_CLK_PARENT_48000] = parent; 484 } else { 485 return -ENOMEM; 486 } 487 488 clk_name = kasprintf(GFP_KERNEL, "%s-44100", prefix); 489 if (clk_name) { 490 parent = devm_clk_get(dev, clk_name); 491 kfree(clk_name); 492 if (IS_ERR(parent)) { 493 ret = PTR_ERR(parent); 494 if (ret == -EPROBE_DEFER) 495 return ret; 496 497 dev_dbg(dev, "no 44.1KHz parent for %s: %d\n", prefix, ret); 498 parent = NULL; 499 } 500 clocks->parent[J721E_CLK_PARENT_44100] = parent; 501 } else { 502 return -ENOMEM; 503 } 504 505 if (!clocks->parent[J721E_CLK_PARENT_44100] && 506 !clocks->parent[J721E_CLK_PARENT_48000]) { 507 dev_err(dev, "At least one parent clock is needed for %s\n", 508 prefix); 509 return -EINVAL; 510 } 511 512 return 0; 513} 514 515static const struct j721e_audio_match_data j721e_cpb_data = { 516 .board_type = J721E_BOARD_CPB, 517 .num_links = 2, /* CPB pcm3168a */ 518 .pll_rates = { 519 [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */ 520 [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */ 521 }, 522}; 523 524static const struct j721e_audio_match_data j721e_cpb_ivi_data = { 525 .board_type = J721E_BOARD_CPB_IVI, 526 .num_links = 4, /* CPB pcm3168a + 2x pcm3168a on IVI */ 527 .pll_rates = { 528 [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */ 529 [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */ 530 }, 531}; 532 533static const struct j721e_audio_match_data j7200_cpb_data = { 534 .board_type = J721E_BOARD_CPB, 535 .num_links = 2, /* CPB pcm3168a */ 536 .pll_rates = { 537 [J721E_CLK_PARENT_48000] = 2359296000u, /* PLL4 */ 538 }, 539}; 540 541static const struct of_device_id j721e_audio_of_match[] = { 542 { 543 .compatible = "ti,j721e-cpb-audio", 544 .data = &j721e_cpb_data, 545 }, { 546 .compatible = "ti,j721e-cpb-ivi-audio", 547 .data = &j721e_cpb_ivi_data, 548 }, { 549 .compatible = "ti,j7200-cpb-audio", 550 .data = &j7200_cpb_data, 551 }, 552 { }, 553}; 554MODULE_DEVICE_TABLE(of, j721e_audio_of_match); 555 556static int j721e_calculate_rate_range(struct j721e_priv *priv) 557{ 558 const struct j721e_audio_match_data *match_data = priv->match_data; 559 struct j721e_audio_clocks *domain_clocks; 560 unsigned int min_rate, max_rate, pll_rate; 561 struct clk *pll; 562 563 domain_clocks = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].mcasp; 564 565 pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_44100]); 566 if (IS_ERR_OR_NULL(pll)) { 567 priv->pll_rates[J721E_CLK_PARENT_44100] = 568 match_data->pll_rates[J721E_CLK_PARENT_44100]; 569 } else { 570 priv->pll_rates[J721E_CLK_PARENT_44100] = clk_get_rate(pll); 571 clk_put(pll); 572 } 573 574 pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_48000]); 575 if (IS_ERR_OR_NULL(pll)) { 576 priv->pll_rates[J721E_CLK_PARENT_48000] = 577 match_data->pll_rates[J721E_CLK_PARENT_48000]; 578 } else { 579 priv->pll_rates[J721E_CLK_PARENT_48000] = clk_get_rate(pll); 580 clk_put(pll); 581 } 582 583 if (!priv->pll_rates[J721E_CLK_PARENT_44100] && 584 !priv->pll_rates[J721E_CLK_PARENT_48000]) { 585 dev_err(priv->dev, "At least one PLL is needed\n"); 586 return -EINVAL; 587 } 588 589 if (priv->pll_rates[J721E_CLK_PARENT_44100]) 590 pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100]; 591 else 592 pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000]; 593 594 min_rate = pll_rate / J721E_MAX_CLK_HSDIV; 595 min_rate /= ratios_for_pcm3168a[ARRAY_SIZE(ratios_for_pcm3168a) - 1]; 596 597 if (priv->pll_rates[J721E_CLK_PARENT_48000]) 598 pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000]; 599 else 600 pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100]; 601 602 if (pll_rate > PCM1368A_MAX_SYSCLK) 603 pll_rate = PCM1368A_MAX_SYSCLK; 604 605 max_rate = pll_rate / ratios_for_pcm3168a[0]; 606 607 snd_interval_any(&priv->rate_range); 608 priv->rate_range.min = min_rate; 609 priv->rate_range.max = max_rate; 610 611 return 0; 612} 613 614static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx, 615 int *conf_idx) 616{ 617 struct device_node *node = priv->dev->of_node; 618 struct snd_soc_dai_link_component *compnent; 619 struct device_node *dai_node, *codec_node; 620 struct j721e_audio_domain *domain; 621 int comp_count, comp_idx; 622 int ret; 623 624 dai_node = of_parse_phandle(node, "ti,cpb-mcasp", 0); 625 if (!dai_node) { 626 dev_err(priv->dev, "CPB McASP node is not provided\n"); 627 return -EINVAL; 628 } 629 630 codec_node = of_parse_phandle(node, "ti,cpb-codec", 0); 631 if (!codec_node) { 632 dev_err(priv->dev, "CPB codec node is not provided\n"); 633 ret = -EINVAL; 634 goto put_dai_node; 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 goto put_codec_node; 641 642 ret = j721e_get_clocks(priv->dev, &domain->mcasp, "cpb-mcasp-auxclk"); 643 if (ret) 644 goto put_codec_node; 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 ret = -ENOMEM; 656 goto put_codec_node; 657 } 658 659 comp_idx = 0; 660 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 661 priv->dai_links[*link_idx].num_cpus = 1; 662 priv->dai_links[*link_idx].codecs = &compnent[comp_idx++]; 663 priv->dai_links[*link_idx].num_codecs = 1; 664 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 665 priv->dai_links[*link_idx].num_platforms = 1; 666 667 priv->dai_links[*link_idx].name = "CPB PCM3168A Playback"; 668 priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog"; 669 priv->dai_links[*link_idx].cpus->of_node = dai_node; 670 priv->dai_links[*link_idx].platforms->of_node = dai_node; 671 priv->dai_links[*link_idx].codecs->of_node = codec_node; 672 priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-dac"; 673 priv->dai_links[*link_idx].playback_only = 1; 674 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB; 675 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 676 priv->dai_links[*link_idx].init = j721e_audio_init; 677 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 678 (*link_idx)++; 679 680 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 681 priv->dai_links[*link_idx].num_cpus = 1; 682 priv->dai_links[*link_idx].codecs = &compnent[comp_idx++]; 683 priv->dai_links[*link_idx].num_codecs = 1; 684 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 685 priv->dai_links[*link_idx].num_platforms = 1; 686 687 priv->dai_links[*link_idx].name = "CPB PCM3168A Capture"; 688 priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog"; 689 priv->dai_links[*link_idx].cpus->of_node = dai_node; 690 priv->dai_links[*link_idx].platforms->of_node = dai_node; 691 priv->dai_links[*link_idx].codecs->of_node = codec_node; 692 priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-adc"; 693 priv->dai_links[*link_idx].capture_only = 1; 694 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB; 695 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 696 priv->dai_links[*link_idx].init = j721e_audio_init; 697 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 698 (*link_idx)++; 699 700 priv->codec_conf[*conf_idx].dlc.of_node = codec_node; 701 priv->codec_conf[*conf_idx].name_prefix = "codec-1"; 702 (*conf_idx)++; 703 priv->codec_conf[*conf_idx].dlc.of_node = dai_node; 704 priv->codec_conf[*conf_idx].name_prefix = "McASP10"; 705 (*conf_idx)++; 706 707 return 0; 708 709put_codec_node: 710 of_node_put(codec_node); 711put_dai_node: 712 of_node_put(dai_node); 713 return ret; 714} 715 716static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx, 717 int *conf_idx) 718{ 719 struct device_node *node = priv->dev->of_node; 720 struct snd_soc_dai_link_component *compnent; 721 struct device_node *dai_node, *codeca_node, *codecb_node; 722 struct j721e_audio_domain *domain; 723 int comp_count, comp_idx; 724 int ret; 725 726 if (priv->match_data->board_type != J721E_BOARD_CPB_IVI) 727 return 0; 728 729 dai_node = of_parse_phandle(node, "ti,ivi-mcasp", 0); 730 if (!dai_node) { 731 dev_err(priv->dev, "IVI McASP node is not provided\n"); 732 return -EINVAL; 733 } 734 735 codeca_node = of_parse_phandle(node, "ti,ivi-codec-a", 0); 736 if (!codeca_node) { 737 dev_err(priv->dev, "IVI codec-a node is not provided\n"); 738 ret = -EINVAL; 739 goto put_dai_node; 740 } 741 742 codecb_node = of_parse_phandle(node, "ti,ivi-codec-b", 0); 743 if (!codecb_node) { 744 dev_warn(priv->dev, "IVI codec-b node is not provided\n"); 745 ret = 0; 746 goto put_codeca_node; 747 } 748 749 domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_IVI]; 750 ret = j721e_get_clocks(priv->dev, &domain->codec, "ivi-codec-scki"); 751 if (ret) 752 goto put_codecb_node; 753 754 ret = j721e_get_clocks(priv->dev, &domain->mcasp, "ivi-mcasp-auxclk"); 755 if (ret) 756 goto put_codecb_node; 757 758 /* 759 * IVI extension, two links 760 * Link 1: McASP0 -> pcm3168a_a DAC 761 * \> pcm3168a_b DAC 762 * Link 2: McASP0 <- pcm3168a_a ADC 763 * \ pcm3168a_b ADC 764 */ 765 comp_count = 8; 766 compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent), 767 GFP_KERNEL); 768 if (!compnent) { 769 ret = -ENOMEM; 770 goto put_codecb_node; 771 } 772 773 comp_idx = 0; 774 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 775 priv->dai_links[*link_idx].num_cpus = 1; 776 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 777 priv->dai_links[*link_idx].num_platforms = 1; 778 priv->dai_links[*link_idx].codecs = &compnent[comp_idx]; 779 priv->dai_links[*link_idx].num_codecs = 2; 780 comp_idx += 2; 781 782 priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Playback"; 783 priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog"; 784 priv->dai_links[*link_idx].cpus->of_node = dai_node; 785 priv->dai_links[*link_idx].platforms->of_node = dai_node; 786 priv->dai_links[*link_idx].codecs[0].of_node = codeca_node; 787 priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-dac"; 788 priv->dai_links[*link_idx].codecs[1].of_node = codecb_node; 789 priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-dac"; 790 priv->dai_links[*link_idx].playback_only = 1; 791 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI; 792 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 793 priv->dai_links[*link_idx].init = j721e_audio_init_ivi; 794 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 795 (*link_idx)++; 796 797 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 798 priv->dai_links[*link_idx].num_cpus = 1; 799 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 800 priv->dai_links[*link_idx].num_platforms = 1; 801 priv->dai_links[*link_idx].codecs = &compnent[comp_idx]; 802 priv->dai_links[*link_idx].num_codecs = 2; 803 804 priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Capture"; 805 priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog"; 806 priv->dai_links[*link_idx].cpus->of_node = dai_node; 807 priv->dai_links[*link_idx].platforms->of_node = dai_node; 808 priv->dai_links[*link_idx].codecs[0].of_node = codeca_node; 809 priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-adc"; 810 priv->dai_links[*link_idx].codecs[1].of_node = codecb_node; 811 priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-adc"; 812 priv->dai_links[*link_idx].capture_only = 1; 813 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI; 814 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 815 priv->dai_links[*link_idx].init = j721e_audio_init; 816 priv->dai_links[*link_idx].ops = &j721e_audio_ops; 817 (*link_idx)++; 818 819 priv->codec_conf[*conf_idx].dlc.of_node = codeca_node; 820 priv->codec_conf[*conf_idx].name_prefix = "codec-a"; 821 (*conf_idx)++; 822 823 priv->codec_conf[*conf_idx].dlc.of_node = codecb_node; 824 priv->codec_conf[*conf_idx].name_prefix = "codec-b"; 825 (*conf_idx)++; 826 827 priv->codec_conf[*conf_idx].dlc.of_node = dai_node; 828 priv->codec_conf[*conf_idx].name_prefix = "McASP0"; 829 (*conf_idx)++; 830 831 return 0; 832 833 834put_codecb_node: 835 of_node_put(codecb_node); 836put_codeca_node: 837 of_node_put(codeca_node); 838put_dai_node: 839 of_node_put(dai_node); 840 return ret; 841} 842 843static int j721e_soc_probe(struct platform_device *pdev) 844{ 845 struct device_node *node = pdev->dev.of_node; 846 struct snd_soc_card *card; 847 const struct of_device_id *match; 848 struct j721e_priv *priv; 849 int link_cnt, conf_cnt, ret, i; 850 851 if (!node) { 852 dev_err(&pdev->dev, "of node is missing.\n"); 853 return -ENODEV; 854 } 855 856 match = of_match_node(j721e_audio_of_match, node); 857 if (!match) { 858 dev_err(&pdev->dev, "No compatible match found\n"); 859 return -ENODEV; 860 } 861 862 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 863 if (!priv) 864 return -ENOMEM; 865 866 priv->match_data = match->data; 867 868 priv->dai_links = devm_kcalloc(&pdev->dev, priv->match_data->num_links, 869 sizeof(*priv->dai_links), GFP_KERNEL); 870 if (!priv->dai_links) 871 return -ENOMEM; 872 873 for (i = 0; i < J721E_AUDIO_DOMAIN_LAST; i++) 874 priv->audio_domains[i].parent_clk_id = -1; 875 876 priv->dev = &pdev->dev; 877 card = &priv->card; 878 card->dev = &pdev->dev; 879 card->owner = THIS_MODULE; 880 card->dapm_widgets = j721e_cpb_dapm_widgets; 881 card->num_dapm_widgets = ARRAY_SIZE(j721e_cpb_dapm_widgets); 882 card->dapm_routes = j721e_cpb_dapm_routes; 883 card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes); 884 card->fully_routed = 1; 885 886 if (snd_soc_of_parse_card_name(card, "model")) { 887 dev_err(&pdev->dev, "Card name is not provided\n"); 888 return -ENODEV; 889 } 890 891 link_cnt = 0; 892 conf_cnt = 0; 893 ret = j721e_soc_probe_cpb(priv, &link_cnt, &conf_cnt); 894 if (ret) 895 return ret; 896 897 ret = j721e_soc_probe_ivi(priv, &link_cnt, &conf_cnt); 898 if (ret) 899 return ret; 900 901 card->dai_link = priv->dai_links; 902 card->num_links = link_cnt; 903 904 card->codec_conf = priv->codec_conf; 905 card->num_configs = conf_cnt; 906 907 ret = j721e_calculate_rate_range(priv); 908 if (ret) 909 return ret; 910 911 snd_soc_card_set_drvdata(card, priv); 912 913 mutex_init(&priv->mutex); 914 ret = devm_snd_soc_register_card(&pdev->dev, card); 915 if (ret) 916 dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", 917 ret); 918 919 return ret; 920} 921 922static struct platform_driver j721e_soc_driver = { 923 .driver = { 924 .name = "j721e-audio", 925 .pm = &snd_soc_pm_ops, 926 .of_match_table = j721e_audio_of_match, 927 }, 928 .probe = j721e_soc_probe, 929}; 930 931module_platform_driver(j721e_soc_driver); 932 933MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); 934MODULE_DESCRIPTION("ASoC machine driver for j721e Common Processor Board"); 935MODULE_LICENSE("GPL v2");