xref: /openbmc/linux/sound/soc/ti/j721e-evm.c (revision a34840c4)
16748d055SPeter Ujfalusi // SPDX-License-Identifier: GPL-2.0
26748d055SPeter Ujfalusi /*
36748d055SPeter Ujfalusi  *  Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
46748d055SPeter Ujfalusi  *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
56748d055SPeter Ujfalusi  */
66748d055SPeter Ujfalusi 
76748d055SPeter Ujfalusi #include <linux/clk.h>
86748d055SPeter Ujfalusi #include <linux/module.h>
96748d055SPeter Ujfalusi #include <linux/of.h>
106748d055SPeter Ujfalusi #include <linux/platform_device.h>
116748d055SPeter Ujfalusi 
126748d055SPeter Ujfalusi #include <sound/core.h>
136748d055SPeter Ujfalusi #include <sound/pcm.h>
146748d055SPeter Ujfalusi #include <sound/pcm_params.h>
156748d055SPeter Ujfalusi #include <sound/soc.h>
166748d055SPeter Ujfalusi 
176748d055SPeter Ujfalusi #include "davinci-mcasp.h"
186748d055SPeter Ujfalusi 
196748d055SPeter Ujfalusi /*
206748d055SPeter Ujfalusi  * Maximum number of configuration entries for prefixes:
216748d055SPeter Ujfalusi  * CPB: 2 (mcasp10 + codec)
226748d055SPeter Ujfalusi  * IVI: 3 (mcasp0 + 2x codec)
236748d055SPeter Ujfalusi  */
246748d055SPeter Ujfalusi #define J721E_CODEC_CONF_COUNT	5
256748d055SPeter Ujfalusi 
26cfc9d37aSPeter Ujfalusi enum j721e_audio_domain_id {
27cfc9d37aSPeter Ujfalusi 	J721E_AUDIO_DOMAIN_CPB = 0,
28cfc9d37aSPeter Ujfalusi 	J721E_AUDIO_DOMAIN_IVI,
29cfc9d37aSPeter Ujfalusi 	J721E_AUDIO_DOMAIN_LAST,
30cfc9d37aSPeter Ujfalusi };
316748d055SPeter Ujfalusi 
326748d055SPeter Ujfalusi #define J721E_CLK_PARENT_48000	0
336748d055SPeter Ujfalusi #define J721E_CLK_PARENT_44100	1
346748d055SPeter Ujfalusi 
356748d055SPeter Ujfalusi #define J721E_MAX_CLK_HSDIV	128
366748d055SPeter Ujfalusi #define PCM1368A_MAX_SYSCLK	36864000
376748d055SPeter Ujfalusi 
386748d055SPeter Ujfalusi #define J721E_DAI_FMT		(SND_SOC_DAIFMT_RIGHT_J | \
396748d055SPeter Ujfalusi 				 SND_SOC_DAIFMT_NB_NF |   \
406748d055SPeter Ujfalusi 				 SND_SOC_DAIFMT_CBS_CFS)
416748d055SPeter Ujfalusi 
426748d055SPeter Ujfalusi enum j721e_board_type {
436748d055SPeter Ujfalusi 	J721E_BOARD_CPB = 1,
446748d055SPeter Ujfalusi 	J721E_BOARD_CPB_IVI,
456748d055SPeter Ujfalusi };
466748d055SPeter Ujfalusi 
476748d055SPeter Ujfalusi struct j721e_audio_match_data {
486748d055SPeter Ujfalusi 	enum j721e_board_type board_type;
496748d055SPeter Ujfalusi 	int num_links;
506748d055SPeter Ujfalusi 	unsigned int pll_rates[2];
516748d055SPeter Ujfalusi };
526748d055SPeter Ujfalusi 
536748d055SPeter Ujfalusi static unsigned int ratios_for_pcm3168a[] = {
546748d055SPeter Ujfalusi 	256,
556748d055SPeter Ujfalusi 	512,
566748d055SPeter Ujfalusi 	768,
576748d055SPeter Ujfalusi };
586748d055SPeter Ujfalusi 
596748d055SPeter Ujfalusi struct j721e_audio_clocks {
606748d055SPeter Ujfalusi 	struct clk *target;
616748d055SPeter Ujfalusi 	struct clk *parent[2];
626748d055SPeter Ujfalusi };
636748d055SPeter Ujfalusi 
646748d055SPeter Ujfalusi struct j721e_audio_domain {
656748d055SPeter Ujfalusi 	struct j721e_audio_clocks codec;
666748d055SPeter Ujfalusi 	struct j721e_audio_clocks mcasp;
676748d055SPeter Ujfalusi 	int parent_clk_id;
686748d055SPeter Ujfalusi 
696748d055SPeter Ujfalusi 	int active;
706748d055SPeter Ujfalusi 	unsigned int active_link;
716748d055SPeter Ujfalusi 	unsigned int rate;
726748d055SPeter Ujfalusi };
736748d055SPeter Ujfalusi 
746748d055SPeter Ujfalusi struct j721e_priv {
756748d055SPeter Ujfalusi 	struct device *dev;
766748d055SPeter Ujfalusi 	struct snd_soc_card card;
776748d055SPeter Ujfalusi 	struct snd_soc_dai_link *dai_links;
786748d055SPeter Ujfalusi 	struct snd_soc_codec_conf codec_conf[J721E_CODEC_CONF_COUNT];
796748d055SPeter Ujfalusi 	struct snd_interval rate_range;
806748d055SPeter Ujfalusi 	const struct j721e_audio_match_data *match_data;
816748d055SPeter Ujfalusi 	u32 pll_rates[2];
826748d055SPeter Ujfalusi 	unsigned int hsdiv_rates[2];
836748d055SPeter Ujfalusi 
84cfc9d37aSPeter Ujfalusi 	struct j721e_audio_domain audio_domains[J721E_AUDIO_DOMAIN_LAST];
856748d055SPeter Ujfalusi 
866748d055SPeter Ujfalusi 	struct mutex mutex;
876748d055SPeter Ujfalusi };
886748d055SPeter Ujfalusi 
896748d055SPeter Ujfalusi static const struct snd_soc_dapm_widget j721e_cpb_dapm_widgets[] = {
906748d055SPeter Ujfalusi 	SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL),
916748d055SPeter Ujfalusi 	SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL),
926748d055SPeter Ujfalusi 	SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL),
936748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("CPB Line Out", NULL),
946748d055SPeter Ujfalusi 	SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL),
956748d055SPeter Ujfalusi 	SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL),
966748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("CPB Line In", NULL),
976748d055SPeter Ujfalusi };
986748d055SPeter Ujfalusi 
996748d055SPeter Ujfalusi static const struct snd_soc_dapm_route j721e_cpb_dapm_routes[] = {
1006748d055SPeter Ujfalusi 	{"CPB Stereo HP 1", NULL, "codec-1 AOUT1L"},
1016748d055SPeter Ujfalusi 	{"CPB Stereo HP 1", NULL, "codec-1 AOUT1R"},
1026748d055SPeter Ujfalusi 	{"CPB Stereo HP 2", NULL, "codec-1 AOUT2L"},
1036748d055SPeter Ujfalusi 	{"CPB Stereo HP 2", NULL, "codec-1 AOUT2R"},
1046748d055SPeter Ujfalusi 	{"CPB Stereo HP 3", NULL, "codec-1 AOUT3L"},
1056748d055SPeter Ujfalusi 	{"CPB Stereo HP 3", NULL, "codec-1 AOUT3R"},
1066748d055SPeter Ujfalusi 	{"CPB Line Out", NULL, "codec-1 AOUT4L"},
1076748d055SPeter Ujfalusi 	{"CPB Line Out", NULL, "codec-1 AOUT4R"},
1086748d055SPeter Ujfalusi 
1096748d055SPeter Ujfalusi 	{"codec-1 AIN1L", NULL, "CPB Stereo Mic 1"},
1106748d055SPeter Ujfalusi 	{"codec-1 AIN1R", NULL, "CPB Stereo Mic 1"},
1116748d055SPeter Ujfalusi 	{"codec-1 AIN2L", NULL, "CPB Stereo Mic 2"},
1126748d055SPeter Ujfalusi 	{"codec-1 AIN2R", NULL, "CPB Stereo Mic 2"},
1136748d055SPeter Ujfalusi 	{"codec-1 AIN3L", NULL, "CPB Line In"},
1146748d055SPeter Ujfalusi 	{"codec-1 AIN3R", NULL, "CPB Line In"},
1156748d055SPeter Ujfalusi };
1166748d055SPeter Ujfalusi 
1176748d055SPeter Ujfalusi static const struct snd_soc_dapm_widget j721e_ivi_codec_a_dapm_widgets[] = {
1186748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI A Line Out 1", NULL),
1196748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI A Line Out 2", NULL),
1206748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI A Line Out 3", NULL),
1216748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI A Line Out 4", NULL),
1226748d055SPeter Ujfalusi 	SND_SOC_DAPM_MIC("IVI A Stereo Mic 1", NULL),
1236748d055SPeter Ujfalusi 	SND_SOC_DAPM_MIC("IVI A Stereo Mic 2", NULL),
1246748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI A Line In", NULL),
1256748d055SPeter Ujfalusi };
1266748d055SPeter Ujfalusi 
1276748d055SPeter Ujfalusi static const struct snd_soc_dapm_route j721e_codec_a_dapm_routes[] = {
1286748d055SPeter Ujfalusi 	{"IVI A Line Out 1", NULL, "codec-a AOUT1L"},
1296748d055SPeter Ujfalusi 	{"IVI A Line Out 1", NULL, "codec-a AOUT1R"},
1306748d055SPeter Ujfalusi 	{"IVI A Line Out 2", NULL, "codec-a AOUT2L"},
1316748d055SPeter Ujfalusi 	{"IVI A Line Out 2", NULL, "codec-a AOUT2R"},
1326748d055SPeter Ujfalusi 	{"IVI A Line Out 3", NULL, "codec-a AOUT3L"},
1336748d055SPeter Ujfalusi 	{"IVI A Line Out 3", NULL, "codec-a AOUT3R"},
1346748d055SPeter Ujfalusi 	{"IVI A Line Out 4", NULL, "codec-a AOUT4L"},
1356748d055SPeter Ujfalusi 	{"IVI A Line Out 4", NULL, "codec-a AOUT4R"},
1366748d055SPeter Ujfalusi 
1376748d055SPeter Ujfalusi 	{"codec-a AIN1L", NULL, "IVI A Stereo Mic 1"},
1386748d055SPeter Ujfalusi 	{"codec-a AIN1R", NULL, "IVI A Stereo Mic 1"},
1396748d055SPeter Ujfalusi 	{"codec-a AIN2L", NULL, "IVI A Stereo Mic 2"},
1406748d055SPeter Ujfalusi 	{"codec-a AIN2R", NULL, "IVI A Stereo Mic 2"},
1416748d055SPeter Ujfalusi 	{"codec-a AIN3L", NULL, "IVI A Line In"},
1426748d055SPeter Ujfalusi 	{"codec-a AIN3R", NULL, "IVI A Line In"},
1436748d055SPeter Ujfalusi };
1446748d055SPeter Ujfalusi 
1456748d055SPeter Ujfalusi static const struct snd_soc_dapm_widget j721e_ivi_codec_b_dapm_widgets[] = {
1466748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI B Line Out 1", NULL),
1476748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI B Line Out 2", NULL),
1486748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI B Line Out 3", NULL),
1496748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI B Line Out 4", NULL),
1506748d055SPeter Ujfalusi 	SND_SOC_DAPM_MIC("IVI B Stereo Mic 1", NULL),
1516748d055SPeter Ujfalusi 	SND_SOC_DAPM_MIC("IVI B Stereo Mic 2", NULL),
1526748d055SPeter Ujfalusi 	SND_SOC_DAPM_LINE("IVI B Line In", NULL),
1536748d055SPeter Ujfalusi };
1546748d055SPeter Ujfalusi 
1556748d055SPeter Ujfalusi static const struct snd_soc_dapm_route j721e_codec_b_dapm_routes[] = {
1566748d055SPeter Ujfalusi 	{"IVI B Line Out 1", NULL, "codec-b AOUT1L"},
1576748d055SPeter Ujfalusi 	{"IVI B Line Out 1", NULL, "codec-b AOUT1R"},
1586748d055SPeter Ujfalusi 	{"IVI B Line Out 2", NULL, "codec-b AOUT2L"},
1596748d055SPeter Ujfalusi 	{"IVI B Line Out 2", NULL, "codec-b AOUT2R"},
1606748d055SPeter Ujfalusi 	{"IVI B Line Out 3", NULL, "codec-b AOUT3L"},
1616748d055SPeter Ujfalusi 	{"IVI B Line Out 3", NULL, "codec-b AOUT3R"},
1626748d055SPeter Ujfalusi 	{"IVI B Line Out 4", NULL, "codec-b AOUT4L"},
1636748d055SPeter Ujfalusi 	{"IVI B Line Out 4", NULL, "codec-b AOUT4R"},
1646748d055SPeter Ujfalusi 
1656748d055SPeter Ujfalusi 	{"codec-b AIN1L", NULL, "IVI B Stereo Mic 1"},
1666748d055SPeter Ujfalusi 	{"codec-b AIN1R", NULL, "IVI B Stereo Mic 1"},
1676748d055SPeter Ujfalusi 	{"codec-b AIN2L", NULL, "IVI B Stereo Mic 2"},
1686748d055SPeter Ujfalusi 	{"codec-b AIN2R", NULL, "IVI B Stereo Mic 2"},
1696748d055SPeter Ujfalusi 	{"codec-b AIN3L", NULL, "IVI B Line In"},
1706748d055SPeter Ujfalusi 	{"codec-b AIN3R", NULL, "IVI B Line In"},
1716748d055SPeter Ujfalusi };
1726748d055SPeter Ujfalusi 
j721e_configure_refclk(struct j721e_priv * priv,unsigned int audio_domain,unsigned int rate)1736748d055SPeter Ujfalusi static int j721e_configure_refclk(struct j721e_priv *priv,
1746748d055SPeter Ujfalusi 				  unsigned int audio_domain, unsigned int rate)
1756748d055SPeter Ujfalusi {
1766748d055SPeter Ujfalusi 	struct j721e_audio_domain *domain = &priv->audio_domains[audio_domain];
1776748d055SPeter Ujfalusi 	unsigned int scki;
1786748d055SPeter Ujfalusi 	int ret = -EINVAL;
1796748d055SPeter Ujfalusi 	int i, clk_id;
1806748d055SPeter Ujfalusi 
1816748d055SPeter Ujfalusi 	if (!(rate % 8000) && priv->pll_rates[J721E_CLK_PARENT_48000])
1826748d055SPeter Ujfalusi 		clk_id = J721E_CLK_PARENT_48000;
1836748d055SPeter Ujfalusi 	else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_44100])
1846748d055SPeter Ujfalusi 		clk_id = J721E_CLK_PARENT_44100;
1856748d055SPeter Ujfalusi 	else
1866748d055SPeter Ujfalusi 		return ret;
1876748d055SPeter Ujfalusi 
1886748d055SPeter Ujfalusi 	for (i = 0; i < ARRAY_SIZE(ratios_for_pcm3168a); i++) {
1896748d055SPeter Ujfalusi 		scki = ratios_for_pcm3168a[i] * rate;
1906748d055SPeter Ujfalusi 
1916748d055SPeter Ujfalusi 		if (priv->pll_rates[clk_id] / scki <= J721E_MAX_CLK_HSDIV) {
1926748d055SPeter Ujfalusi 			ret = 0;
1936748d055SPeter Ujfalusi 			break;
1946748d055SPeter Ujfalusi 		}
1956748d055SPeter Ujfalusi 	}
1966748d055SPeter Ujfalusi 
1976748d055SPeter Ujfalusi 	if (ret) {
1986748d055SPeter Ujfalusi 		dev_err(priv->dev, "No valid clock configuration for %u Hz\n",
1996748d055SPeter Ujfalusi 			rate);
2006748d055SPeter Ujfalusi 		return ret;
2016748d055SPeter Ujfalusi 	}
2026748d055SPeter Ujfalusi 
20382d28b67SPeter Ujfalusi 	if (domain->parent_clk_id == -1 || priv->hsdiv_rates[domain->parent_clk_id] != scki) {
2046748d055SPeter Ujfalusi 		dev_dbg(priv->dev,
205cfc9d37aSPeter Ujfalusi 			"domain%u configuration for %u Hz: %s, %dxFS (SCKI: %u Hz)\n",
206cfc9d37aSPeter Ujfalusi 			audio_domain, rate,
2076748d055SPeter Ujfalusi 			clk_id == J721E_CLK_PARENT_48000 ? "PLL4" : "PLL15",
2086748d055SPeter Ujfalusi 			ratios_for_pcm3168a[i], scki);
2096748d055SPeter Ujfalusi 
2106748d055SPeter Ujfalusi 		if (domain->parent_clk_id != clk_id) {
2116748d055SPeter Ujfalusi 			ret = clk_set_parent(domain->codec.target,
2126748d055SPeter Ujfalusi 					     domain->codec.parent[clk_id]);
2136748d055SPeter Ujfalusi 			if (ret)
2146748d055SPeter Ujfalusi 				return ret;
2156748d055SPeter Ujfalusi 
2166748d055SPeter Ujfalusi 			ret = clk_set_parent(domain->mcasp.target,
2176748d055SPeter Ujfalusi 					     domain->mcasp.parent[clk_id]);
2186748d055SPeter Ujfalusi 			if (ret)
2196748d055SPeter Ujfalusi 				return ret;
2206748d055SPeter Ujfalusi 
2216748d055SPeter Ujfalusi 			domain->parent_clk_id = clk_id;
2226748d055SPeter Ujfalusi 		}
2236748d055SPeter Ujfalusi 
2246748d055SPeter Ujfalusi 		ret = clk_set_rate(domain->codec.target, scki);
2256748d055SPeter Ujfalusi 		if (ret) {
2266748d055SPeter Ujfalusi 			dev_err(priv->dev, "codec set rate failed for %u Hz\n",
2276748d055SPeter Ujfalusi 				scki);
2286748d055SPeter Ujfalusi 			return ret;
2296748d055SPeter Ujfalusi 		}
2306748d055SPeter Ujfalusi 
2316748d055SPeter Ujfalusi 		ret = clk_set_rate(domain->mcasp.target, scki);
2326748d055SPeter Ujfalusi 		if (!ret) {
2336748d055SPeter Ujfalusi 			priv->hsdiv_rates[domain->parent_clk_id] = scki;
2346748d055SPeter Ujfalusi 		} else {
2356748d055SPeter Ujfalusi 			dev_err(priv->dev, "mcasp set rate failed for %u Hz\n",
2366748d055SPeter Ujfalusi 				scki);
2376748d055SPeter Ujfalusi 			return ret;
2386748d055SPeter Ujfalusi 		}
2396748d055SPeter Ujfalusi 	}
2406748d055SPeter Ujfalusi 
2416748d055SPeter Ujfalusi 	return ret;
2426748d055SPeter Ujfalusi }
2436748d055SPeter Ujfalusi 
j721e_rule_rate(struct snd_pcm_hw_params * params,struct snd_pcm_hw_rule * rule)2446748d055SPeter Ujfalusi static int j721e_rule_rate(struct snd_pcm_hw_params *params,
2456748d055SPeter Ujfalusi 			   struct snd_pcm_hw_rule *rule)
2466748d055SPeter Ujfalusi {
2476748d055SPeter Ujfalusi 	struct snd_interval *t = rule->private;
2486748d055SPeter Ujfalusi 
2496748d055SPeter Ujfalusi 	return snd_interval_refine(hw_param_interval(params, rule->var), t);
2506748d055SPeter Ujfalusi }
2516748d055SPeter Ujfalusi 
j721e_audio_startup(struct snd_pcm_substream * substream)2526748d055SPeter Ujfalusi static int j721e_audio_startup(struct snd_pcm_substream *substream)
2536748d055SPeter Ujfalusi {
25402cde14aSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2556748d055SPeter Ujfalusi 	struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
2566748d055SPeter Ujfalusi 	unsigned int domain_id = rtd->dai_link->id;
2576748d055SPeter Ujfalusi 	struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
2586748d055SPeter Ujfalusi 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
2596748d055SPeter Ujfalusi 	struct snd_soc_dai *codec_dai;
2606748d055SPeter Ujfalusi 	unsigned int active_rate;
2616748d055SPeter Ujfalusi 	int ret = 0;
2626748d055SPeter Ujfalusi 	int i;
2636748d055SPeter Ujfalusi 
2646748d055SPeter Ujfalusi 	mutex_lock(&priv->mutex);
2656748d055SPeter Ujfalusi 
2666748d055SPeter Ujfalusi 	domain->active++;
2676748d055SPeter Ujfalusi 
268cfc9d37aSPeter Ujfalusi 	for (i = 0; i < J721E_AUDIO_DOMAIN_LAST; i++) {
269cfc9d37aSPeter Ujfalusi 		active_rate = priv->audio_domains[i].rate;
270cfc9d37aSPeter Ujfalusi 		if (active_rate)
271cfc9d37aSPeter Ujfalusi 			break;
272cfc9d37aSPeter Ujfalusi 	}
2736748d055SPeter Ujfalusi 
2746748d055SPeter Ujfalusi 	if (active_rate)
2756748d055SPeter Ujfalusi 		ret = snd_pcm_hw_constraint_single(substream->runtime,
2766748d055SPeter Ujfalusi 						   SNDRV_PCM_HW_PARAM_RATE,
2776748d055SPeter Ujfalusi 						   active_rate);
2786748d055SPeter Ujfalusi 	else
2796748d055SPeter Ujfalusi 		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
2806748d055SPeter Ujfalusi 					  SNDRV_PCM_HW_PARAM_RATE,
2816748d055SPeter Ujfalusi 					  j721e_rule_rate, &priv->rate_range,
2826748d055SPeter Ujfalusi 					  SNDRV_PCM_HW_PARAM_RATE, -1);
2836748d055SPeter Ujfalusi 
2846748d055SPeter Ujfalusi 
2856748d055SPeter Ujfalusi 	if (ret)
28678d2a05eSPeter Ujfalusi 		goto out;
2876748d055SPeter Ujfalusi 
2886748d055SPeter Ujfalusi 	/* Reset TDM slots to 32 */
2896748d055SPeter Ujfalusi 	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
2906748d055SPeter Ujfalusi 	if (ret && ret != -ENOTSUPP)
29178d2a05eSPeter Ujfalusi 		goto out;
2926748d055SPeter Ujfalusi 
2936748d055SPeter Ujfalusi 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
2946748d055SPeter Ujfalusi 		ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32);
2956748d055SPeter Ujfalusi 		if (ret && ret != -ENOTSUPP)
29678d2a05eSPeter Ujfalusi 			goto out;
2976748d055SPeter Ujfalusi 	}
2986748d055SPeter Ujfalusi 
29978d2a05eSPeter Ujfalusi 	if (ret == -ENOTSUPP)
30078d2a05eSPeter Ujfalusi 		ret = 0;
30178d2a05eSPeter Ujfalusi out:
30278d2a05eSPeter Ujfalusi 	if (ret)
30378d2a05eSPeter Ujfalusi 		domain->active--;
30478d2a05eSPeter Ujfalusi 	mutex_unlock(&priv->mutex);
30578d2a05eSPeter Ujfalusi 
30678d2a05eSPeter Ujfalusi 	return ret;
3076748d055SPeter Ujfalusi }
3086748d055SPeter Ujfalusi 
j721e_audio_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)3096748d055SPeter Ujfalusi static int j721e_audio_hw_params(struct snd_pcm_substream *substream,
3106748d055SPeter Ujfalusi 				 struct snd_pcm_hw_params *params)
3116748d055SPeter Ujfalusi {
31202cde14aSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
3136748d055SPeter Ujfalusi 	struct snd_soc_card *card = rtd->card;
3146748d055SPeter Ujfalusi 	struct j721e_priv *priv = snd_soc_card_get_drvdata(card);
3156748d055SPeter Ujfalusi 	unsigned int domain_id = rtd->dai_link->id;
3166748d055SPeter Ujfalusi 	struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
3176748d055SPeter Ujfalusi 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
3186748d055SPeter Ujfalusi 	struct snd_soc_dai *codec_dai;
3196748d055SPeter Ujfalusi 	unsigned int sysclk_rate;
3206748d055SPeter Ujfalusi 	int slot_width = 32;
3216748d055SPeter Ujfalusi 	int ret;
3226748d055SPeter Ujfalusi 	int i;
3236748d055SPeter Ujfalusi 
3246748d055SPeter Ujfalusi 	mutex_lock(&priv->mutex);
3256748d055SPeter Ujfalusi 
3266748d055SPeter Ujfalusi 	if (domain->rate && domain->rate != params_rate(params)) {
3276748d055SPeter Ujfalusi 		ret = -EINVAL;
3286748d055SPeter Ujfalusi 		goto out;
3296748d055SPeter Ujfalusi 	}
3306748d055SPeter Ujfalusi 
3316748d055SPeter Ujfalusi 	if (params_width(params) == 16)
3326748d055SPeter Ujfalusi 		slot_width = 16;
3336748d055SPeter Ujfalusi 
3346748d055SPeter Ujfalusi 	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, slot_width);
3356748d055SPeter Ujfalusi 	if (ret && ret != -ENOTSUPP)
3366748d055SPeter Ujfalusi 		goto out;
3376748d055SPeter Ujfalusi 
3386748d055SPeter Ujfalusi 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
3396748d055SPeter Ujfalusi 		ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2,
3406748d055SPeter Ujfalusi 					       slot_width);
3416748d055SPeter Ujfalusi 		if (ret && ret != -ENOTSUPP)
34259b44649SWei Yongjun 			goto out;
3436748d055SPeter Ujfalusi 	}
3446748d055SPeter Ujfalusi 
3456748d055SPeter Ujfalusi 	ret = j721e_configure_refclk(priv, domain_id, params_rate(params));
3466748d055SPeter Ujfalusi 	if (ret)
3476748d055SPeter Ujfalusi 		goto out;
3486748d055SPeter Ujfalusi 
3496748d055SPeter Ujfalusi 	sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id];
3506748d055SPeter Ujfalusi 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
3516748d055SPeter Ujfalusi 		ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate,
3526748d055SPeter Ujfalusi 					     SND_SOC_CLOCK_IN);
3536748d055SPeter Ujfalusi 		if (ret && ret != -ENOTSUPP) {
3546748d055SPeter Ujfalusi 			dev_err(priv->dev,
3556748d055SPeter Ujfalusi 				"codec set_sysclk failed for %u Hz\n",
3566748d055SPeter Ujfalusi 				sysclk_rate);
3576748d055SPeter Ujfalusi 			goto out;
3586748d055SPeter Ujfalusi 		}
3596748d055SPeter Ujfalusi 	}
3606748d055SPeter Ujfalusi 
3616748d055SPeter Ujfalusi 	ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK,
3626748d055SPeter Ujfalusi 				     sysclk_rate, SND_SOC_CLOCK_IN);
3636748d055SPeter Ujfalusi 
3646748d055SPeter Ujfalusi 	if (ret && ret != -ENOTSUPP) {
3656748d055SPeter Ujfalusi 		dev_err(priv->dev, "mcasp set_sysclk failed for %u Hz\n",
3666748d055SPeter Ujfalusi 			sysclk_rate);
3676748d055SPeter Ujfalusi 	} else {
3686748d055SPeter Ujfalusi 		domain->rate = params_rate(params);
3696748d055SPeter Ujfalusi 		ret = 0;
3706748d055SPeter Ujfalusi 	}
3716748d055SPeter Ujfalusi 
3726748d055SPeter Ujfalusi out:
3736748d055SPeter Ujfalusi 	mutex_unlock(&priv->mutex);
3746748d055SPeter Ujfalusi 	return ret;
3756748d055SPeter Ujfalusi }
3766748d055SPeter Ujfalusi 
j721e_audio_shutdown(struct snd_pcm_substream * substream)3776748d055SPeter Ujfalusi static void j721e_audio_shutdown(struct snd_pcm_substream *substream)
3786748d055SPeter Ujfalusi {
37902cde14aSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
3806748d055SPeter Ujfalusi 	struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
3816748d055SPeter Ujfalusi 	unsigned int domain_id = rtd->dai_link->id;
3826748d055SPeter Ujfalusi 	struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
3836748d055SPeter Ujfalusi 
3846748d055SPeter Ujfalusi 	mutex_lock(&priv->mutex);
3856748d055SPeter Ujfalusi 
3866748d055SPeter Ujfalusi 	domain->active--;
3876748d055SPeter Ujfalusi 	if (!domain->active) {
3886748d055SPeter Ujfalusi 		domain->rate = 0;
3896748d055SPeter Ujfalusi 		domain->active_link = 0;
3906748d055SPeter Ujfalusi 	}
3916748d055SPeter Ujfalusi 
3926748d055SPeter Ujfalusi 	mutex_unlock(&priv->mutex);
3936748d055SPeter Ujfalusi }
3946748d055SPeter Ujfalusi 
3956748d055SPeter Ujfalusi static const struct snd_soc_ops j721e_audio_ops = {
3966748d055SPeter Ujfalusi 	.startup = j721e_audio_startup,
3976748d055SPeter Ujfalusi 	.hw_params = j721e_audio_hw_params,
3986748d055SPeter Ujfalusi 	.shutdown = j721e_audio_shutdown,
3996748d055SPeter Ujfalusi };
4006748d055SPeter Ujfalusi 
j721e_audio_init(struct snd_soc_pcm_runtime * rtd)4016748d055SPeter Ujfalusi static int j721e_audio_init(struct snd_soc_pcm_runtime *rtd)
4026748d055SPeter Ujfalusi {
4036748d055SPeter Ujfalusi 	struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card);
4046748d055SPeter Ujfalusi 	unsigned int domain_id = rtd->dai_link->id;
4056748d055SPeter Ujfalusi 	struct j721e_audio_domain *domain = &priv->audio_domains[domain_id];
4066748d055SPeter Ujfalusi 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
4076748d055SPeter Ujfalusi 	struct snd_soc_dai *codec_dai;
4086748d055SPeter Ujfalusi 	unsigned int sysclk_rate;
4096748d055SPeter Ujfalusi 	int i, ret;
4106748d055SPeter Ujfalusi 
4116748d055SPeter Ujfalusi 	/* Set up initial clock configuration */
4126748d055SPeter Ujfalusi 	ret = j721e_configure_refclk(priv, domain_id, 48000);
4136748d055SPeter Ujfalusi 	if (ret)
4146748d055SPeter Ujfalusi 		return ret;
4156748d055SPeter Ujfalusi 
4166748d055SPeter Ujfalusi 	sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id];
4176748d055SPeter Ujfalusi 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
4186748d055SPeter Ujfalusi 		ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate,
4196748d055SPeter Ujfalusi 					     SND_SOC_CLOCK_IN);
4206748d055SPeter Ujfalusi 		if (ret && ret != -ENOTSUPP)
4216748d055SPeter Ujfalusi 			return ret;
4226748d055SPeter Ujfalusi 	}
4236748d055SPeter Ujfalusi 
4246748d055SPeter Ujfalusi 	ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK,
4256748d055SPeter Ujfalusi 				     sysclk_rate, SND_SOC_CLOCK_IN);
4266748d055SPeter Ujfalusi 	if (ret && ret != -ENOTSUPP)
4276748d055SPeter Ujfalusi 		return ret;
4286748d055SPeter Ujfalusi 
4296748d055SPeter Ujfalusi 	/* Set initial tdm slots */
4306748d055SPeter Ujfalusi 	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
4316748d055SPeter Ujfalusi 	if (ret && ret != -ENOTSUPP)
4326748d055SPeter Ujfalusi 		return ret;
4336748d055SPeter Ujfalusi 
4346748d055SPeter Ujfalusi 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
4356748d055SPeter Ujfalusi 		ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32);
4366748d055SPeter Ujfalusi 		if (ret && ret != -ENOTSUPP)
4376748d055SPeter Ujfalusi 			return ret;
4386748d055SPeter Ujfalusi 	}
4396748d055SPeter Ujfalusi 
4406748d055SPeter Ujfalusi 	return 0;
4416748d055SPeter Ujfalusi }
4426748d055SPeter Ujfalusi 
j721e_audio_init_ivi(struct snd_soc_pcm_runtime * rtd)4436748d055SPeter Ujfalusi static int j721e_audio_init_ivi(struct snd_soc_pcm_runtime *rtd)
4446748d055SPeter Ujfalusi {
4456748d055SPeter Ujfalusi 	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
4466748d055SPeter Ujfalusi 
4476748d055SPeter Ujfalusi 	snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_a_dapm_widgets,
4486748d055SPeter Ujfalusi 				  ARRAY_SIZE(j721e_ivi_codec_a_dapm_widgets));
4496748d055SPeter Ujfalusi 	snd_soc_dapm_add_routes(dapm, j721e_codec_a_dapm_routes,
4506748d055SPeter Ujfalusi 				ARRAY_SIZE(j721e_codec_a_dapm_routes));
4516748d055SPeter Ujfalusi 	snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_b_dapm_widgets,
4526748d055SPeter Ujfalusi 				  ARRAY_SIZE(j721e_ivi_codec_b_dapm_widgets));
4536748d055SPeter Ujfalusi 	snd_soc_dapm_add_routes(dapm, j721e_codec_b_dapm_routes,
4546748d055SPeter Ujfalusi 				ARRAY_SIZE(j721e_codec_b_dapm_routes));
4556748d055SPeter Ujfalusi 
4566748d055SPeter Ujfalusi 	return j721e_audio_init(rtd);
4576748d055SPeter Ujfalusi }
4586748d055SPeter Ujfalusi 
j721e_get_clocks(struct device * dev,struct j721e_audio_clocks * clocks,char * prefix)4596748d055SPeter Ujfalusi static int j721e_get_clocks(struct device *dev,
4606748d055SPeter Ujfalusi 			    struct j721e_audio_clocks *clocks, char *prefix)
4616748d055SPeter Ujfalusi {
4626748d055SPeter Ujfalusi 	struct clk *parent;
4636748d055SPeter Ujfalusi 	char *clk_name;
4646748d055SPeter Ujfalusi 	int ret;
4656748d055SPeter Ujfalusi 
4666748d055SPeter Ujfalusi 	clocks->target = devm_clk_get(dev, prefix);
46788fb6da3SKuninori Morimoto 	if (IS_ERR(clocks->target))
46888fb6da3SKuninori Morimoto 		return dev_err_probe(dev, PTR_ERR(clocks->target),
46988fb6da3SKuninori Morimoto 				     "failed to acquire %s\n", prefix);
4706748d055SPeter Ujfalusi 
4716748d055SPeter Ujfalusi 	clk_name = kasprintf(GFP_KERNEL, "%s-48000", prefix);
4726748d055SPeter Ujfalusi 	if (clk_name) {
4736748d055SPeter Ujfalusi 		parent = devm_clk_get(dev, clk_name);
4746748d055SPeter Ujfalusi 		kfree(clk_name);
4756748d055SPeter Ujfalusi 		if (IS_ERR(parent)) {
4766748d055SPeter Ujfalusi 			ret = PTR_ERR(parent);
4776748d055SPeter Ujfalusi 			if (ret == -EPROBE_DEFER)
4786748d055SPeter Ujfalusi 				return ret;
4796748d055SPeter Ujfalusi 
4806748d055SPeter Ujfalusi 			dev_dbg(dev, "no 48KHz parent for %s: %d\n", prefix, ret);
4816748d055SPeter Ujfalusi 			parent = NULL;
4826748d055SPeter Ujfalusi 		}
4836748d055SPeter Ujfalusi 		clocks->parent[J721E_CLK_PARENT_48000] = parent;
4846748d055SPeter Ujfalusi 	} else {
4856748d055SPeter Ujfalusi 		return -ENOMEM;
4866748d055SPeter Ujfalusi 	}
4876748d055SPeter Ujfalusi 
4886748d055SPeter Ujfalusi 	clk_name = kasprintf(GFP_KERNEL, "%s-44100", prefix);
4896748d055SPeter Ujfalusi 	if (clk_name) {
4906748d055SPeter Ujfalusi 		parent = devm_clk_get(dev, clk_name);
4916748d055SPeter Ujfalusi 		kfree(clk_name);
4926748d055SPeter Ujfalusi 		if (IS_ERR(parent)) {
4936748d055SPeter Ujfalusi 			ret = PTR_ERR(parent);
4946748d055SPeter Ujfalusi 			if (ret == -EPROBE_DEFER)
4956748d055SPeter Ujfalusi 				return ret;
4966748d055SPeter Ujfalusi 
4976748d055SPeter Ujfalusi 			dev_dbg(dev, "no 44.1KHz parent for %s: %d\n", prefix, ret);
4986748d055SPeter Ujfalusi 			parent = NULL;
4996748d055SPeter Ujfalusi 		}
5006748d055SPeter Ujfalusi 		clocks->parent[J721E_CLK_PARENT_44100] = parent;
5016748d055SPeter Ujfalusi 	} else {
5026748d055SPeter Ujfalusi 		return -ENOMEM;
5036748d055SPeter Ujfalusi 	}
5046748d055SPeter Ujfalusi 
5056748d055SPeter Ujfalusi 	if (!clocks->parent[J721E_CLK_PARENT_44100] &&
5066748d055SPeter Ujfalusi 	    !clocks->parent[J721E_CLK_PARENT_48000]) {
5076748d055SPeter Ujfalusi 		dev_err(dev, "At least one parent clock is needed for %s\n",
5086748d055SPeter Ujfalusi 			prefix);
5096748d055SPeter Ujfalusi 		return -EINVAL;
5106748d055SPeter Ujfalusi 	}
5116748d055SPeter Ujfalusi 
5126748d055SPeter Ujfalusi 	return 0;
5136748d055SPeter Ujfalusi }
5146748d055SPeter Ujfalusi 
5156748d055SPeter Ujfalusi static const struct j721e_audio_match_data j721e_cpb_data = {
5166748d055SPeter Ujfalusi 	.board_type = J721E_BOARD_CPB,
5176748d055SPeter Ujfalusi 	.num_links = 2, /* CPB pcm3168a */
5186748d055SPeter Ujfalusi 	.pll_rates = {
5196748d055SPeter Ujfalusi 		[J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */
5206748d055SPeter Ujfalusi 		[J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */
5216748d055SPeter Ujfalusi 	},
5226748d055SPeter Ujfalusi };
5236748d055SPeter Ujfalusi 
5246748d055SPeter Ujfalusi static const struct j721e_audio_match_data j721e_cpb_ivi_data = {
5256748d055SPeter Ujfalusi 	.board_type = J721E_BOARD_CPB_IVI,
5266748d055SPeter Ujfalusi 	.num_links = 4, /* CPB pcm3168a + 2x pcm3168a on IVI */
5276748d055SPeter Ujfalusi 	.pll_rates = {
5286748d055SPeter Ujfalusi 		[J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */
5296748d055SPeter Ujfalusi 		[J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */
5306748d055SPeter Ujfalusi 	},
5316748d055SPeter Ujfalusi };
5326748d055SPeter Ujfalusi 
53318c140f4SPeter Ujfalusi static const struct j721e_audio_match_data j7200_cpb_data = {
53418c140f4SPeter Ujfalusi 	.board_type = J721E_BOARD_CPB,
53518c140f4SPeter Ujfalusi 	.num_links = 2, /* CPB pcm3168a */
53618c140f4SPeter Ujfalusi 	.pll_rates = {
53718c140f4SPeter Ujfalusi 		[J721E_CLK_PARENT_48000] = 2359296000u, /* PLL4 */
53818c140f4SPeter Ujfalusi 	},
53918c140f4SPeter Ujfalusi };
54018c140f4SPeter Ujfalusi 
5416748d055SPeter Ujfalusi static const struct of_device_id j721e_audio_of_match[] = {
5426748d055SPeter Ujfalusi 	{
5436748d055SPeter Ujfalusi 		.compatible = "ti,j721e-cpb-audio",
5446748d055SPeter Ujfalusi 		.data = &j721e_cpb_data,
5456748d055SPeter Ujfalusi 	}, {
5466748d055SPeter Ujfalusi 		.compatible = "ti,j721e-cpb-ivi-audio",
5476748d055SPeter Ujfalusi 		.data = &j721e_cpb_ivi_data,
54818c140f4SPeter Ujfalusi 	}, {
54918c140f4SPeter Ujfalusi 		.compatible = "ti,j7200-cpb-audio",
55018c140f4SPeter Ujfalusi 		.data = &j7200_cpb_data,
5516748d055SPeter Ujfalusi 	},
5526748d055SPeter Ujfalusi 	{ },
5536748d055SPeter Ujfalusi };
5546748d055SPeter Ujfalusi MODULE_DEVICE_TABLE(of, j721e_audio_of_match);
5556748d055SPeter Ujfalusi 
j721e_calculate_rate_range(struct j721e_priv * priv)5566748d055SPeter Ujfalusi static int j721e_calculate_rate_range(struct j721e_priv *priv)
5576748d055SPeter Ujfalusi {
5586748d055SPeter Ujfalusi 	const struct j721e_audio_match_data *match_data = priv->match_data;
5596748d055SPeter Ujfalusi 	struct j721e_audio_clocks *domain_clocks;
5606748d055SPeter Ujfalusi 	unsigned int min_rate, max_rate, pll_rate;
5616748d055SPeter Ujfalusi 	struct clk *pll;
5626748d055SPeter Ujfalusi 
5636748d055SPeter Ujfalusi 	domain_clocks = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].mcasp;
5646748d055SPeter Ujfalusi 
5656748d055SPeter Ujfalusi 	pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_44100]);
5666748d055SPeter Ujfalusi 	if (IS_ERR_OR_NULL(pll)) {
5676748d055SPeter Ujfalusi 		priv->pll_rates[J721E_CLK_PARENT_44100] =
5686748d055SPeter Ujfalusi 				match_data->pll_rates[J721E_CLK_PARENT_44100];
5696748d055SPeter Ujfalusi 	} else {
5706748d055SPeter Ujfalusi 		priv->pll_rates[J721E_CLK_PARENT_44100] = clk_get_rate(pll);
5716748d055SPeter Ujfalusi 		clk_put(pll);
5726748d055SPeter Ujfalusi 	}
5736748d055SPeter Ujfalusi 
5746748d055SPeter Ujfalusi 	pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_48000]);
5756748d055SPeter Ujfalusi 	if (IS_ERR_OR_NULL(pll)) {
5766748d055SPeter Ujfalusi 		priv->pll_rates[J721E_CLK_PARENT_48000] =
5776748d055SPeter Ujfalusi 				match_data->pll_rates[J721E_CLK_PARENT_48000];
5786748d055SPeter Ujfalusi 	} else {
5796748d055SPeter Ujfalusi 		priv->pll_rates[J721E_CLK_PARENT_48000] = clk_get_rate(pll);
5806748d055SPeter Ujfalusi 		clk_put(pll);
5816748d055SPeter Ujfalusi 	}
5826748d055SPeter Ujfalusi 
5836748d055SPeter Ujfalusi 	if (!priv->pll_rates[J721E_CLK_PARENT_44100] &&
5846748d055SPeter Ujfalusi 	    !priv->pll_rates[J721E_CLK_PARENT_48000]) {
5856748d055SPeter Ujfalusi 		dev_err(priv->dev, "At least one PLL is needed\n");
5866748d055SPeter Ujfalusi 		return -EINVAL;
5876748d055SPeter Ujfalusi 	}
5886748d055SPeter Ujfalusi 
5896748d055SPeter Ujfalusi 	if (priv->pll_rates[J721E_CLK_PARENT_44100])
5906748d055SPeter Ujfalusi 		pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100];
5916748d055SPeter Ujfalusi 	else
5926748d055SPeter Ujfalusi 		pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000];
5936748d055SPeter Ujfalusi 
5946748d055SPeter Ujfalusi 	min_rate = pll_rate / J721E_MAX_CLK_HSDIV;
5956748d055SPeter Ujfalusi 	min_rate /= ratios_for_pcm3168a[ARRAY_SIZE(ratios_for_pcm3168a) - 1];
5966748d055SPeter Ujfalusi 
5976748d055SPeter Ujfalusi 	if (priv->pll_rates[J721E_CLK_PARENT_48000])
5986748d055SPeter Ujfalusi 		pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000];
5996748d055SPeter Ujfalusi 	else
6006748d055SPeter Ujfalusi 		pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100];
6016748d055SPeter Ujfalusi 
6026748d055SPeter Ujfalusi 	if (pll_rate > PCM1368A_MAX_SYSCLK)
6036748d055SPeter Ujfalusi 		pll_rate = PCM1368A_MAX_SYSCLK;
6046748d055SPeter Ujfalusi 
6056748d055SPeter Ujfalusi 	max_rate = pll_rate / ratios_for_pcm3168a[0];
6066748d055SPeter Ujfalusi 
6076748d055SPeter Ujfalusi 	snd_interval_any(&priv->rate_range);
6086748d055SPeter Ujfalusi 	priv->rate_range.min = min_rate;
6096748d055SPeter Ujfalusi 	priv->rate_range.max = max_rate;
6106748d055SPeter Ujfalusi 
6116748d055SPeter Ujfalusi 	return 0;
6126748d055SPeter Ujfalusi }
6136748d055SPeter Ujfalusi 
j721e_soc_probe_cpb(struct j721e_priv * priv,int * link_idx,int * conf_idx)6146748d055SPeter Ujfalusi static int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx,
6156748d055SPeter Ujfalusi 			       int *conf_idx)
6166748d055SPeter Ujfalusi {
6176748d055SPeter Ujfalusi 	struct device_node *node = priv->dev->of_node;
6186748d055SPeter Ujfalusi 	struct snd_soc_dai_link_component *compnent;
6196748d055SPeter Ujfalusi 	struct device_node *dai_node, *codec_node;
6206748d055SPeter Ujfalusi 	struct j721e_audio_domain *domain;
6216748d055SPeter Ujfalusi 	int comp_count, comp_idx;
6226748d055SPeter Ujfalusi 	int ret;
6236748d055SPeter Ujfalusi 
6246748d055SPeter Ujfalusi 	dai_node = of_parse_phandle(node, "ti,cpb-mcasp", 0);
6256748d055SPeter Ujfalusi 	if (!dai_node) {
6266748d055SPeter Ujfalusi 		dev_err(priv->dev, "CPB McASP node is not provided\n");
6276748d055SPeter Ujfalusi 		return -EINVAL;
6286748d055SPeter Ujfalusi 	}
6296748d055SPeter Ujfalusi 
6306748d055SPeter Ujfalusi 	codec_node = of_parse_phandle(node, "ti,cpb-codec", 0);
6316748d055SPeter Ujfalusi 	if (!codec_node) {
6326748d055SPeter Ujfalusi 		dev_err(priv->dev, "CPB codec node is not provided\n");
633*a34840c4SMiaoqian Lin 		ret = -EINVAL;
634*a34840c4SMiaoqian Lin 		goto put_dai_node;
6356748d055SPeter Ujfalusi 	}
6366748d055SPeter Ujfalusi 
6376748d055SPeter Ujfalusi 	domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB];
6386748d055SPeter Ujfalusi 	ret = j721e_get_clocks(priv->dev, &domain->codec, "cpb-codec-scki");
6396748d055SPeter Ujfalusi 	if (ret)
640*a34840c4SMiaoqian Lin 		goto put_codec_node;
6416748d055SPeter Ujfalusi 
6426748d055SPeter Ujfalusi 	ret = j721e_get_clocks(priv->dev, &domain->mcasp, "cpb-mcasp-auxclk");
6436748d055SPeter Ujfalusi 	if (ret)
644*a34840c4SMiaoqian Lin 		goto put_codec_node;
6456748d055SPeter Ujfalusi 
6466748d055SPeter Ujfalusi 	/*
6476748d055SPeter Ujfalusi 	 * Common Processor Board, two links
6486748d055SPeter Ujfalusi 	 * Link 1: McASP10 -> pcm3168a_1 DAC
6496748d055SPeter Ujfalusi 	 * Link 2: McASP10 <- pcm3168a_1 ADC
6506748d055SPeter Ujfalusi 	 */
6516748d055SPeter Ujfalusi 	comp_count = 6;
6526748d055SPeter Ujfalusi 	compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
6536748d055SPeter Ujfalusi 				GFP_KERNEL);
654*a34840c4SMiaoqian Lin 	if (!compnent) {
655*a34840c4SMiaoqian Lin 		ret = -ENOMEM;
656*a34840c4SMiaoqian Lin 		goto put_codec_node;
657*a34840c4SMiaoqian Lin 	}
6586748d055SPeter Ujfalusi 
6596748d055SPeter Ujfalusi 	comp_idx = 0;
6606748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
6616748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_cpus = 1;
6626748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs = &compnent[comp_idx++];
6636748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_codecs = 1;
6646748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
6656748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_platforms = 1;
6666748d055SPeter Ujfalusi 
6676748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].name = "CPB PCM3168A Playback";
6686748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog";
6696748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus->of_node = dai_node;
6706748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms->of_node = dai_node;
6716748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs->of_node = codec_node;
6726748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-dac";
6736748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].playback_only = 1;
6746748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB;
6756748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
6766748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].init = j721e_audio_init;
6776748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].ops = &j721e_audio_ops;
6786748d055SPeter Ujfalusi 	(*link_idx)++;
6796748d055SPeter Ujfalusi 
6806748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
6816748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_cpus = 1;
6826748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs = &compnent[comp_idx++];
6836748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_codecs = 1;
6846748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
6856748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_platforms = 1;
6866748d055SPeter Ujfalusi 
6876748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].name = "CPB PCM3168A Capture";
6886748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog";
6896748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus->of_node = dai_node;
6906748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms->of_node = dai_node;
6916748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs->of_node = codec_node;
6926748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-adc";
6936748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].capture_only = 1;
6946748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB;
6956748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
6966748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].init = j721e_audio_init;
6976748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].ops = &j721e_audio_ops;
6986748d055SPeter Ujfalusi 	(*link_idx)++;
6996748d055SPeter Ujfalusi 
7006748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].dlc.of_node = codec_node;
7016748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].name_prefix = "codec-1";
7026748d055SPeter Ujfalusi 	(*conf_idx)++;
7036748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].dlc.of_node = dai_node;
7046748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].name_prefix = "McASP10";
7056748d055SPeter Ujfalusi 	(*conf_idx)++;
7066748d055SPeter Ujfalusi 
7076748d055SPeter Ujfalusi 	return 0;
708*a34840c4SMiaoqian Lin 
709*a34840c4SMiaoqian Lin put_codec_node:
710*a34840c4SMiaoqian Lin 	of_node_put(codec_node);
711*a34840c4SMiaoqian Lin put_dai_node:
712*a34840c4SMiaoqian Lin 	of_node_put(dai_node);
713*a34840c4SMiaoqian Lin 	return ret;
7146748d055SPeter Ujfalusi }
7156748d055SPeter Ujfalusi 
j721e_soc_probe_ivi(struct j721e_priv * priv,int * link_idx,int * conf_idx)7166748d055SPeter Ujfalusi static int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx,
7176748d055SPeter Ujfalusi 			       int *conf_idx)
7186748d055SPeter Ujfalusi {
7196748d055SPeter Ujfalusi 	struct device_node *node = priv->dev->of_node;
7206748d055SPeter Ujfalusi 	struct snd_soc_dai_link_component *compnent;
7216748d055SPeter Ujfalusi 	struct device_node *dai_node, *codeca_node, *codecb_node;
7226748d055SPeter Ujfalusi 	struct j721e_audio_domain *domain;
7236748d055SPeter Ujfalusi 	int comp_count, comp_idx;
7246748d055SPeter Ujfalusi 	int ret;
7256748d055SPeter Ujfalusi 
7266748d055SPeter Ujfalusi 	if (priv->match_data->board_type != J721E_BOARD_CPB_IVI)
7276748d055SPeter Ujfalusi 		return 0;
7286748d055SPeter Ujfalusi 
7296748d055SPeter Ujfalusi 	dai_node = of_parse_phandle(node, "ti,ivi-mcasp", 0);
7306748d055SPeter Ujfalusi 	if (!dai_node) {
7316748d055SPeter Ujfalusi 		dev_err(priv->dev, "IVI McASP node is not provided\n");
7326748d055SPeter Ujfalusi 		return -EINVAL;
7336748d055SPeter Ujfalusi 	}
7346748d055SPeter Ujfalusi 
7356748d055SPeter Ujfalusi 	codeca_node = of_parse_phandle(node, "ti,ivi-codec-a", 0);
7366748d055SPeter Ujfalusi 	if (!codeca_node) {
7376748d055SPeter Ujfalusi 		dev_err(priv->dev, "IVI codec-a node is not provided\n");
738*a34840c4SMiaoqian Lin 		ret = -EINVAL;
739*a34840c4SMiaoqian Lin 		goto put_dai_node;
7406748d055SPeter Ujfalusi 	}
7416748d055SPeter Ujfalusi 
7426748d055SPeter Ujfalusi 	codecb_node = of_parse_phandle(node, "ti,ivi-codec-b", 0);
7436748d055SPeter Ujfalusi 	if (!codecb_node) {
7446748d055SPeter Ujfalusi 		dev_warn(priv->dev, "IVI codec-b node is not provided\n");
745*a34840c4SMiaoqian Lin 		ret = 0;
746*a34840c4SMiaoqian Lin 		goto put_codeca_node;
7476748d055SPeter Ujfalusi 	}
7486748d055SPeter Ujfalusi 
7496748d055SPeter Ujfalusi 	domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_IVI];
7506748d055SPeter Ujfalusi 	ret = j721e_get_clocks(priv->dev, &domain->codec, "ivi-codec-scki");
7516748d055SPeter Ujfalusi 	if (ret)
752*a34840c4SMiaoqian Lin 		goto put_codecb_node;
7536748d055SPeter Ujfalusi 
7546748d055SPeter Ujfalusi 	ret = j721e_get_clocks(priv->dev, &domain->mcasp, "ivi-mcasp-auxclk");
7556748d055SPeter Ujfalusi 	if (ret)
756*a34840c4SMiaoqian Lin 		goto put_codecb_node;
7576748d055SPeter Ujfalusi 
7586748d055SPeter Ujfalusi 	/*
7596748d055SPeter Ujfalusi 	 * IVI extension, two links
7606748d055SPeter Ujfalusi 	 * Link 1: McASP0 -> pcm3168a_a DAC
7616748d055SPeter Ujfalusi 	 *		  \> pcm3168a_b DAC
7626748d055SPeter Ujfalusi 	 * Link 2: McASP0 <- pcm3168a_a ADC
7636748d055SPeter Ujfalusi 	 *		   \ pcm3168a_b ADC
7646748d055SPeter Ujfalusi 	 */
7656748d055SPeter Ujfalusi 	comp_count = 8;
7666748d055SPeter Ujfalusi 	compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent),
7676748d055SPeter Ujfalusi 				GFP_KERNEL);
768*a34840c4SMiaoqian Lin 	if (!compnent) {
769*a34840c4SMiaoqian Lin 		ret = -ENOMEM;
770*a34840c4SMiaoqian Lin 		goto put_codecb_node;
771*a34840c4SMiaoqian Lin 	}
7726748d055SPeter Ujfalusi 
7736748d055SPeter Ujfalusi 	comp_idx = 0;
7746748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
7756748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_cpus = 1;
7766748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
7776748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_platforms = 1;
7786748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs = &compnent[comp_idx];
7796748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_codecs = 2;
7806748d055SPeter Ujfalusi 	comp_idx += 2;
7816748d055SPeter Ujfalusi 
7826748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Playback";
7836748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog";
7846748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus->of_node = dai_node;
7856748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms->of_node = dai_node;
7866748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[0].of_node = codeca_node;
7876748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-dac";
7886748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[1].of_node = codecb_node;
7896748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-dac";
7906748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].playback_only = 1;
7916748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI;
7926748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
7936748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].init = j721e_audio_init_ivi;
7946748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].ops = &j721e_audio_ops;
7956748d055SPeter Ujfalusi 	(*link_idx)++;
7966748d055SPeter Ujfalusi 
7976748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus = &compnent[comp_idx++];
7986748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_cpus = 1;
7996748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms = &compnent[comp_idx++];
8006748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_platforms = 1;
8016748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs = &compnent[comp_idx];
8026748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].num_codecs = 2;
8036748d055SPeter Ujfalusi 
8046748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Capture";
8056748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog";
8066748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].cpus->of_node = dai_node;
8076748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].platforms->of_node = dai_node;
8086748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[0].of_node = codeca_node;
8096748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-adc";
8106748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[1].of_node = codecb_node;
8116748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-adc";
8126748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].capture_only = 1;
8136748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI;
8146748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT;
8156748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].init = j721e_audio_init;
8166748d055SPeter Ujfalusi 	priv->dai_links[*link_idx].ops = &j721e_audio_ops;
8176748d055SPeter Ujfalusi 	(*link_idx)++;
8186748d055SPeter Ujfalusi 
8196748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].dlc.of_node = codeca_node;
8206748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].name_prefix = "codec-a";
8216748d055SPeter Ujfalusi 	(*conf_idx)++;
8226748d055SPeter Ujfalusi 
8236748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].dlc.of_node = codecb_node;
8246748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].name_prefix = "codec-b";
8256748d055SPeter Ujfalusi 	(*conf_idx)++;
8266748d055SPeter Ujfalusi 
8276748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].dlc.of_node = dai_node;
8286748d055SPeter Ujfalusi 	priv->codec_conf[*conf_idx].name_prefix = "McASP0";
8296748d055SPeter Ujfalusi 	(*conf_idx)++;
8306748d055SPeter Ujfalusi 
8316748d055SPeter Ujfalusi 	return 0;
832*a34840c4SMiaoqian Lin 
833*a34840c4SMiaoqian Lin 
834*a34840c4SMiaoqian Lin put_codecb_node:
835*a34840c4SMiaoqian Lin 	of_node_put(codecb_node);
836*a34840c4SMiaoqian Lin put_codeca_node:
837*a34840c4SMiaoqian Lin 	of_node_put(codeca_node);
838*a34840c4SMiaoqian Lin put_dai_node:
839*a34840c4SMiaoqian Lin 	of_node_put(dai_node);
840*a34840c4SMiaoqian Lin 	return ret;
8416748d055SPeter Ujfalusi }
8426748d055SPeter Ujfalusi 
j721e_soc_probe(struct platform_device * pdev)8436748d055SPeter Ujfalusi static int j721e_soc_probe(struct platform_device *pdev)
8446748d055SPeter Ujfalusi {
8456748d055SPeter Ujfalusi 	struct device_node *node = pdev->dev.of_node;
8466748d055SPeter Ujfalusi 	struct snd_soc_card *card;
8476748d055SPeter Ujfalusi 	const struct of_device_id *match;
8486748d055SPeter Ujfalusi 	struct j721e_priv *priv;
849cfc9d37aSPeter Ujfalusi 	int link_cnt, conf_cnt, ret, i;
8506748d055SPeter Ujfalusi 
8516748d055SPeter Ujfalusi 	if (!node) {
8526748d055SPeter Ujfalusi 		dev_err(&pdev->dev, "of node is missing.\n");
8536748d055SPeter Ujfalusi 		return -ENODEV;
8546748d055SPeter Ujfalusi 	}
8556748d055SPeter Ujfalusi 
8566748d055SPeter Ujfalusi 	match = of_match_node(j721e_audio_of_match, node);
8576748d055SPeter Ujfalusi 	if (!match) {
8586748d055SPeter Ujfalusi 		dev_err(&pdev->dev, "No compatible match found\n");
8596748d055SPeter Ujfalusi 		return -ENODEV;
8606748d055SPeter Ujfalusi 	}
8616748d055SPeter Ujfalusi 
8626748d055SPeter Ujfalusi 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
8636748d055SPeter Ujfalusi 	if (!priv)
8646748d055SPeter Ujfalusi 		return -ENOMEM;
8656748d055SPeter Ujfalusi 
8666748d055SPeter Ujfalusi 	priv->match_data = match->data;
8676748d055SPeter Ujfalusi 
8686748d055SPeter Ujfalusi 	priv->dai_links = devm_kcalloc(&pdev->dev, priv->match_data->num_links,
8696748d055SPeter Ujfalusi 				       sizeof(*priv->dai_links), GFP_KERNEL);
8706748d055SPeter Ujfalusi 	if (!priv->dai_links)
8716748d055SPeter Ujfalusi 		return -ENOMEM;
8726748d055SPeter Ujfalusi 
873cfc9d37aSPeter Ujfalusi 	for (i = 0; i < J721E_AUDIO_DOMAIN_LAST; i++)
874cfc9d37aSPeter Ujfalusi 		priv->audio_domains[i].parent_clk_id = -1;
875cfc9d37aSPeter Ujfalusi 
8766748d055SPeter Ujfalusi 	priv->dev = &pdev->dev;
8776748d055SPeter Ujfalusi 	card = &priv->card;
8786748d055SPeter Ujfalusi 	card->dev = &pdev->dev;
8796748d055SPeter Ujfalusi 	card->owner = THIS_MODULE;
8806748d055SPeter Ujfalusi 	card->dapm_widgets = j721e_cpb_dapm_widgets;
8816748d055SPeter Ujfalusi 	card->num_dapm_widgets = ARRAY_SIZE(j721e_cpb_dapm_widgets);
8826748d055SPeter Ujfalusi 	card->dapm_routes = j721e_cpb_dapm_routes;
8836748d055SPeter Ujfalusi 	card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes);
8846748d055SPeter Ujfalusi 	card->fully_routed = 1;
8856748d055SPeter Ujfalusi 
8866748d055SPeter Ujfalusi 	if (snd_soc_of_parse_card_name(card, "model")) {
8876748d055SPeter Ujfalusi 		dev_err(&pdev->dev, "Card name is not provided\n");
8886748d055SPeter Ujfalusi 		return -ENODEV;
8896748d055SPeter Ujfalusi 	}
8906748d055SPeter Ujfalusi 
8916748d055SPeter Ujfalusi 	link_cnt = 0;
8926748d055SPeter Ujfalusi 	conf_cnt = 0;
8936748d055SPeter Ujfalusi 	ret = j721e_soc_probe_cpb(priv, &link_cnt, &conf_cnt);
8946748d055SPeter Ujfalusi 	if (ret)
8956748d055SPeter Ujfalusi 		return ret;
8966748d055SPeter Ujfalusi 
8976748d055SPeter Ujfalusi 	ret = j721e_soc_probe_ivi(priv, &link_cnt, &conf_cnt);
8986748d055SPeter Ujfalusi 	if (ret)
8996748d055SPeter Ujfalusi 		return ret;
9006748d055SPeter Ujfalusi 
9016748d055SPeter Ujfalusi 	card->dai_link = priv->dai_links;
9026748d055SPeter Ujfalusi 	card->num_links = link_cnt;
9036748d055SPeter Ujfalusi 
9046748d055SPeter Ujfalusi 	card->codec_conf = priv->codec_conf;
9056748d055SPeter Ujfalusi 	card->num_configs = conf_cnt;
9066748d055SPeter Ujfalusi 
9076748d055SPeter Ujfalusi 	ret = j721e_calculate_rate_range(priv);
9086748d055SPeter Ujfalusi 	if (ret)
9096748d055SPeter Ujfalusi 		return ret;
9106748d055SPeter Ujfalusi 
9116748d055SPeter Ujfalusi 	snd_soc_card_set_drvdata(card, priv);
9126748d055SPeter Ujfalusi 
9136748d055SPeter Ujfalusi 	mutex_init(&priv->mutex);
9146748d055SPeter Ujfalusi 	ret = devm_snd_soc_register_card(&pdev->dev, card);
9156748d055SPeter Ujfalusi 	if (ret)
9166748d055SPeter Ujfalusi 		dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
9176748d055SPeter Ujfalusi 			ret);
9186748d055SPeter Ujfalusi 
9196748d055SPeter Ujfalusi 	return ret;
9206748d055SPeter Ujfalusi }
9216748d055SPeter Ujfalusi 
9226748d055SPeter Ujfalusi static struct platform_driver j721e_soc_driver = {
9236748d055SPeter Ujfalusi 	.driver = {
9246748d055SPeter Ujfalusi 		.name = "j721e-audio",
9256748d055SPeter Ujfalusi 		.pm = &snd_soc_pm_ops,
9265ec3c854SPeter Ujfalusi 		.of_match_table = j721e_audio_of_match,
9276748d055SPeter Ujfalusi 	},
9286748d055SPeter Ujfalusi 	.probe = j721e_soc_probe,
9296748d055SPeter Ujfalusi };
9306748d055SPeter Ujfalusi 
9316748d055SPeter Ujfalusi module_platform_driver(j721e_soc_driver);
9326748d055SPeter Ujfalusi 
9336748d055SPeter Ujfalusi MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
9346748d055SPeter Ujfalusi MODULE_DESCRIPTION("ASoC machine driver for j721e Common Processor Board");
9356748d055SPeter Ujfalusi MODULE_LICENSE("GPL v2");
936