All of lore.kernel.org
 help / color / mirror / Atom feed
From: Emil Renner Berthing <kernel@esmil.dk>
To: linux-clk@vger.kernel.org, devicetree@vger.kernel.org
Cc: Emil Renner Berthing <kernel@esmil.dk>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>, Rob Herring <robh+dt@kernel.org>,
	Andy Shevchenko <andy.shevchenko@gmail.com>,
	Geert Uytterhoeven <geert@linux-m68k.org>,
	Arnd Bergmann <arnd@arndb.de>,
	Michael Zhu <michael.zhu@starfivetech.com>,
	Fu Wei <tekkamanninja@gmail.com>,
	linux-kernel@vger.kernel.org
Subject: [PATCH v1 2/7] clk: starfive: jh7100: Handle audio_div clock properly
Date: Wed, 26 Jan 2022 18:39:48 +0100	[thread overview]
Message-ID: <20220126173953.1016706-3-kernel@esmil.dk> (raw)
In-Reply-To: <20220126173953.1016706-1-kernel@esmil.dk>

It turns out the audio_div clock is a fractional divider where the
lowest byte of the ctrl register is the integer part of the divider and
the 2nd byte is the number of 100th added to the divider.

The children of this clock is used by the audio peripherals for their
sample rate clock, so round to the closest possible rate rather than
always rounding down like regular dividers.

Fixes: 4210be668a09 ("clk: starfive: Add JH7100 clock generator driver")
Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
---
 drivers/clk/starfive/clk-starfive-jh7100.c | 68 +++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c
index db6a4dc203af..4b59338b5d7d 100644
--- a/drivers/clk/starfive/clk-starfive-jh7100.c
+++ b/drivers/clk/starfive/clk-starfive-jh7100.c
@@ -32,6 +32,13 @@
 #define JH7100_CLK_MUX_MASK	GENMASK(27, 24)
 #define JH7100_CLK_MUX_SHIFT	24
 #define JH7100_CLK_DIV_MASK	GENMASK(23, 0)
+#define JH7100_CLK_FRAC_MASK	GENMASK(15, 8)
+#define JH7100_CLK_FRAC_SHIFT	8
+#define JH7100_CLK_INT_MASK	GENMASK(7, 0)
+
+/* fractional divider min/max */
+#define JH7100_CLK_FRAC_MIN	100UL
+#define JH7100_CLK_FRAC_MAX	25599UL
 
 /* clock data */
 #define JH7100_GATE(_idx, _name, _flags, _parent) [_idx] = {		\
@@ -55,6 +62,13 @@
 	.parents = { [0] = _parent },					\
 }
 
+#define JH7100_FDIV(_idx, _name, _parent) [_idx] = {			\
+	.name = _name,							\
+	.flags = 0,							\
+	.max = JH7100_CLK_FRAC_MAX,					\
+	.parents = { [0] = _parent },					\
+}
+
 #define JH7100__MUX(_idx, _name, _nparents, ...) [_idx] = {		\
 	.name = _name,							\
 	.flags = 0,							\
@@ -225,7 +239,7 @@ static const struct {
 	JH7100__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2,
 		    JH7100_CLK_OSC_SYS,
 		    JH7100_CLK_USBPHY_PLLDIV25M),
-	JH7100__DIV(JH7100_CLK_AUDIO_DIV, "audio_div", 131072, JH7100_CLK_AUDIO_ROOT),
+	JH7100_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT),
 	JH7100_GATE(JH7100_CLK_AUDIO_SRC, "audio_src", 0, JH7100_CLK_AUDIO_DIV),
 	JH7100_GATE(JH7100_CLK_AUDIO_12288, "audio_12288", 0, JH7100_CLK_OSC_AUD),
 	JH7100_GDIV(JH7100_CLK_VIN_SRC, "vin_src", 0, 4, JH7100_CLK_VIN_ROOT),
@@ -440,6 +454,49 @@ static int jh7100_clk_set_rate(struct clk_hw *hw,
 	return 0;
 }
 
