diff options
author | Emilio López <emilio@elopez.com.ar> | 2013-12-22 22:32:32 -0500 |
---|---|---|
committer | Emilio López <emilio@elopez.com.ar> | 2013-12-28 15:07:42 -0500 |
commit | 40a5dcba4e79023f0b511dc0ca498bdf9eacb5db (patch) | |
tree | cb8669f36dde36c379ae806f3c54e2e1c0d87efb | |
parent | 0903ea60173fab226a867ceb080b2e0269a6c975 (diff) |
clk: sunxi: register factors clocks behind composite
This commit reworks factors clock registration to be done behind a
composite clock. This allows us to additionally add a gate, mux or
divisors, as it will be needed by some future PLLs.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | drivers/clk/sunxi/clk-factors.c | 63 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-factors.h | 16 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 70 |
3 files changed, 76 insertions, 73 deletions
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index f05207a27e5f..9e232644f07e 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c | |||
@@ -30,14 +30,6 @@ | |||
30 | * parent - fixed parent. No clk_set_parent support | 30 | * parent - fixed parent. No clk_set_parent support |
31 | */ | 31 | */ |
32 | 32 | ||
33 | struct clk_factors { | ||
34 | struct clk_hw hw; | ||
35 | void __iomem *reg; | ||
36 | struct clk_factors_config *config; | ||
37 | void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); | ||
38 | spinlock_t *lock; | ||
39 | }; | ||
40 | |||
41 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) | 33 | #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) |
42 | 34 | ||
43 | #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) | 35 | #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) |
@@ -120,61 +112,8 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, | |||
120 | return 0; | 112 | return 0; |
121 | } | 113 | } |
122 | 114 | ||
123 | static const struct clk_ops clk_factors_ops = { | 115 | const struct clk_ops clk_factors_ops = { |
124 | .recalc_rate = clk_factors_recalc_rate, | 116 | .recalc_rate = clk_factors_recalc_rate, |
125 | .round_rate = clk_factors_round_rate, | 117 | .round_rate = clk_factors_round_rate, |
126 | .set_rate = clk_factors_set_rate, | 118 | .set_rate = clk_factors_set_rate, |
127 | }; | 119 | }; |
128 | |||
129 | /** | ||
130 | * clk_register_factors - register a factors clock with | ||
131 | * the clock framework | ||
132 | * @dev: device registering this clock | ||
133 | * @name: name of this clock | ||
134 | * @parent_name: name of clock's parent | ||
135 | * @flags: framework-specific flags | ||
136 | * @reg: register address to adjust factors | ||
137 | * @config: shift and width of factors n, k, m and p | ||
138 | * @get_factors: function to calculate the factors for a given frequency | ||
139 | * @lock: shared register lock for this clock | ||
140 | */ | ||
141 | struct clk *clk_register_factors(struct device *dev, const char *name, | ||
142 | const char *parent_name, | ||
143 | unsigned long flags, void __iomem *reg, | ||
144 | struct clk_factors_config *config, | ||
145 | void (*get_factors)(u32 *rate, u32 parent, | ||
146 | u8 *n, u8 *k, u8 *m, u8 *p), | ||
147 | spinlock_t *lock) | ||
148 | { | ||
149 | struct clk_factors *factors; | ||
150 | struct clk *clk; | ||
151 | struct clk_init_data init; | ||
152 | |||
153 | /* allocate the factors */ | ||
154 | factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); | ||
155 | if (!factors) { | ||
156 | pr_err("%s: could not allocate factors clk\n", __func__); | ||
157 | return ERR_PTR(-ENOMEM); | ||
158 | } | ||
159 | |||
160 | init.name = name; | ||
161 | init.ops = &clk_factors_ops; | ||
162 | init.flags = flags; | ||
163 | init.parent_names = (parent_name ? &parent_name : NULL); | ||
164 | init.num_parents = (parent_name ? 1 : 0); | ||
165 | |||
166 | /* struct clk_factors assignments */ | ||
167 | factors->reg = reg; | ||
168 | factors->config = config; | ||
169 | factors->lock = lock; | ||
170 | factors->hw.init = &init; | ||
171 | factors->get_factors = get_factors; | ||
172 | |||
173 | /* register the clock */ | ||
174 | clk = clk_register(dev, &factors->hw); | ||
175 | |||
176 | if (IS_ERR(clk)) | ||
177 | kfree(factors); | ||
178 | |||
179 | return clk; | ||
180 | } | ||
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index f49851cc4380..02e1a43ebac7 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h | |||
@@ -17,11 +17,13 @@ struct clk_factors_config { | |||
17 | u8 pwidth; | 17 | u8 pwidth; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | struct clk *clk_register_factors(struct device *dev, const char *name, | 20 | struct clk_factors { |
21 | const char *parent_name, | 21 | struct clk_hw hw; |
22 | unsigned long flags, void __iomem *reg, | 22 | void __iomem *reg; |
23 | struct clk_factors_config *config, | 23 | struct clk_factors_config *config; |
24 | void (*get_factors) (u32 *rate, u32 parent_rate, | 24 | void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p); |
25 | u8 *n, u8 *k, u8 *m, u8 *p), | 25 | spinlock_t *lock; |
26 | spinlock_t *lock); | 26 | }; |
27 | |||
28 | extern const struct clk_ops clk_factors_ops; | ||
27 | #endif | 29 | #endif |
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 98fec4e4baa7..1c1172d6bdbe 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -23,6 +23,9 @@ | |||
23 | 23 | ||
24 | static DEFINE_SPINLOCK(clk_lock); | 24 | static DEFINE_SPINLOCK(clk_lock); |
25 | 25 | ||
26 | /* Maximum number of parents our clocks have */ | ||
27 | #define SUNXI_MAX_PARENTS 5 | ||
28 | |||
26 | /** | 29 | /** |
27 | * sun4i_osc_clk_setup() - Setup function for gatable oscillator | 30 | * sun4i_osc_clk_setup() - Setup function for gatable oscillator |
28 | */ | 31 | */ |
@@ -261,7 +264,11 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate, | |||
261 | * sunxi_factors_clk_setup() - Setup function for factor clocks | 264 | * sunxi_factors_clk_setup() - Setup function for factor clocks |
262 | */ | 265 | */ |
263 | 266 | ||
267 | #define SUNXI_FACTORS_MUX_MASK 0x3 | ||
268 | |||
264 | struct factors_data { | 269 | struct factors_data { |
270 | int enable; | ||
271 | int mux; | ||
265 | struct clk_factors_config *table; | 272 | struct clk_factors_config *table; |
266 | void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); | 273 | void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); |
267 | }; | 274 | }; |
@@ -312,16 +319,71 @@ static void __init sunxi_factors_clk_setup(struct device_node *node, | |||
312 | struct factors_data *data) | 319 | struct factors_data *data) |
313 | { | 320 | { |
314 | struct clk *clk; | 321 | struct clk *clk; |
322 | struct clk_factors *factors; | ||
323 | struct clk_gate *gate = NULL; | ||
324 | struct clk_mux *mux = NULL; | ||
325 | struct clk_hw *gate_hw = NULL; | ||
326 | struct clk_hw *mux_hw = NULL; | ||
315 | const char *clk_name = node->name; | 327 | const char *clk_name = node->name; |
316 | const char *parent; | 328 | const char *parents[SUNXI_MAX_PARENTS]; |
317 | void *reg; | 329 | void *reg; |
330 | int i = 0; | ||
318 | 331 | ||
319 | reg = of_iomap(node, 0); | 332 | reg = of_iomap(node, 0); |
320 | 333 | ||
321 | parent = of_clk_get_parent_name(node, 0); | 334 | /* if we have a mux, we will have >1 parents */ |
335 | while (i < SUNXI_MAX_PARENTS && | ||
336 | (parents[i] = of_clk_get_parent_name(node, i)) != NULL) | ||
337 | i++; | ||
338 | |||
339 | factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL); | ||
340 | if (!factors) | ||
341 | return; | ||
342 | |||
343 | /* Add a gate if this factor clock can be gated */ | ||
344 | if (data->enable) { | ||
345 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
346 | if (!gate) { | ||
347 | kfree(factors); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | /* set up gate properties */ | ||
352 | gate->reg = reg; | ||
353 | gate->bit_idx = data->enable; | ||
354 | gate->lock = &clk_lock; | ||
355 | gate_hw = &gate->hw; | ||
356 | } | ||
357 | |||
358 | /* Add a mux if this factor clock can be muxed */ | ||
359 | if (data->mux) { | ||
360 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
361 | if (!mux) { | ||
362 | kfree(factors); | ||
363 | kfree(gate); | ||
364 | return; | ||
365 | } | ||
366 | |||
367 | /* set up gate properties */ | ||
368 | mux->reg = reg; | ||
369 | mux->shift = data->mux; | ||
370 | mux->mask = SUNXI_FACTORS_MUX_MASK; | ||
371 | mux->lock = &clk_lock; | ||
372 | mux_hw = &mux->hw; | ||
373 | } | ||
374 | |||
375 | /* set up factors properties */ | ||
376 | factors->reg = reg; | ||
377 | factors->config = data->table; | ||
378 | factors->get_factors = data->getter; | ||
379 | factors->lock = &clk_lock; | ||
322 | 380 | ||
323 | clk = clk_register_factors(NULL, clk_name, parent, 0, reg, | 381 | clk = clk_register_composite(NULL, clk_name, |
324 | data->table, data->getter, &clk_lock); | 382 | parents, i, |
383 | mux_hw, &clk_mux_ops, | ||
384 | &factors->hw, &clk_factors_ops, | ||
385 | gate_hw, &clk_gate_ops, | ||
386 | i ? 0 : CLK_IS_ROOT); | ||
325 | 387 | ||
326 | if (!IS_ERR(clk)) { | 388 | if (!IS_ERR(clk)) { |
327 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 389 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |