18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com 48c2ecf20Sopenharmony_ci * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <sound/core.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 158c2ecf20Sopenharmony_ci#include <sound/soc.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "davinci-mcasp.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Maximum number of configuration entries for prefixes: 218c2ecf20Sopenharmony_ci * CPB: 2 (mcasp10 + codec) 228c2ecf20Sopenharmony_ci * IVI: 3 (mcasp0 + 2x codec) 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci#define J721E_CODEC_CONF_COUNT 5 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define J721E_AUDIO_DOMAIN_CPB 0 278c2ecf20Sopenharmony_ci#define J721E_AUDIO_DOMAIN_IVI 1 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define J721E_CLK_PARENT_48000 0 308c2ecf20Sopenharmony_ci#define J721E_CLK_PARENT_44100 1 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define J721E_MAX_CLK_HSDIV 128 338c2ecf20Sopenharmony_ci#define PCM1368A_MAX_SYSCLK 36864000 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define J721E_DAI_FMT (SND_SOC_DAIFMT_RIGHT_J | \ 368c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_NB_NF | \ 378c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cienum j721e_board_type { 408c2ecf20Sopenharmony_ci J721E_BOARD_CPB = 1, 418c2ecf20Sopenharmony_ci J721E_BOARD_CPB_IVI, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct j721e_audio_match_data { 458c2ecf20Sopenharmony_ci enum j721e_board_type board_type; 468c2ecf20Sopenharmony_ci int num_links; 478c2ecf20Sopenharmony_ci unsigned int pll_rates[2]; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic unsigned int ratios_for_pcm3168a[] = { 518c2ecf20Sopenharmony_ci 256, 528c2ecf20Sopenharmony_ci 512, 538c2ecf20Sopenharmony_ci 768, 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct j721e_audio_clocks { 578c2ecf20Sopenharmony_ci struct clk *target; 588c2ecf20Sopenharmony_ci struct clk *parent[2]; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct j721e_audio_domain { 628c2ecf20Sopenharmony_ci struct j721e_audio_clocks codec; 638c2ecf20Sopenharmony_ci struct j721e_audio_clocks mcasp; 648c2ecf20Sopenharmony_ci int parent_clk_id; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci int active; 678c2ecf20Sopenharmony_ci unsigned int active_link; 688c2ecf20Sopenharmony_ci unsigned int rate; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct j721e_priv { 728c2ecf20Sopenharmony_ci struct device *dev; 738c2ecf20Sopenharmony_ci struct snd_soc_card card; 748c2ecf20Sopenharmony_ci struct snd_soc_dai_link *dai_links; 758c2ecf20Sopenharmony_ci struct snd_soc_codec_conf codec_conf[J721E_CODEC_CONF_COUNT]; 768c2ecf20Sopenharmony_ci struct snd_interval rate_range; 778c2ecf20Sopenharmony_ci const struct j721e_audio_match_data *match_data; 788c2ecf20Sopenharmony_ci u32 pll_rates[2]; 798c2ecf20Sopenharmony_ci unsigned int hsdiv_rates[2]; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci struct j721e_audio_domain audio_domains[2]; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci struct mutex mutex; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget j721e_cpb_dapm_widgets[] = { 878c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL), 888c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL), 898c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL), 908c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("CPB Line Out", NULL), 918c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL), 928c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL), 938c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("CPB Line In", NULL), 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route j721e_cpb_dapm_routes[] = { 978c2ecf20Sopenharmony_ci {"CPB Stereo HP 1", NULL, "codec-1 AOUT1L"}, 988c2ecf20Sopenharmony_ci {"CPB Stereo HP 1", NULL, "codec-1 AOUT1R"}, 998c2ecf20Sopenharmony_ci {"CPB Stereo HP 2", NULL, "codec-1 AOUT2L"}, 1008c2ecf20Sopenharmony_ci {"CPB Stereo HP 2", NULL, "codec-1 AOUT2R"}, 1018c2ecf20Sopenharmony_ci {"CPB Stereo HP 3", NULL, "codec-1 AOUT3L"}, 1028c2ecf20Sopenharmony_ci {"CPB Stereo HP 3", NULL, "codec-1 AOUT3R"}, 1038c2ecf20Sopenharmony_ci {"CPB Line Out", NULL, "codec-1 AOUT4L"}, 1048c2ecf20Sopenharmony_ci {"CPB Line Out", NULL, "codec-1 AOUT4R"}, 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci {"codec-1 AIN1L", NULL, "CPB Stereo Mic 1"}, 1078c2ecf20Sopenharmony_ci {"codec-1 AIN1R", NULL, "CPB Stereo Mic 1"}, 1088c2ecf20Sopenharmony_ci {"codec-1 AIN2L", NULL, "CPB Stereo Mic 2"}, 1098c2ecf20Sopenharmony_ci {"codec-1 AIN2R", NULL, "CPB Stereo Mic 2"}, 1108c2ecf20Sopenharmony_ci {"codec-1 AIN3L", NULL, "CPB Line In"}, 1118c2ecf20Sopenharmony_ci {"codec-1 AIN3R", NULL, "CPB Line In"}, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget j721e_ivi_codec_a_dapm_widgets[] = { 1158c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI A Line Out 1", NULL), 1168c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI A Line Out 2", NULL), 1178c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI A Line Out 3", NULL), 1188c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI A Line Out 4", NULL), 1198c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("IVI A Stereo Mic 1", NULL), 1208c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("IVI A Stereo Mic 2", NULL), 1218c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI A Line In", NULL), 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route j721e_codec_a_dapm_routes[] = { 1258c2ecf20Sopenharmony_ci {"IVI A Line Out 1", NULL, "codec-a AOUT1L"}, 1268c2ecf20Sopenharmony_ci {"IVI A Line Out 1", NULL, "codec-a AOUT1R"}, 1278c2ecf20Sopenharmony_ci {"IVI A Line Out 2", NULL, "codec-a AOUT2L"}, 1288c2ecf20Sopenharmony_ci {"IVI A Line Out 2", NULL, "codec-a AOUT2R"}, 1298c2ecf20Sopenharmony_ci {"IVI A Line Out 3", NULL, "codec-a AOUT3L"}, 1308c2ecf20Sopenharmony_ci {"IVI A Line Out 3", NULL, "codec-a AOUT3R"}, 1318c2ecf20Sopenharmony_ci {"IVI A Line Out 4", NULL, "codec-a AOUT4L"}, 1328c2ecf20Sopenharmony_ci {"IVI A Line Out 4", NULL, "codec-a AOUT4R"}, 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci {"codec-a AIN1L", NULL, "IVI A Stereo Mic 1"}, 1358c2ecf20Sopenharmony_ci {"codec-a AIN1R", NULL, "IVI A Stereo Mic 1"}, 1368c2ecf20Sopenharmony_ci {"codec-a AIN2L", NULL, "IVI A Stereo Mic 2"}, 1378c2ecf20Sopenharmony_ci {"codec-a AIN2R", NULL, "IVI A Stereo Mic 2"}, 1388c2ecf20Sopenharmony_ci {"codec-a AIN3L", NULL, "IVI A Line In"}, 1398c2ecf20Sopenharmony_ci {"codec-a AIN3R", NULL, "IVI A Line In"}, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget j721e_ivi_codec_b_dapm_widgets[] = { 1438c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI B Line Out 1", NULL), 1448c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI B Line Out 2", NULL), 1458c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI B Line Out 3", NULL), 1468c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI B Line Out 4", NULL), 1478c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("IVI B Stereo Mic 1", NULL), 1488c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("IVI B Stereo Mic 2", NULL), 1498c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("IVI B Line In", NULL), 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route j721e_codec_b_dapm_routes[] = { 1538c2ecf20Sopenharmony_ci {"IVI B Line Out 1", NULL, "codec-b AOUT1L"}, 1548c2ecf20Sopenharmony_ci {"IVI B Line Out 1", NULL, "codec-b AOUT1R"}, 1558c2ecf20Sopenharmony_ci {"IVI B Line Out 2", NULL, "codec-b AOUT2L"}, 1568c2ecf20Sopenharmony_ci {"IVI B Line Out 2", NULL, "codec-b AOUT2R"}, 1578c2ecf20Sopenharmony_ci {"IVI B Line Out 3", NULL, "codec-b AOUT3L"}, 1588c2ecf20Sopenharmony_ci {"IVI B Line Out 3", NULL, "codec-b AOUT3R"}, 1598c2ecf20Sopenharmony_ci {"IVI B Line Out 4", NULL, "codec-b AOUT4L"}, 1608c2ecf20Sopenharmony_ci {"IVI B Line Out 4", NULL, "codec-b AOUT4R"}, 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci {"codec-b AIN1L", NULL, "IVI B Stereo Mic 1"}, 1638c2ecf20Sopenharmony_ci {"codec-b AIN1R", NULL, "IVI B Stereo Mic 1"}, 1648c2ecf20Sopenharmony_ci {"codec-b AIN2L", NULL, "IVI B Stereo Mic 2"}, 1658c2ecf20Sopenharmony_ci {"codec-b AIN2R", NULL, "IVI B Stereo Mic 2"}, 1668c2ecf20Sopenharmony_ci {"codec-b AIN3L", NULL, "IVI B Line In"}, 1678c2ecf20Sopenharmony_ci {"codec-b AIN3R", NULL, "IVI B Line In"}, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int j721e_configure_refclk(struct j721e_priv *priv, 1718c2ecf20Sopenharmony_ci unsigned int audio_domain, unsigned int rate) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct j721e_audio_domain *domain = &priv->audio_domains[audio_domain]; 1748c2ecf20Sopenharmony_ci unsigned int scki; 1758c2ecf20Sopenharmony_ci int ret = -EINVAL; 1768c2ecf20Sopenharmony_ci int i, clk_id; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!(rate % 8000) && priv->pll_rates[J721E_CLK_PARENT_48000]) 1798c2ecf20Sopenharmony_ci clk_id = J721E_CLK_PARENT_48000; 1808c2ecf20Sopenharmony_ci else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_44100]) 1818c2ecf20Sopenharmony_ci clk_id = J721E_CLK_PARENT_44100; 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ratios_for_pcm3168a); i++) { 1868c2ecf20Sopenharmony_ci scki = ratios_for_pcm3168a[i] * rate; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (priv->pll_rates[clk_id] / scki <= J721E_MAX_CLK_HSDIV) { 1898c2ecf20Sopenharmony_ci ret = 0; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (ret) { 1958c2ecf20Sopenharmony_ci dev_err(priv->dev, "No valid clock configuration for %u Hz\n", 1968c2ecf20Sopenharmony_ci rate); 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (domain->parent_clk_id == -1 || priv->hsdiv_rates[domain->parent_clk_id] != scki) { 2018c2ecf20Sopenharmony_ci dev_dbg(priv->dev, 2028c2ecf20Sopenharmony_ci "%s configuration for %u Hz: %s, %dxFS (SCKI: %u Hz)\n", 2038c2ecf20Sopenharmony_ci audio_domain == J721E_AUDIO_DOMAIN_CPB ? "CPB" : "IVI", 2048c2ecf20Sopenharmony_ci rate, 2058c2ecf20Sopenharmony_ci clk_id == J721E_CLK_PARENT_48000 ? "PLL4" : "PLL15", 2068c2ecf20Sopenharmony_ci ratios_for_pcm3168a[i], scki); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (domain->parent_clk_id != clk_id) { 2098c2ecf20Sopenharmony_ci ret = clk_set_parent(domain->codec.target, 2108c2ecf20Sopenharmony_ci domain->codec.parent[clk_id]); 2118c2ecf20Sopenharmony_ci if (ret) 2128c2ecf20Sopenharmony_ci return ret; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci ret = clk_set_parent(domain->mcasp.target, 2158c2ecf20Sopenharmony_ci domain->mcasp.parent[clk_id]); 2168c2ecf20Sopenharmony_ci if (ret) 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci domain->parent_clk_id = clk_id; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci ret = clk_set_rate(domain->codec.target, scki); 2238c2ecf20Sopenharmony_ci if (ret) { 2248c2ecf20Sopenharmony_ci dev_err(priv->dev, "codec set rate failed for %u Hz\n", 2258c2ecf20Sopenharmony_ci scki); 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ret = clk_set_rate(domain->mcasp.target, scki); 2308c2ecf20Sopenharmony_ci if (!ret) { 2318c2ecf20Sopenharmony_ci priv->hsdiv_rates[domain->parent_clk_id] = scki; 2328c2ecf20Sopenharmony_ci } else { 2338c2ecf20Sopenharmony_ci dev_err(priv->dev, "mcasp set rate failed for %u Hz\n", 2348c2ecf20Sopenharmony_ci scki); 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int j721e_rule_rate(struct snd_pcm_hw_params *params, 2438c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct snd_interval *t = rule->private; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, rule->var), t); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int j721e_audio_startup(struct snd_pcm_substream *substream) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2538c2ecf20Sopenharmony_ci struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card); 2548c2ecf20Sopenharmony_ci unsigned int domain_id = rtd->dai_link->id; 2558c2ecf20Sopenharmony_ci struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 2568c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 2578c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai; 2588c2ecf20Sopenharmony_ci unsigned int active_rate; 2598c2ecf20Sopenharmony_ci int ret = 0; 2608c2ecf20Sopenharmony_ci int i; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci domain->active++; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].rate) 2678c2ecf20Sopenharmony_ci active_rate = priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].rate; 2688c2ecf20Sopenharmony_ci else 2698c2ecf20Sopenharmony_ci active_rate = priv->audio_domains[J721E_AUDIO_DOMAIN_IVI].rate; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (active_rate) 2728c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_single(substream->runtime, 2738c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 2748c2ecf20Sopenharmony_ci active_rate); 2758c2ecf20Sopenharmony_ci else 2768c2ecf20Sopenharmony_ci ret = snd_pcm_hw_rule_add(substream->runtime, 0, 2778c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 2788c2ecf20Sopenharmony_ci j721e_rule_rate, &priv->rate_range, 2798c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, -1); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (ret) 2838c2ecf20Sopenharmony_ci goto out; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Reset TDM slots to 32 */ 2868c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32); 2878c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 2888c2ecf20Sopenharmony_ci goto out; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 2918c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32); 2928c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 2938c2ecf20Sopenharmony_ci goto out; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (ret == -ENOTSUPP) 2978c2ecf20Sopenharmony_ci ret = 0; 2988c2ecf20Sopenharmony_ciout: 2998c2ecf20Sopenharmony_ci if (ret) 3008c2ecf20Sopenharmony_ci domain->active--; 3018c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int j721e_audio_hw_params(struct snd_pcm_substream *substream, 3078c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 3108c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 3118c2ecf20Sopenharmony_ci struct j721e_priv *priv = snd_soc_card_get_drvdata(card); 3128c2ecf20Sopenharmony_ci unsigned int domain_id = rtd->dai_link->id; 3138c2ecf20Sopenharmony_ci struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 3148c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 3158c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai; 3168c2ecf20Sopenharmony_ci unsigned int sysclk_rate; 3178c2ecf20Sopenharmony_ci int slot_width = 32; 3188c2ecf20Sopenharmony_ci int ret; 3198c2ecf20Sopenharmony_ci int i; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (domain->rate && domain->rate != params_rate(params)) { 3248c2ecf20Sopenharmony_ci ret = -EINVAL; 3258c2ecf20Sopenharmony_ci goto out; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (params_width(params) == 16) 3298c2ecf20Sopenharmony_ci slot_width = 16; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, slot_width); 3328c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 3338c2ecf20Sopenharmony_ci goto out; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 3368c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 3378c2ecf20Sopenharmony_ci slot_width); 3388c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ret = j721e_configure_refclk(priv, domain_id, params_rate(params)); 3438c2ecf20Sopenharmony_ci if (ret) 3448c2ecf20Sopenharmony_ci goto out; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id]; 3478c2ecf20Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 3488c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate, 3498c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 3508c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) { 3518c2ecf20Sopenharmony_ci dev_err(priv->dev, 3528c2ecf20Sopenharmony_ci "codec set_sysclk failed for %u Hz\n", 3538c2ecf20Sopenharmony_ci sysclk_rate); 3548c2ecf20Sopenharmony_ci goto out; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK, 3598c2ecf20Sopenharmony_ci sysclk_rate, SND_SOC_CLOCK_IN); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) { 3628c2ecf20Sopenharmony_ci dev_err(priv->dev, "mcasp set_sysclk failed for %u Hz\n", 3638c2ecf20Sopenharmony_ci sysclk_rate); 3648c2ecf20Sopenharmony_ci } else { 3658c2ecf20Sopenharmony_ci domain->rate = params_rate(params); 3668c2ecf20Sopenharmony_ci ret = 0; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ciout: 3708c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 3718c2ecf20Sopenharmony_ci return ret; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic void j721e_audio_shutdown(struct snd_pcm_substream *substream) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 3778c2ecf20Sopenharmony_ci struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card); 3788c2ecf20Sopenharmony_ci unsigned int domain_id = rtd->dai_link->id; 3798c2ecf20Sopenharmony_ci struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci mutex_lock(&priv->mutex); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci domain->active--; 3848c2ecf20Sopenharmony_ci if (!domain->active) { 3858c2ecf20Sopenharmony_ci domain->rate = 0; 3868c2ecf20Sopenharmony_ci domain->active_link = 0; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci mutex_unlock(&priv->mutex); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic const struct snd_soc_ops j721e_audio_ops = { 3938c2ecf20Sopenharmony_ci .startup = j721e_audio_startup, 3948c2ecf20Sopenharmony_ci .hw_params = j721e_audio_hw_params, 3958c2ecf20Sopenharmony_ci .shutdown = j721e_audio_shutdown, 3968c2ecf20Sopenharmony_ci}; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int j721e_audio_init(struct snd_soc_pcm_runtime *rtd) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct j721e_priv *priv = snd_soc_card_get_drvdata(rtd->card); 4018c2ecf20Sopenharmony_ci unsigned int domain_id = rtd->dai_link->id; 4028c2ecf20Sopenharmony_ci struct j721e_audio_domain *domain = &priv->audio_domains[domain_id]; 4038c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 4048c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai; 4058c2ecf20Sopenharmony_ci unsigned int sysclk_rate; 4068c2ecf20Sopenharmony_ci int i, ret; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Set up initial clock configuration */ 4098c2ecf20Sopenharmony_ci ret = j721e_configure_refclk(priv, domain_id, 48000); 4108c2ecf20Sopenharmony_ci if (ret) 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci sysclk_rate = priv->hsdiv_rates[domain->parent_clk_id]; 4148c2ecf20Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 4158c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk_rate, 4168c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 4178c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, MCASP_CLK_HCLK_AUXCLK, 4228c2ecf20Sopenharmony_ci sysclk_rate, SND_SOC_CLOCK_IN); 4238c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Set initial tdm slots */ 4278c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32); 4288c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 4298c2ecf20Sopenharmony_ci return ret; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 4328c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32); 4338c2ecf20Sopenharmony_ci if (ret && ret != -ENOTSUPP) 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int j721e_audio_init_ivi(struct snd_soc_pcm_runtime *rtd) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = &rtd->card->dapm; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_a_dapm_widgets, 4458c2ecf20Sopenharmony_ci ARRAY_SIZE(j721e_ivi_codec_a_dapm_widgets)); 4468c2ecf20Sopenharmony_ci snd_soc_dapm_add_routes(dapm, j721e_codec_a_dapm_routes, 4478c2ecf20Sopenharmony_ci ARRAY_SIZE(j721e_codec_a_dapm_routes)); 4488c2ecf20Sopenharmony_ci snd_soc_dapm_new_controls(dapm, j721e_ivi_codec_b_dapm_widgets, 4498c2ecf20Sopenharmony_ci ARRAY_SIZE(j721e_ivi_codec_b_dapm_widgets)); 4508c2ecf20Sopenharmony_ci snd_soc_dapm_add_routes(dapm, j721e_codec_b_dapm_routes, 4518c2ecf20Sopenharmony_ci ARRAY_SIZE(j721e_codec_b_dapm_routes)); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return j721e_audio_init(rtd); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int j721e_get_clocks(struct device *dev, 4578c2ecf20Sopenharmony_ci struct j721e_audio_clocks *clocks, char *prefix) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct clk *parent; 4608c2ecf20Sopenharmony_ci char *clk_name; 4618c2ecf20Sopenharmony_ci int ret; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci clocks->target = devm_clk_get(dev, prefix); 4648c2ecf20Sopenharmony_ci if (IS_ERR(clocks->target)) { 4658c2ecf20Sopenharmony_ci ret = PTR_ERR(clocks->target); 4668c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 4678c2ecf20Sopenharmony_ci dev_err(dev, "failed to acquire %s: %d\n", 4688c2ecf20Sopenharmony_ci prefix, ret); 4698c2ecf20Sopenharmony_ci return ret; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci clk_name = kasprintf(GFP_KERNEL, "%s-48000", prefix); 4738c2ecf20Sopenharmony_ci if (clk_name) { 4748c2ecf20Sopenharmony_ci parent = devm_clk_get(dev, clk_name); 4758c2ecf20Sopenharmony_ci kfree(clk_name); 4768c2ecf20Sopenharmony_ci if (IS_ERR(parent)) { 4778c2ecf20Sopenharmony_ci ret = PTR_ERR(parent); 4788c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 4798c2ecf20Sopenharmony_ci return ret; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci dev_dbg(dev, "no 48KHz parent for %s: %d\n", prefix, ret); 4828c2ecf20Sopenharmony_ci parent = NULL; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci clocks->parent[J721E_CLK_PARENT_48000] = parent; 4858c2ecf20Sopenharmony_ci } else { 4868c2ecf20Sopenharmony_ci return -ENOMEM; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci clk_name = kasprintf(GFP_KERNEL, "%s-44100", prefix); 4908c2ecf20Sopenharmony_ci if (clk_name) { 4918c2ecf20Sopenharmony_ci parent = devm_clk_get(dev, clk_name); 4928c2ecf20Sopenharmony_ci kfree(clk_name); 4938c2ecf20Sopenharmony_ci if (IS_ERR(parent)) { 4948c2ecf20Sopenharmony_ci ret = PTR_ERR(parent); 4958c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci dev_dbg(dev, "no 44.1KHz parent for %s: %d\n", prefix, ret); 4998c2ecf20Sopenharmony_ci parent = NULL; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci clocks->parent[J721E_CLK_PARENT_44100] = parent; 5028c2ecf20Sopenharmony_ci } else { 5038c2ecf20Sopenharmony_ci return -ENOMEM; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (!clocks->parent[J721E_CLK_PARENT_44100] && 5078c2ecf20Sopenharmony_ci !clocks->parent[J721E_CLK_PARENT_48000]) { 5088c2ecf20Sopenharmony_ci dev_err(dev, "At least one parent clock is needed for %s\n", 5098c2ecf20Sopenharmony_ci prefix); 5108c2ecf20Sopenharmony_ci return -EINVAL; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci return 0; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic const struct j721e_audio_match_data j721e_cpb_data = { 5178c2ecf20Sopenharmony_ci .board_type = J721E_BOARD_CPB, 5188c2ecf20Sopenharmony_ci .num_links = 2, /* CPB pcm3168a */ 5198c2ecf20Sopenharmony_ci .pll_rates = { 5208c2ecf20Sopenharmony_ci [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */ 5218c2ecf20Sopenharmony_ci [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */ 5228c2ecf20Sopenharmony_ci }, 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic const struct j721e_audio_match_data j721e_cpb_ivi_data = { 5268c2ecf20Sopenharmony_ci .board_type = J721E_BOARD_CPB_IVI, 5278c2ecf20Sopenharmony_ci .num_links = 4, /* CPB pcm3168a + 2x pcm3168a on IVI */ 5288c2ecf20Sopenharmony_ci .pll_rates = { 5298c2ecf20Sopenharmony_ci [J721E_CLK_PARENT_44100] = 1083801600, /* PLL15 */ 5308c2ecf20Sopenharmony_ci [J721E_CLK_PARENT_48000] = 1179648000, /* PLL4 */ 5318c2ecf20Sopenharmony_ci }, 5328c2ecf20Sopenharmony_ci}; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic const struct j721e_audio_match_data j7200_cpb_data = { 5358c2ecf20Sopenharmony_ci .board_type = J721E_BOARD_CPB, 5368c2ecf20Sopenharmony_ci .num_links = 2, /* CPB pcm3168a */ 5378c2ecf20Sopenharmony_ci .pll_rates = { 5388c2ecf20Sopenharmony_ci [J721E_CLK_PARENT_48000] = 2359296000u, /* PLL4 */ 5398c2ecf20Sopenharmony_ci }, 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic const struct of_device_id j721e_audio_of_match[] = { 5438c2ecf20Sopenharmony_ci { 5448c2ecf20Sopenharmony_ci .compatible = "ti,j721e-cpb-audio", 5458c2ecf20Sopenharmony_ci .data = &j721e_cpb_data, 5468c2ecf20Sopenharmony_ci }, { 5478c2ecf20Sopenharmony_ci .compatible = "ti,j721e-cpb-ivi-audio", 5488c2ecf20Sopenharmony_ci .data = &j721e_cpb_ivi_data, 5498c2ecf20Sopenharmony_ci }, { 5508c2ecf20Sopenharmony_ci .compatible = "ti,j7200-cpb-audio", 5518c2ecf20Sopenharmony_ci .data = &j7200_cpb_data, 5528c2ecf20Sopenharmony_ci }, 5538c2ecf20Sopenharmony_ci { }, 5548c2ecf20Sopenharmony_ci}; 5558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, j721e_audio_of_match); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int j721e_calculate_rate_range(struct j721e_priv *priv) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci const struct j721e_audio_match_data *match_data = priv->match_data; 5608c2ecf20Sopenharmony_ci struct j721e_audio_clocks *domain_clocks; 5618c2ecf20Sopenharmony_ci unsigned int min_rate, max_rate, pll_rate; 5628c2ecf20Sopenharmony_ci struct clk *pll; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci domain_clocks = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].mcasp; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_44100]); 5678c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(pll)) { 5688c2ecf20Sopenharmony_ci priv->pll_rates[J721E_CLK_PARENT_44100] = 5698c2ecf20Sopenharmony_ci match_data->pll_rates[J721E_CLK_PARENT_44100]; 5708c2ecf20Sopenharmony_ci } else { 5718c2ecf20Sopenharmony_ci priv->pll_rates[J721E_CLK_PARENT_44100] = clk_get_rate(pll); 5728c2ecf20Sopenharmony_ci clk_put(pll); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci pll = clk_get_parent(domain_clocks->parent[J721E_CLK_PARENT_48000]); 5768c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(pll)) { 5778c2ecf20Sopenharmony_ci priv->pll_rates[J721E_CLK_PARENT_48000] = 5788c2ecf20Sopenharmony_ci match_data->pll_rates[J721E_CLK_PARENT_48000]; 5798c2ecf20Sopenharmony_ci } else { 5808c2ecf20Sopenharmony_ci priv->pll_rates[J721E_CLK_PARENT_48000] = clk_get_rate(pll); 5818c2ecf20Sopenharmony_ci clk_put(pll); 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (!priv->pll_rates[J721E_CLK_PARENT_44100] && 5858c2ecf20Sopenharmony_ci !priv->pll_rates[J721E_CLK_PARENT_48000]) { 5868c2ecf20Sopenharmony_ci dev_err(priv->dev, "At least one PLL is needed\n"); 5878c2ecf20Sopenharmony_ci return -EINVAL; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (priv->pll_rates[J721E_CLK_PARENT_44100]) 5918c2ecf20Sopenharmony_ci pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100]; 5928c2ecf20Sopenharmony_ci else 5938c2ecf20Sopenharmony_ci pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000]; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci min_rate = pll_rate / J721E_MAX_CLK_HSDIV; 5968c2ecf20Sopenharmony_ci min_rate /= ratios_for_pcm3168a[ARRAY_SIZE(ratios_for_pcm3168a) - 1]; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (priv->pll_rates[J721E_CLK_PARENT_48000]) 5998c2ecf20Sopenharmony_ci pll_rate = priv->pll_rates[J721E_CLK_PARENT_48000]; 6008c2ecf20Sopenharmony_ci else 6018c2ecf20Sopenharmony_ci pll_rate = priv->pll_rates[J721E_CLK_PARENT_44100]; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (pll_rate > PCM1368A_MAX_SYSCLK) 6048c2ecf20Sopenharmony_ci pll_rate = PCM1368A_MAX_SYSCLK; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci max_rate = pll_rate / ratios_for_pcm3168a[0]; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci snd_interval_any(&priv->rate_range); 6098c2ecf20Sopenharmony_ci priv->rate_range.min = min_rate; 6108c2ecf20Sopenharmony_ci priv->rate_range.max = max_rate; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return 0; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int j721e_soc_probe_cpb(struct j721e_priv *priv, int *link_idx, 6168c2ecf20Sopenharmony_ci int *conf_idx) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct device_node *node = priv->dev->of_node; 6198c2ecf20Sopenharmony_ci struct snd_soc_dai_link_component *compnent; 6208c2ecf20Sopenharmony_ci struct device_node *dai_node, *codec_node; 6218c2ecf20Sopenharmony_ci struct j721e_audio_domain *domain; 6228c2ecf20Sopenharmony_ci int comp_count, comp_idx; 6238c2ecf20Sopenharmony_ci int ret; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci dai_node = of_parse_phandle(node, "ti,cpb-mcasp", 0); 6268c2ecf20Sopenharmony_ci if (!dai_node) { 6278c2ecf20Sopenharmony_ci dev_err(priv->dev, "CPB McASP node is not provided\n"); 6288c2ecf20Sopenharmony_ci return -EINVAL; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci codec_node = of_parse_phandle(node, "ti,cpb-codec", 0); 6328c2ecf20Sopenharmony_ci if (!codec_node) { 6338c2ecf20Sopenharmony_ci dev_err(priv->dev, "CPB codec node is not provided\n"); 6348c2ecf20Sopenharmony_ci ret = -EINVAL; 6358c2ecf20Sopenharmony_ci goto put_dai_node; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_CPB]; 6398c2ecf20Sopenharmony_ci ret = j721e_get_clocks(priv->dev, &domain->codec, "cpb-codec-scki"); 6408c2ecf20Sopenharmony_ci if (ret) 6418c2ecf20Sopenharmony_ci goto put_codec_node; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci ret = j721e_get_clocks(priv->dev, &domain->mcasp, "cpb-mcasp-auxclk"); 6448c2ecf20Sopenharmony_ci if (ret) 6458c2ecf20Sopenharmony_ci goto put_codec_node; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Common Processor Board, two links 6498c2ecf20Sopenharmony_ci * Link 1: McASP10 -> pcm3168a_1 DAC 6508c2ecf20Sopenharmony_ci * Link 2: McASP10 <- pcm3168a_1 ADC 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_ci comp_count = 6; 6538c2ecf20Sopenharmony_ci compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent), 6548c2ecf20Sopenharmony_ci GFP_KERNEL); 6558c2ecf20Sopenharmony_ci if (!compnent) { 6568c2ecf20Sopenharmony_ci ret = -ENOMEM; 6578c2ecf20Sopenharmony_ci goto put_codec_node; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci comp_idx = 0; 6618c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 6628c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_cpus = 1; 6638c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs = &compnent[comp_idx++]; 6648c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_codecs = 1; 6658c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 6668c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_platforms = 1; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].name = "CPB PCM3168A Playback"; 6698c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog"; 6708c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus->of_node = dai_node; 6718c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms->of_node = dai_node; 6728c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs->of_node = codec_node; 6738c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-dac"; 6748c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].playback_only = 1; 6758c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB; 6768c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 6778c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].init = j721e_audio_init; 6788c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].ops = &j721e_audio_ops; 6798c2ecf20Sopenharmony_ci (*link_idx)++; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 6828c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_cpus = 1; 6838c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs = &compnent[comp_idx++]; 6848c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_codecs = 1; 6858c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 6868c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_platforms = 1; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].name = "CPB PCM3168A Capture"; 6898c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].stream_name = "CPB PCM3168A Analog"; 6908c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus->of_node = dai_node; 6918c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms->of_node = dai_node; 6928c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs->of_node = codec_node; 6938c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs->dai_name = "pcm3168a-adc"; 6948c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].capture_only = 1; 6958c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_CPB; 6968c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 6978c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].init = j721e_audio_init; 6988c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].ops = &j721e_audio_ops; 6998c2ecf20Sopenharmony_ci (*link_idx)++; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].dlc.of_node = codec_node; 7028c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].name_prefix = "codec-1"; 7038c2ecf20Sopenharmony_ci (*conf_idx)++; 7048c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].dlc.of_node = dai_node; 7058c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].name_prefix = "McASP10"; 7068c2ecf20Sopenharmony_ci (*conf_idx)++; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return 0; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ciput_codec_node: 7118c2ecf20Sopenharmony_ci of_node_put(codec_node); 7128c2ecf20Sopenharmony_ciput_dai_node: 7138c2ecf20Sopenharmony_ci of_node_put(dai_node); 7148c2ecf20Sopenharmony_ci return ret; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int j721e_soc_probe_ivi(struct j721e_priv *priv, int *link_idx, 7188c2ecf20Sopenharmony_ci int *conf_idx) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct device_node *node = priv->dev->of_node; 7218c2ecf20Sopenharmony_ci struct snd_soc_dai_link_component *compnent; 7228c2ecf20Sopenharmony_ci struct device_node *dai_node, *codeca_node, *codecb_node; 7238c2ecf20Sopenharmony_ci struct j721e_audio_domain *domain; 7248c2ecf20Sopenharmony_ci int comp_count, comp_idx; 7258c2ecf20Sopenharmony_ci int ret; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (priv->match_data->board_type != J721E_BOARD_CPB_IVI) 7288c2ecf20Sopenharmony_ci return 0; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci dai_node = of_parse_phandle(node, "ti,ivi-mcasp", 0); 7318c2ecf20Sopenharmony_ci if (!dai_node) { 7328c2ecf20Sopenharmony_ci dev_err(priv->dev, "IVI McASP node is not provided\n"); 7338c2ecf20Sopenharmony_ci return -EINVAL; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci codeca_node = of_parse_phandle(node, "ti,ivi-codec-a", 0); 7378c2ecf20Sopenharmony_ci if (!codeca_node) { 7388c2ecf20Sopenharmony_ci dev_err(priv->dev, "IVI codec-a node is not provided\n"); 7398c2ecf20Sopenharmony_ci ret = -EINVAL; 7408c2ecf20Sopenharmony_ci goto put_dai_node; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci codecb_node = of_parse_phandle(node, "ti,ivi-codec-b", 0); 7448c2ecf20Sopenharmony_ci if (!codecb_node) { 7458c2ecf20Sopenharmony_ci dev_warn(priv->dev, "IVI codec-b node is not provided\n"); 7468c2ecf20Sopenharmony_ci ret = 0; 7478c2ecf20Sopenharmony_ci goto put_codeca_node; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci domain = &priv->audio_domains[J721E_AUDIO_DOMAIN_IVI]; 7518c2ecf20Sopenharmony_ci ret = j721e_get_clocks(priv->dev, &domain->codec, "ivi-codec-scki"); 7528c2ecf20Sopenharmony_ci if (ret) 7538c2ecf20Sopenharmony_ci goto put_codecb_node; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci ret = j721e_get_clocks(priv->dev, &domain->mcasp, "ivi-mcasp-auxclk"); 7568c2ecf20Sopenharmony_ci if (ret) 7578c2ecf20Sopenharmony_ci goto put_codecb_node; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* 7608c2ecf20Sopenharmony_ci * IVI extension, two links 7618c2ecf20Sopenharmony_ci * Link 1: McASP0 -> pcm3168a_a DAC 7628c2ecf20Sopenharmony_ci * \> pcm3168a_b DAC 7638c2ecf20Sopenharmony_ci * Link 2: McASP0 <- pcm3168a_a ADC 7648c2ecf20Sopenharmony_ci * \ pcm3168a_b ADC 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_ci comp_count = 8; 7678c2ecf20Sopenharmony_ci compnent = devm_kzalloc(priv->dev, comp_count * sizeof(*compnent), 7688c2ecf20Sopenharmony_ci GFP_KERNEL); 7698c2ecf20Sopenharmony_ci if (!compnent) { 7708c2ecf20Sopenharmony_ci ret = -ENOMEM; 7718c2ecf20Sopenharmony_ci goto put_codecb_node; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci comp_idx = 0; 7758c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 7768c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_cpus = 1; 7778c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 7788c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_platforms = 1; 7798c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs = &compnent[comp_idx]; 7808c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_codecs = 2; 7818c2ecf20Sopenharmony_ci comp_idx += 2; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Playback"; 7848c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog"; 7858c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus->of_node = dai_node; 7868c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms->of_node = dai_node; 7878c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[0].of_node = codeca_node; 7888c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-dac"; 7898c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[1].of_node = codecb_node; 7908c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-dac"; 7918c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].playback_only = 1; 7928c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI; 7938c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 7948c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].init = j721e_audio_init_ivi; 7958c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].ops = &j721e_audio_ops; 7968c2ecf20Sopenharmony_ci (*link_idx)++; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus = &compnent[comp_idx++]; 7998c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_cpus = 1; 8008c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms = &compnent[comp_idx++]; 8018c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_platforms = 1; 8028c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs = &compnent[comp_idx]; 8038c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].num_codecs = 2; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].name = "IVI 2xPCM3168A Capture"; 8068c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].stream_name = "IVI 2xPCM3168A Analog"; 8078c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].cpus->of_node = dai_node; 8088c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].platforms->of_node = dai_node; 8098c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[0].of_node = codeca_node; 8108c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[0].dai_name = "pcm3168a-adc"; 8118c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[1].of_node = codecb_node; 8128c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].codecs[1].dai_name = "pcm3168a-adc"; 8138c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].capture_only = 1; 8148c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].id = J721E_AUDIO_DOMAIN_IVI; 8158c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].dai_fmt = J721E_DAI_FMT; 8168c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].init = j721e_audio_init; 8178c2ecf20Sopenharmony_ci priv->dai_links[*link_idx].ops = &j721e_audio_ops; 8188c2ecf20Sopenharmony_ci (*link_idx)++; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].dlc.of_node = codeca_node; 8218c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].name_prefix = "codec-a"; 8228c2ecf20Sopenharmony_ci (*conf_idx)++; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].dlc.of_node = codecb_node; 8258c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].name_prefix = "codec-b"; 8268c2ecf20Sopenharmony_ci (*conf_idx)++; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].dlc.of_node = dai_node; 8298c2ecf20Sopenharmony_ci priv->codec_conf[*conf_idx].name_prefix = "McASP0"; 8308c2ecf20Sopenharmony_ci (*conf_idx)++; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci return 0; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ciput_codecb_node: 8368c2ecf20Sopenharmony_ci of_node_put(codecb_node); 8378c2ecf20Sopenharmony_ciput_codeca_node: 8388c2ecf20Sopenharmony_ci of_node_put(codeca_node); 8398c2ecf20Sopenharmony_ciput_dai_node: 8408c2ecf20Sopenharmony_ci of_node_put(dai_node); 8418c2ecf20Sopenharmony_ci return ret; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic int j721e_soc_probe(struct platform_device *pdev) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 8478c2ecf20Sopenharmony_ci struct snd_soc_card *card; 8488c2ecf20Sopenharmony_ci const struct of_device_id *match; 8498c2ecf20Sopenharmony_ci struct j721e_priv *priv; 8508c2ecf20Sopenharmony_ci int link_cnt, conf_cnt, ret; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (!node) { 8538c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "of node is missing.\n"); 8548c2ecf20Sopenharmony_ci return -ENODEV; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci match = of_match_node(j721e_audio_of_match, node); 8588c2ecf20Sopenharmony_ci if (!match) { 8598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No compatible match found\n"); 8608c2ecf20Sopenharmony_ci return -ENODEV; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 8648c2ecf20Sopenharmony_ci if (!priv) 8658c2ecf20Sopenharmony_ci return -ENOMEM; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci priv->match_data = match->data; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci priv->dai_links = devm_kcalloc(&pdev->dev, priv->match_data->num_links, 8708c2ecf20Sopenharmony_ci sizeof(*priv->dai_links), GFP_KERNEL); 8718c2ecf20Sopenharmony_ci if (!priv->dai_links) 8728c2ecf20Sopenharmony_ci return -ENOMEM; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci priv->audio_domains[J721E_AUDIO_DOMAIN_CPB].parent_clk_id = -1; 8758c2ecf20Sopenharmony_ci priv->audio_domains[J721E_AUDIO_DOMAIN_IVI].parent_clk_id = -1; 8768c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 8778c2ecf20Sopenharmony_ci card = &priv->card; 8788c2ecf20Sopenharmony_ci card->dev = &pdev->dev; 8798c2ecf20Sopenharmony_ci card->owner = THIS_MODULE; 8808c2ecf20Sopenharmony_ci card->dapm_widgets = j721e_cpb_dapm_widgets; 8818c2ecf20Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(j721e_cpb_dapm_widgets); 8828c2ecf20Sopenharmony_ci card->dapm_routes = j721e_cpb_dapm_routes; 8838c2ecf20Sopenharmony_ci card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes); 8848c2ecf20Sopenharmony_ci card->fully_routed = 1; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (snd_soc_of_parse_card_name(card, "model")) { 8878c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Card name is not provided\n"); 8888c2ecf20Sopenharmony_ci return -ENODEV; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci link_cnt = 0; 8928c2ecf20Sopenharmony_ci conf_cnt = 0; 8938c2ecf20Sopenharmony_ci ret = j721e_soc_probe_cpb(priv, &link_cnt, &conf_cnt); 8948c2ecf20Sopenharmony_ci if (ret) 8958c2ecf20Sopenharmony_ci return ret; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci ret = j721e_soc_probe_ivi(priv, &link_cnt, &conf_cnt); 8988c2ecf20Sopenharmony_ci if (ret) 8998c2ecf20Sopenharmony_ci return ret; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci card->dai_link = priv->dai_links; 9028c2ecf20Sopenharmony_ci card->num_links = link_cnt; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci card->codec_conf = priv->codec_conf; 9058c2ecf20Sopenharmony_ci card->num_configs = conf_cnt; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci ret = j721e_calculate_rate_range(priv); 9088c2ecf20Sopenharmony_ci if (ret) 9098c2ecf20Sopenharmony_ci return ret; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci snd_soc_card_set_drvdata(card, priv); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci mutex_init(&priv->mutex); 9148c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_card(&pdev->dev, card); 9158c2ecf20Sopenharmony_ci if (ret) 9168c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", 9178c2ecf20Sopenharmony_ci ret); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return ret; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic struct platform_driver j721e_soc_driver = { 9238c2ecf20Sopenharmony_ci .driver = { 9248c2ecf20Sopenharmony_ci .name = "j721e-audio", 9258c2ecf20Sopenharmony_ci .pm = &snd_soc_pm_ops, 9268c2ecf20Sopenharmony_ci .of_match_table = j721e_audio_of_match, 9278c2ecf20Sopenharmony_ci }, 9288c2ecf20Sopenharmony_ci .probe = j721e_soc_probe, 9298c2ecf20Sopenharmony_ci}; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cimodule_platform_driver(j721e_soc_driver); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); 9348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC machine driver for j721e Common Processor Board"); 9358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 936