diff options
-rw-r--r-- | arch/sh/include/asm/clock.h | 4 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/clock-cpg.c | 94 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4a/clock-sh7722.c | 25 |
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 | ||
149 | int sh_clk_div4_register(struct clk *clks, int nr, | 149 | int sh_clk_div4_register(struct clk *clks, int nr, |
150 | struct clk_div_mult_table *table); | 150 | struct clk_div_mult_table *table); |
151 | int sh_clk_div4_enable_register(struct clk *clks, int nr, | ||
152 | struct clk_div_mult_table *table); | ||
153 | int 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 | ||
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", |
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 | ||
120 | enum { 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 | ||
123 | enum { DIV4_I, DIV4_U, DIV4_SH, DIV4_B, DIV4_B3, DIV4_P, DIV4_NR }; | ||
124 | |||
126 | struct clk div4_clks[DIV4_NR] = { | 125 | struct 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 | |||
134 | enum { DIV4_IRDA, DIV4_ENABLE_NR }; | ||
135 | |||
136 | struct clk div4_enable_clks[DIV4_ENABLE_NR] = { | ||
137 | [DIV4_IRDA] = DIV4("irda_clk", IRDACLKCR, 0, 0x1fff, 0), | ||
138 | }; | ||
139 | |||
140 | enum { DIV4_SIUA, DIV4_SIUB, DIV4_REPARENT_NR }; | ||
141 | |||
142 | struct 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 | ||
138 | struct clk div6_clks[] = { | 147 | struct 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) |