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