mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Artem Novak <artem122novak@gmail.com>
To: ysato@users.sourceforge.jp, dalias@libc.org,
	glaubitz@physik.fu-berlin.de, geert+renesas@glider.be
Cc: linux-sh@vger.kernel.org, linux-kernel@vger.kernel.org,
	Artem Novak <artem122novak@gmail.com>
Subject: [PATCH v4 1/2] sh: sh7305: add TMU0 clock support
Date: Tue, 10 Nov 2026 19:07:13 -0600	[thread overview]
Message-ID: <20261111010714.227429-2-artem122novak@gmail.com> (raw)
In-Reply-To: <20261111010714.227429-1-artem122novak@gmail.com>

Convert the SH7305 clock implementation to the Common Clock
Framework.

Register the master clock and the CPU, bus and peripheral
divider clocks, and add the TMU0 module clock gate.

Provide a clkdev mapping for the TMU0 functional clock so
the TMU driver can acquire it through its existing clock
lookup.

Signed-off-by: Artem Novak <artem122novak@gmail.com>
---
 arch/sh/include/asm/clock-sh7305.h     |  11 ++
 arch/sh/kernel/cpu/sh4a/clock-sh7305.c | 262 +++++++++++++++++--------
 2 files changed, 195 insertions(+), 78 deletions(-)
 create mode 100644 arch/sh/include/asm/clock-sh7305.h

diff --git a/arch/sh/include/asm/clock-sh7305.h b/arch/sh/include/asm/clock-sh7305.h
new file mode 100644
index 000000000000..2ef73845eacc
--- /dev/null
+++ b/arch/sh/include/asm/clock-sh7305.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_SH_CLOCK_SH7305_H
+#define __ASM_SH_CLOCK_SH7305_H
+
+#include <linux/init.h>
+
+int __init sh7305_clk_init(void);
+
+void __init sh7305_of_setup(char **cmdline_p);
+
+#endif /* __ASM_SH_CLOCK_SH7305_H */
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7305.c b/arch/sh/kernel/cpu/sh4a/clock-sh7305.c
index 0e683dd6de11..fc941524c268 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7305.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7305.c
@@ -4,12 +4,15 @@
  * Renesas SH7305 clock framework support
  */
 
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
 #include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/io.h>
-#include <linux/sh_clk.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
 
-#include <asm/clock.h>
+#include <asm/clock-sh7305.h>
 
 /*
  * SH7305 Clock Pulse Generator
@@ -17,6 +20,7 @@
 #define SH7305_FRQCR		0xa4150000
 #define SH7305_PLLCR		0xa4150024
 #define SH7305_FLLFRQ		0xa4150050
+#define SH7305_MSTPCR0		0xa4150030
 
 /*
  * FRQCR:
@@ -34,34 +38,28 @@
  *   FLF   bits 10..0
  */
 