+static unsigned long jh7100_clk_frac_recalc_rate(struct clk_hw *hw,
+						 unsigned long parent_rate)
+{
+	struct jh7100_clk *clk = jh7100_clk_from(hw);
+	u32 reg = jh7100_clk_reg_get(clk);
+	unsigned long div100 = 100 * (reg & JH7100_CLK_INT_MASK) +
+			       ((reg & JH7100_CLK_FRAC_MASK) >> JH7100_CLK_FRAC_SHIFT);
+
+	return (div100 >= JH7100_CLK_FRAC_MIN) ? 100 * parent_rate / div100 : 0;
+}
+
+static int jh7100_clk_frac_determine_rate(struct clk_hw *hw,
+					  struct clk_rate_request *req)
+{
+	unsigned long parent100 = 100 * req->best_parent_rate;
+	unsigned long rate = clamp(req->rate, req->min_rate, req->max_rate);
+	unsigned long div100 = clamp(DIV_ROUND_CLOSEST(parent100, rate),
+				     JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX);
+	unsigned long result = parent100 / div100;
+
+	/* clamp the result as in jh7100_clk_determine_rate() above */
+	if (result > req->max_rate && div100 < JH7100_CLK_FRAC_MAX)
+		result = parent100 / (div100 + 1);
+	if (result < req->min_rate && div100 > JH7100_CLK_FRAC_MIN)
+		result = parent100 / (div100 - 1);
+
+	req->rate = result;
+	return 0;
+}
+
+static int jh7100_clk_frac_set_rate(struct clk_hw *hw,
+				    unsigned long rate,
+				    unsigned long parent_rate)
+{
+	struct jh7100_clk *clk = jh7100_clk_from(hw);
+	unsigned long div100 = clamp(DIV_ROUND_CLOSEST(100 * parent_rate, rate),
+				     JH7100_CLK_FRAC_MIN, JH7100_CLK_FRAC_MAX);
+	u32 value = ((div100 % 100) << JH7100_CLK_FRAC_SHIFT) | (div100 / 100);
+
+	jh7100_clk_reg_rmw(clk, JH7100_CLK_DIV_MASK, value);
+	return 0;
+}
+
 static u8 jh7100_clk_get_parent(struct clk_hw *hw)
 {
 	struct jh7100_clk *clk = jh7100_clk_from(hw);
@@ -526,6 +583,13 @@ static const struct clk_ops jh7100_clk_div_ops = {
 	.debug_init = jh7100_clk_debug_init,
 };
 
+static const struct clk_ops jh7100_clk_fdiv_ops = {
+	.recalc_rate = jh7100_clk_frac_recalc_rate,
+	.determine_rate = jh7100_clk_frac_determine_rate,
+	.set_rate = jh7100_clk_frac_set_rate,
+	.debug_init = jh7100_clk_debug_init,
+};
+
 static const struct clk_ops jh7100_clk_gdiv_ops = {
 	.enable = jh7100_clk_enable,
 	.disable = jh7100_clk_disable,
@@ -564,6 +628,8 @@ static const struct clk_ops *__init jh7100_clk_ops(u32 max)
 	if (max & JH7100_CLK_DIV_MASK) {
 		if (max & JH7100_CLK_ENABLE)
 			return &jh7100_clk_gdiv_ops;
+		if (max == JH7100_CLK_FRAC_MAX)
+			return &jh7100_clk_fdiv_ops;
 		return &jh7100_clk_div_ops;
 	}
 
-- 
2.34.1


  parent reply	other threads:[~2022-01-26 17:40 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-26 17:39 [PATCH v1 0/7] JH7100 Audio Clocks Emil Renner Berthing
2022-01-26 17:39 ` [PATCH v1 1/7] clk: starfive: jh7100: Don't round divisor up twice Emil Renner Berthing
2022-03-11  2:53   ` Stephen Boyd
2022-01-26 17:39 ` Emil Renner Berthing [this message]
2022-03-11  2:53   ` [PATCH v1 2/7] clk: starfive: jh7100: Handle audio_div clock properly Stephen Boyd
2022-01-26 17:39 ` [PATCH v1 3/7] dt-bindings: clock: Add JH7100 audio clock definitions Emil Renner Berthing
2022-02-09  3:32   ` Rob Herring
2022-03-11  2:53   ` Stephen Boyd
2022-01-26 17:39 ` [PATCH v1 4/7] dt-bindings: clock: Add starfive,jh7100-audclk bindings Emil Renner Berthing
2022-02-09  3:33   ` Rob Herring
2022-03-11  2:54   ` Stephen Boyd
2022-01-26 17:39 ` [PATCH v1 5/7] clk: starfive: jh7100: Make hw clock implementation reusable Emil Renner Berthing
2022-03-11  2:54   ` Stephen Boyd
2022-01-26 17:39 ` [PATCH v1 6/7] clk: starfive: jh7100: Support more clock types Emil Renner Berthing
2022-03-11  2:54   ` Stephen Boyd
2022-01-26 17:39 ` [PATCH v1 7/7] clk: starfive: Add JH7100 audio clock driver Emil Renner Berthing
2022-03-11  2:54   ` Stephen Boyd

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220126173953.1016706-3-kernel@esmil.dk \
    --to=kernel@esmil.dk \
    --cc=andy.shevchenko@gmail.com \
    --cc=arnd@arndb.de \
    --cc=devicetree@vger.kernel.org \
    --cc=geert@linux-m68k.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michael.zhu@starfivetech.com \
    --cc=mturquette@baylibre.com \
    --cc=robh+dt@kernel.org \
    --cc=sboyd@kernel.org \
    --cc=tekkamanninja@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.