diff options
-rw-r--r-- | drivers/sh/clk/cpg.c | 77 | ||||
-rw-r--r-- | include/linux/sh_clk.h | 6 |
2 files changed, 38 insertions, 45 deletions
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 29ee5f7072a4..06537f2b2fb8 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/sh_clk.h> | 15 | #include <linux/sh_clk.h> |
16 | 16 | ||
17 | #define CPG_CKSTP_BIT BIT(8) | ||
18 | |||
17 | static unsigned int sh_clk_read(struct clk *clk) | 19 | static unsigned int sh_clk_read(struct clk *clk) |
18 | { | 20 | { |
19 | if (clk->flags & CLK_ENABLE_REG_8BIT) | 21 | if (clk->flags & CLK_ENABLE_REG_8BIT) |
@@ -122,6 +124,30 @@ static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate) | |||
122 | return 0; | 124 | return 0; |
123 | } | 125 | } |
124 | 126 | ||
127 | static int sh_clk_div_enable(struct clk *clk) | ||
128 | { | ||
129 | sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static void sh_clk_div_disable(struct clk *clk) | ||
134 | { | ||
135 | unsigned int val; | ||
136 | |||
137 | val = sh_clk_read(clk); | ||
138 | val |= CPG_CKSTP_BIT; | ||
139 | |||
140 | /* | ||
141 | * div6 clocks require the divisor field to be non-zero or the | ||
142 | * above CKSTP toggle silently fails. Ensure that the divisor | ||
143 | * array is reset to its initial state on disable. | ||
144 | */ | ||
145 | if (clk->flags & CLK_MASK_DIV_ON_DISABLE) | ||
146 | val |= clk->div_mask; | ||
147 | |||
148 | sh_clk_write(val, clk); | ||
149 | } | ||
150 | |||
125 | /* | 151 | /* |
126 | * div6 support | 152 | * div6 support |
127 | */ | 153 | */ |
@@ -174,44 +200,20 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent) | |||
174 | return 0; | 200 | return 0; |
175 | } | 201 | } |
176 | 202 | ||
177 | static int sh_clk_div6_enable(struct clk *clk) | ||
178 | { | ||
179 | unsigned long value; | ||
180 | int ret; | ||
181 | |||
182 | ret = sh_clk_div_set_rate(clk, clk->rate); | ||
183 | if (ret == 0) { | ||
184 | value = sh_clk_read(clk); | ||
185 | value &= ~0x100; /* clear stop bit to enable clock */ | ||
186 | sh_clk_write(value, clk); | ||
187 | } | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | static void sh_clk_div6_disable(struct clk *clk) | ||
192 | { | ||
193 | unsigned long value; | ||
194 | |||
195 | value = sh_clk_read(clk); | ||
196 | value |= 0x100; /* stop clock */ | ||
197 | value |= clk->div_mask; /* VDIV bits must be non-zero, overwrite divider */ | ||
198 | sh_clk_write(value, clk); | ||
199 | } | ||
200 | |||
201 | static struct sh_clk_ops sh_clk_div6_clk_ops = { | 203 | static struct sh_clk_ops sh_clk_div6_clk_ops = { |
202 | .recalc = sh_clk_div_recalc, | 204 | .recalc = sh_clk_div_recalc, |
203 | .round_rate = sh_clk_div_round_rate, | 205 | .round_rate = sh_clk_div_round_rate, |
204 | .set_rate = sh_clk_div_set_rate, | 206 | .set_rate = sh_clk_div_set_rate, |
205 | .enable = sh_clk_div6_enable, | 207 | .enable = sh_clk_div_enable, |
206 | .disable = sh_clk_div6_disable, | 208 | .disable = sh_clk_div_disable, |
207 | }; | 209 | }; |
208 | 210 | ||
209 | static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = { | 211 | static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = { |
210 | .recalc = sh_clk_div_recalc, | 212 | .recalc = sh_clk_div_recalc, |
211 | .round_rate = sh_clk_div_round_rate, | 213 | .round_rate = sh_clk_div_round_rate, |
212 | .set_rate = sh_clk_div_set_rate, | 214 | .set_rate = sh_clk_div_set_rate, |
213 | .enable = sh_clk_div6_enable, | 215 | .enable = sh_clk_div_enable, |
214 | .disable = sh_clk_div6_disable, | 216 | .disable = sh_clk_div_disable, |
215 | .set_parent = sh_clk_div6_set_parent, | 217 | .set_parent = sh_clk_div6_set_parent, |
216 | }; | 218 | }; |
217 | 219 | ||
@@ -325,17 +327,6 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent) | |||
325 | return 0; | 327 | return 0; |
326 | } | 328 | } |
327 | 329 | ||
328 | static int sh_clk_div4_enable(struct clk *clk) | ||
329 | { | ||
330 | sh_clk_write(sh_clk_read(clk) & ~(1 << 8), clk); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static void sh_clk_div4_disable(struct clk *clk) | ||
335 | { | ||
336 | sh_clk_write(sh_clk_read(clk) | (1 << 8), clk); | ||
337 | } | ||
338 | |||
339 | static struct sh_clk_ops sh_clk_div4_clk_ops = { | 330 | static struct sh_clk_ops sh_clk_div4_clk_ops = { |
340 | .recalc = sh_clk_div_recalc, | 331 | .recalc = sh_clk_div_recalc, |
341 | .set_rate = sh_clk_div_set_rate, | 332 | .set_rate = sh_clk_div_set_rate, |
@@ -346,16 +337,16 @@ static struct sh_clk_ops sh_clk_div4_enable_clk_ops = { | |||
346 | .recalc = sh_clk_div_recalc, | 337 | .recalc = sh_clk_div_recalc, |
347 | .set_rate = sh_clk_div_set_rate, | 338 | .set_rate = sh_clk_div_set_rate, |
348 | .round_rate = sh_clk_div_round_rate, | 339 | .round_rate = sh_clk_div_round_rate, |
349 | .enable = sh_clk_div4_enable, | 340 | .enable = sh_clk_div_enable, |
350 | .disable = sh_clk_div4_disable, | 341 | .disable = sh_clk_div_disable, |
351 | }; | 342 | }; |
352 | 343 | ||
353 | static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = { | 344 | static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = { |
354 | .recalc = sh_clk_div_recalc, | 345 | .recalc = sh_clk_div_recalc, |
355 | .set_rate = sh_clk_div_set_rate, | 346 | .set_rate = sh_clk_div_set_rate, |
356 | .round_rate = sh_clk_div_round_rate, | 347 | .round_rate = sh_clk_div_round_rate, |
357 | .enable = sh_clk_div4_enable, | 348 | .enable = sh_clk_div_enable, |
358 | .disable = sh_clk_div4_disable, | 349 | .disable = sh_clk_div_disable, |
359 | .set_parent = sh_clk_div4_set_parent, | 350 | .set_parent = sh_clk_div4_set_parent, |
360 | }; | 351 | }; |
361 | 352 | ||
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 35a04f19fb53..50910913b268 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h | |||
@@ -69,6 +69,8 @@ struct clk { | |||
69 | #define CLK_ENABLE_REG_16BIT BIT(2) | 69 | #define CLK_ENABLE_REG_16BIT BIT(2) |
70 | #define CLK_ENABLE_REG_8BIT BIT(3) | 70 | #define CLK_ENABLE_REG_8BIT BIT(3) |
71 | 71 | ||
72 | #define CLK_MASK_DIV_ON_DISABLE BIT(4) | ||
73 | |||
72 | #define CLK_ENABLE_REG_MASK (CLK_ENABLE_REG_32BIT | \ | 74 | #define CLK_ENABLE_REG_MASK (CLK_ENABLE_REG_32BIT | \ |
73 | CLK_ENABLE_REG_16BIT | \ | 75 | CLK_ENABLE_REG_16BIT | \ |
74 | CLK_ENABLE_REG_8BIT) | 76 | CLK_ENABLE_REG_8BIT) |
@@ -173,7 +175,7 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr, | |||
173 | { \ | 175 | { \ |
174 | .enable_reg = (void __iomem *)_reg, \ | 176 | .enable_reg = (void __iomem *)_reg, \ |
175 | .enable_bit = 0, /* unused */ \ | 177 | .enable_bit = 0, /* unused */ \ |
176 | .flags = _flags, \ | 178 | .flags = _flags | CLK_MASK_DIV_ON_DISABLE, \ |
177 | .div_mask = SH_CLK_DIV6_MSK, \ | 179 | .div_mask = SH_CLK_DIV6_MSK, \ |
178 | .parent_table = _parents, \ | 180 | .parent_table = _parents, \ |
179 | .parent_num = _num_parents, \ | 181 | .parent_num = _num_parents, \ |
@@ -187,7 +189,7 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr, | |||
187 | .enable_reg = (void __iomem *)_reg, \ | 189 | .enable_reg = (void __iomem *)_reg, \ |
188 | .enable_bit = 0, /* unused */ \ | 190 | .enable_bit = 0, /* unused */ \ |
189 | .div_mask = SH_CLK_DIV6_MSK, \ | 191 | .div_mask = SH_CLK_DIV6_MSK, \ |
190 | .flags = _flags, \ | 192 | .flags = _flags | CLK_MASK_DIV_ON_DISABLE, \ |
191 | } | 193 | } |
192 | 194 | ||
193 | int sh_clk_div6_register(struct clk *clks, int nr); | 195 | int sh_clk_div6_register(struct clk *clks, int nr); |