+static void __iomem *sh7305_cpg_base;
+
 static unsigned long sh7305_base_rate(void)
 {
-	u32 frqcr  = __raw_readl(SH7305_FRQCR);
-	u32 pllcr  = __raw_readl(SH7305_PLLCR);
-	u32 fllfrq = __raw_readl(SH7305_FLLFRQ);
-
-	unsigned int pll;
-	unsigned int fll;
+	u32 frqcr = __raw_readl(sh7305_cpg_base);
+	u32 pllcr = __raw_readl(sh7305_cpg_base + (SH7305_PLLCR - SH7305_FRQCR));
+	u32 fllfrq = __raw_readl(sh7305_cpg_base + (SH7305_FLLFRQ - SH7305_FRQCR));
+	unsigned int pll, fll;
 	unsigned long rate = 32768;
 
-	/*
-	 * SH7305 PLL ratio is STC + 1.
-	 * Unlike SH7724 it must NOT be doubled.
-	 */
+	/* SH7305 PLL ratio is STC + 1; it is not doubled. */
 	pll = ((frqcr >> 24) & 0x3f) + 1;
 
-	/*
-	 * FLL ratio is FLF, halved when SELXM == 1.
-	 */
+	/* FLL ratio is FLF, halved when SELXM == 1. */
 	fll = fllfrq & 0x7ff;
-
 	if (((fllfrq >> 14) & 0x3) == 1)
 		fll >>= 1;
 
-	if (pllcr & (1 << 12))
+	if (pllcr & BIT(12))
 		rate *= fll;
 
-	if (pllcr & (1 << 14))
+	if (pllcr & BIT(14))
 		rate *= pll;
 
 	return rate;
@@ -69,98 +67,206 @@ static unsigned long sh7305_base_rate(void)
 
 static unsigned int sh7305_divisor(unsigned int shift)
 {
-	u32 frqcr = __raw_readl(SH7305_FRQCR);
+	u32 frqcr = __raw_readl(sh7305_cpg_base);
 	unsigned int field = (frqcr >> shift) & 0xf;
 
-	/*
-	 * SH7305 divider:
-	 *
-	 *     divisor = 2^(field + 1)
-	 */
 	return 1U << (field + 1);
 }
 
-
 /*
- * master_clk is the clock before the B/I/P divider stages.
+ * Master clock: the clock before the B/I/P divider stages.
  */
-static void master_clk_init(struct clk *clk)
+static unsigned long sh7305_master_recalc_rate(struct clk_hw *hw,
+					       unsigned long parent_rate)
 {
-	clk->rate = sh7305_base_rate();
+	return sh7305_base_rate();
 }
 
-static struct sh_clk_ops sh7305_master_clk_ops = {
-	.init = master_clk_init,
+static const struct clk_ops sh7305_master_clk_ops = {
+	.recalc_rate = sh7305_master_recalc_rate,
 };
 
+static const struct clk_init_data sh7305_master_clk_init = {
+	.name = "master_clk",
+	.ops = &sh7305_master_clk_ops,
+};
+
+static struct clk_hw sh7305_master_clk = {
+	.init = &sh7305_master_clk_init,
+};
 
 /*
- * Pphi - peripheral clock.
- *
- * P1FC occupies FRQCR bits 3..0.
+ * Peripheral, bus and CPU clocks share the master clock as parent.
  */
-static unsigned long peripheral_clk_recalc(struct clk *clk)
+struct sh7305_divider {
+	struct clk_hw hw;
+	unsigned int shift;
+};
+
+static unsigned long sh7305_divider_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
 {
-	return clk->parent->rate / sh7305_divisor(0);
+	struct sh7305_divider *divider =
+		container_of(hw, struct sh7305_divider, hw);
+
+	return parent_rate / sh7305_divisor(divider->shift);
 }
 
-static struct sh_clk_ops sh7305_peripheral_clk_ops = {
-	.recalc = peripheral_clk_recalc,
+static const struct clk_ops sh7305_divider_clk_ops = {
+	.recalc_rate = sh7305_divider_recalc_rate,
 };
 
+static const char * const sh7305_parent_names[] = {
+	"master_clk",
+};
 
-/*
- * Bphi - bus clock.
- *
- * BFC occupies FRQCR bits 11..8.
- */
-static unsigned long bus_clk_recalc(struct clk *clk)
-{
-	return clk->parent->rate / sh7305_divisor(8);
-}
+static const struct clk_init_data sh7305_peripheral_clk_init = {
+	.name = "peripheral_clk",
+	.ops = &sh7305_divider_clk_ops,
+	.parent_names = sh7305_parent_names,
+	.num_parents = ARRAY_SIZE(sh7305_parent_names),
+};
 
-static struct sh_clk_ops sh7305_bus_clk_ops = {
-	.recalc = bus_clk_recalc,
+static struct sh7305_divider sh7305_peripheral_clk = {
+	.hw.init = &sh7305_peripheral_clk_init,
+	.shift = 0,
 };
 
+static const struct clk_init_data sh7305_bus_clk_init = {
+	.name = "bus_clk",
+	.ops = &sh7305_divider_clk_ops,
+	.parent_names = sh7305_parent_names,
+	.num_parents = ARRAY_SIZE(sh7305_parent_names),
+};
 
-/*
- * Iphi - CPU/internal clock.
- *
- * IFC occupies FRQCR bits 23..20.
- */
-static unsigned long cpu_clk_recalc(struct clk *clk)
-{
-	return clk->parent->rate / sh7305_divisor(20);
-}
+static struct sh7305_divider sh7305_bus_clk = {
+	.hw.init = &sh7305_bus_clk_init,
+	.shift = 8,
+};
 
-static struct sh_clk_ops sh7305_cpu_clk_ops = {
-	.recalc = cpu_clk_recalc,
+static const struct clk_init_data sh7305_cpu_clk_init = {
+	.name = "cpu_clk",
+	.ops = &sh7305_divider_clk_ops,
+	.parent_names = sh7305_parent_names,
+	.num_parents = ARRAY_SIZE(sh7305_parent_names),
 };
 
+static struct sh7305_divider sh7305_cpu_clk = {
+	.hw.init = &sh7305_cpu_clk_init,
+	.shift = 20,
+};
 
-/*
- * Ordering must match arch/sh/kernel/cpu/clock-cpg.c:
- *
- *   0 master
- *   1 peripheral
- *   2 bus
- *   3 cpu
- */
-static struct sh_clk_ops *sh7305_clk_ops[] = {
-	&sh7305_master_clk_ops,
-	&sh7305_peripheral_clk_ops,
-	&sh7305_bus_clk_ops,
-	&sh7305_cpu_clk_ops,
+static struct clk_hw *sh7305_main_clks[] = {
+	&sh7305_master_clk,
+	&sh7305_peripheral_clk.hw,
+	&sh7305_bus_clk.hw,
+	&sh7305_cpu_clk.hw,
 };
 
-void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
+static const struct {
+	struct clk_hw *hw;
+	const char *con_id;
+} sh7305_clk_lookups[] = {
+	{ &sh7305_master_clk, "master_clk" },
+	{ &sh7305_peripheral_clk.hw, "peripheral_clk" },
+	{ &sh7305_bus_clk.hw, "bus_clk" },
+	{ &sh7305_cpu_clk.hw, "cpu_clk" },
+};
+
+#define SH7305_MAIN_CLK_COUNT	ARRAY_SIZE(sh7305_main_clks)
+#define SH7305_LOOKUP_COUNT	(SH7305_MAIN_CLK_COUNT + 1)
+
+static struct clk_lookup *sh7305_lookups[SH7305_LOOKUP_COUNT];
+static struct clk_hw *sh7305_tmu0_clk;
+
+static DEFINE_SPINLOCK(sh7305_mstp_lock);
+
+static void sh7305_clk_unregister_lookups(void)
 {
-	if (idx < ARRAY_SIZE(sh7305_clk_ops))
-		*ops = sh7305_clk_ops[idx];
+	int i;
+
+	for (i = SH7305_LOOKUP_COUNT - 1; i >= 0; i--) {
+		if (sh7305_lookups[i]) {
+			clkdev_drop(sh7305_lookups[i]);
+			sh7305_lookups[i] = NULL;
+		}
+	}
 }
 
-int __init arch_clk_init(void)
+static void sh7305_clk_unregister_all(unsigned int registered)
 {
-	return cpg_clk_init();
+	/* Remove clkdev references before unregistering their clocks. */
+	sh7305_clk_unregister_lookups();
+
+	if (sh7305_tmu0_clk) {
+		clk_hw_unregister_gate(sh7305_tmu0_clk);
+		sh7305_tmu0_clk = NULL;
+	}
+
+	while (registered--)
+		clk_hw_unregister(sh7305_main_clks[registered]);
+
+	if (sh7305_cpg_base) {
+		iounmap(sh7305_cpg_base);
+		sh7305_cpg_base = NULL;
+	}
+}
+
+int __init sh7305_clk_init(void)
+{
+	unsigned int i, registered = 0;
+	int ret;
+
+	sh7305_cpg_base = ioremap(SH7305_FRQCR,
+				  SH7305_FLLFRQ - SH7305_FRQCR + sizeof(u32));
+	if (!sh7305_cpg_base)
+		return -ENOMEM;
+
+	for (i = 0; i < SH7305_MAIN_CLK_COUNT; i++) {
+		ret = clk_hw_register(NULL, sh7305_main_clks[i]);
+		if (ret)
+			goto err_unregister;
+
+		registered++;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sh7305_clk_lookups); i++) {
+		sh7305_lookups[i] =
+			clkdev_hw_create(sh7305_clk_lookups[i].hw,
+					 sh7305_clk_lookups[i].con_id, NULL);
+		if (!sh7305_lookups[i]) {
+			ret = -ENOMEM;
+			goto err_unregister;
+		}
+	}
+
+	/*
+	 * MSTPCR0 bit 15 is active-high stop control.
+	 * CLK_GATE_SET_TO_DISABLE describes this polarity without
+	 * changing the hardware state during registration.
+	 */
+	sh7305_tmu0_clk =
+		clk_hw_register_gate(NULL, "tmu0_fck", "peripheral_clk", 0,
+				     sh7305_cpg_base +
+				     (SH7305_MSTPCR0 - SH7305_FRQCR),
+				     15, CLK_GATE_SET_TO_DISABLE,
+				     &sh7305_mstp_lock);
+	if (IS_ERR(sh7305_tmu0_clk)) {
+		ret = PTR_ERR(sh7305_tmu0_clk);
+		sh7305_tmu0_clk = NULL;
+		goto err_unregister;
+	}
+
+	sh7305_lookups[SH7305_MAIN_CLK_COUNT] =
+		clkdev_hw_create(sh7305_tmu0_clk, "fck", "sh-tmu.0");
+	if (!sh7305_lookups[SH7305_MAIN_CLK_COUNT]) {
+		ret = -ENOMEM;
+		goto err_unregister;
+	}
+
+	return 0;
+
+err_unregister:
+	sh7305_clk_unregister_all(registered);
+	return ret;
 }
-- 
2.56.0


  reply	other threads:[~2026-11-11  1:07 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-11  1:07 [PATCH v4 0/2] " Artem Novak
2026-11-11  1:07 ` Artem Novak [this message]
2026-11-11  1:07 ` [PATCH v4 2/2] sh: sh7305: exclude from legacy CPG clock framework Artem Novak

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=20261111010714.227429-2-artem122novak@gmail.com \
    --to=artem122novak@gmail.com \
    --cc=dalias@libc.org \
    --cc=geert+renesas@glider.be \
    --cc=glaubitz@physik.fu-berlin.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sh@vger.kernel.org \
    --cc=ysato@users.sourceforge.jp \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®