diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2010-07-21 06:13:10 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-08-04 03:12:01 -0400 |
commit | b3dd51a8a6ce2e618e8a1be8fa0e7d3d4733c300 (patch) | |
tree | 7a843ef70cb0a680dbf118d1e7a9a73e56f0d45c /drivers/sh | |
parent | b5272b509a8570bb559156001e74ee162c5cb96a (diff) |
sh: add a reparent function to DIV6 clocks
Add support for reparenting of div6 clocks on SuperH and SH-Mobile SoCs.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/clk-cpg.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/drivers/sh/clk-cpg.c b/drivers/sh/clk-cpg.c index f5c80ba9ab1c..8c024b984ed8 100644 --- a/drivers/sh/clk-cpg.c +++ b/drivers/sh/clk-cpg.c | |||
@@ -68,6 +68,39 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk) | |||
68 | return clk->freq_table[idx].frequency; | 68 | return clk->freq_table[idx].frequency; |
69 | } | 69 | } |
70 | 70 | ||
71 | static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent) | ||
72 | { | ||
73 | struct clk_div_mult_table *table = &sh_clk_div6_table; | ||
74 | u32 value; | ||
75 | int ret, i; | ||
76 | |||
77 | if (!clk->parent_table || !clk->parent_num) | ||
78 | return -EINVAL; | ||
79 | |||
80 | /* Search the parent */ | ||
81 | for (i = 0; i < clk->parent_num; i++) | ||
82 | if (clk->parent_table[i] == parent) | ||
83 | break; | ||
84 | |||
85 | if (i == clk->parent_num) | ||
86 | return -ENODEV; | ||
87 | |||
88 | ret = clk_reparent(clk, parent); | ||
89 | if (ret < 0) | ||
90 | return ret; | ||
91 | |||
92 | value = __raw_readl(clk->enable_reg) & | ||
93 | ~(((1 << clk->src_width) - 1) << clk->src_shift); | ||
94 | |||
95 | __raw_writel(value | (i << clk->src_shift), clk->enable_reg); | ||
96 | |||
97 | /* Rebuild the frequency table */ | ||
98 | clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, | ||
99 | table, &clk->arch_flags); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
71 | static int sh_clk_div6_set_rate(struct clk *clk, | 104 | static int sh_clk_div6_set_rate(struct clk *clk, |
72 | unsigned long rate, int algo_id) | 105 | unsigned long rate, int algo_id) |
73 | { | 106 | { |
@@ -117,7 +150,17 @@ static struct clk_ops sh_clk_div6_clk_ops = { | |||
117 | .disable = sh_clk_div6_disable, | 150 | .disable = sh_clk_div6_disable, |
118 | }; | 151 | }; |
119 | 152 | ||
120 | int __init sh_clk_div6_register(struct clk *clks, int nr) | 153 | static struct clk_ops sh_clk_div6_reparent_clk_ops = { |
154 | .recalc = sh_clk_div6_recalc, | ||
155 | .round_rate = sh_clk_div_round_rate, | ||
156 | .set_rate = sh_clk_div6_set_rate, | ||
157 | .enable = sh_clk_div6_enable, | ||
158 | .disable = sh_clk_div6_disable, | ||
159 | .set_parent = sh_clk_div6_set_parent, | ||
160 | }; | ||
161 | |||
162 | static int __init sh_clk_div6_register_ops(struct clk *clks, int nr, | ||
163 | struct clk_ops *ops) | ||
121 | { | 164 | { |
122 | struct clk *clkp; | 165 | struct clk *clkp; |
123 | void *freq_table; | 166 | void *freq_table; |
@@ -136,7 +179,7 @@ int __init sh_clk_div6_register(struct clk *clks, int nr) | |||
136 | for (k = 0; !ret && (k < nr); k++) { | 179 | for (k = 0; !ret && (k < nr); k++) { |
137 | clkp = clks + k; | 180 | clkp = clks + k; |
138 | 181 | ||
139 | clkp->ops = &sh_clk_div6_clk_ops; | 182 | clkp->ops = ops; |
140 | clkp->id = -1; | 183 | clkp->id = -1; |
141 | clkp->freq_table = freq_table + (k * freq_table_size); | 184 | clkp->freq_table = freq_table + (k * freq_table_size); |
142 | clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; | 185 | clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; |
@@ -147,6 +190,17 @@ int __init sh_clk_div6_register(struct clk *clks, int nr) | |||
147 | return ret; | 190 | return ret; |
148 | } | 191 | } |
149 | 192 | ||
193 | int __init sh_clk_div6_register(struct clk *clks, int nr) | ||
194 | { | ||
195 | return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops); | ||
196 | } | ||
197 | |||
198 | int __init sh_clk_div6_reparent_register(struct clk *clks, int nr) | ||
199 | { | ||
200 | return sh_clk_div6_register_ops(clks, nr, | ||
201 | &sh_clk_div6_reparent_clk_ops); | ||
202 | } | ||
203 | |||
150 | static unsigned long sh_clk_div4_recalc(struct clk *clk) | 204 | static unsigned long sh_clk_div4_recalc(struct clk *clk) |
151 | { | 205 | { |
152 | struct clk_div4_table *d4t = clk->priv; | 206 | struct clk_div4_table *d4t = clk->priv; |