Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
[sfrench/cifs-2.6.git] / arch / sh / kernel / cpu / sh4a / clock-sh7786.c
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);