I want to realize two sound cards working at the same time on TX2. Now I2S1 and I2S2 of TX2 are connected with two audio codec chips TLV320AIC32X4, I2S1 is used for recording, I2S2 is used for audio playback.
tegra_t186ref_mobile_rt565x_i2s1.c
#define DRV_NAME_I2S1 "tegra-snd-t186ref-mobile-rt565x-i2s1"
static int tegra_t186ref_dai_init(struct snd_soc_pcm_runtime *rtd,
int rate,
int channels,
u64 formats,
bool is_playback)
{
struct snd_soc_card *card = rtd->card;
struct tegra_t186ref *machine = snd_soc_card_get_drvdata(card);
struct snd_soc_pcm_stream *dai_params;
unsigned int idx, clk_out_rate;
int err, codec_rate, clk_rate;
codec_rate = tegra_t186ref_srate_values[machine->rate_via_kcontrol];
clk_rate = (machine->rate_via_kcontrol) ? codec_rate : rate;
err = tegra_alt_asoc_utils_set_rate(&machine->audio_clock, clk_rate,
0, 0);
if (err < 0) {
dev_err(card->dev, "Can't configure clocks\n");
return err;
}
clk_out_rate = machine->audio_clock.clk_out_rate;
pr_debug("pll_a_out0 = %d Hz, aud_mclk = %d Hz, codec rate = %d Hz\n",
machine->audio_clock.set_mclk, clk_out_rate, clk_rate);
tegra_t186ref_set_params(card, machine, rate, channels, formats);
idx = tegra_machine_get_codec_dai_link_idx_t18x("ti-playback-i2s1");
//printk(KERN_ERR "tegra_t186ref_dai_init:====ti-playback-i2s1-idx = %d \n",idx);
/* check if idx has valid number */
if (idx != -EINVAL) {
dai_params =
(struct snd_soc_pcm_stream *)card->rtd[idx].dai_link->params;
dai_params->rate_min = clk_rate;
dai_params->formats = (machine->fmt_via_kcontrol == 2) ?
(1ULL << SNDRV_PCM_FORMAT_S32_LE) : formats;
if (!machine->is_codec_dummy) {
err = snd_soc_dai_set_sysclk(card->rtd[idx].codec_dai,
0, 12000000, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
}
}
}
return 0;
}
static int tegra_t186ref_driver_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct snd_soc_card *card = &snd_soc_tegra_t186ref;
struct tegra_t186ref *machine;
struct tegra_asoc_platform_data *pdata = NULL;
struct snd_soc_codec *codec = NULL;
int idx = 0;
int ret = 0;
const char *codec_dai_name;
if (!np) {
dev_err(&pdev->dev, "No device tree node for t186ref driver");
return -ENODEV;
}
machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_t186ref),
GFP_KERNEL);
if (!machine) {
dev_err(&pdev->dev, "Can't allocate t186ref struct\n");
ret = -ENOMEM;
goto err;
}
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
machine->is_codec_dummy = 0;
machine->audio_clock.clk_cdev1_state = 0;
machine->digital_reg = NULL;
machine->spk_reg = NULL;
machine->dmic_reg = NULL;
card->dapm.idle_bias_off = true;
ret = snd_soc_of_parse_card_name(card, "nvidia,model");
if (ret)
goto err;
ret = snd_soc_of_parse_audio_routing(card,
"nvidia,audio-routing");
if (ret)
goto err;
if (of_property_read_u32(np, "nvidia,num-clk",
&machine->audio_clock.num_clk) < 0) {
dev_err(&pdev->dev,
"Missing property nvidia,num-clk\n");
ret = -ENODEV;
goto err;
}
if (of_property_read_u32_array(np, "nvidia,clk-rates",
(u32 *)&machine->audio_clock.clk_rates,
machine->audio_clock.num_clk) < 0) {
dev_err(&pdev->dev,
"Missing property nvidia,clk-rates\n");
ret = -ENODEV;
goto err;
}
dai_link_setup(pdev);
#ifdef CONFIG_SWITCH
/* Addd h2w swith class support */
ret = tegra_alt_asoc_switch_register(&tegra_t186ref_headset_switch);
if (ret < 0)
goto err_alloc_dai_link;
#endif
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct tegra_asoc_platform_data),
GFP_KERNEL);
if (!pdata) {
dev_err(&pdev->dev,
"Can't allocate tegra_asoc_platform_data struct\n");
return -ENOMEM;
}
pdata->gpio_codec1 = pdata->gpio_codec2 = pdata->gpio_codec3 =
pdata->gpio_spkr_en = pdata->gpio_hp_mute =
pdata->gpio_int_mic_en = pdata->gpio_ext_mic_en = -1;
machine->pdata = pdata;
machine->pcard = card;
ret = tegra_alt_asoc_utils_init(&machine->audio_clock,
&pdev->dev,
card);
if (ret)
goto err_switch_unregister;
#if 1
ret = tegra_alt_asoc_utils_set_parent(&machine->audio_clock, false);
if (ret){
dev_err(&pdev->dev, "tegra_alt_asoc_utils_set_parent failed (%d)\n",
ret);
goto err_switch_unregister;
}
#endif
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
ret);
goto err_fini_utils;
}
printk(KERN_ERR "aic32x4-idx:===========ti-playback-i2s1-idx=====================");
idx = tegra_machine_get_codec_dai_link_idx_t18x("ti-playback-i2s1");
printk(KERN_ERR "ti-playback-i2s1-idx = %d \n",idx);
/* check if idx has valid number */
if (idx == -EINVAL)
dev_warn(&pdev->dev, "codec link not defined - codec not part of sound card --i2s1");
else {
codec = card->rtd[idx].codec;
codec_dai_name = card->rtd[idx].dai_link->codec_dai_name;
dev_info(&pdev->dev,
"codec-dai \"%s\" registered\n", codec_dai_name);
if (!strcmp("tlv320aic32x4-hifi", codec_dai_name)) {
dev_info(&pdev->dev, "This is a dummy codec\n");
machine->is_codec_dummy = 2;
}
}
return 0;
err_fini_utils:
tegra_alt_asoc_utils_fini(&machine->audio_clock);
err_switch_unregister:
#ifdef CONFIG_SWITCH
tegra_alt_asoc_switch_unregister(&tegra_t186ref_headset_switch);
#endif
err_alloc_dai_link:
tegra_machine_remove_dai_link();
tegra_machine_remove_codec_conf();
err:
return ret;
}
static const struct of_device_id tegra_t186ref_of_match[] = {
{ .compatible = "nvidia,tegra-audio-t186ref-mobile-rt565x-i2s1", },
};
MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
MODULE_DESCRIPTION("Tegra+t186ref machine ASoC driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME_I2S1);
MODULE_DEVICE_TABLE(of, tegra_t186ref_of_match);
tegra186-quill-common.dtsi
i2c@3180000 {
status = "okay";
aic32x4_1: tlv320aic32x4.2-0018@18 {
compatible = "ti,tlv320aic32x4";
status = "okay";
reg = <0x18>;
clocks = <&tegra_car TEGRA186_CLK_AUD_MCLK>;
clock-names = "mclk";
};
};
i2c@3160000 {
status = "okay";
aic32x4: tlv320aic32x4.0-0018@18 {
compatible = "ti,tlv320aic32x4";
status = "okay";
reg = <0x18>;
clocks = <&tegra_car TEGRA186_CLK_AUD_MCLK>;
clock-names = "mclk";
};
};
rt565x_dai_link: nvidia,dai-link-1 {
link-name = "ti-playback-i2s2";
cpu-dai = <&tegra_i2s2>;
codec-dai = <&aic32x4_1>;
cpu-dai-name = "I2S2";
codec-dai-name = "tlv320aic32x4-hifi";
tx-mask = <0xFF>;
rx-mask = <0xFF>;
format = "i2s";
bitclock-slave;
frame-slave;
bitclock-noninversion;
frame-noninversion;
bit-format = "s16_le";
bclk_ratio = <0>;
srate = <48000>;
num-channel = <1>;
ignore_suspend;
name-prefix = "z";
status = "okay";
};
nvidia,dai-link-2 {
link-name = "ti-playback-i2s1";
cpu-dai = <&tegra_i2s1>;
codec-dai = <&aic32x4>;
cpu-dai-name = "I2S1";
codec-dai-name = "tlv320aic32x4-hifi";
tx-mask = <0xFF>;
rx-mask = <0xFF>;
format = "i2s";
bitclock-slave;
frame-slave;
bitclock-noninversion;
frame-noninversion;
bit-format = "s16_le";
bclk_ratio = <0>;
srate = <48000>;
num-channel = <1>;
ignore_suspend;
name-prefix = "z";
status = "okay";
};
However, both sound cards failed to drive and no sound card device was displayed. How can I successfully add the drivers of two sound card devices to TX2?
thanks