From 1f93a7dfd1f8d5ff7a5c53246c7534fe2332d6f4 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 11 Dec 2023 02:46:07 +0000
Subject: [PATCH] add audio

---
 kernel/sound/soc/rockchip/rockchip_i2s_tdm.c |   75 +++++++++++++++++++++++++++++++++++--
 1 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c b/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c
index 1824ea5..a8da138 100644
--- a/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/kernel/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -27,6 +27,7 @@
 #include <sound/dmaengine_pcm.h>
 
 #include "rockchip_i2s_tdm.h"
+#include "rockchip_dlp.h"
 
 #define DRV_NAME "rockchip-i2s-tdm"
 
@@ -266,7 +267,7 @@
 			writeq(val, addr);
 			break;
 		}
-		/* fallthrough */
+		fallthrough;
 	default:
 		local_irq_save(flags);
 		writel(BIT(tx_offset) | (BIT(tx_offset) << 16),
@@ -328,7 +329,7 @@
 			writeq(val, addr);
 			break;
 		}
-		/* fallthrough */
+		fallthrough;
 	default:
 		local_irq_save(flags);
 		writel((BIT(tx_offset) << 16),
@@ -395,6 +396,12 @@
 	default:
 		return -EINVAL;
 	}
+
+	regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr);
+	ret = regmap_read_poll_timeout_atomic(i2s_tdm->regmap, I2S_CLR, val,
+					      !(val & clr), 10, 100);
+	if (ret == 0)
+		return 0;
 
 	/*
 	 * Workaround for FIFO clear on SLAVE mode:
@@ -654,6 +661,19 @@
 	case SND_SOC_DAIFMT_CBM_CFM:
 		val = I2S_CKR_MSS_SLAVE;
 		i2s_tdm->is_master_mode = false;
+		/*
+		 * TRCM require TX/RX enabled at the same time, or need the one
+		 * which provide clk enabled at first for master mode.
+		 *
+		 * It is quite a different for slave mode which does not have
+		 * these restrictions, because the BCLK / LRCK are provided by
+		 * external master devices.
+		 *
+		 * So, we just set the right clk path value on TRCM register on
+		 * stage probe and then drop the trcm value to make TX / RX work
+		 * independently.
+		 */
+		i2s_tdm->clk_trcm = 0;
 		break;
 	default:
 		ret = -EINVAL;
@@ -924,13 +944,26 @@
 	switch (i2s_tdm->clk_trcm) {
 	case I2S_CKR_TRCM_TXONLY:
 		parent = clk_get_parent(i2s_tdm->mclk_tx);
+		/*
+		 * API clk_has_parent is not available yet on GKI, so we
+		 * use clk_set_parent directly and ignore the ret value.
+		 * if the API has addressed on GKI, should remove it.
+		 */
+#ifdef CONFIG_NO_GKI
 		if (clk_has_parent(i2s_tdm->mclk_rx, parent))
 			ret = clk_set_parent(i2s_tdm->mclk_rx, parent);
+#else
+		clk_set_parent(i2s_tdm->mclk_rx, parent);
+#endif
 		break;
 	case I2S_CKR_TRCM_RXONLY:
 		parent = clk_get_parent(i2s_tdm->mclk_rx);
+#ifdef CONFIG_NO_GKI
 		if (clk_has_parent(i2s_tdm->mclk_tx, parent))
 			ret = clk_set_parent(i2s_tdm->mclk_tx, parent);
+#else
+		clk_set_parent(i2s_tdm->mclk_tx, parent);
+#endif
 		break;
 	}
 
@@ -1789,6 +1822,12 @@
 #ifdef CONFIG_CPU_RK3568
 	{ .compatible = "rockchip,rk3568-i2s-tdm", .data = &rk3568_i2s_soc_data },
 #endif
+#ifdef CONFIG_CPU_RK3588
+	{ .compatible = "rockchip,rk3588-i2s-tdm", },
+#endif
+#ifdef CONFIG_CPU_RV1106
+	{ .compatible = "rockchip,rv1106-i2s-tdm", },
+#endif
 #ifdef CONFIG_CPU_RV1126
 	{ .compatible = "rockchip,rv1126-i2s-tdm", .data = &rv1126_i2s_soc_data },
 #endif
@@ -1998,6 +2037,28 @@
 	return rockchip_i2s_tdm_path_prepare(i2s_tdm, np, 1);
 }
 
+static int rockchip_i2s_tdm_get_fifo_count(struct device *dev, int stream)
+{
+	struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
+	int val = 0;
+
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		regmap_read(i2s_tdm->regmap, I2S_TXFIFOLR, &val);
+	else
+		regmap_read(i2s_tdm->regmap, I2S_RXFIFOLR, &val);
+
+	val = ((val & I2S_FIFOLR_TFL3_MASK) >> I2S_FIFOLR_TFL3_SHIFT) +
+	      ((val & I2S_FIFOLR_TFL2_MASK) >> I2S_FIFOLR_TFL2_SHIFT) +
+	      ((val & I2S_FIFOLR_TFL1_MASK) >> I2S_FIFOLR_TFL1_SHIFT) +
+	      ((val & I2S_FIFOLR_TFL0_MASK) >> I2S_FIFOLR_TFL0_SHIFT);
+
+	return val;
+}
+
+static const struct snd_dlp_config dconfig = {
+	.get_fifo_count = rockchip_i2s_tdm_get_fifo_count,
+};
+
 static irqreturn_t rockchip_i2s_tdm_isr(int irq, void *devid)
 {
 	struct rk_i2s_tdm_dev *i2s_tdm = (struct rk_i2s_tdm_dev *)devid;
@@ -2050,7 +2111,7 @@
 	i2s_tdm->dev = &pdev->dev;
 
 	of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev);
-	if (!of_id || !of_id->data)
+	if (!of_id)
 		return -EINVAL;
 
 	spin_lock_init(&i2s_tdm->lock);
@@ -2170,7 +2231,7 @@
 	if (IS_ERR(i2s_tdm->regmap))
 		return PTR_ERR(i2s_tdm->regmap);
 
-	irq = platform_get_irq(pdev, 0);
+	irq = platform_get_irq_optional(pdev, 0);
 	if (irq > 0) {
 		ret = devm_request_irq(&pdev->dev, irq, rockchip_i2s_tdm_isr,
 				       IRQF_SHARED, node->name, i2s_tdm);
@@ -2264,7 +2325,11 @@
 		return 0;
 	}
 
-	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+	if (of_property_read_bool(node, "rockchip,digital-loopback"))
+		ret = devm_snd_dmaengine_dlp_register(&pdev->dev, &dconfig);
+	else
+		ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+
 	if (ret) {
 		dev_err(&pdev->dev, "Could not register PCM\n");
 		return ret;

--
Gitblit v1.6.2