cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

j721e-evm.c (26847B)


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