18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * arch/sh/kernel/cpu/sh4a/clock-sh7763.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * SH7763 support for the clock framework
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Copyright (C) 2005  Paul Mundt
88c2ecf20Sopenharmony_ci *  Copyright (C) 2007  Yoshihiro Shimoda
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
148c2ecf20Sopenharmony_ci#include <asm/clock.h>
158c2ecf20Sopenharmony_ci#include <asm/freq.h>
168c2ecf20Sopenharmony_ci#include <asm/io.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic int bfc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
198c2ecf20Sopenharmony_cistatic int p0fc_divisors[] = { 1, 1, 1, 8, 1, 1, 1, 1 };
208c2ecf20Sopenharmony_cistatic int cfc_divisors[] = { 1, 1, 4, 1, 1, 1, 1, 1 };
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic void master_clk_init(struct clk *clk)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	clk->rate *= p0fc_divisors[(__raw_readl(FRQCR) >> 4) & 0x07];
258c2ecf20Sopenharmony_ci}
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7763_master_clk_ops = {
288c2ecf20Sopenharmony_ci	.init		= master_clk_init,
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic unsigned long module_clk_recalc(struct clk *clk)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	int idx = ((__raw_readl(FRQCR) >> 4) & 0x07);
348c2ecf20Sopenharmony_ci	return clk->parent->rate / p0fc_divisors[idx];
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7763_module_clk_ops = {
388c2ecf20Sopenharmony_ci	.recalc		= module_clk_recalc,
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic unsigned long bus_clk_recalc(struct clk *clk)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	int idx = ((__raw_readl(FRQCR) >> 16) & 0x07);
448c2ecf20Sopenharmony_ci	return clk->parent->rate / bfc_divisors[idx];
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7763_bus_clk_ops = {
488c2ecf20Sopenharmony_ci	.recalc		= bus_clk_recalc,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7763_cpu_clk_ops = {
528c2ecf20Sopenharmony_ci	.recalc		= followparent_recalc,
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic struct sh_clk_ops *sh7763_clk_ops[] = {
568c2ecf20Sopenharmony_ci	&sh7763_master_clk_ops,
578c2ecf20Sopenharmony_ci	&sh7763_module_clk_ops,
588c2ecf20Sopenharmony_ci	&sh7763_bus_clk_ops,
598c2ecf20Sopenharmony_ci	&sh7763_cpu_clk_ops,
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_civoid __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	if (idx < ARRAY_SIZE(sh7763_clk_ops))
658c2ecf20Sopenharmony_ci		*ops = sh7763_clk_ops[idx];
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic unsigned long shyway_clk_recalc(struct clk *clk)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	int idx = ((__raw_readl(FRQCR) >> 20) & 0x07);
718c2ecf20Sopenharmony_ci	return clk->parent->rate / cfc_divisors[idx];
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7763_shyway_clk_ops = {
758c2ecf20Sopenharmony_ci	.recalc		= shyway_clk_recalc,
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic struct clk sh7763_shyway_clk = {
798c2ecf20Sopenharmony_ci	.flags		= CLK_ENABLE_ON_INIT,
808c2ecf20Sopenharmony_ci	.ops		= &sh7763_shyway_clk_ops,
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/*
848c2ecf20Sopenharmony_ci * Additional SH7763-specific on-chip clocks that aren't already part of the
858c2ecf20Sopenharmony_ci * clock framework
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistatic struct clk *sh7763_onchip_clocks[] = {
888c2ecf20Sopenharmony_ci	&sh7763_shyway_clk,
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic struct clk_lookup lookups[] = {
928c2ecf20Sopenharmony_ci	/* main clocks */
938c2ecf20Sopenharmony_ci	CLKDEV_CON_ID("shyway_clk", &sh7763_shyway_clk),
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ciint __init arch_clk_init(void)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct clk *clk;
998c2ecf20Sopenharmony_ci	int i, ret = 0;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	cpg_clk_init();
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	clk = clk_get(NULL, "master_clk");
1048c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sh7763_onchip_clocks); i++) {
1058c2ecf20Sopenharmony_ci		struct clk *clkp = sh7763_onchip_clocks[i];
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci		clkp->parent = clk;
1088c2ecf20Sopenharmony_ci		ret |= clk_register(clkp);
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	clk_put(clk);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return ret;
1168c2ecf20Sopenharmony_ci}
117