How to enable Jetson nano I2S "BCLK" and "RLCLK"?

Hi

We are using Texas Instruments TAS5805M on our carrier board for Jetson nano to play some music.

During initialization of internal registers, TAS5805M needs stable I2S BCLK and RLCLK, but without any data on I2S at the same time.

How to provide TAS5805M with stable I2S BCLK and RLCLK?

Thank you very much!

Best Regards!

Hi,

There is no direct way to enable clocks by default. It involves code changes. Which JetPack are you using?

Thanks,
Sharad

Hi

Thanks very much for your reply.

We are using JetPack4.2.2.

We have done some code change works in function “tegra210_i2s_platform_probe” in file “kernel_src/kernel/nvidia/sound/soc/tegra-alt/tegra210_i2s_alt.c”, but have no effect.

Thank you very much!
Best Regards!

Please refer to below patch : There are changes done in I2S Driver and Tegra Machine driver to enable I2S (I2S4) clocks by default.

diff --git a/sound/soc/tegra-alt/include/tegra210_i2s_alt.h b/sound/soc/tegra-alt/include/tegra210_i2s_alt.h
index cae0d01..886dab0 100644
--- a/sound/soc/tegra-alt/include/tegra210_i2s_alt.h
+++ b/sound/soc/tegra-alt/include/tegra210_i2s_alt.h
@@ -220,4 +220,7 @@
 	unsigned int rx_fifo_th; /* should be programmed interms of frames */
 };
 
+/* exported functions to enable I@S from other driver */
+int tegra210_i2s_enable(int id);
+int tegra210_i2s_disable(int id);
 #endif
diff --git a/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c b/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c
index fbca469..a595ca1 100644
--- a/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c
+++ b/sound/soc/tegra-alt/machine_drivers/tegra_machine_driver_mobile.c
@@ -32,6 +32,7 @@
 #include "sgtl5000.h"
 #include "tegra_asoc_machine_alt.h"
 #include "tegra210_xbar_alt.h"
+#include "tegra210_i2s_alt.h"
 
 #define DRV_NAME "tegra-asoc:"
 
@@ -727,7 +728,7 @@
 	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &snd_soc_tegra_card;
 	struct tegra_machine *machine;
-	int ret = 0;
+	int ret = 0, i2s_id;
 	const struct of_device_id *match;
 
 	card->dev = &pdev->dev;
@@ -797,6 +798,10 @@
 					machine->soc_data->num_ahub_links +
 					machine->num_codec_links);
 
+	/* Change to required I2S instance number to enable it by default */
+	i2s_id = 3; //For I2S4
+	tegra210_i2s_enable(i2s_id);
+
 	return 0;
 cleanup_asoc:
 	release_asoc_phandles(machine);
diff --git a/sound/soc/tegra-alt/tegra210_i2s_alt.c b/sound/soc/tegra-alt/tegra210_i2s_alt.c
index 9d1bcf8..bd487b1 100644
--- a/sound/soc/tegra-alt/tegra210_i2s_alt.c
+++ b/sound/soc/tegra-alt/tegra210_i2s_alt.c
@@ -40,6 +40,7 @@
 
 #define DRV_NAME "tegra210-i2s"
 
+static struct platform_device *pdev_bkp[6];
 
 static const struct reg_default tegra210_i2s_reg_defaults[] = {
 	{ TEGRA210_I2S_AXBAR_RX_INT_MASK, 0x00000003},
@@ -683,6 +684,104 @@
 	return 0;
 }
 
