1 /*
2  * arch/sh/kernel/cpu/sh4a/clock-sh7786.c
3  *
4  * SH7786 support for the clock framework
5  *
6  * Copyright (C) 2008, 2009  Renesas Solutions Corp.
7  * Kuninori Morimoto <morimoto.kuninori@renesas.com>
8  *
9  * Based on SH7785
10  *  Copyright (C) 2007  Paul Mundt
11  *
12  * This file is subject to the terms and conditions of the GNU General Public
13  * License.  See the file "COPYING" in the main directory of this archive
14  * for more details.
15  */
16 #include <linux/init.h>
17 #include <linux/kernel.h>
18 #include <asm/clock.h>
19 #include <asm/freq.h>
20 #include <asm/io.h>
21 
22 static int ifc_divisors[] = { 1, 2, 4, 1 };
23 static int sfc_divisors[] = { 1, 1, 4, 1 };
24 static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 1,
25 			     24, 32, 1, 1, 1, 1, 1, 1 };
26 static int mfc_divisors[] = { 1, 1, 4, 1 };
27 static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 16, 1,
28 			      24, 32, 1, 48, 1, 1, 1, 1 };
29 
30 static void master_clk_init(struct clk *clk)
31 {
32 	clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f];
33 }
34 
35 static struct clk_ops sh7786_master_clk_ops = {
36 	.init		= master_clk_init,
37 };
38 
39 static void module_clk_recalc(struct clk *clk)
40 {
41 	int idx = (ctrl_inl(FRQMR1) & 0x000f);
42 	clk->rate = clk->parent->rate / pfc_divisors[idx];
43 }
44 
45 static struct clk_ops sh7786_module_clk_ops = {
46 	.recalc		= module_clk_recalc,
47 };
48 
49 static void bus_clk_recalc(struct clk *clk)
50 {
51 	int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
52 	clk->rate = clk->parent->rate / bfc_divisors[idx];
53 }
54 
55 static struct clk_ops sh7786_bus_clk_ops = {
56 	.recalc		= bus_clk_recalc,
57 };
58 
59 static void cpu_clk_recalc(struct clk *clk)
60 {
61 	int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
62 	clk->rate = clk->parent->rate / ifc_divisors[idx];
63 }
64 
65 static struct clk_ops sh7786_cpu_clk_ops = {
66 	.recalc		= cpu_clk_recalc,
67 };
68 
69 static struct clk_ops *sh7786_clk_ops[] = {
70 	&sh7786_master_clk_ops,
71 	&sh7786_module_clk_ops,
72 	&sh7786_bus_clk_ops,
73 	&sh7786_cpu_clk_ops,
74 };
75 
76 void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
77 {
78 	if (idx < ARRAY_SIZE(sh7786_clk_ops))
79 		*ops = sh7786_clk_ops[idx];
80 }
81 
82 static void shyway_clk_recalc(struct clk *clk)
83 {
84 	int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
85 	clk->rate = clk->parent->rate / sfc_divisors[idx];
86 }
87 
88 static struct clk_ops sh7786_shyway_clk_ops = {
89 	.recalc		= shyway_clk_recalc,
90 };
91 
92 static struct clk sh7786_shyway_clk = {
93 	.name		= "shyway_clk",
94 	.flags		= CLK_ALWAYS_ENABLED,
95 	.ops		= &sh7786_shyway_clk_ops,
96 };
97 
98 static void ddr_clk_recalc(struct clk *clk)
99 {
100 	int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
101 	clk->rate = clk->parent->rate / mfc_divisors[idx];
102 }
103 
104 static struct clk_ops sh7786_ddr_clk_ops = {
105 	.recalc		= ddr_clk_recalc,
106 };
107 
108 static struct clk sh7786_ddr_clk = {
109 	.name		= "ddr_clk",
110 	.flags		= CLK_ALWAYS_ENABLED,
111 	.ops		= &sh7786_ddr_clk_ops,
112 };
113 
114 /*
115  * Additional SH7786-specific on-chip clocks that aren't already part of the
116  * clock framework
117  */
118 static struct clk *sh7786_onchip_clocks[] = {
119 	&sh7786_shyway_clk,
120 	&sh7786_ddr_clk,
121 };
122 
123 static int __init sh7786_clk_init(void)
124 {
125 	struct clk *clk = clk_get(NULL, "master_clk");
126 	int i;
127 
128 	for (i = 0; i < ARRAY_SIZE(sh7786_onchip_clocks); i++) {
129 		struct clk *clkp = sh7786_onchip_clocks[i];
130 
131 		clkp->parent = clk;
132 		clk_register(clkp);
133 		clk_enable(clkp);
134 	}
135 
136 	/*
137 	 * Now that we have the rest of the clocks registered, we need to
138 	 * force the parent clock to propagate so that these clocks will
139 	 * automatically figure out their rate. We cheat by handing the
140 	 * parent clock its current rate and forcing child propagation.
141 	 */
142 	clk_set_rate(clk, clk_get_rate(clk));
143 
144 	clk_put(clk);
145 
146 	return 0;
147 }
148 arch_initcall(sh7786_clk_init);
149