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
next prev parent 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®