+int tegra210_i2s_enable(int id)
+{
+	struct tegra210_i2s *i2s;
+	struct platform_device *pdev = pdev_bkp[id];
+	int ret = 0;
+	int val, mask;
+	int i2sclock, bitcnt;
+	struct tegra210_xbar_cif_conf cif_conf;
+
+	memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf));
+
+	if (!pdev) {
+		pr_err("No I2S Device registered for id %d\n", id);
+		return -EINVAL;
+	}
+
+	i2s = dev_get_drvdata(&pdev->dev);
+	if (!i2s)
+		return -EINVAL;
+
+	i2sclock = 48000 * 2 * 16; // 48KHz, 2CH, 16Bit
+
+	ret = tegra210_i2s_set_clock_rate(&pdev->dev, i2sclock);
+	if (ret) {
+		dev_err(&pdev->dev, "Can't set I2S clock rate: %d\n", ret);
+		return ret;
+	}
+
+	pm_runtime_get_sync(&pdev->dev);
+
+	ret = clk_prepare_enable(i2s->clk_i2s);
+	if (ret) {
+		dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
+		return ret;
+	}
+
+	mask = TEGRA210_I2S_CTRL_MASTER_EN_MASK |
+		TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK |
+                TEGRA210_I2S_CTRL_LRCK_POLARITY_MASK |
+		TEGRA210_I2S_CTRL_EDGE_CTRL_MASK;
+	val = TEGRA210_I2S_CTRL_FRAME_FORMAT_LRCK_MODE |
+		TEGRA210_I2S_CTRL_LRCK_POLARITY_LOW |
+		TEGRA210_I2S_CTRL_EDGE_CTRL_POS_EDGE;
+
+	tegra210_i2s_set_data_offset(i2s, 1);
+
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, mask, val);
+	/* FIXME: global enabling */
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_ENABLE,
+					TEGRA210_I2S_EN_MASK, TEGRA210_I2S_EN);
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+		TEGRA210_I2S_CTRL_FSYNC_WIDTH_MASK,
+		31 << TEGRA210_I2S_CTRL_FSYNC_WIDTH_SHIFT);
+
+	regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+				TEGRA210_I2S_CTRL_BIT_SIZE_MASK,
+				TEGRA210_I2S_CTRL_BIT_SIZE_16);
+
+	bitcnt = (i2sclock / 48000) - 1;
+	bitcnt >>= 1; // for TEGRA210_I2S_FRAME_FORMAT_LRCK
+
+	val = bitcnt << TEGRA210_I2S_TIMING_CHANNEL_BIT_CNT_SHIFT;
+	regmap_write(i2s->regmap, TEGRA210_I2S_TIMING, val);
+
+	cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16;
+	cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_16;
+	tegra210_xbar_set_cif(i2s->regmap, TEGRA210_I2S_AXBAR_RX_CIF_CTRL, &cif_conf);
+	//Enable I2S
+	regmap_write(i2s->regmap, TEGRA210_I2S_AXBAR_RX_ENABLE, 1);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra210_i2s_enable);
+
+int tegra210_i2s_disable(int id)
+{
+	struct tegra210_i2s *i2s;
+	struct platform_device *pdev = pdev_bkp[id];
+
+	if (!pdev) {
+		pr_err("No I2S Device registered for id %d\n", id);
+		return -EINVAL;
+	}
+
+	i2s = dev_get_drvdata(&pdev->dev);
+	if (!i2s)
+		return -EINVAL;
+
+	//Disable I2S
+	regmap_write(i2s->regmap, TEGRA210_I2S_AXBAR_RX_ENABLE, 0);
+
+	clk_disable_unprepare(i2s->clk_i2s);
+	pm_runtime_put(&pdev->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tegra210_i2s_disable);
+
 static struct snd_soc_dai_ops tegra210_i2s_dai_ops = {
 	.set_fmt	= tegra210_i2s_set_fmt,
 	.hw_params	= tegra210_i2s_hw_params,
@@ -1147,6 +1246,8 @@
 		return ret;
 	}
 
+	pdev_bkp[pdev->dev.id] = pdev;
+
 	return 0;
 }

Thanks,
Sharad

1 Like

Hi, sharadg!

Thank you very much for your help, and it WORKS!
Now I can enable I2S4 clocks by default.

Thank you very much, sharadg!

Best Regards!