]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - drivers/sh/clk/cpg.c
a0d8faa40baa87abb07793046c028bddf2c5570a
[~shefty/rdma-dev.git] / drivers / sh / clk / cpg.c
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 = sh_clk_init_parent(clkp);
226                 if (ret < 0)
227                         break;
228
229                 ret = clk_register(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 }