xref: /linux/drivers/sh/clk/cpg.c (revision b43ab901d671e3e3cad425ea5e9a3c74e266dcdd)
1 /*
2  * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
3  *
4  *  Copyright (C) 2010  Magnus Damm
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10 #include <linux/clk.h>
11 #include <linux/compiler.h>
12 #include <linux/slab.h>
13 #include <linux/io.h>
14 #include <linux/sh_clk.h>
15 
16 static int sh_clk_mstp32_enable(struct clk *clk)
17 {
18 	iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
19 		  clk->mapped_reg);
20 	return 0;
21 }
22 
23 static void sh_clk_mstp32_disable(struct clk *clk)
24 {
25 	iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
26 		  clk->mapped_reg);
27 }
28 
29 static struct clk_ops sh_clk_mstp32_clk_ops = {
30 	.enable		= sh_clk_mstp32_enable,
31 	.disable	= sh_clk_mstp32_disable,
32 	.recalc		= followparent_recalc,
33 };
34 
35 int __init sh_clk_mstp32_register(struct clk *clks, int nr)
36 {
37 	struct clk *clkp;
38 	int ret = 0;
39 	int k;
40 
41 	for (k = 0; !ret && (k < nr); k++) {
42 		clkp = clks + k;
43 		clkp->ops = &sh_clk_mstp32_clk_ops;
44 		ret |= clk_register(clkp);
45 	}
46 
47 	return ret;
48 }
49 
50 static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
51 {
52 	return clk_rate_table_round(clk, clk->freq_table, rate);
53 }
54 
55 static int sh_clk_div6_divisors[64] = {
56 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
57 	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
58 	33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
59 	49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
60 };
61 
62 static struct clk_div_mult_table sh_clk_div6_table = {
63 	.divisors = sh_clk_div6_divisors,
64 	.nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
65 };
66 
67 static unsigned long sh_clk_div6_recalc(struct clk *clk)
68 {
69 	struct clk_div_mult_table *table = &sh_clk_div6_table;
70 	unsigned int idx;
71 
72 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
73 			     table, NULL);
74 
75 	idx = ioread32(clk->mapped_reg) & 0x003f;
76 
77 	return clk->freq_table[idx].frequency;
78 }
79 
80 static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
81 {
82 	struct clk_div_mult_table *table = &sh_clk_div6_table;
83 	u32 value;
84 	int ret, i;
85 
86 	if (!clk->parent_table || !clk->parent_num)
87 		return -EINVAL;
88 
89 	/* Search the parent */
90 	for (i = 0; i < clk->parent_num; i++)
91 		if (clk->parent_table[i] == parent)
92 			break;
93 
94 	if (i == clk->parent_num)
95 		return -ENODEV;
96 
97 	ret = clk_reparent(clk, parent);
98 	if (ret < 0)
99 		return ret;
100 
101 	value = ioread32(clk->mapped_reg) &
102 		~(((1 << clk->src_width) - 1) << clk->src_shift);
103 
104 	iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
105 
106 	/* Rebuild the frequency table */
107 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
108 			     table, NULL);
109 
110 	return 0;
111 }
112 
113 static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
114 {
115 	unsigned long value;
116 	int idx;
117 
118 	idx = clk_rate_table_find(clk, clk->freq_table, rate);
119 	if (idx < 0)
120 		return idx;
121 
122 	value = ioread32(clk->mapped_reg);
123 	value &= ~0x3f;
124 	value |= idx;
125 	iowrite32(value, clk->mapped_reg);
126 	return 0;
127 }
128 
129 static int sh_clk_div6_enable(struct clk *clk)
130 {
131 	unsigned long value;
132 	int ret;
133 
134 	ret = sh_clk_div6_set_rate(clk, clk->rate);
135 	if (ret == 0) {
136 		value = ioread32(clk->mapped_reg);
137 		value &= ~0x100; /* clear stop bit to enable clock */
138 		iowrite32(value, clk->mapped_reg);
139 	}
140 	return ret;
141 }
142 
143 static void sh_clk_div6_disable(struct clk *clk)
144 {
145 	unsigned long value;
146 
147 	value = ioread32(clk->mapped_reg);
148 	value |= 0x100; /* stop clock */
149 	value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
150 	iowrite32(value, clk->mapped_reg);
151 }
152 
153 static struct clk_ops sh_clk_div6_clk_ops = {
154 	.recalc		= sh_clk_div6_recalc,
155 	.round_rate	= sh_clk_div_round_rate,
156 	.set_rate	= sh_clk_div6_set_rate,
157 	.enable		= sh_clk_div6_enable,
158 	.disable	= sh_clk_div6_disable,
159 };
160 
161 static struct clk_ops sh_clk_div6_reparent_clk_ops = {
162 	.recalc		= sh_clk_div6_recalc,
163 	.round_rate	= sh_clk_div_round_rate,
164 	.set_rate	= sh_clk_div6_set_rate,
165 	.enable		= sh_clk_div6_enable,
166 	.disable	= sh_clk_div6_disable,
167 	.set_parent	= sh_clk_div6_set_parent,
168 };
169 
170 static int __init sh_clk_init_parent(struct clk *clk)
171 {
172 	u32 val;
173 
174 	if (clk->parent)
175 		return 0;
176 
177 	if (!clk->parent_table || !clk->parent_num)
178 		return 0;
179 
180 	if (!clk->src_width) {
181 		pr_err("sh_clk_init_parent: cannot select parent clock\n");
182 		return -EINVAL;
183 	}
184 
185 	val  = (ioread32(clk->mapped_reg) >> clk->src_shift);
186 	val &= (1 << clk->src_width) - 1;
187 
188 	if (val >= clk->parent_num) {
189 		pr_err("sh_clk_init_parent: parent table size failed\n");
190 		return -EINVAL;
191 	}
192 
193 	clk->parent = clk->parent_table[val];
194 	if (!clk->parent) {
195 		pr_err("sh_clk_init_parent: unable to set parent");
196 		return -EINVAL;
197 	}
198 
199 	return 0;
200 }
201 
202 static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
203 					   struct clk_ops *ops)
204 {
205 	struct clk *clkp;
206 	void *freq_table;
207 	int nr_divs = sh_clk_div6_table.nr_divisors;
208 	int freq_table_size = sizeof(struct cpufreq_frequency_table);
209 	int ret = 0;
210 	int k;
211 
212 	freq_table_size *= (nr_divs + 1);
213 	freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
214 	if (!freq_table) {
215 		pr_err("sh_clk_div6_register: unable to alloc memory\n");
216 		return -ENOMEM;
217 	}
218 
219 	for (k = 0; !ret && (k < nr); k++) {
220 		clkp = clks + k;
221 
222 		clkp->ops = ops;
223 		clkp->freq_table = freq_table + (k * freq_table_size);
224 		clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
225 		ret = clk_register(clkp);
226 		if (ret < 0)
227 			break;
228 
229 		ret = sh_clk_init_parent(clkp);
230 	}
231 
232 	return ret;
233 }
234 
235 int __init sh_clk_div6_register(struct clk *clks, int nr)
236 {
237 	return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops);
238 }
239 
240 int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
241 {
242 	return sh_clk_div6_register_ops(clks, nr,
243 					&sh_clk_div6_reparent_clk_ops);
244 }
245 
246 static unsigned long sh_clk_div4_recalc(struct clk *clk)
247 {
248 	struct clk_div4_table *d4t = clk->priv;
249 	struct clk_div_mult_table *table = d4t->div_mult_table;
250 	unsigned int idx;
251 
252 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
253 			     table, &clk->arch_flags);
254 
255 	idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
256 
257 	return clk->freq_table[idx].frequency;
258 }
259 
260 static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
261 {
262 	struct clk_div4_table *d4t = clk->priv;
263 	struct clk_div_mult_table *table = d4t->div_mult_table;
264 	u32 value;
265 	int ret;
266 
267 	/* we really need a better way to determine parent index, but for
268 	 * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
269 	 * no CLK_ENABLE_ON_INIT means external clock...
270 	 */
271 
272 	if (parent->flags & CLK_ENABLE_ON_INIT)
273 		value = ioread32(clk->mapped_reg) & ~(1 << 7);
274 	else
275 		value = ioread32(clk->mapped_reg) | (1 << 7);
276 
277 	ret = clk_reparent(clk, parent);
278 	if (ret < 0)
279 		return ret;
280 
281 	iowrite32(value, clk->mapped_reg);
282 
283 	/* Rebiuld the frequency table */
284 	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
285 			     table, &clk->arch_flags);
286 
287 	return 0;
288 }
289 
290 static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
291 {
292 	struct clk_div4_table *d4t = clk->priv;
293 	unsigned long value;
294 	int idx = clk_rate_table_find(clk, clk->freq_table, rate);
295 	if (idx < 0)
296 		return idx;
297 
298 	value = ioread32(clk->mapped_reg);
299 	value &= ~(0xf << clk->enable_bit);
300 	value |= (idx << clk->enable_bit);
301 	iowrite32(value, clk->mapped_reg);
302 
303 	if (d4t->kick)
304 		d4t->kick(clk);
305 
306 	return 0;
307 }
308 
309 static int sh_clk_div4_enable(struct clk *clk)
310 {
311 	iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
312 	return 0;
313 }
314 
315 static void sh_clk_div4_disable(struct clk *clk)
316 {
317 	iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
318 }
319 
320 static struct clk_ops sh_clk_div4_clk_ops = {
321 	.recalc		= sh_clk_div4_recalc,
322 	.set_rate	= sh_clk_div4_set_rate,
323 	.round_rate	= sh_clk_div_round_rate,
324 };
325 
326 static struct clk_ops sh_clk_div4_enable_clk_ops = {
327 	.recalc		= sh_clk_div4_recalc,
328 	.set_rate	= sh_clk_div4_set_rate,
329 	.round_rate	= sh_clk_div_round_rate,
330 	.enable		= sh_clk_div4_enable,
331 	.disable	= sh_clk_div4_disable,
332 };
333 
334 static struct clk_ops sh_clk_div4_reparent_clk_ops = {
335 	.recalc		= sh_clk_div4_recalc,
336 	.set_rate	= sh_clk_div4_set_rate,
337 	.round_rate	= sh_clk_div_round_rate,
338 	.enable		= sh_clk_div4_enable,
339 	.disable	= sh_clk_div4_disable,
340 	.set_parent	= sh_clk_div4_set_parent,
341 };
342 
343 static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
344 			struct clk_div4_table *table, struct clk_ops *ops)
345 {
346 	struct clk *clkp;
347 	void *freq_table;
348 	int nr_divs = table->div_mult_table->nr_divisors;
349 	int freq_table_size = sizeof(struct cpufreq_frequency_table);
350 	int ret = 0;
351 	int k;
352 
353 	freq_table_size *= (nr_divs + 1);
354 	freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
355 	if (!freq_table) {
356 		pr_err("sh_clk_div4_register: unable to alloc memory\n");
357 		return -ENOMEM;
358 	}
359 
360 	for (k = 0; !ret && (k < nr); k++) {
361 		clkp = clks + k;
362 
363 		clkp->ops = ops;
364 		clkp->priv = table;
365 
366 		clkp->freq_table = freq_table + (k * freq_table_size);
367 		clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
368 
369 		ret = clk_register(clkp);
370 	}
371 
372 	return ret;
373 }
374 
375 int __init sh_clk_div4_register(struct clk *clks, int nr,
376 				struct clk_div4_table *table)
377 {
378 	return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops);
379 }
380 
381 int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
382 				struct clk_div4_table *table)
383 {
384 	return sh_clk_div4_register_ops(clks, nr, table,
385 					&sh_clk_div4_enable_clk_ops);
386 }
387 
388 int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
389 				struct clk_div4_table *table)
390 {
391 	return sh_clk_div4_register_ops(clks, nr, table,
392 					&sh_clk_div4_reparent_clk_ops);
393 }
394