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