0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/platform_device.h>
0011
0012 #include <sound/core.h>
0013 #include <sound/pcm.h>
0014 #include <sound/pcm_params.h>
0015 #include <sound/soc.h>
0016
0017 #include "davinci-mcasp.h"
0018
0019
0020
0021
0022
0023
0024 #define J721E_CODEC_CONF_COUNT 5
0025
0026 enum j721e_audio_domain_id {
0027 J721E_AUDIO_DOMAIN_CPB = 0,
0028 J721E_AUDIO_DOMAIN_IVI,
0029 J721E_AUDIO_DOMAIN_LAST,
0030 };
0031
0032 #define J721E_CLK_PARENT_48000 0
0033 #define J721E_CLK_PARENT_44100 1
0034
0035 #define J721E_MAX_CLK_HSDIV 128
0036 #define PCM1368A_MAX_SYSCLK 36864000
0037
0038 #define J721E_DAI_FMT (SND_SOC_DAIFMT_RIGHT_J | \
0039 SND_SOC_DAIFMT_NB_NF | \
0040 SND_SOC_DAIFMT_CBS_CFS)
0041
0042 enum j721e_board_type {
0043 J721E_BOARD_CPB = 1,
0044 J721E_BOARD_CPB_IVI,
0045 };
0046
0047 struct j721e_audio_match_data {
0048 enum j721e_board_type board_type;
0049 int num_links;
0050 unsigned int pll_rates[2];
0051 };
0052
0053 static unsigned int ratios_for_pcm3168a[] = {
0054 256,
0055 512,
0056 768,
0057 };
0058
0059 struct j721e_audio_clocks {
0060 struct clk *target;
0061 struct clk *parent[2];
0062 };
0063
0064 struct j721e_audio_domain {
0065 struct j721e_audio_clocks codec;
0066 struct j721e_audio_clocks mcasp;
0067 int parent_clk_id;
0068
0069 int active;
0070 unsigned int active_link;
0071 unsigned int rate;
0072 };
0073
0074 struct j721e_priv {
0075 struct device *dev;
0076 struct snd_soc_card card;
0077 struct snd_soc_dai_link *dai_links;
0078 struct snd_soc_codec_conf codec_conf[J721E_CODEC_CONF_COUNT];
0079 struct snd_interval rate_range;
0080 const struct j721e_audio_match_data *match_data;
0081 u32 pll_rates[2];
0082 unsigned int hsdiv_rates[2];
0083
0084 struct j721e_audio_domain audio_domains[J721E_AUDIO_DOMAIN_LAST];
0085
0086 struct mutex mutex;
0087 };
0088
0089 static const struct snd_soc_dapm_widget j721e_cpb_dapm_widgets[] = {
0090 SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL),
0091 SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL),
0092 SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL),
0093 SND_SOC_DAPM_LINE("CPB Line Out", NULL),
0094 SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL),
0095 SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL),
0096 SND_SOC_DAPM_LINE("CPB Line In", NULL),
0097 };
0098
0099 static const struct snd_soc_dapm_route j721e_cpb_dapm_routes[] = {
0100 {"CPB Stereo HP 1", NULL, "codec-1 AOUT1L"},
0101 {"CPB Stereo HP 1", NULL, "codec-1 AOUT1R"},
0102 {"CPB Stereo HP 2", NULL, "codec-1 AOUT2L"},
0103 {"CPB Stereo HP 2", NULL, "codec-1 AOUT2R"},
0104 {"CPB Stereo HP 3", NULL, "codec-1 AOUT3L"},
0105 {"CPB Stereo HP 3", NULL, "codec-1 AOUT3R"},
0106 {"CPB Line Out", NULL, "codec-1 AOUT4L"},
0107 {"CPB Line Out", NULL, "codec-1 AOUT4R"},
0108
0109 {"codec-1 AIN1L", NULL, "CPB Stereo Mic 1"},
0110 {"codec-1 AIN1R", NULL, "CPB Stereo Mic 1"},
0111 {"codec-1 AIN2L", NULL, "CPB Stereo Mic 2"},
0112 {"codec-1 AIN2R", NULL, "CPB Stereo Mic 2"},
0113 {"codec-1 AIN3L", NULL, "CPB Line In"},
0114 {"codec-1 AIN3R", NULL, "CPB Line In"},
0115 };
0116
0117 static const struct snd_soc_dapm_widget j721e_ivi_codec_a_dapm_widgets[] = {
0118 SND_SOC_DAPM_LINE("IVI A Line Out 1", NULL),
0119 SND_SOC_DAPM_LINE("IVI A Line Out 2", NULL),
0120 SND_SOC_DAPM_LINE("IVI A Line Out 3", NULL),
0121 SND_SOC_DAPM_LINE("IVI A Line Out 4", NULL),
0122 SND_SOC_DAPM_MIC("IVI A Stereo Mic 1", NULL),
0123 SND_SOC_DAPM_MIC("IVI A Stereo Mic 2", NULL),
0124 SND_SOC_DAPM_LINE("IVI A Line In", NULL),
0125 };
0126
0127 static const struct snd_soc_dapm_route j721e_codec_a_dapm_routes[] = {
0128 {"IVI A Line Out 1", NULL, "codec-a AOUT1L"},
0129 {"IVI A Line Out 1", NULL, "codec-a AOUT1R"},
0130 {"IVI A Line Out 2", NULL, "codec-a AOUT2L"},
0131 {"IVI A Line Out 2", NULL, "codec-a AOUT2R"},
0132 {"IVI A Line Out 3", NULL, "codec-a AOUT3L"},
0133 {"IVI A Line Out 3", NULL, "codec-a AOUT3R"},
0134 {"IVI A Line Out 4", NULL, "codec-a AOUT4L"},
0135 {"IVI A Line Out 4", NULL, "codec-a AOUT4R"},
0136
0137 {"codec-a AIN1L", NULL, "IVI A Stereo Mic 1"},
0138 {"codec-a AIN1R", NULL, "IVI A Stereo Mic 1"},
0139 {"codec-a AIN2L", NULL, "IVI A Stereo Mic 2"},
0140 {"codec-a AIN2R", NULL, "IVI A Stereo Mic 2"},
0141 {"codec-a AIN3L", NULL, "IVI A Line In"},
0142 {"codec-a AIN3R", NULL, "IVI A Line In"},
0143 };
0144
0145 static const struct snd_soc_dapm_widget j721e_ivi_codec_b_dapm_widgets[] = {
0146 SND_SOC_DAPM_LINE("IVI B Line Out 1", NULL),
0147 SND_SOC_DAPM_LINE("IVI B Line Out 2", NULL),
0148 SND_SOC_DAPM_LINE("IVI B Line Out 3", NULL),
0149 SND_SOC_DAPM_LINE("IVI B Line Out 4", NULL),
0150 SND_SOC_DAPM_MIC("IVI B Stereo Mic 1", NULL),
0151 SND_SOC_DAPM_MIC("IVI B Stereo Mic 2", NULL),
0152 SND_SOC_DAPM_LINE("IVI B Line In", NULL),
0153 };
0154
0155 static const struct snd_soc_dapm_route j721e_codec_b_dapm_routes[] = {
0156 {"IVI B Line Out 1", NULL, "codec-b AOUT1L"},
0157 {"IVI B Line Out 1", NULL, "codec-b AOUT1R"},
0158 {"IVI B Line Out 2", NULL, "codec-b AOUT2L"},
0159 {"IVI B Line Out 2", NULL, "codec-b AOUT2R"},
0160 {"IVI B Line Out 3", NULL, "codec-b AOUT3L"},
0161 {"IVI B Line Out 3", NULL, "codec-b AOUT3R"},
0162 {"IVI B Line Out 4", NULL, "codec-b AOUT4L"},
0163 {"IVI B Line Out 4", NULL, "codec-b AOUT4R"},
0164
0165 {"codec-b AIN1L", NULL, "IVI B Stereo Mic 1"},
0166 {"codec-b AIN1R", NULL, "IVI B Stereo Mic 1"},
0167 {"codec-b AIN2L", NULL, "IVI B Stereo Mic 2"},
0168 {"codec-b AIN2R", NULL, "IVI B Stereo Mic 2"},
0169 {"codec-b AIN3L", NULL, "IVI B Line In"},
0170 {"codec-b AIN3R", NULL, "IVI B Line In"},
0171 };
0172
0173 static int j721e_configure_refclk(struct j721e_priv *priv,
0174 unsigned int audio_domain, unsigned int rate)
0175 {
0176 struct j721e_audio_domain *domain = &priv->audio_domains[audio_domain];
0177 unsigned int scki;
0178 int ret = -EINVAL;
0179 int i, clk_id;
0180
0181 if (!(rate % 8000) && priv->pll_rates[J721E_CLK_PARENT_48000])
0182 clk_id = J721E_CLK_PARENT_48000;
0183 else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_44100])
0184 clk_id = J721E_CLK_PARENT_44100;
0185 else
0186 return ret;
0187
0188 for (i = 0; i < ARRAY_SIZE(ratios_for_pcm3168a); i++) {
0189 scki = ratios_for_pcm3168a[i] * rate;
0190
0191 if (priv->pll_rates[clk_id] / scki <= J721E_MAX_CLK_HSDIV) {
0192 ret = 0;
0193 break;
0194 }
0195 }
0196
0197 if (ret) {
0198 dev_err(priv->dev, "No valid clock configuration for %u Hz\n",
0199 rate);
0200 return ret;
0201 }
0202
0203 if (domain->parent_clk_id == -1 || priv->hsdiv_rates[domain->parent_clk_id] != scki) {
0204 dev_dbg(priv->dev,
0205 "domain%u configuration for %u Hz: %s, %dxFS (SCKI: %u Hz)\n",
0206 audio_domain, rate,
0207 clk_id == J721E_CLK_PARENT_48000 ? "PLL4" : "PLL15",
0208 ratios_for_pcm3168a[i], scki);
0209
0210 if (domain->parent_clk_id != clk_id) {
0211 ret = clk_set_parent(domain->codec.target,
0212 domain->codec.parent[clk_id]);
0213 if (ret)
0214 return ret;
0215
0216 ret = clk_set_parent(domain->mcasp.target,
0217 domain->mcasp.parent[clk_id]);
0218 if (ret)
0219 return ret;
0220
0221 domain->parent_clk_id = clk_id;
0222 }
0223
0224 ret = clk_set_rate(domain->codec.target, scki);
0225 if (ret) {
0226 dev_err(priv->dev, "codec set rate failed for %u Hz\n",
0227 scki);
0228 return ret;
0229 }
0230
0231 ret = clk_set_rate(domain->mcasp.target, scki);
0232 if (!ret) {
0233 priv->hsdiv_rates[domain->parent_clk_id] = scki;
0234 } else {
0235 dev_err(priv->dev, "mcasp set rate failed for %u Hz\n",
0236 scki);
0237 return ret;
0238 }
0239 }
0240
0241 return ret;
0242 }
0243
0244 static int j721e_rule_rate(struct snd_pcm_hw_params *params,
0245 struct snd_pcm_hw_rule *rule)
0246 {
0247 struct snd_interval *t = rule->private;
0248
0249 return snd_interval_refine(hw_param_interval(params, rule->var), t);
0250 }
0251
0252 static int j721e_audio_startup(struct snd_pcm_substream *substream)
0253 {
0254 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0255 struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0256 unsigned int domain_id = rtd->dai_link->id;
0257 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
0258 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0259 struct snd_soc_dai *codec_dai;
0260 unsigned int active_rate;
0261 int ret = 0;
0262 int i;
0263
0264 mutex_lock(&priv->mutex);
0265
0266 domain->active++;
0267
0268 for (i = 0; i < J721E_AUDIO_DOMAIN_LAST; i++) {
0269 active_rate = priv->audio_domains[i].rate;
0270 if (active_rate)
0271 break;
0272 }
0273
0274 if (active_rate)
0275 ret = snd_pcm_hw_constraint_single(substream->runtime,
0276 SNDRV_PCM_HW_PARAM_RATE,
0277 active_rate);
0278 else
0279 ret = snd_pcm_hw_rule_add(substream->runtime, 0,
0280 SNDRV_PCM_HW_PARAM_RATE,
0281 j721e_rule_rate, &priv->rate_range,
0282 SNDRV_PCM_HW_PARAM_RATE, -1);
0283
0284
0285 if (ret)
0286 goto out;
0287
0288
0289 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
0290 if (ret && ret != -ENOTSUPP)
0291 goto out;
0292
0293 for_each_rtd_codec_dais(rtd, i, codec_dai) {
0294 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32);
0295 if (ret && ret != -ENOTSUPP)
0296 goto out;
0297 }
0298
0299 if (ret == -ENOTSUPP)
0300 ret = 0;
0301 out:
0302 if (ret)
0303 domain->active--;
0304 mutex_unlock(&priv->mutex);
0305
0306 return ret;
0307 }
0308
0309 static int j721e_audio_hw_params(struct snd_pcm_substream *substream,
0310 struct snd_pcm_hw_params *params)
0311 {
0312 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0313 struct snd_soc_card *card = rtd->card;
0314 struct j721e_priv *priv = snd_soc_card_get_drvdata(card);
0315 unsigned int domain_id = rtd->dai_link->id;
0316 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
0317 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0318 struct snd_soc_dai *codec_dai;
0319 unsigned int sysclk_rate;
0320 int slot_width = 32;
0321 int ret;
0322 int i;
0323
0324 mutex_lock(&priv->mutex);
0325
0326 if (domain->rate && domain->rate != params_rate(params)) {
0327 ret = -EINVAL;
0328 goto out;
0329 }
0330
0331 if (params_width(params) == 16)
0332 slot_width = 16;
0333
0334 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, slot_width);
0335 if (ret && ret != -ENOTSUPP)
0336 goto out;
0337
0338 for_each_rtd_codec_dais(rtd, i, codec_dai) {
0339 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2,
0340 slot_width);
0341 if (ret && ret != -ENOTSUPP)
0342 goto out;
0343 }
0344
0345 ret = j721e_configure_refclk(priv, domain_id, params_rate(params));
0346 if (ret)
0347 goto out;
0348
0349 sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id];
0350 for_each_rtd_codec_dais(rtd, i, codec_dai) {
0351 ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate,
0352 SND_SOC_CLOCK_IN);
0353 if (ret && ret != -ENOTSUPP) {
0354 dev_err(priv->dev,
0355 "codec set_sysclk failed for %u Hz\n",
0356 sysclk_rate);
0357 goto out;
0358 }
0359 }
0360
0361 ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK,
0362 sysclk_rate, SND_SOC_CLOCK_IN);
0363
0364 if (ret && ret != -ENOTSUPP) {
0365 dev_err(priv->dev, "mcasp set_sysclk failed for %u Hz\n",
0366 sysclk_rate);
0367 } else {
0368 domain->rate = params_rate(params);
0369 ret = 0;
0370 }
0371
0372 out:
0373 mutex_unlock(&priv->mutex);
0374 return ret;
0375 }
0376
0377 static void j721e_audio_shutdown(struct snd_pcm_substream *substream)
0378 {
0379 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0380 struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0381 unsigned int domain_id = rtd->dai_link->id;
0382 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
0383
0384 mutex_lock(&priv->mutex);
0385
0386 domain->active--;
0387 if (!domain->active) {
0388 domain->rate = 0;
0389 domain->active_link = 0;
0390 }
0391
0392 mutex_unlock(&priv->mutex);
0393 }
0394
0395 static const struct snd_soc_ops j721e_audio_ops = {
0396 .startup = j721e_audio_startup,
0397 .hw_params = j721e_audio_hw_params,
0398 .shutdown = j721e_audio_shutdown,
0399 };
0400
0401 static int j721e_audio_init(struct snd_soc_pcm_runtime *rtd)
0402 {
0403 struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0404 unsigned int domain_id = rtd->dai_link->id;
0405 struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
0406 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0407 struct snd_soc_dai *codec_dai;
0408 unsigned int sysclk_rate;
0409 int i, ret;
0410
0411
0412 ret = j721e_configure_refclk(priv, domain_id, 48000);
0413 if (ret)
0414 return ret;
0415
0416 sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id];
0417 for_each_rtd_codec_dais(rtd, i, codec_dai) {
0418 ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate,
0419 SND_SOC_CLOCK_IN);
0420 if (ret && ret != -ENOTSUPP)
0421 return ret;
0422 }
0423
0424 ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK,
0425 sysclk_rate, SND_SOC_CLOCK_IN);
0426 if (ret && ret != -ENOTSUPP)
0427 return ret;
0428
0429
0430 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
0431 if (ret && ret != -ENOTSUPP)
0432 return ret;
0433
0434 for_each_rtd_codec_dais(rtd, i, codec_dai) {
0435 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32);
0436 if (ret && ret != -ENOTSUPP)
0437 return ret;
0438 }
0439
0440 return 0;
0441 }
0442
0443 static int j721e_audio_init_ivi(struct snd_soc_pcm_runtime *rtd)
0444 {
0445 struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
0446
0447 snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_a_dapm_widgets,
0448 ARRAY_SIZE(j721e_ivi_codec_a_dapm_widgets));
0449 snd_soc_dapm_add_routes(dapm, j721e_codec_a_dapm_routes,
0450 ARRAY_SIZE(j721e_codec_a_dapm_routes));
0451 snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_b_dapm_widgets,
0452 ARRAY_SIZE(j721e_ivi_codec_b_dapm_widgets));
0453 snd_soc_dapm_add_routes(dapm, j721e_codec_b_dapm_routes,
0454 ARRAY_SIZE(j721e_codec_b_dapm_routes));
0455
0456 return j721e_audio_init(rtd);
0457 }
0458
0459 static int j721e_get_clocks(struct device *dev,
0460 struct j721e_audio_clocks *clocks, char *prefix)
0461 {
0462 struct clk *parent;
0463 char *clk_name;
0464 int ret;
0465
0466 clocks->target = devm_clk_get(dev, prefix);
0467 if (IS_ERR(clocks->target))
0468 return dev_err_probe(dev, PTR_ERR(clocks->target),
0469 "failed to acquire %s\n", prefix);
0470
0471 clk_name = kasprintf(GFP_KERNEL, "%s-48000", prefix);
0472 if (clk_name) {
0473 parent = devm_clk_get(dev, clk_name);
0474 kfree(clk_name);
0475 if (IS_ERR(parent)) {
0476 ret = PTR_ERR(parent);
0477 if (ret == -EPROBE_DEFER)
0478 return ret;
0479
0480 dev_dbg(dev, "no 48KHz parent for %s: %d\n", prefix, ret);
0481 parent = NULL;
0482 }
0483 clocks->parent[J721E_CLK_PARENT_48000] = parent;
0484 } else {
0485 return -ENOMEM;
0486 }
0487
0488 clk_name = kasprintf(GFP_KERNEL, "%s-44100", prefix);
0489 if (clk_name) {
0490 parent = devm_clk_get(dev, clk_name);
0491 kfree(clk_name);
0492 if (IS_ERR(parent)) {
0493 ret = PTR_ERR(parent);
0494 if (ret == -EPROBE_DEFER)
0495 return ret;
0496
0497 dev_dbg(dev, "no 44.1KHz parent for %s: %d\n", prefix, ret);
0498 parent = NULL;
0499 }
0500 clocks->parent[J721E_CLK_PARENT_44100] = parent;
0501 } else {
0502 return -ENOMEM;
0503 }
0504
0505 if (!clocks->parent[J721E_CLK_PARENT_44100] &&
0506 !clocks->parent[J721E_CLK_PARENT_48000]) {
0507 dev_err(dev, "At least one parent clock is needed for %s\n",
0508 prefix);
0509 return -EINVAL;
0510 }
0511
0512 return 0;
0513 }
0514
0515 static const struct j721e_audio_match_data j721e_cpb_data = {
0516 .board_type = J721E_BOARD_CPB,
0517 .num_links = 2,
0518 .pll_rates = {
0519 [J721E_CLK_PARENT_44100] = 1083801600,
0520 [J721E_CLK_PARENT_48000] = 1179648000,
0521 },
0522 };
0523
0524 static const struct j721e_audio_match_data j721e_cpb_ivi_data = {
0525 .board_type = J721E_BOARD_CPB_IVI,
0526 .num_links = 4,
0527 .pll_rates = {
0528 [J721E_CLK_PARENT_44100] = 1083801600,
0529 [J721E_CLK_PARENT_48000] = 1179648000,
0530 },
0531 };
0532
0533 static const struct j721e_audio_match_data j7200_cpb_data = {
0534 .board_type = J721E_BOARD_CPB,
0535 .num_links = 2,
0536 .pll_rates = {
0537 [J721E_CLK_PARENT_48000] = 2359296000u,
0538 },
0539 };
0540
0541 static const struct of_device_id j721e_audio_of_match[] = {
0542 {
0543 .compatible = "ti,j721e-cpb-audio",
0544 .data = &j721e_cpb_data,
0545 }, {
0546 .compatible = "ti,j721e-cpb-ivi-audio",
0547 .data = &j721e_cpb_ivi_data,
0548 }, {
0549 .compatible = "ti,j7200-cpb-audio",
0550 .data = &j7200_cpb_data,
0551 },
0552 { },
0553 };
0554 MODULE_DEVICE_TABLE(of, j721e_audio_of_match);
0555
0556 static int j721e_calculate_rate_range(struct j721e_priv *priv)
0557 {
0558 const struct j721e_audio_match_data *match_data = priv->match_data;
0559 struct j721e_audio_clocks *domain_clocks;
0560 unsigned int min_rate, max_rate, pll_rate;
0561 struct clk *pll;
0562
0563 domain_clocks = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].mcasp;
0564
0565 pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_44100]);
0566 if (IS_ERR_OR_NULL(pll)) {
0567 priv->pll_rates[J721E_CLK_PARENT_44100] =
0568 match_data->pll_rates[J721E_CLK_PARENT_44100];
0569 } else {
0570 priv->pll_rates[J721E_CLK_PARENT_44100] = clk_get_rate(pll);
0571 clk_put(pll);
0572 }
0573
0574 pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_48000]);
0575 if (IS_ERR_OR_NULL(pll)) {
0576 priv->pll_rates[J721E_CLK_PARENT_48000] =
0577 match_data->pll_rates[J721E_CLK_PARENT_48000];
0578 } else {
0579 priv->pll_rates[J721E_CLK_PARENT_48000] = clk_get_rate(pll);
0580 clk_put(pll);
0581 }
0582
0583 if (!priv->pll_rates[J721E_CLK_PARENT_44100] &&
0584 !priv->pll_rates[J721E_CLK_PARENT_48000]) {
0585 dev_err(priv->dev, "At least one PLL is needed\n");
0586 return -EINVAL;
0587 }
0588
0589 if (priv->pll_rates[J721E_CLK_PARENT_44100])
0590 pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100];
0591 else
0592 pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000];
0593
0594 min_rate = pll_rate / J721E_MAX_CLK_HSDIV;
0595 min_rate /= ratios_for_pcm3168a[ARRAY_SIZE(ratios_for_pcm3168a) - 1];
0596
0597 if (priv->pll_rates[J721E_CLK_PARENT_48000])
0598 pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000];
0599 else
0600 pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100];
0601
0602 if (pll_rate > PCM1368A_MAX_SYSCLK)
0603 pll_rate = PCM1368A_MAX_SYSCLK;
0604
0605 max_rate = pll_rate / ratios_for_pcm3168a[0];
0606
0607 snd_interval_any(&priv->rate_range);
0608 priv->rate_range.min = min_rate;
0609 priv->rate_range.max = max_rate;
0610
0611 return 0;
0612 }
0613
0614 static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx,
0615 int *conf_idx)
0616 {
0617 struct device_node *node = priv->dev->of_node;
0618 struct snd_soc_dai_link_component *compnent;
0619 struct device_node *dai_node, *codec_node;
0620 struct j721e_audio_domain *domain;
0621 int comp_count, comp_idx;
0622 int ret;
0623
0624 dai_node = of_parse_phandle(node, "ti,cpb-mcasp", 0);
0625 if (!dai_node) {
0626 dev_err(priv->dev, "CPB McASP node is not provided\n");
0627 return -EINVAL;
0628 }
0629
0630 codec_node = of_parse_phandle(node, "ti,cpb-codec", 0);
0631 if (!codec_node) {
0632 dev_err(priv->dev, "CPB codec node is not provided\n");
0633 ret = -EINVAL;
0634 goto put_dai_node;
0635 }
0636
0637 domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB];
0638 ret = j721e_get_clocks(priv->dev, &domain->codec, "cpb-codec-scki");
0639 if (ret)
0640 goto put_codec_node;
0641
0642 ret = j721e_get_clocks(priv->dev, &domain->mcasp, "cpb-mcasp-auxclk");
0643 if (ret)
0644 goto put_codec_node;
0645
0646
0647
0648
0649
0650
0651 comp_count = 6;
0652 compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
0653 GFP_KERNEL);
0654 if (!compnent) {
0655 ret = -ENOMEM;
0656 goto put_codec_node;
0657 }
0658
0659 comp_idx = 0;
0660 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
0661 priv->dai_links[*link_idx].num_cpus = 1;
0662 priv->dai_links[*link_idx].codecs = &compnent[comp_idx++];
0663 priv->dai_links[*link_idx].num_codecs = 1;
0664 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
0665 priv->dai_links[*link_idx].num_platforms = 1;
0666
0667 priv->dai_links[*link_idx].name = "CPB PCM3168A Playback";
0668 priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog";
0669 priv->dai_links[*link_idx].cpus->of_node = dai_node;
0670 priv->dai_links[*link_idx].platforms->of_node = dai_node;
0671 priv->dai_links[*link_idx].codecs->of_node = codec_node;
0672 priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-dac";
0673 priv->dai_links[*link_idx].playback_only = 1;
0674 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB;
0675 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
0676 priv->dai_links[*link_idx].init = j721e_audio_init;
0677 priv->dai_links[*link_idx].ops = &j721e_audio_ops;
0678 (*link_idx)++;
0679
0680 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
0681 priv->dai_links[*link_idx].num_cpus = 1;
0682 priv->dai_links[*link_idx].codecs = &compnent[comp_idx++];
0683 priv->dai_links[*link_idx].num_codecs = 1;
0684 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
0685 priv->dai_links[*link_idx].num_platforms = 1;
0686
0687 priv->dai_links[*link_idx].name = "CPB PCM3168A Capture";
0688 priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog";
0689 priv->dai_links[*link_idx].cpus->of_node = dai_node;
0690 priv->dai_links[*link_idx].platforms->of_node = dai_node;
0691 priv->dai_links[*link_idx].codecs->of_node = codec_node;
0692 priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-adc";
0693 priv->dai_links[*link_idx].capture_only = 1;
0694 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB;
0695 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
0696 priv->dai_links[*link_idx].init = j721e_audio_init;
0697 priv->dai_links[*link_idx].ops = &j721e_audio_ops;
0698 (*link_idx)++;
0699
0700 priv->codec_conf[*conf_idx].dlc.of_node = codec_node;
0701 priv->codec_conf[*conf_idx].name_prefix = "codec-1";
0702 (*conf_idx)++;
0703 priv->codec_conf[*conf_idx].dlc.of_node = dai_node;
0704 priv->codec_conf[*conf_idx].name_prefix = "McASP10";
0705 (*conf_idx)++;
0706
0707 return 0;
0708
0709 put_codec_node:
0710 of_node_put(codec_node);
0711 put_dai_node:
0712 of_node_put(dai_node);
0713 return ret;
0714 }
0715
0716 static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx,
0717 int *conf_idx)
0718 {
0719 struct device_node *node = priv->dev->of_node;
0720 struct snd_soc_dai_link_component *compnent;
0721 struct device_node *dai_node, *codeca_node, *codecb_node;
0722 struct j721e_audio_domain *domain;
0723 int comp_count, comp_idx;
0724 int ret;
0725
0726 if (priv->match_data->board_type != J721E_BOARD_CPB_IVI)
0727 return 0;
0728
0729 dai_node = of_parse_phandle(node, "ti,ivi-mcasp", 0);
0730 if (!dai_node) {
0731 dev_err(priv->dev, "IVI McASP node is not provided\n");
0732 return -EINVAL;
0733 }
0734
0735 codeca_node = of_parse_phandle(node, "ti,ivi-codec-a", 0);
0736 if (!codeca_node) {
0737 dev_err(priv->dev, "IVI codec-a node is not provided\n");
0738 ret = -EINVAL;
0739 goto put_dai_node;
0740 }
0741
0742 codecb_node = of_parse_phandle(node, "ti,ivi-codec-b", 0);
0743 if (!codecb_node) {
0744 dev_warn(priv->dev, "IVI codec-b node is not provided\n");
0745 ret = 0;
0746 goto put_codeca_node;
0747 }
0748
0749 domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_IVI];
0750 ret = j721e_get_clocks(priv->dev, &domain->codec, "ivi-codec-scki");
0751 if (ret)
0752 goto put_codecb_node;
0753
0754 ret = j721e_get_clocks(priv->dev, &domain->mcasp, "ivi-mcasp-auxclk");
0755 if (ret)
0756 goto put_codecb_node;
0757
0758
0759
0760
0761
0762
0763
0764
0765 comp_count = 8;
0766 compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
0767 GFP_KERNEL);
0768 if (!compnent) {
0769 ret = -ENOMEM;
0770 goto put_codecb_node;
0771 }
0772
0773 comp_idx = 0;
0774 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
0775 priv->dai_links[*link_idx].num_cpus = 1;
0776 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
0777 priv->dai_links[*link_idx].num_platforms = 1;
0778 priv->dai_links[*link_idx].codecs = &compnent[comp_idx];
0779 priv->dai_links[*link_idx].num_codecs = 2;
0780 comp_idx += 2;
0781
0782 priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Playback";
0783 priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog";
0784 priv->dai_links[*link_idx].cpus->of_node = dai_node;
0785 priv->dai_links[*link_idx].platforms->of_node = dai_node;
0786 priv->dai_links[*link_idx].codecs[0].of_node = codeca_node;
0787 priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-dac";
0788 priv->dai_links[*link_idx].codecs[1].of_node = codecb_node;
0789 priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-dac";
0790 priv->dai_links[*link_idx].playback_only = 1;
0791 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI;
0792 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
0793 priv->dai_links[*link_idx].init = j721e_audio_init_ivi;
0794 priv->dai_links[*link_idx].ops = &j721e_audio_ops;
0795 (*link_idx)++;
0796
0797 priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
0798 priv->dai_links[*link_idx].num_cpus = 1;
0799 priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
0800 priv->dai_links[*link_idx].num_platforms = 1;
0801 priv->dai_links[*link_idx].codecs = &compnent[comp_idx];
0802 priv->dai_links[*link_idx].num_codecs = 2;
0803
0804 priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Capture";
0805 priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog";
0806 priv->dai_links[*link_idx].cpus->of_node = dai_node;
0807 priv->dai_links[*link_idx].platforms->of_node = dai_node;
0808 priv->dai_links[*link_idx].codecs[0].of_node = codeca_node;
0809 priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-adc";
0810 priv->dai_links[*link_idx].codecs[1].of_node = codecb_node;
0811 priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-adc";
0812 priv->dai_links[*link_idx].capture_only = 1;
0813 priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI;
0814 priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
0815 priv->dai_links[*link_idx].init = j721e_audio_init;
0816 priv->dai_links[*link_idx].ops = &j721e_audio_ops;
0817 (*link_idx)++;
0818
0819 priv->codec_conf[*conf_idx].dlc.of_node = codeca_node;
0820 priv->codec_conf[*conf_idx].name_prefix = "codec-a";
0821 (*conf_idx)++;
0822
0823 priv->codec_conf[*conf_idx].dlc.of_node = codecb_node;
0824 priv->codec_conf[*conf_idx].name_prefix = "codec-b";
0825 (*conf_idx)++;
0826
0827 priv->codec_conf[*conf_idx].dlc.of_node = dai_node;
0828 priv->codec_conf[*conf_idx].name_prefix = "McASP0";
0829 (*conf_idx)++;
0830
0831 return 0;
0832
0833
0834 put_codecb_node:
0835 of_node_put(codecb_node);
0836 put_codeca_node:
0837 of_node_put(codeca_node);
0838 put_dai_node:
0839 of_node_put(dai_node);
0840 return ret;
0841 }
0842
0843 static int j721e_soc_probe(struct platform_device *pdev)
0844 {
0845 struct device_node *node = pdev->dev.of_node;
0846 struct snd_soc_card *card;
0847 const struct of_device_id *match;
0848 struct j721e_priv *priv;
0849 int link_cnt, conf_cnt, ret, i;
0850
0851 if (!node) {
0852 dev_err(&pdev->dev, "of node is missing.\n");
0853 return -ENODEV;
0854 }
0855
0856 match = of_match_node(j721e_audio_of_match, node);
0857 if (!match) {
0858 dev_err(&pdev->dev, "No compatible match found\n");
0859 return -ENODEV;
0860 }
0861
0862 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0863 if (!priv)
0864 return -ENOMEM;
0865
0866 priv->match_data = match->data;
0867
0868 priv->dai_links = devm_kcalloc(&pdev->dev, priv->match_data->num_links,
0869 sizeof(*priv->dai_links), GFP_KERNEL);
0870 if (!priv->dai_links)
0871 return -ENOMEM;
0872
0873 for (i = 0; i < J721E_AUDIO_DOMAIN_LAST; i++)
0874 priv->audio_domains[i].parent_clk_id = -1;
0875
0876 priv->dev = &pdev->dev;
0877 card = &priv->card;
0878 card->dev = &pdev->dev;
0879 card->owner = THIS_MODULE;
0880 card->dapm_widgets = j721e_cpb_dapm_widgets;
0881 card->num_dapm_widgets = ARRAY_SIZE(j721e_cpb_dapm_widgets);
0882 card->dapm_routes = j721e_cpb_dapm_routes;
0883 card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes);
0884 card->fully_routed = 1;
0885
0886 if (snd_soc_of_parse_card_name(card, "model")) {
0887 dev_err(&pdev->dev, "Card name is not provided\n");
0888 return -ENODEV;
0889 }
0890
0891 link_cnt = 0;
0892 conf_cnt = 0;
0893 ret = j721e_soc_probe_cpb(priv, &link_cnt, &conf_cnt);
0894 if (ret)
0895 return ret;
0896
0897 ret = j721e_soc_probe_ivi(priv, &link_cnt, &conf_cnt);
0898 if (ret)
0899 return ret;
0900
0901 card->dai_link = priv->dai_links;
0902 card->num_links = link_cnt;
0903
0904 card->codec_conf = priv->codec_conf;
0905 card->num_configs = conf_cnt;
0906
0907 ret = j721e_calculate_rate_range(priv);
0908 if (ret)
0909 return ret;
0910
0911 snd_soc_card_set_drvdata(card, priv);
0912
0913 mutex_init(&priv->mutex);
0914 ret = devm_snd_soc_register_card(&pdev->dev, card);
0915 if (ret)
0916 dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
0917 ret);
0918
0919 return ret;
0920 }
0921
0922 static struct platform_driver j721e_soc_driver = {
0923 .driver = {
0924 .name = "j721e-audio",
0925 .pm = &snd_soc_pm_ops,
0926 .of_match_table = j721e_audio_of_match,
0927 },
0928 .probe = j721e_soc_probe,
0929 };
0930
0931 module_platform_driver(j721e_soc_driver);
0932
0933 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
0934 MODULE_DESCRIPTION("ASoC machine driver for j721e Common Processor Board");
0935 MODULE_LICENSE("GPL v2");