diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2010-01-19 06:14:31 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-01-19 06:23:00 -0500 |
commit | 31c3af503eb75488aafb7a3d292b9e00962f2cee (patch) | |
tree | c7a7905b50cc524d9ce0f92ad5aa9f80d04fad42 /arch/sh/kernel/cpu/clock-cpg.c | |
parent | 14965f16b4bb8f3e51b09c1d8f61b8e98f9d12db (diff) |
sh: support SIU sourcing from external clock on sh7722
Implement .set_rate() for all SH "div4 clocks," .enable(), .disable(), and
.set_parent() for those, that support them. This allows, among other uses,
reparenting of SIU clocks to the external source, and enabling and
disabling of the IrDA clock on sh7722.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu/clock-cpg.c')
-rw-r--r-- | arch/sh/kernel/cpu/clock-cpg.c | 94 |
1 files changed, 91 insertions, 3 deletions
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 | ||
163 | static 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 | |||
187 | static 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 | |||
202 | static 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 | |||
208 | static void sh_clk_div4_disable(struct clk *clk) | ||
209 | { | ||
210 | __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg); | ||
211 | } | ||
212 | |||
163 | static struct clk_ops sh_clk_div4_clk_ops = { | 213 | static 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 | ||
168 | int __init sh_clk_div4_register(struct clk *clks, int nr, | 219 | static 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 | |||
227 | static 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 | |||
236 | static 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 | ||
269 | int __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 | |||
275 | int __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 | |||
282 | int __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 |
202 | static struct clk master_clk = { | 290 | static struct clk master_clk = { |
203 | .name = "master_clk", | 291 | .name = "master_clk", |