aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/include/asm/clock.h4
-rw-r--r--arch/sh/kernel/cpu/clock-cpg.c94
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c25
3 files changed, 116 insertions, 7 deletions
diff --git a/arch/sh/include/asm/clock.h b/arch/sh/include/asm/clock.h
index 9fe7d7f8af40..501d0b076283 100644
--- a/arch/sh/include/asm/clock.h
+++ b/arch/sh/include/asm/clock.h
@@ -148,6 +148,10 @@ int sh_clk_mstp32_register(struct clk *clks, int nr);
148 148
149int sh_clk_div4_register(struct clk *clks, int nr, 149int sh_clk_div4_register(struct clk *clks, int nr,
150 struct clk_div_mult_table *table); 150 struct clk_div_mult_table *table);
151int sh_clk_div4_enable_register(struct clk *clks, int nr,
152 struct clk_div_mult_table *table);
153int sh_clk_div4_reparent_register(struct clk *clks, int nr,
154 struct clk_div_mult_table *table);
151 155
152#define SH_CLK_DIV6(_name, _parent, _reg, _flags) \ 156#define SH_CLK_DIV6(_name, _parent, _reg, _flags) \
153{ \ 157{ \
diff --git a/arch/sh/kernel/cpu/clock-cpg.c b/arch/sh/kernel/cpu/clock-cpg.c
index 6dfe2cced3fc..2827abb5d2ab 100644
--- a/arch/sh/kernel/cpu/clock-cpg.c
+++ b/arch/sh/kernel/cpu/clock-cpg.c
@@ -160,13 +160,81 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
160 return clk->freq_table[idx].frequency; 160 return clk->freq_table[idx].frequency;
161} 161}
162 162
163static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
164{
165 struct clk_div_mult_table *table = clk->priv;
166 u32 value;
167 int ret;
168
169 if (!strcmp("pll_clk", parent->name))
170 value = __raw_readl(clk->enable_reg) & ~(1 << 7);
171 else
172 value = __raw_readl(clk->enable_reg) | (1 << 7);
173
174 ret = clk_reparent(clk, parent);
175 if (ret < 0)
176 return ret;
177
178 __raw_writel(value, clk->enable_reg);
179
180 /* Rebiuld the frequency table */
181 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
182 table, &clk->arch_flags);
183
184 return 0;
185}
186
187static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id)
188{
189 unsigned long value;
190 int idx = clk_rate_table_find(clk, clk->freq_table, rate);
191 if (idx < 0)
192 return idx;
193
194 value = __raw_readl(clk->enable_reg);
195 value &= ~0xf;
196 value |= idx;
197 __raw_writel(value, clk->enable_reg);
198
199 return 0;
200}
201
202static int sh_clk_div4_enable(struct clk *clk)
203{
204 __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
205 return 0;
206}
207
208static void sh_clk_div4_disable(struct clk *clk)
209{
210 __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
211}
212
163static struct clk_ops sh_clk_div4_clk_ops = { 213static struct clk_ops sh_clk_div4_clk_ops = {
164 .recalc = sh_clk_div4_recalc, 214 .recalc = sh_clk_div4_recalc,
215 .set_rate = sh_clk_div4_set_rate,
165 .round_rate = sh_clk_div_round_rate, 216 .round_rate = sh_clk_div_round_rate,
166}; 217};
167 218
168int __init sh_clk_div4_register(struct clk *clks, int nr, 219static struct clk_ops sh_clk_div4_enable_clk_ops = {
169 struct clk_div_mult_table *table) 220 .recalc = sh_clk_div4_recalc,
221 .set_rate = sh_clk_div4_set_rate,
222 .round_rate = sh_clk_div_round_rate,
223 .enable = sh_clk_div4_enable,
224 .disable = sh_clk_div4_disable,
225};
226
227static struct clk_ops sh_clk_div4_reparent_clk_ops = {
228 .recalc = sh_clk_div4_recalc,
229 .set_rate = sh_clk_div4_set_rate,
230 .round_rate = sh_clk_div_round_rate,
231 .enable = sh_clk_div4_enable,
232 .disable = sh_clk_div4_disable,
233 .set_parent = sh_clk_div4_set_parent,
234};
235
236static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
237 struct clk_div_mult_table *table, struct clk_ops *ops)
170{ 238{
171 struct clk *clkp; 239 struct clk *clkp;
172 void *freq_table; 240 void *freq_table;
@@ -185,7 +253,7 @@ int __init sh_clk_div4_register(struct clk *clks, int nr,
185 for (k = 0; !ret && (k < nr); k++) { 253 for (k = 0; !ret && (k < nr); k++) {
186 clkp = clks + k; 254 clkp = clks + k;
187 255
188 clkp->ops = &sh_clk_div4_clk_ops; 256 clkp->ops = ops;
189 clkp->id = -1; 257 clkp->id = -1;
190 clkp->priv = table; 258 clkp->priv = table;
191 259
@@ -198,6 +266,26 @@ int __init sh_clk_div4_register(struct clk *clks, int nr,
198 return ret; 266 return ret;
199} 267}
200 268
269int __init sh_clk_div4_register(struct clk *clks, int nr,
270 struct clk_div_mult_table *table)
271{
272 return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops);
273}
274
275int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
276 struct clk_div_mult_table *table)
277{
278 return sh_clk_div4_register_ops(clks, nr, table,
279 &sh_clk_div4_enable_clk_ops);
280}
281
282int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
283 struct clk_div_mult_table *table)
284{
285 return sh_clk_div4_register_ops(clks, nr, table,
286 &sh_clk_div4_reparent_clk_ops);
287}
288
201#ifdef CONFIG_SH_CLK_CPG_LEGACY 289#ifdef CONFIG_SH_CLK_CPG_LEGACY
202static struct clk master_clk = { 290static struct clk master_clk = {
203 .name = "master_clk", 291 .name = "master_clk",
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index ea38b554dc05..860ee2bf4bf0 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -117,12 +117,11 @@ static struct clk_div_mult_table div4_table = {
117 .nr_multipliers = ARRAY_SIZE(multipliers), 117 .nr_multipliers = ARRAY_SIZE(multipliers),
118}; 118};
119 119
120enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P,
121 DIV4_SIUA, DIV4_SIUB, DIV4_IRDA, DIV4_NR };
122
123#define DIV4(_str, _reg, _bit, _mask, _flags) \ 120#define DIV4(_str, _reg, _bit, _mask, _flags) \
124 SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags) 121 SH_CLK_DIV4(_str, &pll_clk, _reg, _bit, _mask, _flags)
125 122
123enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, DIV4_NR };
124
126struct clk div4_clks[DIV4_NR] = { 125struct clk div4_clks[DIV4_NR] = {
127 [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT), 126 [DIV4_I] = DIV4("cpu_clk", FRQCR, 20, 0x1fef, CLK_ENABLE_ON_INIT),
128 [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT), 127 [DIV4_U] = DIV4("umem_clk", FRQCR, 16, 0x1fff, CLK_ENABLE_ON_INIT),
@@ -130,9 +129,19 @@ struct clk div4_clks[DIV4_NR] = {
130 [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT), 129 [DIV4_B] = DIV4("bus_clk", FRQCR, 8, 0x1fff, CLK_ENABLE_ON_INIT),
131 [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT), 130 [DIV4_B3] = DIV4("b3_clk", FRQCR, 4, 0x1fff, CLK_ENABLE_ON_INIT),
132 [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0), 131 [DIV4_P] = DIV4("peripheral_clk", FRQCR, 0, 0x1fff, 0),
132};
133
134enum { DIV4_IRDA, DIV4_ENABLE_NR };
135
136struct clk div4_enable_clks[DIV4_ENABLE_NR] = {
137 [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x1fff, 0),
138};
139
140enum { DIV4_SIUA, DIV4_SIUB, DIV4_REPARENT_NR };
141
142struct clk div4_reparent_clks[DIV4_REPARENT_NR] = {
133 [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0), 143 [DIV4_SIUA] = DIV4("siua_clk", SCLKACR, 0, 0x1fff, 0),
134 [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0), 144 [DIV4_SIUB] = DIV4("siub_clk", SCLKBCR, 0, 0x1fff, 0),
135 [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x1fff, 0),
136}; 145};
137 146
138struct clk div6_clks[] = { 147struct clk div6_clks[] = {
@@ -189,6 +198,14 @@ int __init arch_clk_init(void)
189 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); 198 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
190 199
191 if (!ret) 200 if (!ret)
201 ret = sh_clk_div4_enable_register(div4_enable_clks,
202 DIV4_ENABLE_NR, &div4_table);
203
204 if (!ret)
205 ret = sh_clk_div4_reparent_register(div4_reparent_clks,
206 DIV4_REPARENT_NR, &div4_table);
207
208 if (!ret)
192 ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); 209 ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));
193 210
194 if (!ret) 211 if (!ret)