xref: /openbmc/linux/drivers/sh/clk/cpg.c (revision 1c2f87c2)
1 /*
2  * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
3  *
4  *  Copyright (C) 2010  Magnus Damm
5  *  Copyright (C) 2010 - 2012  Paul Mundt
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11 #include <linux/clk.h>
12 #include <linux/compiler.h>
13 #include <linux/slab.h>
14 #include <linux/io.h>
15 #include <linux/sh_clk.h>
16 
17 #define CPG_CKSTP_BIT	BIT(8)
18 
19 static unsigned int sh_clk_read(struct clk *clk)
20 {
21 	if (clk->flags & CLK_ENABLE_REG_8BIT)
22 		return ioread8(clk->mapped_reg);
23 	else if (clk->flags & CLK_ENABLE_REG_16BIT)
24 		return ioread16(clk->mapped_reg);
25 
26 	return ioread32(clk->mapped_reg);
27 }
28 
29 static void sh_clk_write(int value, struct clk *clk)
30 {
31 	if (clk->flags & CLK_ENABLE_REG_8BIT)
32 		iowrite8(value, clk->mapped_reg);
33 	else if (clk->flags & CLK_ENABLE_REG_16BIT)
34 		iowrite16(value, clk->mapped_reg);
35 	else
36 		iowrite32(value, clk->mapped_reg);
37 }
38 
39 static unsigned int r8(const void __iomem *addr)
40 {
41 	return ioread8(addr);
42 }
43 
44 static unsigned int r16(const void __iomem *addr)
45 {
46 	return ioread16(addr);
47 }
48 
49 static unsigned int r32(const void __iomem *addr)
50 {
51 	return ioread32(addr);
52 }
53 
54 static int sh_clk_mstp_enable(struct clk *clk)
55 {
56 	sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
57 	if (clk->status_reg) {
58 		unsigned int (*read)(const void __iomem *addr);
59 		int i;
60 		void __iomem *mapped_status = (phys_addr_t)clk->status_reg -
61 			(phys_addr_t)clk->enable_reg + clk->mapped_reg;
62 
63 		if (clk->flags & CLK_ENABLE_REG_8BIT)
64 			read = r8;
65 		else if (clk->flags & CLK_ENABLE_REG_16BIT)
66 			read = r16;
67 		else
68 			read = r32;
69 
70 		for (i = 1000;
71 		     (read(mapped_status) & (1 << clk->enable_bit)) && i;
72 		     i--)
73 			cpu_relax();
74 		if (!i) {
75 			pr_err("cpg: failed to enable %p[%d]\n",
76 			       clk->enable_reg, clk->enable_bit);
77 			return -ETIMEDOUT;
78 		}
79 	}
80 	return 0;
81 }
82 
83 static void sh_clk_mstp_disable(struct clk *clk)
84 {
85 	sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
86 }
87 
88 static struct sh_clk_ops sh_clk_mstp_clk_ops = {
89 	.enable		= sh_clk_mstp_enable,
90 	.disable	= sh_clk_mstp_disable,
91 	.recalc		= followparent_recalc,
92 };
93 
94 int __init sh_clk_mstp_register(struct clk *clks, int nr)
95 {
96 	struct clk *clkp;
97 	int ret = 0;
98 	int k;
99 
100 	for (k = 0; !ret && (k < nr); k++) {
101 		clkp = clks + k;
102 		clkp->ops = &sh_clk_mstp_clk_ops;
103 		ret |= clk_register(clkp);
104 	}
105 
106 	return ret;
107 }
108 
109 /*
110  * Div/mult table lookup helpers
111  */
112 static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
113 {
114 	return clk->priv;
115 }
116 
117 static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
118 {
119 	return clk_to_div_table(clk)->div_mult_table;
120 }
121 
122 /*
123  * Common div ops
124  */
125 static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
126 {
127 	return clk_rate_table_round(clk, clk->freq_table, rate);
128 }
129 
130 static unsigned long sh_clk_div_recalc(struct clk *clk)
131 {
132 	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
133 	unsigned int idx;
134 
135 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
136 			     table, clk->arch_flags ? &clk->arch_flags : NULL);
137 
138 	idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask;
139 
140 	return clk->freq_table[idx].frequency;
141 }
142 
143 static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
144 {
145 	struct clk_div_table *dt = clk_to_div_table(clk);
146 	unsigned long value;
147 	int idx;
148 
149 	idx = clk_rate_table_find(clk, clk->freq_table, rate);
150 	if (idx < 0)
151 		return idx;
152 
153 	value = sh_clk_read(clk);
154 	value &= ~(clk->div_mask << clk->enable_bit);
155 	value |= (idx << clk->enable_bit);
156 	sh_clk_write(value, clk);
157 
158 	/* XXX: Should use a post-change notifier */
159 	if (dt->kick)
160 		dt->kick(clk);
161 
162 	return 0;
163 }
164 
165 static int sh_clk_div_enable(struct clk *clk)
166 {
167 	if (clk->div_mask == SH_CLK_DIV6_MSK) {
168 		int ret = sh_clk_div_set_rate(clk, clk->rate);
169 		if (ret < 0)
170 			return ret;
171 	}
172 
173 	sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk);
174 	return 0;
175 }
176 
177 static void sh_clk_div_disable(struct clk *clk)
178 {
179 	unsigned int val;
180 
181 	val = sh_clk_read(clk);
182 	val |= CPG_CKSTP_BIT;
183 
184 	/*
185 	 * div6 clocks require the divisor field to be non-zero or the
186 	 * above CKSTP toggle silently fails. Ensure that the divisor
187 	 * array is reset to its initial state on disable.
188 	 */
189 	if (clk->flags & CLK_MASK_DIV_ON_DISABLE)
190 		val |= clk->div_mask;
191 
192 	sh_clk_write(val, clk);
193 }
194 
195 static struct sh_clk_ops sh_clk_div_clk_ops = {
196 	.recalc		= sh_clk_div_recalc,
197 	.set_rate	= sh_clk_div_set_rate,
198 	.round_rate	= sh_clk_div_round_rate,
199 };
200 
201 static struct sh_clk_ops sh_clk_div_enable_clk_ops = {
202 	.recalc		= sh_clk_div_recalc,
203 	.set_rate	= sh_clk_div_set_rate,
204 	.round_rate	= sh_clk_div_round_rate,
205 	.enable		= sh_clk_div_enable,
206 	.disable	= sh_clk_div_disable,
207 };
208 
209 static int __init sh_clk_init_parent(struct clk *clk)
210 {
211 	u32 val;
212 
213 	if (clk->parent)
214 		return 0;
215 
216 	if (!clk->parent_table || !clk->parent_num)
217 		return 0;
218 
219 	if (!clk->src_width) {
220 		pr_err("sh_clk_init_parent: cannot select parent clock\n");
221 		return -EINVAL;
222 	}
223 
224 	val  = (sh_clk_read(clk) >> clk->src_shift);
225 	val &= (1 << clk->src_width) - 1;
226 
227 	if (val >= clk->parent_num) {
228 		pr_err("sh_clk_init_parent: parent table size failed\n");
229 		return -EINVAL;
230 	}
231 
232 	clk_reparent(clk, clk->parent_table[val]);
233 	if (!clk->parent) {
234 		pr_err("sh_clk_init_parent: unable to set parent");
235 		return -EINVAL;
236 	}
237 
238 	return 0;
239 }
240 
241 static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
242 			struct clk_div_table *table, struct sh_clk_ops *ops)
243 {
244 	struct clk *clkp;
245 	void *freq_table;
246 	int nr_divs = table->div_mult_table->nr_divisors;
247 	int freq_table_size = sizeof(struct cpufreq_frequency_table);
248 	int ret = 0;
249 	int k;
250 
251 	freq_table_size *= (nr_divs + 1);
252 	freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
253 	if (!freq_table) {
254 		pr_err("%s: unable to alloc memory\n", __func__);
255 		return -ENOMEM;
256 	}
257 
258 	for (k = 0; !ret && (k < nr); k++) {
259 		clkp = clks + k;
260 
261 		clkp->ops = ops;
262 		clkp->priv = table;
263 
264 		clkp->freq_table = freq_table + (k * freq_table_size);
265 		clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
266 
267 		ret = clk_register(clkp);
268 		if (ret == 0)
269 			ret = sh_clk_init_parent(clkp);
270 	}
271 
272 	return ret;
273 }
274 
275 /*
276  * div6 support
277  */
278 static int sh_clk_div6_divisors[64] = {
279 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
280 	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
281 	33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
282 	49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
283 };
284 
285 static struct clk_div_mult_table div6_div_mult_table = {
286 	.divisors = sh_clk_div6_divisors,
287 	.nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
288 };
289 
290 static struct clk_div_table sh_clk_div6_table = {
291 	.div_mult_table	= &div6_div_mult_table,
292 };
293 
294 static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
295 {
296 	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
297 	u32 value;
298 	int ret, i;
299 
300 	if (!clk->parent_table || !clk->parent_num)
301 		return -EINVAL;
302 
303 	/* Search the parent */
304 	for (i = 0; i < clk->parent_num; i++)
305 		if (clk->parent_table[i] == parent)
306 			break;
307 
308 	if (i == clk->parent_num)
309 		return -ENODEV;
310 
311 	ret = clk_reparent(clk, parent);
312 	if (ret < 0)
313 		return ret;
314 
315 	value = sh_clk_read(clk) &
316 		~(((1 << clk->src_width) - 1) << clk->src_shift);
317 
318 	sh_clk_write(value | (i << clk->src_shift), clk);
319 
320 	/* Rebuild the frequency table */
321 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
322 			     table, NULL);
323 
324 	return 0;
325 }
326 
327 static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
328 	.recalc		= sh_clk_div_recalc,
329 	.round_rate	= sh_clk_div_round_rate,
330 	.set_rate	= sh_clk_div_set_rate,
331 	.enable		= sh_clk_div_enable,
332 	.disable	= sh_clk_div_disable,
333 	.set_parent	= sh_clk_div6_set_parent,
334 };
335 
336 int __init sh_clk_div6_register(struct clk *clks, int nr)
337 {
338 	return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
339 				       &sh_clk_div_enable_clk_ops);
340 }
341 
342 int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
343 {
344 	return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
345 				       &sh_clk_div6_reparent_clk_ops);
346 }
347 
348 /*
349  * div4 support
350  */
351 static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
352 {
353 	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
354 	u32 value;
355 	int ret;
356 
357 	/* we really need a better way to determine parent index, but for
358 	 * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
359 	 * no CLK_ENABLE_ON_INIT means external clock...
360 	 */
361 
362 	if (parent->flags & CLK_ENABLE_ON_INIT)
363 		value = sh_clk_read(clk) & ~(1 << 7);
364 	else
365 		value = sh_clk_read(clk) | (1 << 7);
366 
367 	ret = clk_reparent(clk, parent);
368 	if (ret < 0)
369 		return ret;
370 
371 	sh_clk_write(value, clk);
372 
373 	/* Rebiuld the frequency table */
374 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
375 			     table, &clk->arch_flags);
376 
377 	return 0;
378 }
379 
380 static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
381 	.recalc		= sh_clk_div_recalc,
382 	.set_rate	= sh_clk_div_set_rate,
383 	.round_rate	= sh_clk_div_round_rate,
384 	.enable		= sh_clk_div_enable,
385 	.disable	= sh_clk_div_disable,
386 	.set_parent	= sh_clk_div4_set_parent,
387 };
388 
389 int __init sh_clk_div4_register(struct clk *clks, int nr,
390 				struct clk_div4_table *table)
391 {
392 	return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops);
393 }
394 
395 int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
396 				struct clk_div4_table *table)
397 {
398 	return sh_clk_div_register_ops(clks, nr, table,
399 				       &sh_clk_div_enable_clk_ops);
400 }
401 
402 int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
403 				struct clk_div4_table *table)
404 {
405 	return sh_clk_div_register_ops(clks, nr, table,
406 				       &sh_clk_div4_reparent_clk_ops);
407 }
408 
409 /* FSI-DIV */
410 static unsigned long fsidiv_recalc(struct clk *clk)
411 {
412 	u32 value;
413 
414 	value = __raw_readl(clk->mapping->base);
415 
416 	value >>= 16;
417 	if (value < 2)
418 		return clk->parent->rate;
419 
420 	return clk->parent->rate / value;
421 }
422 
423 static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
424 {
425 	return clk_rate_div_range_round(clk, 1, 0xffff, rate);
426 }
427 
428 static void fsidiv_disable(struct clk *clk)
429 {
430 	__raw_writel(0, clk->mapping->base);
431 }
432 
433 static int fsidiv_enable(struct clk *clk)
434 {
435 	u32 value;
436 
437 	value  = __raw_readl(clk->mapping->base) >> 16;
438 	if (value < 2)
439 		return 0;
440 
441 	__raw_writel((value << 16) | 0x3, clk->mapping->base);
442 
443 	return 0;
444 }
445 
446 static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
447 {
448 	int idx;
449 
450 	idx = (clk->parent->rate / rate) & 0xffff;
451 	if (idx < 2)
452 		__raw_writel(0, clk->mapping->base);
453 	else
454 		__raw_writel(idx << 16, clk->mapping->base);
455 
456 	return 0;
457 }
458 
459 static struct sh_clk_ops fsidiv_clk_ops = {
460 	.recalc		= fsidiv_recalc,
461 	.round_rate	= fsidiv_round_rate,
462 	.set_rate	= fsidiv_set_rate,
463 	.enable		= fsidiv_enable,
464 	.disable	= fsidiv_disable,
465 };
466 
467 int __init sh_clk_fsidiv_register(struct clk *clks, int nr)
468 {
469 	struct clk_mapping *map;
470 	int i;
471 
472 	for (i = 0; i < nr; i++) {
473 
474 		map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL);
475 		if (!map) {
476 			pr_err("%s: unable to alloc memory\n", __func__);
477 			return -ENOMEM;
478 		}
479 
480 		/* clks[i].enable_reg came from SH_CLK_FSIDIV() */
481 		map->phys		= (phys_addr_t)clks[i].enable_reg;
482 		map->len		= 8;
483 
484 		clks[i].enable_reg	= 0; /* remove .enable_reg */
485 		clks[i].ops		= &fsidiv_clk_ops;
486 		clks[i].mapping		= map;
487 
488 		clk_register(&clks[i]);
489 	}
490 
491 	return 0;
492 }
493