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