1*add5ca2cSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
241504c39SPaul Mundt /*
358862699SUwe Kleine-König * arch/sh/kernel/cpu/sh4a/clock-sh7780.c
441504c39SPaul Mundt *
541504c39SPaul Mundt * SH7780 support for the clock framework
641504c39SPaul Mundt *
741504c39SPaul Mundt * Copyright (C) 2005 Paul Mundt
841504c39SPaul Mundt */
941504c39SPaul Mundt #include <linux/init.h>
1041504c39SPaul Mundt #include <linux/kernel.h>
1129497ec4SMagnus Damm #include <linux/io.h>
126d803ba7SJean-Christop PLAGNIOL-VILLARD #include <linux/clkdev.h>
1341504c39SPaul Mundt #include <asm/clock.h>
1441504c39SPaul Mundt #include <asm/freq.h>
1541504c39SPaul Mundt #include <asm/io.h>
1641504c39SPaul Mundt
1741504c39SPaul Mundt static int ifc_divisors[] = { 2, 4 };
1841504c39SPaul Mundt static int bfc_divisors[] = { 1, 1, 1, 8, 12, 16, 24, 1 };
1941504c39SPaul Mundt static int pfc_divisors[] = { 1, 24, 24, 1 };
2041504c39SPaul Mundt static int cfc_divisors[] = { 1, 1, 4, 1, 6, 1, 1, 1 };
2141504c39SPaul Mundt
master_clk_init(struct clk * clk)2241504c39SPaul Mundt static void master_clk_init(struct clk *clk)
2341504c39SPaul Mundt {
249d56dd3bSPaul Mundt clk->rate *= pfc_divisors[__raw_readl(FRQCR) & 0x0003];
2541504c39SPaul Mundt }
2641504c39SPaul Mundt
2733cb61a4SMagnus Damm static struct sh_clk_ops sh7780_master_clk_ops = {
2841504c39SPaul Mundt .init = master_clk_init,
2941504c39SPaul Mundt };
3041504c39SPaul Mundt
module_clk_recalc(struct clk * clk)31b68d8201SPaul Mundt static unsigned long module_clk_recalc(struct clk *clk)
3241504c39SPaul Mundt {
339d56dd3bSPaul Mundt int idx = (__raw_readl(FRQCR) & 0x0003);
34b68d8201SPaul Mundt return clk->parent->rate / pfc_divisors[idx];
3541504c39SPaul Mundt }
3641504c39SPaul Mundt
3733cb61a4SMagnus Damm static struct sh_clk_ops sh7780_module_clk_ops = {
3841504c39SPaul Mundt .recalc = module_clk_recalc,
3941504c39SPaul Mundt };
4041504c39SPaul Mundt
bus_clk_recalc(struct clk * clk)41b68d8201SPaul Mundt static unsigned long bus_clk_recalc(struct clk *clk)
4241504c39SPaul Mundt {
439d56dd3bSPaul Mundt int idx = ((__raw_readl(FRQCR) >> 16) & 0x0007);
44b68d8201SPaul Mundt return clk->parent->rate / bfc_divisors[idx];
4541504c39SPaul Mundt }
4641504c39SPaul Mundt
4733cb61a4SMagnus Damm static struct sh_clk_ops sh7780_bus_clk_ops = {
4841504c39SPaul Mundt .recalc = bus_clk_recalc,
4941504c39SPaul Mundt };
5041504c39SPaul Mundt
cpu_clk_recalc(struct clk * clk)51b68d8201SPaul Mundt static unsigned long cpu_clk_recalc(struct clk *clk)
5241504c39SPaul Mundt {
539d56dd3bSPaul Mundt int idx = ((__raw_readl(FRQCR) >> 24) & 0x0001);
54b68d8201SPaul Mundt return clk->parent->rate / ifc_divisors[idx];
5541504c39SPaul Mundt }
5641504c39SPaul Mundt
5733cb61a4SMagnus Damm static struct sh_clk_ops sh7780_cpu_clk_ops = {
5841504c39SPaul Mundt .recalc = cpu_clk_recalc,
5941504c39SPaul Mundt };
6041504c39SPaul Mundt
6133cb61a4SMagnus Damm static struct sh_clk_ops *sh7780_clk_ops[] = {
6241504c39SPaul Mundt &sh7780_master_clk_ops,
6341504c39SPaul Mundt &sh7780_module_clk_ops,
6441504c39SPaul Mundt &sh7780_bus_clk_ops,
6541504c39SPaul Mundt &sh7780_cpu_clk_ops,
6641504c39SPaul Mundt };
6741504c39SPaul Mundt
arch_init_clk_ops(struct sh_clk_ops ** ops,int idx)6833cb61a4SMagnus Damm void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
6941504c39SPaul Mundt {
7041504c39SPaul Mundt if (idx < ARRAY_SIZE(sh7780_clk_ops))
7141504c39SPaul Mundt *ops = sh7780_clk_ops[idx];
7241504c39SPaul Mundt }
7341504c39SPaul Mundt
shyway_clk_recalc(struct clk * clk)74b68d8201SPaul Mundt static unsigned long shyway_clk_recalc(struct clk *clk)
7541504c39SPaul Mundt {
769d56dd3bSPaul Mundt int idx = ((__raw_readl(FRQCR) >> 20) & 0x0007);
77b68d8201SPaul Mundt return clk->parent->rate / cfc_divisors[idx];
7841504c39SPaul Mundt }
7941504c39SPaul Mundt
8033cb61a4SMagnus Damm static struct sh_clk_ops sh7780_shyway_clk_ops = {
8141504c39SPaul Mundt .recalc = shyway_clk_recalc,
8241504c39SPaul Mundt };
8341504c39SPaul Mundt
8441504c39SPaul Mundt static struct clk sh7780_shyway_clk = {
854ff29ff8SPaul Mundt .flags = CLK_ENABLE_ON_INIT,
8641504c39SPaul Mundt .ops = &sh7780_shyway_clk_ops,
8741504c39SPaul Mundt };
8841504c39SPaul Mundt
8941504c39SPaul Mundt /*
9041504c39SPaul Mundt * Additional SH7780-specific on-chip clocks that aren't already part of the
9141504c39SPaul Mundt * clock framework
9241504c39SPaul Mundt */
9341504c39SPaul Mundt static struct clk *sh7780_onchip_clocks[] = {
9441504c39SPaul Mundt &sh7780_shyway_clk,
9541504c39SPaul Mundt };
9641504c39SPaul Mundt
9729497ec4SMagnus Damm static struct clk_lookup lookups[] = {
9829497ec4SMagnus Damm /* main clocks */
9929497ec4SMagnus Damm CLKDEV_CON_ID("shyway_clk", &sh7780_shyway_clk),
10029497ec4SMagnus Damm };
10129497ec4SMagnus Damm
arch_clk_init(void)1029fe5ee0eSPaul Mundt int __init arch_clk_init(void)
10341504c39SPaul Mundt {
104253b0887SPaul Mundt struct clk *clk;
105f5c84cf5SPaul Mundt int i, ret = 0;
10641504c39SPaul Mundt
107253b0887SPaul Mundt cpg_clk_init();
108253b0887SPaul Mundt
109253b0887SPaul Mundt clk = clk_get(NULL, "master_clk");
11041504c39SPaul Mundt for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) {
11141504c39SPaul Mundt struct clk *clkp = sh7780_onchip_clocks[i];
11241504c39SPaul Mundt
11341504c39SPaul Mundt clkp->parent = clk;
114f5c84cf5SPaul Mundt ret |= clk_register(clkp);
11541504c39SPaul Mundt }
11641504c39SPaul Mundt
11741504c39SPaul Mundt clk_put(clk);
11841504c39SPaul Mundt
11929497ec4SMagnus Damm clkdev_add_table(lookups, ARRAY_SIZE(lookups));
12029497ec4SMagnus Damm
121f5c84cf5SPaul Mundt return ret;
12241504c39SPaul Mundt }
123