aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorEmilio López <emilio@elopez.com.ar>2013-12-22 22:32:32 -0500
committerEmilio López <emilio@elopez.com.ar>2013-12-28 15:07:42 -0500
commit40a5dcba4e79023f0b511dc0ca498bdf9eacb5db (patch)
treecb8669f36dde36c379ae806f3c54e2e1c0d87efb /drivers/clk
parent0903ea60173fab226a867ceb080b2e0269a6c975 (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>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/sunxi/clk-factors.c63
-rw-r--r--drivers/clk/sunxi/clk-factors.h16
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c70
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
33struct 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
123static const struct clk_ops clk_factors_ops = { 115const 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 */
141struct 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
20struct clk *clk_register_factors(struct device *dev, const char *name, 20struct 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
28extern 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
24static DEFINE_SPINLOCK(clk_lock); 24static 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
264struct factors_data { 269struct 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);