18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * arch/sh/kernel/cpu/sh2a/clock-sh7203.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * SH7203 support for the clock framework
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Copyright (C) 2007 Kieran Bingham (MPC-Data Ltd)
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Based on clock-sh7263.c
108c2ecf20Sopenharmony_ci *  Copyright (C) 2006  Yoshinori Sato
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Based on clock-sh4.c
138c2ecf20Sopenharmony_ci *  Copyright (C) 2005  Paul Mundt
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <asm/clock.h>
188c2ecf20Sopenharmony_ci#include <asm/freq.h>
198c2ecf20Sopenharmony_ci#include <asm/io.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic const int pll1rate[]={8,12,16,0};
228c2ecf20Sopenharmony_cistatic const int pfc_divisors[]={1,2,3,4,6,8,12};
238c2ecf20Sopenharmony_ci#define ifc_divisors pfc_divisors
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic unsigned int pll2_mult;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic void master_clk_init(struct clk *clk)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	clk->rate *= pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0003] * pll2_mult;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7203_master_clk_ops = {
338c2ecf20Sopenharmony_ci	.init		= master_clk_init,
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic unsigned long module_clk_recalc(struct clk *clk)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	int idx = (__raw_readw(FREQCR) & 0x0007);
398c2ecf20Sopenharmony_ci	return clk->parent->rate / pfc_divisors[idx];
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7203_module_clk_ops = {
438c2ecf20Sopenharmony_ci	.recalc		= module_clk_recalc,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic unsigned long bus_clk_recalc(struct clk *clk)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	int idx = (__raw_readw(FREQCR) & 0x0007);
498c2ecf20Sopenharmony_ci	return clk->parent->rate / pfc_divisors[idx-2];
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7203_bus_clk_ops = {
538c2ecf20Sopenharmony_ci	.recalc		= bus_clk_recalc,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic struct sh_clk_ops sh7203_cpu_clk_ops = {
578c2ecf20Sopenharmony_ci	.recalc		= followparent_recalc,
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic struct sh_clk_ops *sh7203_clk_ops[] = {
618c2ecf20Sopenharmony_ci	&sh7203_master_clk_ops,
628c2ecf20Sopenharmony_ci	&sh7203_module_clk_ops,
638c2ecf20Sopenharmony_ci	&sh7203_bus_clk_ops,
648c2ecf20Sopenharmony_ci	&sh7203_cpu_clk_ops,
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_civoid __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	if (test_mode_pin(MODE_PIN1))
708c2ecf20Sopenharmony_ci		pll2_mult = 4;
718c2ecf20Sopenharmony_ci	else if (test_mode_pin(MODE_PIN0))
728c2ecf20Sopenharmony_ci		pll2_mult = 2;
738c2ecf20Sopenharmony_ci	else
748c2ecf20Sopenharmony_ci		pll2_mult = 1;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (idx < ARRAY_SIZE(sh7203_clk_ops))
778c2ecf20Sopenharmony_ci		*ops = sh7203_clk_ops[idx];
788c2ecf20Sopenharmony_ci}
79