[ARM] S3C: Fix scaler1 clock rate information
[linux-2.6] / arch / arm / plat-s3c / pwm-clock.c
1 /* linux/arch/arm/plat-s3c24xx/pwm-clock.c
2  *
3  * Copyright (c) 2007 Simtec Electronics
4  * Copyright (c) 2007, 2008 Ben Dooks
5  *      Ben Dooks <ben-linux@fluff.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License.
10 */
11
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/list.h>
16 #include <linux/errno.h>
17 #include <linux/clk.h>
18 #include <linux/err.h>
19 #include <linux/io.h>
20
21 #include <mach/hardware.h>
22 #include <asm/irq.h>
23
24 #include <mach/regs-clock.h>
25 #include <mach/regs-gpio.h>
26
27 #include <plat/clock.h>
28 #include <plat/cpu.h>
29
30 #include <plat/regs-timer.h>
31
32 /* Each of the timers 0 through 5 go through the following
33  * clock tree, with the inputs depending on the timers.
34  *
35  * pclk ---- [ prescaler 0 ] -+---> timer 0
36  *                            +---> timer 1
37  *
38  * pclk ---- [ prescaler 1 ] -+---> timer 2
39  *                            +---> timer 3
40  *                            \---> timer 4
41  *
42  * Which are fed into the timers as so:
43  *
44  * prescaled 0 ---- [ div 2,4,8,16 ] ---\
45  *                                     [mux] -> timer 0
46  * tclk 0 ------------------------------/
47  *
48  * prescaled 0 ---- [ div 2,4,8,16 ] ---\
49  *                                     [mux] -> timer 1
50  * tclk 0 ------------------------------/
51  *
52  *
53  * prescaled 1 ---- [ div 2,4,8,16 ] ---\
54  *                                     [mux] -> timer 2
55  * tclk 1 ------------------------------/
56  *
57  * prescaled 1 ---- [ div 2,4,8,16 ] ---\
58  *                                     [mux] -> timer 3
59  * tclk 1 ------------------------------/
60  *
61  * prescaled 1 ---- [ div 2,4,8, 16 ] --\
62  *                                     [mux] -> timer 4
63  * tclk 1 ------------------------------/
64  *
65  * Since the mux and the divider are tied together in the
66  * same register space, it is impossible to set the parent
67  * and the rate at the same time. To avoid this, we add an
68  * intermediate 'prescaled-and-divided' clock to select
69  * as the parent for the timer input clock called tdiv.
70  *
71  * prescaled clk --> pwm-tdiv ---\
72  *                             [ mux ] --> timer X
73  * tclk -------------------------/
74 */
75
76 static struct clk clk_timer_scaler[];
77
78 static unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
79 {
80         unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
81
82         if (clk == &clk_timer_scaler[1]) {
83                 tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
84                 tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
85         } else {
86                 tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK;
87         }
88
89         return clk_get_rate(clk->parent) / (tcfg0 + 1);
90 }
91
92 static unsigned long clk_pwm_scaler_round_rate(struct clk *clk,
93                                                unsigned long rate)
94 {
95         unsigned long parent_rate = clk_get_rate(clk->parent);
96         unsigned long divisor = parent_rate / rate;
97
98         if (divisor > 256)
99                 divisor = 256;
100         else if (divisor < 2)
101                 divisor = 2;
102
103         return parent_rate / divisor;
104 }
105
106 static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
107 {
108         unsigned long round = clk_pwm_scaler_round_rate(clk, rate);
109         unsigned long tcfg0;
110         unsigned long divisor;
111         unsigned long flags;
112
113         divisor = clk_get_rate(clk->parent) / round;
114         divisor--;
115
116         local_irq_save(flags);
117         tcfg0 = __raw_readl(S3C2410_TCFG0);
118
119         if (clk == &clk_timer_scaler[1]) {
120                 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
121                 tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
122         } else {
123                 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
124                 tcfg0 |= divisor;
125         }
126
127         __raw_writel(tcfg0, S3C2410_TCFG0);
128         local_irq_restore(flags);
129
130         return 0;
131 }
132
133 static struct clk clk_timer_scaler[] = {
134         [0]     = {
135                 .name           = "pwm-scaler0",
136                 .id             = -1,
137                 .get_rate       = clk_pwm_scaler_get_rate,
138                 .set_rate       = clk_pwm_scaler_set_rate,
139                 .round_rate     = clk_pwm_scaler_round_rate,
140         },
141         [1]     = {
142                 .name           = "pwm-scaler1",
143                 .id             = -1,
144                 .get_rate       = clk_pwm_scaler_get_rate,
145                 .set_rate       = clk_pwm_scaler_set_rate,
146                 .round_rate     = clk_pwm_scaler_round_rate,
147         },
148 };
149
150 static struct clk clk_timer_tclk[] = {
151         [0]     = {
152                 .name           = "pwm-tclk0",
153                 .id             = -1,
154         },
155         [1]     = {
156                 .name           = "pwm-tclk1",
157                 .id             = -1,
158         },
159 };
160
161 struct pwm_tdiv_clk {
162         struct clk      clk;
163         unsigned int    divisor;
164 };
165
166 static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
167 {
168         return container_of(clk, struct pwm_tdiv_clk, clk);
169 }
170
171 static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
172 {
173         return 1 << (1 + tcfg1);
174 }
175
176 static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
177 {
178         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
179         unsigned int divisor;
180
181         tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
182         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
183
184         if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
185                 divisor = to_tdiv(clk)->divisor;
186         else
187                 divisor = tcfg_to_divisor(tcfg1);
188
189         return clk_get_rate(clk->parent) / divisor;
190 }
191
192 static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
193                                              unsigned long rate)
194 {
195         unsigned long parent_rate;
196         unsigned long divisor;
197
198         parent_rate = clk_get_rate(clk->parent);
199         divisor = parent_rate / rate;
200
201         if (divisor <= 2)
202                 divisor = 2;
203         else if (divisor <= 4)
204                 divisor = 4;
205         else if (divisor <= 8)
206                 divisor = 8;
207         else
208                 divisor = 16;
209
210         return parent_rate / divisor;
211 }
212
213 static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
214 {
215         unsigned long bits;
216
217         switch (divclk->divisor) {
218         case 2:
219                 bits = S3C2410_TCFG1_MUX_DIV2;
220                 break;
221         case 4:
222                 bits = S3C2410_TCFG1_MUX_DIV4;
223                 break;
224         case 8:
225                 bits = S3C2410_TCFG1_MUX_DIV8;
226                 break;
227         case 16:
228         default:
229                 bits = S3C2410_TCFG1_MUX_DIV16;
230                 break;
231         }
232
233         return bits;
234 }
235
236 static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
237 {
238         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
239         unsigned long bits = clk_pwm_tdiv_bits(divclk);
240         unsigned long flags;
241         unsigned long shift =  S3C2410_TCFG1_SHIFT(divclk->clk.id);
242
243         local_irq_save(flags);
244
245         tcfg1 = __raw_readl(S3C2410_TCFG1);
246         tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
247         tcfg1 |= bits << shift;
248         __raw_writel(tcfg1, S3C2410_TCFG1);
249
250         local_irq_restore(flags);
251 }
252
253 static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
254 {
255         struct pwm_tdiv_clk *divclk = to_tdiv(clk);
256         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
257         unsigned long parent_rate = clk_get_rate(clk->parent);
258         unsigned long divisor;
259
260         tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
261         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
262
263         rate = clk_round_rate(clk, rate);
264         divisor = parent_rate / rate;
265
266         if (divisor > 16)
267                 return -EINVAL;
268
269         divclk->divisor = divisor;
270
271         /* Update the current MUX settings if we are currently
272          * selected as the clock source for this clock. */
273
274         if (tcfg1 != S3C2410_TCFG1_MUX_TCLK)
275                 clk_pwm_tdiv_update(divclk);
276
277         return 0;
278 }
279
280 static struct pwm_tdiv_clk clk_timer_tdiv[] = {
281         [0]     = {
282                 .clk    = {
283                         .name           = "pwm-tdiv",
284                         .parent         = &clk_timer_scaler[0],
285                         .get_rate       = clk_pwm_tdiv_get_rate,
286                         .set_rate       = clk_pwm_tdiv_set_rate,
287                         .round_rate     = clk_pwm_tdiv_round_rate,
288                 },
289         },
290         [1]     = {
291                 .clk    = {
292                         .name           = "pwm-tdiv",
293                         .parent         = &clk_timer_scaler[0],
294                         .get_rate       = clk_pwm_tdiv_get_rate,
295                         .set_rate       = clk_pwm_tdiv_set_rate,
296                         .round_rate     = clk_pwm_tdiv_round_rate,
297                 }
298         },
299         [2]     = {
300                 .clk    = {
301                         .name           = "pwm-tdiv",
302                         .parent         = &clk_timer_scaler[1],
303                         .get_rate       = clk_pwm_tdiv_get_rate,
304                         .set_rate       = clk_pwm_tdiv_set_rate,
305                         .round_rate     = clk_pwm_tdiv_round_rate,
306                 },
307         },
308         [3]     = {
309                 .clk    = {
310                         .name           = "pwm-tdiv",
311                         .parent         = &clk_timer_scaler[1],
312                         .get_rate       = clk_pwm_tdiv_get_rate,
313                         .set_rate       = clk_pwm_tdiv_set_rate,
314                         .round_rate     = clk_pwm_tdiv_round_rate,
315                 },
316         },
317         [4]     = {
318                 .clk    = {
319                         .name           = "pwm-tdiv",
320                         .parent         = &clk_timer_scaler[1],
321                         .get_rate       = clk_pwm_tdiv_get_rate,
322                         .set_rate       = clk_pwm_tdiv_set_rate,
323                         .round_rate     = clk_pwm_tdiv_round_rate,
324                 },
325         },
326 };
327
328 static int __init clk_pwm_tdiv_register(unsigned int id)
329 {
330         struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
331         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
332
333         tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
334         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
335
336         divclk->clk.id = id;
337         divclk->divisor = tcfg_to_divisor(tcfg1);
338
339         return s3c24xx_register_clock(&divclk->clk);
340 }
341
342 static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
343 {
344         return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
345 }
346
347 static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
348 {
349         return &clk_timer_tdiv[id].clk;
350 }
351
352 static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
353 {
354         unsigned int id = clk->id;
355         unsigned long tcfg1;
356         unsigned long flags;
357         unsigned long bits;
358         unsigned long shift = S3C2410_TCFG1_SHIFT(id);
359
360         if (parent == s3c24xx_pwmclk_tclk(id))
361                 bits = S3C2410_TCFG1_MUX_TCLK << shift;
362         else if (parent == s3c24xx_pwmclk_tdiv(id))
363                 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
364         else
365                 return -EINVAL;
366
367         clk->parent = parent;
368
369         local_irq_save(flags);
370
371         tcfg1 = __raw_readl(S3C2410_TCFG1);
372         tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
373         __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
374
375         local_irq_restore(flags);
376
377         return 0;
378 }
379
380 static struct clk clk_tin[] = {
381         [0]     = {
382                 .name           = "pwm-tin",
383                 .id             = 0,
384                 .set_parent     = clk_pwm_tin_set_parent,
385         },
386         [1]     = {
387                 .name           = "pwm-tin",
388                 .id             = 1,
389                 .set_parent     = clk_pwm_tin_set_parent,
390         },
391         [2]     = {
392                 .name           = "pwm-tin",
393                 .id             = 2,
394                 .set_parent     = clk_pwm_tin_set_parent,
395         },
396         [3]     = {
397                 .name           = "pwm-tin",
398                 .id             = 3,
399                 .set_parent     = clk_pwm_tin_set_parent,
400         },
401         [4]     = {
402                 .name           = "pwm-tin",
403                 .id             = 4,
404                 .set_parent     = clk_pwm_tin_set_parent,
405         },
406 };
407
408 static __init int clk_pwm_tin_register(struct clk *pwm)
409 {
410         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
411         unsigned int id = pwm->id;
412
413         struct clk *parent;
414         int ret;
415
416         ret = s3c24xx_register_clock(pwm);
417         if (ret < 0)
418                 return ret;
419
420         tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
421         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
422
423         if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
424                 parent = s3c24xx_pwmclk_tclk(id);
425         else
426                 parent = s3c24xx_pwmclk_tdiv(id);
427
428         return clk_set_parent(pwm, parent);
429 }
430
431 static __init int s3c24xx_pwmclk_init(void)
432 {
433         struct clk *clk_timers;
434         unsigned int clk;
435         int ret;
436
437         clk_timers = clk_get(NULL, "timers");
438         if (IS_ERR(clk_timers)) {
439                 printk(KERN_ERR "%s: no parent clock\n", __func__);
440                 return -EINVAL;
441         }
442
443         for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
444                 clk_timer_scaler[clk].parent = clk_timers;
445                 ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
446                 if (ret < 0) {
447                         printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
448                         goto err;
449                 }
450         }
451
452         for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
453                 ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
454                 if (ret < 0) {
455                         printk(KERN_ERR "error adding pww tclk%d\n", clk);
456                         goto err;
457                 }
458         }
459
460         for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
461                 ret = clk_pwm_tdiv_register(clk);
462                 if (ret < 0) {
463                         printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
464                         goto err;
465                 }
466         }
467
468         for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
469                 ret = clk_pwm_tin_register(&clk_tin[clk]);
470                 if (ret < 0) {
471                         printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
472                         goto err;
473                 }
474         }
475
476         return 0;
477
478  err:
479         return ret;
480 }
481
482 arch_initcall(s3c24xx_pwmclk_init);