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 | |
| 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>
| -rw-r--r-- | drivers/sh/clk-cpg.c | 58 | ||||
| -rw-r--r-- | include/linux/sh_clk.h | 19 |
2 files changed, 70 insertions, 7 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; |
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 08a07b9a894f..875ce50719a9 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h | |||
| @@ -142,13 +142,22 @@ int sh_clk_div4_enable_register(struct clk *clks, int nr, | |||
| 142 | int sh_clk_div4_reparent_register(struct clk *clks, int nr, | 142 | int sh_clk_div4_reparent_register(struct clk *clks, int nr, |
| 143 | struct clk_div4_table *table); | 143 | struct clk_div4_table *table); |
| 144 | 144 | ||
| 145 | #define SH_CLK_DIV6(_parent, _reg, _flags) \ | 145 | #define SH_CLK_DIV6_EXT(_parent, _reg, _flags, _parents, \ |
| 146 | { \ | 146 | _num_parents, _src_shift, _src_width) \ |
| 147 | .parent = _parent, \ | 147 | { \ |
| 148 | .enable_reg = (void __iomem *)_reg, \ | 148 | .parent = _parent, \ |
| 149 | .flags = _flags, \ | 149 | .enable_reg = (void __iomem *)_reg, \ |
| 150 | .flags = _flags, \ | ||
| 151 | .parent_table = _parents, \ | ||
| 152 | .parent_num = _num_parents, \ | ||
| 153 | .src_shift = _src_shift, \ | ||
| 154 | .src_width = _src_width, \ | ||
| 150 | } | 155 | } |
| 151 | 156 | ||
| 157 | #define SH_CLK_DIV6(_parent, _reg, _flags) \ | ||
| 158 | SH_CLK_DIV6_EXT(_parent, _reg, _flags, NULL, 0, 0, 0) | ||
| 159 | |||
| 152 | int sh_clk_div6_register(struct clk *clks, int nr); | 160 | int sh_clk_div6_register(struct clk *clks, int nr); |
| 161 | int sh_clk_div6_reparent_register(struct clk *clks, int nr); | ||
| 153 | 162 | ||
| 154 | #endif /* __SH_CLOCK_H */ | 163 | #endif /* __SH_CLOCK_H */ |
