aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/sh/clk/cpg.c77
-rw-r--r--include/linux/sh_clk.h6
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
17static unsigned int sh_clk_read(struct clk *clk) 19static 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
127static 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
133static 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
177static 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
191static 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
201static struct sh_clk_ops sh_clk_div6_clk_ops = { 203static 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
209static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = { 211static 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
328static 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
334static void sh_clk_div4_disable(struct clk *clk)
335{
336 sh_clk_write(sh_clk_read(clk) | (1 << 8), clk);
337}
338
339static struct sh_clk_ops sh_clk_div4_clk_ops = { 330static 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
353static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = { 344static 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
193int sh_clk_div6_register(struct clk *clks, int nr); 195int sh_clk_div6_register(struct clk *clks, int nr);