aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/sh4a/clock-sh7786.c')
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7786.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
new file mode 100644
index 000000000000..f84a9c134471
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c
@@ -0,0 +1,148 @@
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
22static int ifc_divisors[] = { 1, 2, 4, 1 };
23static int sfc_divisors[] = { 1, 1, 4, 1 };
24static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 1,
25 24, 32, 1, 1, 1, 1, 1, 1 };
26static int mfc_divisors[] = { 1, 1, 4, 1 };
27static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 16, 1,
28 24, 32, 1, 48, 1, 1, 1, 1 };
29
30static void master_clk_init(struct clk *clk)
31{
32 clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f];
33}
34
35static struct clk_ops sh7786_master_clk_ops = {
36 .init = master_clk_init,
37};
38
39static 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
45static struct clk_ops sh7786_module_clk_ops = {
46 .recalc = module_clk_recalc,
47};
48
49static 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
55static struct clk_ops sh7786_bus_clk_ops = {
56 .recalc = bus_clk_recalc,
57};
58
59static 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
65static struct clk_ops sh7786_cpu_clk_ops = {
66 .recalc = cpu_clk_recalc,
67};
68
69static 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
76void __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
82static 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
88static struct clk_ops sh7786_shyway_clk_ops = {
89 .recalc = shyway_clk_recalc,
90};
91
92static struct clk sh7786_shyway_clk = {
93 .name = "shyway_clk",
94 .flags = CLK_ALWAYS_ENABLED,
95 .ops = &sh7786_shyway_clk_ops,
96};
97
98static 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
104static struct clk_ops sh7786_ddr_clk_ops = {
105 .recalc = ddr_clk_recalc,
106};
107
108static 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 */
118static struct clk *sh7786_onchip_clocks[] = {
119 &sh7786_shyway_clk,
120 &sh7786_ddr_clk,
121};
122
123static 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}
148arch_initcall(sh7786_clk_init);