[PATCH v1 2/7] clk: rockchip: rk3568: add i2s3 clk

Elaine Zhang zhangqing at rock-chips.com
Tue Oct 10 10:51:50 CEST 2023


Change-Id: If20fe16260d2b584d4216d1dbabffcb25478fb1d
Signed-off-by: Elaine Zhang <zhangqing at rock-chips.com>
---
 .../include/asm/arch-rockchip/cru_rk3568.h    |  36 +++
 drivers/clk/rockchip/clk_rk3568.c             | 218 ++++++++++++++++++
 2 files changed, 254 insertions(+)

diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3568.h b/arch/arm/include/asm/arch-rockchip/cru_rk3568.h
index 9c7ddd751f72..0306ce57e369 100644
--- a/arch/arm/include/asm/arch-rockchip/cru_rk3568.h
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3568.h
@@ -211,6 +211,31 @@ enum {
 	ACLK_PERIMID_SEL_100M,
 	ACLK_PERIMID_SEL_24M,
 
+	/* CRU_CLK_SEL21_CON */
+	I2S3_MCLKOUT_TX_SEL_SHIFT	= 15,
+	I2S3_MCLKOUT_TX_SEL_MASK	= 1 << I2S3_MCLKOUT_TX_SEL_SHIFT,
+	I2S3_MCLKOUT_TX_SEL_MCLK	= 0,
+	I2S3_MCLKOUT_TX_SEL_12M,
+	CLK_I2S3_SEL_SHIFT		= 10,
+	CLK_I2S3_SEL_MASK		= 0x3 << CLK_I2S3_SEL_SHIFT,
+	CLK_I2S3_SEL_SRC		= 0,
+	CLK_I2S3_SEL_FRAC,
+	CLK_I2S3_SEL_CLKIN,
+	CLK_I2S3_SEL_XIN12M,
+	CLK_I2S3_SRC_SEL_SHIFT		= 8,
+	CLK_I2S3_SRC_SEL_MASK		= 0x3 << CLK_I2S3_SRC_SEL_SHIFT,
+	CLK_I2S3_SRC_SEL_GPLL		= 0,
+	CLK_I2S3_SRC_SEL_CPLL,
+	CLK_I2S3_SRC_SEL_NPLL,
+	CLK_I2S3_SRC_DIV_SHIFT		= 0,
+	CLK_I2S3_SRC_DIV_MASK		= 0x7f << CLK_I2S3_SRC_DIV_SHIFT,
+
+	/* CRU_CLK_SEL22_CON */
+	CLK_I2S3_FRAC_NUMERATOR_SHIFT	= 16,
+	CLK_I2S3_FRAC_NUMERATOR_MASK	= 0xffff << 16,
+	CLK_I2S3_FRAC_DENOMINATOR_SHIFT	= 0,
+	CLK_I2S3_FRAC_DENOMINATOR_MASK	= 0xffff,
+
 	/* CRU_CLK_SEL27_CON */
 	CLK_CRYPTO_PKA_SEL_SHIFT	= 6,
 	CLK_CRYPTO_PKA_SEL_MASK		= 3 << CLK_CRYPTO_PKA_SEL_SHIFT,
@@ -502,5 +527,16 @@ enum {
 	/* CRU_CLK_SEL82_CON */
 	CPLL_100M_DIV_SHIFT		= 0,
 	CPLL_100M_DIV_MASK		= 0x1f << CPLL_100M_DIV_SHIFT,
+
+	/* GRF_SOC_CON2 */
+	I2S3_MCLKOUT_SEL_SHIFT		= 15,
+	I2S3_MCLKOUT_SEL_MASK		= 0x1 << I2S3_MCLKOUT_SEL_SHIFT,
+	I2S3_MCLKOUT_SEL_RX		= 0,
+	I2S3_MCLKOUT_SEL_TX,
+	I2S3_MCLK_IOE_SEL_SHIFT		= 3,
+	I2S3_MCLK_IOE_SEL_MASK		= 0x1 << I2S3_MCLK_IOE_SEL_SHIFT,
+	I2S3_MCLK_IOE_SEL_CLKIN		= 0,
+	I2S3_MCLK_IOE_SEL_CLKOUT,
+
 };
 #endif
diff --git a/drivers/clk/rockchip/clk_rk3568.c b/drivers/clk/rockchip/clk_rk3568.c
index 599b7b130eb9..469014439be4 100644
--- a/drivers/clk/rockchip/clk_rk3568.c
+++ b/drivers/clk/rockchip/clk_rk3568.c
@@ -13,6 +13,7 @@
 #include <asm/arch-rockchip/cru_rk3568.h>
 #include <asm/arch-rockchip/clock.h>
 #include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/grf_rk3568.h>
 #include <asm/io.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
@@ -2326,6 +2327,170 @@ static ulong rk3568_uart_set_rate(struct rk3568_clk_priv *priv,
 	return rk3568_uart_get_rate(priv, clk_id);
 }
 
+#ifndef CONFIG_SPL_BUILD
+static ulong rk3568_i2s3_get_rate(struct rk3568_clk_priv *priv, ulong clk_id)
+{
+	struct rk3568_cru *cru = priv->cru;
+	struct rk3568_grf *grf = priv->grf;
+	u32 con, div, src, p_rate;
+	u32 reg, fracdiv, p_src;
+	unsigned long m, n;
+
+	switch (clk_id) {
+	case I2S3_MCLKOUT_TX:
+		con = readl(&cru->clksel_con[21]);
+		src = (con & I2S3_MCLKOUT_TX_SEL_MASK) >>
+		      I2S3_MCLKOUT_TX_SEL_SHIFT;
+		if (src == I2S3_MCLKOUT_TX_SEL_12M)
+			p_rate = 12000000;
+		else
+			p_rate = rk3568_i2s3_get_rate(priv, MCLK_I2S3_2CH_TX);
+		return p_rate;
+	case I2S3_MCLKOUT_RX:
+		con = readl(&cru->clksel_con[83]);
+		src = (con & I2S3_MCLKOUT_TX_SEL_MASK) >>
+		      I2S3_MCLKOUT_TX_SEL_SHIFT;
+		if (src == I2S3_MCLKOUT_TX_SEL_12M)
+			p_rate = 12000000;
+		else
+			p_rate = rk3568_i2s3_get_rate(priv, MCLK_I2S3_2CH_RX);
+		return p_rate;
+	case I2S3_MCLKOUT:
+		con = readl(&grf->soc_con2);
+		src = (con & I2S3_MCLKOUT_SEL_MASK)
+		      >> I2S3_MCLKOUT_SEL_SHIFT;
+		if (src == I2S3_MCLKOUT_SEL_RX)
+			p_rate = rk3568_i2s3_get_rate(priv, I2S3_MCLKOUT_RX);
+		else
+			p_rate = rk3568_i2s3_get_rate(priv, I2S3_MCLKOUT_TX);
+		return p_rate;
+	case MCLK_I2S3_2CH_RX:
+		reg = 83;
+		break;
+	case MCLK_I2S3_2CH_TX:
+		reg = 21;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	con = readl(&cru->clksel_con[reg]);
+	src = (con & CLK_I2S3_SEL_MASK) >> CLK_I2S3_SEL_SHIFT;
+	div = (con & CLK_I2S3_SRC_DIV_MASK) >> CLK_I2S3_SRC_DIV_SHIFT;
+	p_src = (con & CLK_I2S3_SRC_SEL_MASK) >> CLK_I2S3_SRC_SEL_SHIFT;
+	if (p_src == CLK_I2S3_SRC_SEL_GPLL)
+		p_rate = priv->gpll_hz;
+	else if (p_src == CLK_I2S3_SRC_SEL_CPLL)
+		p_rate = priv->cpll_hz;
+	else
+		p_rate = priv->npll_hz;
+	if (src == CLK_I2S3_SEL_SRC) {
+		return DIV_TO_RATE(p_rate, div);
+	} else if (src == CLK_I2S3_SEL_FRAC) {
+		fracdiv = readl(&cru->clksel_con[reg + 1]);
+		n = fracdiv & CLK_I2S3_FRAC_NUMERATOR_MASK;
+		n >>= CLK_I2S3_FRAC_NUMERATOR_SHIFT;
+		m = fracdiv & CLK_I2S3_FRAC_DENOMINATOR_MASK;
+		m >>= CLK_I2S3_FRAC_DENOMINATOR_SHIFT;
+		return DIV_TO_RATE(p_rate, div) * n / m;
+	} else {
+		return OSC_HZ / 2;
+	}
+}
+
+static ulong rk3568_i2s3_set_rate(struct rk3568_clk_priv *priv,
+				  ulong clk_id, ulong rate)
+{
+	struct rk3568_cru *cru = priv->cru;
+	struct rk3568_grf *grf = priv->grf;
+	u32 reg, con, clk_src, i2s_src, div;
+	unsigned long m = 0, n = 0, val;
+
+	if (priv->gpll_hz % rate == 0) {
+		clk_src = CLK_I2S3_SRC_SEL_GPLL;
+		i2s_src = CLK_I2S3_SEL_SRC;
+		div = DIV_ROUND_UP(priv->gpll_hz, rate);
+	} else if (priv->cpll_hz % rate == 0) {
+		clk_src = CLK_I2S3_SRC_SEL_CPLL;
+		i2s_src = CLK_I2S3_SEL_SRC;
+		div = DIV_ROUND_UP(priv->gpll_hz, rate);
+	} else if (rate == OSC_HZ / 2) {
+		clk_src = CLK_I2S3_SRC_SEL_GPLL;
+		i2s_src = CLK_I2S3_SEL_XIN12M;
+		div = 1;
+	} else {
+		clk_src = CLK_I2S3_SRC_SEL_GPLL;
+		i2s_src = CLK_I2S3_SEL_FRAC;
+		div = 1;
+		rational_best_approximation(rate, priv->gpll_hz / div,
+					    GENMASK(16 - 1, 0),
+					    GENMASK(16 - 1, 0),
+					    &m, &n);
+	}
+
+	switch (clk_id) {
+	case I2S3_MCLKOUT_TX:
+		if (rate == 12000000) {
+			rk_clrsetreg(&cru->clksel_con[21],
+				     I2S3_MCLKOUT_TX_SEL_MASK,
+				     I2S3_MCLKOUT_TX_SEL_12M <<
+				     I2S3_MCLKOUT_TX_SEL_SHIFT);
+		} else {
+			rk3568_i2s3_set_rate(priv, MCLK_I2S3_2CH_TX, rate),
+			rk_clrsetreg(&cru->clksel_con[21],
+				     I2S3_MCLKOUT_TX_SEL_MASK,
+				     I2S3_MCLKOUT_TX_SEL_MCLK <<
+				     I2S3_MCLKOUT_TX_SEL_SHIFT);
+		}
+		return rk3568_i2s3_get_rate(priv, clk_id);
+	case I2S3_MCLKOUT_RX:
+		if (rate == 12000000) {
+			rk_clrsetreg(&cru->clksel_con[83],
+				     I2S3_MCLKOUT_TX_SEL_MASK,
+				     I2S3_MCLKOUT_TX_SEL_12M <<
+				     I2S3_MCLKOUT_TX_SEL_SHIFT);
+		} else {
+			rk3568_i2s3_set_rate(priv, MCLK_I2S3_2CH_RX, rate),
+			rk_clrsetreg(&cru->clksel_con[21],
+				     I2S3_MCLKOUT_TX_SEL_MASK,
+				     I2S3_MCLKOUT_TX_SEL_MCLK <<
+				     I2S3_MCLKOUT_TX_SEL_SHIFT);
+		}
+		return rk3568_i2s3_get_rate(priv, clk_id);
+	case I2S3_MCLKOUT:
+		con = readl(&grf->soc_con2);
+		clk_src = (con & I2S3_MCLKOUT_SEL_MASK)
+		      >> I2S3_MCLKOUT_SEL_SHIFT;
+		if (clk_src == I2S3_MCLKOUT_SEL_RX)
+			rk3568_i2s3_set_rate(priv, I2S3_MCLKOUT_RX, rate);
+		else
+			rk3568_i2s3_set_rate(priv, I2S3_MCLKOUT_TX, rate);
+		return rk3568_i2s3_get_rate(priv, clk_id);
+	case MCLK_I2S3_2CH_RX:
+		reg = 83;
+		break;
+	case MCLK_I2S3_2CH_TX:
+		reg = 21;
+		break;
+	default:
+		return -ENOENT;
+	}
+
+	rk_clrsetreg(&cru->clksel_con[reg],
+		     CLK_I2S3_SEL_MASK | CLK_I2S3_SRC_SEL_MASK |
+		     CLK_I2S3_SRC_DIV_MASK,
+		     (clk_src << CLK_I2S3_SRC_SEL_SHIFT) |
+		     (i2s_src << CLK_I2S3_SEL_SHIFT) |
+		     ((div - 1) << CLK_I2S3_SRC_DIV_SHIFT));
+	if (m && n) {
+		val = m << CLK_I2S3_FRAC_NUMERATOR_SHIFT | n;
+		writel(val, &cru->clksel_con[reg + 1]);
+	}
+	return rk3568_i2s3_get_rate(priv, clk_id);
+}
+
+#endif
+
 static ulong rk3568_clk_get_rate(struct clk *clk)
 {
 	struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
@@ -2463,6 +2628,13 @@ static ulong rk3568_clk_get_rate(struct clk *clk)
 	case TCLK_WDT_NS:
 		rate = OSC_HZ;
 		break;
+	case I2S3_MCLKOUT_RX:
+	case I2S3_MCLKOUT_TX:
+	case MCLK_I2S3_2CH_RX:
+	case MCLK_I2S3_2CH_TX:
+	case I2S3_MCLKOUT:
+		rate = rk3568_i2s3_get_rate(priv, clk->id);
+		break;
 #endif
 	case SCLK_UART1:
 	case SCLK_UART2:
@@ -2648,6 +2820,13 @@ static ulong rk3568_clk_set_rate(struct clk *clk, ulong rate)
 	case TCLK_WDT_NS:
 		ret = OSC_HZ;
 		break;
+	case I2S3_MCLKOUT_RX:
+	case I2S3_MCLKOUT_TX:
+	case MCLK_I2S3_2CH_RX:
+	case MCLK_I2S3_2CH_TX:
+	case I2S3_MCLKOUT:
+		ret = rk3568_i2s3_set_rate(priv, clk->id, rate);
+		break;
 #endif
 	case SCLK_UART1:
 	case SCLK_UART2:
@@ -2824,6 +3003,42 @@ static int rk3568_rkvdec_set_parent(struct clk *clk, struct clk *parent)
 	return 0;
 }
 
+static int __maybe_unused rk3568_i2s3_set_parent(struct clk *clk,
+						 struct clk *parent)
+{
+	struct rk3568_clk_priv *priv = dev_get_priv(clk->dev);
+	struct rk3568_grf *grf = priv->grf;
+
+	switch (clk->id) {
+	case I2S3_MCLK_IOE:
+		if (parent->id == I2S3_MCLKOUT) {
+			rk_clrsetreg(&grf->soc_con2, I2S3_MCLK_IOE_SEL_MASK,
+				     I2S3_MCLK_IOE_SEL_CLKOUT <<
+				     I2S3_MCLK_IOE_SEL_SHIFT);
+		} else {
+			rk_clrsetreg(&grf->soc_con2, I2S3_MCLK_IOE_SEL_MASK,
+				     I2S3_MCLK_IOE_SEL_CLKIN <<
+				     I2S3_MCLK_IOE_SEL_SHIFT);
+		}
+		break;
+	case I2S3_MCLKOUT:
+		if (parent->id == I2S3_MCLKOUT_RX) {
+			rk_clrsetreg(&grf->soc_con2, I2S3_MCLKOUT_SEL_MASK,
+				     I2S3_MCLKOUT_SEL_RX <<
+				     I2S3_MCLKOUT_SEL_SHIFT);
+		} else {
+			rk_clrsetreg(&grf->soc_con2, I2S3_MCLKOUT_SEL_MASK,
+				     I2S3_MCLKOUT_SEL_TX <<
+				     I2S3_MCLKOUT_SEL_SHIFT);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int rk3568_clk_set_parent(struct clk *clk, struct clk *parent)
 {
 	switch (clk->id) {
@@ -2848,6 +3063,9 @@ static int rk3568_clk_set_parent(struct clk *clk, struct clk *parent)
 	case SCLK_GMAC1_RGMII_SPEED:
 	case SCLK_GMAC1_RMII_SPEED:
 		break;
+	case I2S3_MCLK_IOE:
+	case I2S3_MCLKOUT:
+		return rk3568_i2s3_set_parent(clk, parent);
 	default:
 		return -ENOENT;
 	}
-- 
2.17.1



More information about the U-Boot mailing list