sh: clkfwk: Improve the generic clk_set_parent() implementation.
[deliverable/linux.git] / arch / sh / kernel / cpu / sh4a / clock-sh7785.c
CommitLineData
32351a28
PM
1/*
2 * arch/sh/kernel/cpu/sh4a/clock-sh7785.c
3 *
4 * SH7785 support for the clock framework
5 *
6 * Copyright (C) 2007 Paul Mundt
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <asm/clock.h>
15#include <asm/freq.h>
16#include <asm/io.h>
17
18static int ifc_divisors[] = { 1, 2, 4, 6 };
19static int ufc_divisors[] = { 1, 1, 4, 6 };
20static int sfc_divisors[] = { 1, 1, 4, 6 };
21static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18,
22 24, 32, 36, 48, 1, 1, 1, 1 };
23static int mfc_divisors[] = { 1, 1, 4, 6 };
24static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18,
25 24, 32, 36, 48, 1, 1, 1, 1 };
26
27static void master_clk_init(struct clk *clk)
28{
65b83427 29 clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f];
32351a28
PM
30}
31
32static struct clk_ops sh7785_master_clk_ops = {
33 .init = master_clk_init,
34};
35
b68d8201 36static unsigned long module_clk_recalc(struct clk *clk)
32351a28
PM
37{
38 int idx = (ctrl_inl(FRQMR1) & 0x000f);
b68d8201 39 return clk->parent->rate / pfc_divisors[idx];
32351a28
PM
40}
41
42static struct clk_ops sh7785_module_clk_ops = {
43 .recalc = module_clk_recalc,
44};
45
b68d8201 46static unsigned long bus_clk_recalc(struct clk *clk)
32351a28
PM
47{
48 int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
b68d8201 49 return clk->parent->rate / bfc_divisors[idx];
32351a28
PM
50}
51
52static struct clk_ops sh7785_bus_clk_ops = {
53 .recalc = bus_clk_recalc,
54};
55
b68d8201 56static unsigned long cpu_clk_recalc(struct clk *clk)
32351a28
PM
57{
58 int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
b68d8201 59 return clk->parent->rate / ifc_divisors[idx];
32351a28
PM
60}
61
62static struct clk_ops sh7785_cpu_clk_ops = {
63 .recalc = cpu_clk_recalc,
64};
65
66static struct clk_ops *sh7785_clk_ops[] = {
67 &sh7785_master_clk_ops,
68 &sh7785_module_clk_ops,
69 &sh7785_bus_clk_ops,
70 &sh7785_cpu_clk_ops,
71};
72
73void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
74{
75 if (idx < ARRAY_SIZE(sh7785_clk_ops))
76 *ops = sh7785_clk_ops[idx];
77}
78
b68d8201 79static unsigned long shyway_clk_recalc(struct clk *clk)
32351a28
PM
80{
81 int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
b68d8201 82 return clk->parent->rate / sfc_divisors[idx];
32351a28
PM
83}
84
85static struct clk_ops sh7785_shyway_clk_ops = {
86 .recalc = shyway_clk_recalc,
87};
88
89static struct clk sh7785_shyway_clk = {
90 .name = "shyway_clk",
4ff29ff8 91 .flags = CLK_ENABLE_ON_INIT,
32351a28
PM
92 .ops = &sh7785_shyway_clk_ops,
93};
94
b68d8201 95static unsigned long ddr_clk_recalc(struct clk *clk)
32351a28
PM
96{
97 int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
b68d8201 98 return clk->parent->rate / mfc_divisors[idx];
32351a28
PM
99}
100
101static struct clk_ops sh7785_ddr_clk_ops = {
102 .recalc = ddr_clk_recalc,
103};
104
105static struct clk sh7785_ddr_clk = {
106 .name = "ddr_clk",
4ff29ff8 107 .flags = CLK_ENABLE_ON_INIT,
32351a28
PM
108 .ops = &sh7785_ddr_clk_ops,
109};
110
b68d8201 111static unsigned long ram_clk_recalc(struct clk *clk)
32351a28
PM
112{
113 int idx = ((ctrl_inl(FRQMR1) >> 24) & 0x0003);
b68d8201 114 return clk->parent->rate / ufc_divisors[idx];
32351a28
PM
115}
116
117static struct clk_ops sh7785_ram_clk_ops = {
118 .recalc = ram_clk_recalc,
119};
120
121static struct clk sh7785_ram_clk = {
122 .name = "ram_clk",
4ff29ff8 123 .flags = CLK_ENABLE_ON_INIT,
32351a28
PM
124 .ops = &sh7785_ram_clk_ops,
125};
126
127/*
128 * Additional SH7785-specific on-chip clocks that aren't already part of the
129 * clock framework
130 */
131static struct clk *sh7785_onchip_clocks[] = {
132 &sh7785_shyway_clk,
133 &sh7785_ddr_clk,
134 &sh7785_ram_clk,
135};
136
137static int __init sh7785_clk_init(void)
138{
139 struct clk *clk = clk_get(NULL, "master_clk");
140 int i;
141
142 for (i = 0; i < ARRAY_SIZE(sh7785_onchip_clocks); i++) {
143 struct clk *clkp = sh7785_onchip_clocks[i];
144
145 clkp->parent = clk;
146 clk_register(clkp);
147 clk_enable(clkp);
148 }
149
150 /*
151 * Now that we have the rest of the clocks registered, we need to
152 * force the parent clock to propagate so that these clocks will
153 * automatically figure out their rate. We cheat by handing the
154 * parent clock its current rate and forcing child propagation.
155 */
156 clk_set_rate(clk, clk_get_rate(clk));
157
158 clk_put(clk);
159
160 return 0;
161}
162arch_initcall(sh7785_clk_init);
This page took 0.229076 seconds and 5 git commands to generate.