Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
0004  *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
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  * Maximum number of configuration entries for prefixes:
0021  * CPB: 2 (mcasp10 + codec)
0022  * IVI: 3 (mcasp0 + 2x codec)
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     /* Reset TDM slots to 32 */
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     /* Set up initial clock configuration */
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     /* Set initial tdm slots */
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, /* CPB pcm3168a */
0518     .pll_rates = {
0519         [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */
0520         [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */
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, /* CPB pcm3168a + 2x pcm3168a on IVI */
0527     .pll_rates = {
0528         [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */
0529         [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */
0530     },
0531 };
0532 
0533 static const struct j721e_audio_match_data j7200_cpb_data = {
0534     .board_type = J721E_BOARD_CPB,
0535     .num_links = 2, /* CPB pcm3168a */
0536     .pll_rates = {
0537         [J721E_CLK_PARENT_48000] = 2359296000u, /* PLL4 */
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      * Common Processor Board, two links
0648      * Link 1: McASP10 -> pcm3168a_1 DAC
0649      * Link 2: McASP10 <- pcm3168a_1 ADC
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      * IVI extension, two links
0760      * Link 1: McASP0 -> pcm3168a_a DAC
0761      *        \> pcm3168a_b DAC
0762      * Link 2: McASP0 <- pcm3168a_a ADC
0763      *         \ pcm3168a_b ADC
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");