1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com
4 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
8 #include <linux/module.h>
10 #include <linux/platform_device.h>
12 #include <sound/core.h>
13 #include <sound/pcm.h>
14 #include <sound/pcm_params.h>
15 #include <sound/soc.h>
17 #include "davinci-mcasp.h"
20 * Maximum number of configuration entries for prefixes:
21 * CPB: 2 (mcasp10 + codec)
22 * IVI: 3 (mcasp0 + 2x codec)
24 #define J721E_CODEC_CONF_COUNT 5
26 enum j721e_audio_domain_id
{
27 J721E_AUDIO_DOMAIN_CPB
= 0,
28 J721E_AUDIO_DOMAIN_IVI
,
29 J721E_AUDIO_DOMAIN_LAST
,
32 #define J721E_CLK_PARENT_48000 0
33 #define J721E_CLK_PARENT_44100 1
35 #define J721E_MAX_CLK_HSDIV 128
36 #define PCM1368A_MAX_SYSCLK 36864000
38 #define J721E_DAI_FMT (SND_SOC_DAIFMT_RIGHT_J | \
39 SND_SOC_DAIFMT_NB_NF | \
40 SND_SOC_DAIFMT_CBS_CFS)
42 enum j721e_board_type
{
47 struct j721e_audio_match_data
{
48 enum j721e_board_type board_type
;
50 unsigned int pll_rates
[2];
53 static unsigned int ratios_for_pcm3168a
[] = {
59 struct j721e_audio_clocks
{
61 struct clk
*parent
[2];
64 struct j721e_audio_domain
{
65 struct j721e_audio_clocks codec
;
66 struct j721e_audio_clocks mcasp
;
70 unsigned int active_link
;
76 struct snd_soc_card card
;
77 struct snd_soc_dai_link
*dai_links
;
78 struct snd_soc_codec_conf codec_conf
[J721E_CODEC_CONF_COUNT
];
79 struct snd_interval rate_range
;
80 const struct j721e_audio_match_data
*match_data
;
82 unsigned int hsdiv_rates
[2];
84 struct j721e_audio_domain audio_domains
[J721E_AUDIO_DOMAIN_LAST
];
89 static const struct snd_soc_dapm_widget j721e_cpb_dapm_widgets
[] = {
90 SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL
),
91 SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL
),
92 SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL
),
93 SND_SOC_DAPM_LINE("CPB Line Out", NULL
),
94 SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL
),
95 SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL
),
96 SND_SOC_DAPM_LINE("CPB Line In", NULL
),
99 static const struct snd_soc_dapm_route j721e_cpb_dapm_routes
[] = {
100 {"CPB Stereo HP 1", NULL
, "codec-1 AOUT1L"},
101 {"CPB Stereo HP 1", NULL
, "codec-1 AOUT1R"},
102 {"CPB Stereo HP 2", NULL
, "codec-1 AOUT2L"},
103 {"CPB Stereo HP 2", NULL
, "codec-1 AOUT2R"},
104 {"CPB Stereo HP 3", NULL
, "codec-1 AOUT3L"},
105 {"CPB Stereo HP 3", NULL
, "codec-1 AOUT3R"},
106 {"CPB Line Out", NULL
, "codec-1 AOUT4L"},
107 {"CPB Line Out", NULL
, "codec-1 AOUT4R"},
109 {"codec-1 AIN1L", NULL
, "CPB Stereo Mic 1"},
110 {"codec-1 AIN1R", NULL
, "CPB Stereo Mic 1"},
111 {"codec-1 AIN2L", NULL
, "CPB Stereo Mic 2"},
112 {"codec-1 AIN2R", NULL
, "CPB Stereo Mic 2"},
113 {"codec-1 AIN3L", NULL
, "CPB Line In"},
114 {"codec-1 AIN3R", NULL
, "CPB Line In"},
117 static const struct snd_soc_dapm_widget j721e_ivi_codec_a_dapm_widgets
[] = {
118 SND_SOC_DAPM_LINE("IVI A Line Out 1", NULL
),
119 SND_SOC_DAPM_LINE("IVI A Line Out 2", NULL
),
120 SND_SOC_DAPM_LINE("IVI A Line Out 3", NULL
),
121 SND_SOC_DAPM_LINE("IVI A Line Out 4", NULL
),
122 SND_SOC_DAPM_MIC("IVI A Stereo Mic 1", NULL
),
123 SND_SOC_DAPM_MIC("IVI A Stereo Mic 2", NULL
),
124 SND_SOC_DAPM_LINE("IVI A Line In", NULL
),
127 static const struct snd_soc_dapm_route j721e_codec_a_dapm_routes
[] = {
128 {"IVI A Line Out 1", NULL
, "codec-a AOUT1L"},
129 {"IVI A Line Out 1", NULL
, "codec-a AOUT1R"},
130 {"IVI A Line Out 2", NULL
, "codec-a AOUT2L"},
131 {"IVI A Line Out 2", NULL
, "codec-a AOUT2R"},
132 {"IVI A Line Out 3", NULL
, "codec-a AOUT3L"},
133 {"IVI A Line Out 3", NULL
, "codec-a AOUT3R"},
134 {"IVI A Line Out 4", NULL
, "codec-a AOUT4L"},
135 {"IVI A Line Out 4", NULL
, "codec-a AOUT4R"},
137 {"codec-a AIN1L", NULL
, "IVI A Stereo Mic 1"},
138 {"codec-a AIN1R", NULL
, "IVI A Stereo Mic 1"},
139 {"codec-a AIN2L", NULL
, "IVI A Stereo Mic 2"},
140 {"codec-a AIN2R", NULL
, "IVI A Stereo Mic 2"},
141 {"codec-a AIN3L", NULL
, "IVI A Line In"},
142 {"codec-a AIN3R", NULL
, "IVI A Line In"},
145 static const struct snd_soc_dapm_widget j721e_ivi_codec_b_dapm_widgets
[] = {
146 SND_SOC_DAPM_LINE("IVI B Line Out 1", NULL
),
147 SND_SOC_DAPM_LINE("IVI B Line Out 2", NULL
),
148 SND_SOC_DAPM_LINE("IVI B Line Out 3", NULL
),
149 SND_SOC_DAPM_LINE("IVI B Line Out 4", NULL
),
150 SND_SOC_DAPM_MIC("IVI B Stereo Mic 1", NULL
),
151 SND_SOC_DAPM_MIC("IVI B Stereo Mic 2", NULL
),
152 SND_SOC_DAPM_LINE("IVI B Line In", NULL
),
155 static const struct snd_soc_dapm_route j721e_codec_b_dapm_routes
[] = {
156 {"IVI B Line Out 1", NULL
, "codec-b AOUT1L"},
157 {"IVI B Line Out 1", NULL
, "codec-b AOUT1R"},
158 {"IVI B Line Out 2", NULL
, "codec-b AOUT2L"},
159 {"IVI B Line Out 2", NULL
, "codec-b AOUT2R"},
160 {"IVI B Line Out 3", NULL
, "codec-b AOUT3L"},
161 {"IVI B Line Out 3", NULL
, "codec-b AOUT3R"},
162 {"IVI B Line Out 4", NULL
, "codec-b AOUT4L"},
163 {"IVI B Line Out 4", NULL
, "codec-b AOUT4R"},
165 {"codec-b AIN1L", NULL
, "IVI B Stereo Mic 1"},
166 {"codec-b AIN1R", NULL
, "IVI B Stereo Mic 1"},
167 {"codec-b AIN2L", NULL
, "IVI B Stereo Mic 2"},
168 {"codec-b AIN2R", NULL
, "IVI B Stereo Mic 2"},
169 {"codec-b AIN3L", NULL
, "IVI B Line In"},
170 {"codec-b AIN3R", NULL
, "IVI B Line In"},
173 static int j721e_configure_refclk(struct j721e_priv
*priv
,
174 unsigned int audio_domain
, unsigned int rate
)
176 struct j721e_audio_domain
*domain
= &priv
->audio_domains
[audio_domain
];
181 if (!(rate
% 8000) && priv
->pll_rates
[J721E_CLK_PARENT_48000
])
182 clk_id
= J721E_CLK_PARENT_48000
;
183 else if (!(rate
% 11025) && priv
->pll_rates
[J721E_CLK_PARENT_44100
])
184 clk_id
= J721E_CLK_PARENT_44100
;
188 for (i
= 0; i
< ARRAY_SIZE(ratios_for_pcm3168a
); i
++) {
189 scki
= ratios_for_pcm3168a
[i
] * rate
;
191 if (priv
->pll_rates
[clk_id
] / scki
<= J721E_MAX_CLK_HSDIV
) {
198 dev_err(priv
->dev
, "No valid clock configuration for %u Hz\n",
203 if (domain
->parent_clk_id
== -1 || priv
->hsdiv_rates
[domain
->parent_clk_id
] != scki
) {
205 "domain%u configuration for %u Hz: %s, %dxFS (SCKI: %u Hz)\n",
207 clk_id
== J721E_CLK_PARENT_48000
? "PLL4" : "PLL15",
208 ratios_for_pcm3168a
[i
], scki
);
210 if (domain
->parent_clk_id
!= clk_id
) {
211 ret
= clk_set_parent(domain
->codec
.target
,
212 domain
->codec
.parent
[clk_id
]);
216 ret
= clk_set_parent(domain
->mcasp
.target
,
217 domain
->mcasp
.parent
[clk_id
]);
221 domain
->parent_clk_id
= clk_id
;
224 ret
= clk_set_rate(domain
->codec
.target
, scki
);
226 dev_err(priv
->dev
, "codec set rate failed for %u Hz\n",
231 ret
= clk_set_rate(domain
->mcasp
.target
, scki
);
233 priv
->hsdiv_rates
[domain
->parent_clk_id
] = scki
;
235 dev_err(priv
->dev
, "mcasp set rate failed for %u Hz\n",
244 static int j721e_rule_rate(struct snd_pcm_hw_params
*params
,
245 struct snd_pcm_hw_rule
*rule
)
247 struct snd_interval
*t
= rule
->private;
249 return snd_interval_refine(hw_param_interval(params
, rule
->var
), t
);
252 static int j721e_audio_startup(struct snd_pcm_substream
*substream
)
254 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
255 struct j721e_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
256 unsigned int domain_id
= rtd
->dai_link
->id
;
257 struct j721e_audio_domain
*domain
= &priv
->audio_domains
[domain_id
];
258 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
259 struct snd_soc_dai
*codec_dai
;
260 unsigned int active_rate
;
264 mutex_lock(&priv
->mutex
);
268 for (i
= 0; i
< J721E_AUDIO_DOMAIN_LAST
; i
++) {
269 active_rate
= priv
->audio_domains
[i
].rate
;
275 ret
= snd_pcm_hw_constraint_single(substream
->runtime
,
276 SNDRV_PCM_HW_PARAM_RATE
,
279 ret
= snd_pcm_hw_rule_add(substream
->runtime
, 0,
280 SNDRV_PCM_HW_PARAM_RATE
,
281 j721e_rule_rate
, &priv
->rate_range
,
282 SNDRV_PCM_HW_PARAM_RATE
, -1);
288 /* Reset TDM slots to 32 */
289 ret
= snd_soc_dai_set_tdm_slot(cpu_dai
, 0x3, 0x3, 2, 32);
290 if (ret
&& ret
!= -ENOTSUPP
)
293 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
294 ret
= snd_soc_dai_set_tdm_slot(codec_dai
, 0x3, 0x3, 2, 32);
295 if (ret
&& ret
!= -ENOTSUPP
)
299 if (ret
== -ENOTSUPP
)
304 mutex_unlock(&priv
->mutex
);
309 static int j721e_audio_hw_params(struct snd_pcm_substream
*substream
,
310 struct snd_pcm_hw_params
*params
)
312 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
313 struct snd_soc_card
*card
= rtd
->card
;
314 struct j721e_priv
*priv
= snd_soc_card_get_drvdata(card
);
315 unsigned int domain_id
= rtd
->dai_link
->id
;
316 struct j721e_audio_domain
*domain
= &priv
->audio_domains
[domain_id
];
317 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
318 struct snd_soc_dai
*codec_dai
;
319 unsigned int sysclk_rate
;
324 mutex_lock(&priv
->mutex
);
326 if (domain
->rate
&& domain
->rate
!= params_rate(params
)) {
331 if (params_width(params
) == 16)
334 ret
= snd_soc_dai_set_tdm_slot(cpu_dai
, 0x3, 0x3, 2, slot_width
);
335 if (ret
&& ret
!= -ENOTSUPP
)
338 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
339 ret
= snd_soc_dai_set_tdm_slot(codec_dai
, 0x3, 0x3, 2,
341 if (ret
&& ret
!= -ENOTSUPP
)
345 ret
= j721e_configure_refclk(priv
, domain_id
, params_rate(params
));
349 sysclk_rate
= priv
->hsdiv_rates
[domain
->parent_clk_id
];
350 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
351 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, sysclk_rate
,
353 if (ret
&& ret
!= -ENOTSUPP
) {
355 "codec set_sysclk failed for %u Hz\n",
361 ret
= snd_soc_dai_set_sysclk(cpu_dai
, MCASP_CLK_HCLK_AUXCLK
,
362 sysclk_rate
, SND_SOC_CLOCK_IN
);
364 if (ret
&& ret
!= -ENOTSUPP
) {
365 dev_err(priv
->dev
, "mcasp set_sysclk failed for %u Hz\n",
368 domain
->rate
= params_rate(params
);
373 mutex_unlock(&priv
->mutex
);
377 static void j721e_audio_shutdown(struct snd_pcm_substream
*substream
)
379 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
380 struct j721e_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
381 unsigned int domain_id
= rtd
->dai_link
->id
;
382 struct j721e_audio_domain
*domain
= &priv
->audio_domains
[domain_id
];
384 mutex_lock(&priv
->mutex
);
387 if (!domain
->active
) {
389 domain
->active_link
= 0;
392 mutex_unlock(&priv
->mutex
);
395 static const struct snd_soc_ops j721e_audio_ops
= {
396 .startup
= j721e_audio_startup
,
397 .hw_params
= j721e_audio_hw_params
,
398 .shutdown
= j721e_audio_shutdown
,
401 static int j721e_audio_init(struct snd_soc_pcm_runtime
*rtd
)
403 struct j721e_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
404 unsigned int domain_id
= rtd
->dai_link
->id
;
405 struct j721e_audio_domain
*domain
= &priv
->audio_domains
[domain_id
];
406 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
407 struct snd_soc_dai
*codec_dai
;
408 unsigned int sysclk_rate
;
411 /* Set up initial clock configuration */
412 ret
= j721e_configure_refclk(priv
, domain_id
, 48000);
416 sysclk_rate
= priv
->hsdiv_rates
[domain
->parent_clk_id
];
417 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
418 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, sysclk_rate
,
420 if (ret
&& ret
!= -ENOTSUPP
)
424 ret
= snd_soc_dai_set_sysclk(cpu_dai
, MCASP_CLK_HCLK_AUXCLK
,
425 sysclk_rate
, SND_SOC_CLOCK_IN
);
426 if (ret
&& ret
!= -ENOTSUPP
)
429 /* Set initial tdm slots */
430 ret
= snd_soc_dai_set_tdm_slot(cpu_dai
, 0x3, 0x3, 2, 32);
431 if (ret
&& ret
!= -ENOTSUPP
)
434 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
435 ret
= snd_soc_dai_set_tdm_slot(codec_dai
, 0x3, 0x3, 2, 32);
436 if (ret
&& ret
!= -ENOTSUPP
)
443 static int j721e_audio_init_ivi(struct snd_soc_pcm_runtime
*rtd
)
445 struct snd_soc_dapm_context
*dapm
= &rtd
->card
->dapm
;
447 snd_soc_dapm_new_controls(dapm
, j721e_ivi_codec_a_dapm_widgets
,
448 ARRAY_SIZE(j721e_ivi_codec_a_dapm_widgets
));
449 snd_soc_dapm_add_routes(dapm
, j721e_codec_a_dapm_routes
,
450 ARRAY_SIZE(j721e_codec_a_dapm_routes
));
451 snd_soc_dapm_new_controls(dapm
, j721e_ivi_codec_b_dapm_widgets
,
452 ARRAY_SIZE(j721e_ivi_codec_b_dapm_widgets
));
453 snd_soc_dapm_add_routes(dapm
, j721e_codec_b_dapm_routes
,
454 ARRAY_SIZE(j721e_codec_b_dapm_routes
));
456 return j721e_audio_init(rtd
);
459 static int j721e_get_clocks(struct device
*dev
,
460 struct j721e_audio_clocks
*clocks
, char *prefix
)
466 clocks
->target
= devm_clk_get(dev
, prefix
);
467 if (IS_ERR(clocks
->target
))
468 return dev_err_probe(dev
, PTR_ERR(clocks
->target
),
469 "failed to acquire %s\n", prefix
);
471 clk_name
= kasprintf(GFP_KERNEL
, "%s-48000", prefix
);
473 parent
= devm_clk_get(dev
, clk_name
);
475 if (IS_ERR(parent
)) {
476 ret
= PTR_ERR(parent
);
477 if (ret
== -EPROBE_DEFER
)
480 dev_dbg(dev
, "no 48KHz parent for %s: %d\n", prefix
, ret
);
483 clocks
->parent
[J721E_CLK_PARENT_48000
] = parent
;
488 clk_name
= kasprintf(GFP_KERNEL
, "%s-44100", prefix
);
490 parent
= devm_clk_get(dev
, clk_name
);
492 if (IS_ERR(parent
)) {
493 ret
= PTR_ERR(parent
);
494 if (ret
== -EPROBE_DEFER
)
497 dev_dbg(dev
, "no 44.1KHz parent for %s: %d\n", prefix
, ret
);
500 clocks
->parent
[J721E_CLK_PARENT_44100
] = parent
;
505 if (!clocks
->parent
[J721E_CLK_PARENT_44100
] &&
506 !clocks
->parent
[J721E_CLK_PARENT_48000
]) {
507 dev_err(dev
, "At least one parent clock is needed for %s\n",
515 static const struct j721e_audio_match_data j721e_cpb_data
= {
516 .board_type
= J721E_BOARD_CPB
,
517 .num_links
= 2, /* CPB pcm3168a */
519 [J721E_CLK_PARENT_44100
] = 1083801600, /* PLL15 */
520 [J721E_CLK_PARENT_48000
] = 1179648000, /* PLL4 */
524 static const struct j721e_audio_match_data j721e_cpb_ivi_data
= {
525 .board_type
= J721E_BOARD_CPB_IVI
,
526 .num_links
= 4, /* CPB pcm3168a + 2x pcm3168a on IVI */
528 [J721E_CLK_PARENT_44100
] = 1083801600, /* PLL15 */
529 [J721E_CLK_PARENT_48000
] = 1179648000, /* PLL4 */
533 static const struct j721e_audio_match_data j7200_cpb_data
= {
534 .board_type
= J721E_BOARD_CPB
,
535 .num_links
= 2, /* CPB pcm3168a */
537 [J721E_CLK_PARENT_48000
] = 2359296000u, /* PLL4 */
541 static const struct of_device_id j721e_audio_of_match
[] = {
543 .compatible
= "ti,j721e-cpb-audio",
544 .data
= &j721e_cpb_data
,
546 .compatible
= "ti,j721e-cpb-ivi-audio",
547 .data
= &j721e_cpb_ivi_data
,
549 .compatible
= "ti,j7200-cpb-audio",
550 .data
= &j7200_cpb_data
,
554 MODULE_DEVICE_TABLE(of
, j721e_audio_of_match
);
556 static int j721e_calculate_rate_range(struct j721e_priv
*priv
)
558 const struct j721e_audio_match_data
*match_data
= priv
->match_data
;
559 struct j721e_audio_clocks
*domain_clocks
;
560 unsigned int min_rate
, max_rate
, pll_rate
;
563 domain_clocks
= &priv
->audio_domains
[J721E_AUDIO_DOMAIN_CPB
].mcasp
;
565 pll
= clk_get_parent(domain_clocks
->parent
[J721E_CLK_PARENT_44100
]);
566 if (IS_ERR_OR_NULL(pll
)) {
567 priv
->pll_rates
[J721E_CLK_PARENT_44100
] =
568 match_data
->pll_rates
[J721E_CLK_PARENT_44100
];
570 priv
->pll_rates
[J721E_CLK_PARENT_44100
] = clk_get_rate(pll
);
574 pll
= clk_get_parent(domain_clocks
->parent
[J721E_CLK_PARENT_48000
]);
575 if (IS_ERR_OR_NULL(pll
)) {
576 priv
->pll_rates
[J721E_CLK_PARENT_48000
] =
577 match_data
->pll_rates
[J721E_CLK_PARENT_48000
];
579 priv
->pll_rates
[J721E_CLK_PARENT_48000
] = clk_get_rate(pll
);
583 if (!priv
->pll_rates
[J721E_CLK_PARENT_44100
] &&
584 !priv
->pll_rates
[J721E_CLK_PARENT_48000
]) {
585 dev_err(priv
->dev
, "At least one PLL is needed\n");
589 if (priv
->pll_rates
[J721E_CLK_PARENT_44100
])
590 pll_rate
= priv
->pll_rates
[J721E_CLK_PARENT_44100
];
592 pll_rate
= priv
->pll_rates
[J721E_CLK_PARENT_48000
];
594 min_rate
= pll_rate
/ J721E_MAX_CLK_HSDIV
;
595 min_rate
/= ratios_for_pcm3168a
[ARRAY_SIZE(ratios_for_pcm3168a
) - 1];
597 if (priv
->pll_rates
[J721E_CLK_PARENT_48000
])
598 pll_rate
= priv
->pll_rates
[J721E_CLK_PARENT_48000
];
600 pll_rate
= priv
->pll_rates
[J721E_CLK_PARENT_44100
];
602 if (pll_rate
> PCM1368A_MAX_SYSCLK
)
603 pll_rate
= PCM1368A_MAX_SYSCLK
;
605 max_rate
= pll_rate
/ ratios_for_pcm3168a
[0];
607 snd_interval_any(&priv
->rate_range
);
608 priv
->rate_range
.min
= min_rate
;
609 priv
->rate_range
.max
= max_rate
;
614 static int j721e_soc_probe_cpb(struct j721e_priv
*priv
, int *link_idx
,
617 struct device_node
*node
= priv
->dev
->of_node
;
618 struct snd_soc_dai_link_component
*compnent
;
619 struct device_node
*dai_node
, *codec_node
;
620 struct j721e_audio_domain
*domain
;
621 int comp_count
, comp_idx
;
624 dai_node
= of_parse_phandle(node
, "ti,cpb-mcasp", 0);
626 dev_err(priv
->dev
, "CPB McASP node is not provided\n");
630 codec_node
= of_parse_phandle(node
, "ti,cpb-codec", 0);
632 dev_err(priv
->dev
, "CPB codec node is not provided\n");
637 domain
= &priv
->audio_domains
[J721E_AUDIO_DOMAIN_CPB
];
638 ret
= j721e_get_clocks(priv
->dev
, &domain
->codec
, "cpb-codec-scki");
642 ret
= j721e_get_clocks(priv
->dev
, &domain
->mcasp
, "cpb-mcasp-auxclk");
647 * Common Processor Board, two links
648 * Link 1: McASP10 -> pcm3168a_1 DAC
649 * Link 2: McASP10 <- pcm3168a_1 ADC
652 compnent
= devm_kcalloc(priv
->dev
, comp_count
, sizeof(*compnent
),
660 priv
->dai_links
[*link_idx
].cpus
= &compnent
[comp_idx
++];
661 priv
->dai_links
[*link_idx
].num_cpus
= 1;
662 priv
->dai_links
[*link_idx
].codecs
= &compnent
[comp_idx
++];
663 priv
->dai_links
[*link_idx
].num_codecs
= 1;
664 priv
->dai_links
[*link_idx
].platforms
= &compnent
[comp_idx
++];
665 priv
->dai_links
[*link_idx
].num_platforms
= 1;
667 priv
->dai_links
[*link_idx
].name
= "CPB PCM3168A Playback";
668 priv
->dai_links
[*link_idx
].stream_name
= "CPB PCM3168A Analog";
669 priv
->dai_links
[*link_idx
].cpus
->of_node
= dai_node
;
670 priv
->dai_links
[*link_idx
].platforms
->of_node
= dai_node
;
671 priv
->dai_links
[*link_idx
].codecs
->of_node
= codec_node
;
672 priv
->dai_links
[*link_idx
].codecs
->dai_name
= "pcm3168a-dac";
673 priv
->dai_links
[*link_idx
].playback_only
= 1;
674 priv
->dai_links
[*link_idx
].id
= J721E_AUDIO_DOMAIN_CPB
;
675 priv
->dai_links
[*link_idx
].dai_fmt
= J721E_DAI_FMT
;
676 priv
->dai_links
[*link_idx
].init
= j721e_audio_init
;
677 priv
->dai_links
[*link_idx
].ops
= &j721e_audio_ops
;
680 priv
->dai_links
[*link_idx
].cpus
= &compnent
[comp_idx
++];
681 priv
->dai_links
[*link_idx
].num_cpus
= 1;
682 priv
->dai_links
[*link_idx
].codecs
= &compnent
[comp_idx
++];
683 priv
->dai_links
[*link_idx
].num_codecs
= 1;
684 priv
->dai_links
[*link_idx
].platforms
= &compnent
[comp_idx
++];
685 priv
->dai_links
[*link_idx
].num_platforms
= 1;
687 priv
->dai_links
[*link_idx
].name
= "CPB PCM3168A Capture";
688 priv
->dai_links
[*link_idx
].stream_name
= "CPB PCM3168A Analog";
689 priv
->dai_links
[*link_idx
].cpus
->of_node
= dai_node
;
690 priv
->dai_links
[*link_idx
].platforms
->of_node
= dai_node
;
691 priv
->dai_links
[*link_idx
].codecs
->of_node
= codec_node
;
692 priv
->dai_links
[*link_idx
].codecs
->dai_name
= "pcm3168a-adc";
693 priv
->dai_links
[*link_idx
].capture_only
= 1;
694 priv
->dai_links
[*link_idx
].id
= J721E_AUDIO_DOMAIN_CPB
;
695 priv
->dai_links
[*link_idx
].dai_fmt
= J721E_DAI_FMT
;
696 priv
->dai_links
[*link_idx
].init
= j721e_audio_init
;
697 priv
->dai_links
[*link_idx
].ops
= &j721e_audio_ops
;
700 priv
->codec_conf
[*conf_idx
].dlc
.of_node
= codec_node
;
701 priv
->codec_conf
[*conf_idx
].name_prefix
= "codec-1";
703 priv
->codec_conf
[*conf_idx
].dlc
.of_node
= dai_node
;
704 priv
->codec_conf
[*conf_idx
].name_prefix
= "McASP10";
710 of_node_put(codec_node
);
712 of_node_put(dai_node
);
716 static int j721e_soc_probe_ivi(struct j721e_priv
*priv
, int *link_idx
,
719 struct device_node
*node
= priv
->dev
->of_node
;
720 struct snd_soc_dai_link_component
*compnent
;
721 struct device_node
*dai_node
, *codeca_node
, *codecb_node
;
722 struct j721e_audio_domain
*domain
;
723 int comp_count
, comp_idx
;
726 if (priv
->match_data
->board_type
!= J721E_BOARD_CPB_IVI
)
729 dai_node
= of_parse_phandle(node
, "ti,ivi-mcasp", 0);
731 dev_err(priv
->dev
, "IVI McASP node is not provided\n");
735 codeca_node
= of_parse_phandle(node
, "ti,ivi-codec-a", 0);
737 dev_err(priv
->dev
, "IVI codec-a node is not provided\n");
742 codecb_node
= of_parse_phandle(node
, "ti,ivi-codec-b", 0);
744 dev_warn(priv
->dev
, "IVI codec-b node is not provided\n");
746 goto put_codeca_node
;
749 domain
= &priv
->audio_domains
[J721E_AUDIO_DOMAIN_IVI
];
750 ret
= j721e_get_clocks(priv
->dev
, &domain
->codec
, "ivi-codec-scki");
752 goto put_codecb_node
;
754 ret
= j721e_get_clocks(priv
->dev
, &domain
->mcasp
, "ivi-mcasp-auxclk");
756 goto put_codecb_node
;
759 * IVI extension, two links
760 * Link 1: McASP0 -> pcm3168a_a DAC
762 * Link 2: McASP0 <- pcm3168a_a ADC
766 compnent
= devm_kcalloc(priv
->dev
, comp_count
, sizeof(*compnent
),
770 goto put_codecb_node
;
774 priv
->dai_links
[*link_idx
].cpus
= &compnent
[comp_idx
++];
775 priv
->dai_links
[*link_idx
].num_cpus
= 1;
776 priv
->dai_links
[*link_idx
].platforms
= &compnent
[comp_idx
++];
777 priv
->dai_links
[*link_idx
].num_platforms
= 1;
778 priv
->dai_links
[*link_idx
].codecs
= &compnent
[comp_idx
];
779 priv
->dai_links
[*link_idx
].num_codecs
= 2;
782 priv
->dai_links
[*link_idx
].name
= "IVI 2xPCM3168A Playback";
783 priv
->dai_links
[*link_idx
].stream_name
= "IVI 2xPCM3168A Analog";
784 priv
->dai_links
[*link_idx
].cpus
->of_node
= dai_node
;
785 priv
->dai_links
[*link_idx
].platforms
->of_node
= dai_node
;
786 priv
->dai_links
[*link_idx
].codecs
[0].of_node
= codeca_node
;
787 priv
->dai_links
[*link_idx
].codecs
[0].dai_name
= "pcm3168a-dac";
788 priv
->dai_links
[*link_idx
].codecs
[1].of_node
= codecb_node
;
789 priv
->dai_links
[*link_idx
].codecs
[1].dai_name
= "pcm3168a-dac";
790 priv
->dai_links
[*link_idx
].playback_only
= 1;
791 priv
->dai_links
[*link_idx
].id
= J721E_AUDIO_DOMAIN_IVI
;
792 priv
->dai_links
[*link_idx
].dai_fmt
= J721E_DAI_FMT
;
793 priv
->dai_links
[*link_idx
].init
= j721e_audio_init_ivi
;
794 priv
->dai_links
[*link_idx
].ops
= &j721e_audio_ops
;
797 priv
->dai_links
[*link_idx
].cpus
= &compnent
[comp_idx
++];
798 priv
->dai_links
[*link_idx
].num_cpus
= 1;
799 priv
->dai_links
[*link_idx
].platforms
= &compnent
[comp_idx
++];
800 priv
->dai_links
[*link_idx
].num_platforms
= 1;
801 priv
->dai_links
[*link_idx
].codecs
= &compnent
[comp_idx
];
802 priv
->dai_links
[*link_idx
].num_codecs
= 2;
804 priv
->dai_links
[*link_idx
].name
= "IVI 2xPCM3168A Capture";
805 priv
->dai_links
[*link_idx
].stream_name
= "IVI 2xPCM3168A Analog";
806 priv
->dai_links
[*link_idx
].cpus
->of_node
= dai_node
;
807 priv
->dai_links
[*link_idx
].platforms
->of_node
= dai_node
;
808 priv
->dai_links
[*link_idx
].codecs
[0].of_node
= codeca_node
;
809 priv
->dai_links
[*link_idx
].codecs
[0].dai_name
= "pcm3168a-adc";
810 priv
->dai_links
[*link_idx
].codecs
[1].of_node
= codecb_node
;
811 priv
->dai_links
[*link_idx
].codecs
[1].dai_name
= "pcm3168a-adc";
812 priv
->dai_links
[*link_idx
].capture_only
= 1;
813 priv
->dai_links
[*link_idx
].id
= J721E_AUDIO_DOMAIN_IVI
;
814 priv
->dai_links
[*link_idx
].dai_fmt
= J721E_DAI_FMT
;
815 priv
->dai_links
[*link_idx
].init
= j721e_audio_init
;
816 priv
->dai_links
[*link_idx
].ops
= &j721e_audio_ops
;
819 priv
->codec_conf
[*conf_idx
].dlc
.of_node
= codeca_node
;
820 priv
->codec_conf
[*conf_idx
].name_prefix
= "codec-a";
823 priv
->codec_conf
[*conf_idx
].dlc
.of_node
= codecb_node
;
824 priv
->codec_conf
[*conf_idx
].name_prefix
= "codec-b";
827 priv
->codec_conf
[*conf_idx
].dlc
.of_node
= dai_node
;
828 priv
->codec_conf
[*conf_idx
].name_prefix
= "McASP0";
835 of_node_put(codecb_node
);
837 of_node_put(codeca_node
);
839 of_node_put(dai_node
);
843 static int j721e_soc_probe(struct platform_device
*pdev
)
845 struct device_node
*node
= pdev
->dev
.of_node
;
846 struct snd_soc_card
*card
;
847 const struct of_device_id
*match
;
848 struct j721e_priv
*priv
;
849 int link_cnt
, conf_cnt
, ret
, i
;
852 dev_err(&pdev
->dev
, "of node is missing.\n");
856 match
= of_match_node(j721e_audio_of_match
, node
);
858 dev_err(&pdev
->dev
, "No compatible match found\n");
862 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
866 priv
->match_data
= match
->data
;
868 priv
->dai_links
= devm_kcalloc(&pdev
->dev
, priv
->match_data
->num_links
,
869 sizeof(*priv
->dai_links
), GFP_KERNEL
);
870 if (!priv
->dai_links
)
873 for (i
= 0; i
< J721E_AUDIO_DOMAIN_LAST
; i
++)
874 priv
->audio_domains
[i
].parent_clk_id
= -1;
876 priv
->dev
= &pdev
->dev
;
878 card
->dev
= &pdev
->dev
;
879 card
->owner
= THIS_MODULE
;
880 card
->dapm_widgets
= j721e_cpb_dapm_widgets
;
881 card
->num_dapm_widgets
= ARRAY_SIZE(j721e_cpb_dapm_widgets
);
882 card
->dapm_routes
= j721e_cpb_dapm_routes
;
883 card
->num_dapm_routes
= ARRAY_SIZE(j721e_cpb_dapm_routes
);
884 card
->fully_routed
= 1;
886 if (snd_soc_of_parse_card_name(card
, "model")) {
887 dev_err(&pdev
->dev
, "Card name is not provided\n");
893 ret
= j721e_soc_probe_cpb(priv
, &link_cnt
, &conf_cnt
);
897 ret
= j721e_soc_probe_ivi(priv
, &link_cnt
, &conf_cnt
);
901 card
->dai_link
= priv
->dai_links
;
902 card
->num_links
= link_cnt
;
904 card
->codec_conf
= priv
->codec_conf
;
905 card
->num_configs
= conf_cnt
;
907 ret
= j721e_calculate_rate_range(priv
);
911 snd_soc_card_set_drvdata(card
, priv
);
913 mutex_init(&priv
->mutex
);
914 ret
= devm_snd_soc_register_card(&pdev
->dev
, card
);
916 dev_err(&pdev
->dev
, "devm_snd_soc_register_card() failed: %d\n",
922 static struct platform_driver j721e_soc_driver
= {
924 .name
= "j721e-audio",
925 .pm
= &snd_soc_pm_ops
,
926 .of_match_table
= j721e_audio_of_match
,
928 .probe
= j721e_soc_probe
,
931 module_platform_driver(j721e_soc_driver
);
933 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
934 MODULE_DESCRIPTION("ASoC machine driver for j721e Common Processor Board");
935 MODULE_LICENSE("GPL v2");