[ARM] S3C: Add set_rate/round_rate methods for pwm-scaler clock
[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 unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
77 {
78         unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
79
80         if (clk->id == 1) {
81                 tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
82                 tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
83         } else {
84                 tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK;
85         }
86
87         return clk_get_rate(clk->parent) / (tcfg0 + 1);
88 }
89
90 static unsigned long clk_pwm_scaler_round_rate(struct clk *clk,
91                                                unsigned long rate)
92 {
93         unsigned long parent_rate = clk_get_rate(clk->parent);
94         unsigned long divisor = parent_rate / rate;
95
96         if (divisor > 256)
97                 divisor = 256;
98         else if (divisor < 2)
99                 divisor = 2;
100
101         return parent_rate / divisor;
102 }
103
104 static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
105 {
106         unsigned long round = clk_pwm_scaler_round_rate(clk, rate);
107         unsigned long tcfg0;
108         unsigned long divisor;
109         unsigned long flags;
110
111         divisor = clk_get_rate(clk->parent) / round;
112         divisor--;
113
114         local_irq_save(flags);
115         tcfg0 = __raw_readl(S3C2410_TCFG0);
116
117         if (clk->id == 1) {
118                 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
119                 tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
120         } else {
121                 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
122                 tcfg0 |= divisor;
123         }
124
125         __raw_writel(tcfg0, S3C2410_TCFG0);
126         local_irq_restore(flags);
127
128         return 0;
129 }
130
131 static struct clk clk_timer_scaler[] = {
132         [0]     = {
133                 .name           = "pwm-scaler0",
134                 .id             = -1,
135                 .get_rate       = clk_pwm_scaler_get_rate,
136                 .set_rate       = clk_pwm_scaler_set_rate,
137                 .round_rate     = clk_pwm_scaler_round_rate,
138         },
139         [1]     = {
140                 .name           = "pwm-scaler1",
141                 .id             = -1,
142                 .get_rate       = clk_pwm_scaler_get_rate,
143                 .set_rate       = clk_pwm_scaler_set_rate,
144                 .round_rate     = clk_pwm_scaler_round_rate,
145         },
146 };
147
148 static struct clk clk_timer_tclk[] = {
149         [0]     = {
150                 .name           = "pwm-tclk0",
151                 .id             = -1,
152         },
153         [1]     = {
154                 .name           = "pwm-tclk1",
155                 .id             = -1,
156         },
157 };
158
159 struct pwm_tdiv_clk {
160         struct clk      clk;
161         unsigned int    divisor;
162 };
163
164 static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
165 {
166         return container_of(clk, struct pwm_tdiv_clk, clk);
167 }
168
169 static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
170 {
171         return 1 << (1 + tcfg1);
172 }
173
174 static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
175 {
176         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
177         unsigned int divisor;
178
179         tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
180         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
181
182         if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
183                 divisor = to_tdiv(clk)->divisor;
184         else
185                 divisor = tcfg_to_divisor(tcfg1);
186
187         return clk_get_rate(clk->parent) / divisor;
188 }
189
190 static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
191                                              unsigned long rate)
192 {
193         unsigned long parent_rate;
194         unsigned long divisor;
195
196         parent_rate = clk_get_rate(clk->parent);
197         divisor = parent_rate / rate;
198
199         if (divisor <= 2)
200                 divisor = 2;
201         else if (divisor <= 4)
202                 divisor = 4;
203         else if (divisor <= 8)
204                 divisor = 8;
205         else
206                 divisor = 16;
207
208         return parent_rate / divisor;
209 }
210
211 static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
212 {
213         unsigned long bits;
214
215         switch (divclk->divisor) {
216         case 2:
217                 bits = S3C2410_TCFG1_MUX_DIV2;
218                 break;
219         case 4:
220                 bits = S3C2410_TCFG1_MUX_DIV4;
221                 break;
222         case 8:
223                 bits = S3C2410_TCFG1_MUX_DIV8;
224                 break;
225         case 16:
226         default:
227                 bits = S3C2410_TCFG1_MUX_DIV16;
228                 break;
229         }
230
231         return bits;
232 }
233
234 static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
235 {
236         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
237         unsigned long bits = clk_pwm_tdiv_bits(divclk);
238         unsigned long flags;
239         unsigned long shift =  S3C2410_TCFG1_SHIFT(divclk->clk.id);
240
241         local_irq_save(flags);
242
243         tcfg1 = __raw_readl(S3C2410_TCFG1);
244         tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
245         tcfg1 |= bits << shift;
246         __raw_writel(tcfg1, S3C2410_TCFG1);
247
248         local_irq_restore(flags);
249 }
250
251 static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
252 {
253         struct pwm_tdiv_clk *divclk = to_tdiv(clk);
254         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
255         unsigned long parent_rate = clk_get_rate(clk->parent);
256         unsigned long divisor;
257
258         tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
259         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
260
261         rate = clk_round_rate(clk, rate);
262         divisor = parent_rate / rate;
263
264         if (divisor > 16)
265                 return -EINVAL;
266
267         divclk->divisor = divisor;
268
269         /* Update the current MUX settings if we are currently
270          * selected as the clock source for this clock. */
271
272         if (tcfg1 != S3C2410_TCFG1_MUX_TCLK)
273                 clk_pwm_tdiv_update(divclk);
274
275         return 0;
276 }
277
278 static struct pwm_tdiv_clk clk_timer_tdiv[] = {
279         [0]     = {
280                 .clk    = {
281                         .name           = "pwm-tdiv",
282                         .parent         = &clk_timer_scaler[0],
283                         .get_rate       = clk_pwm_tdiv_get_rate,
284                         .set_rate       = clk_pwm_tdiv_set_rate,
285                         .round_rate     = clk_pwm_tdiv_round_rate,
286                 },
287         },
288         [1]     = {
289                 .clk    = {
290                         .name           = "pwm-tdiv",
291                         .parent         = &clk_timer_scaler[0],
292                         .get_rate       = clk_pwm_tdiv_get_rate,
293                         .set_rate       = clk_pwm_tdiv_set_rate,
294                         .round_rate     = clk_pwm_tdiv_round_rate,
295                 }
296         },
297         [2]     = {
298                 .clk    = {
299                         .name           = "pwm-tdiv",
300                         .parent         = &clk_timer_scaler[1],
301                         .get_rate       = clk_pwm_tdiv_get_rate,
302                         .set_rate       = clk_pwm_tdiv_set_rate,
303                         .round_rate     = clk_pwm_tdiv_round_rate,
304                 },
305         },
306         [3]     = {
307                 .clk    = {
308                         .name           = "pwm-tdiv",
309                         .parent         = &clk_timer_scaler[1],
310                         .get_rate       = clk_pwm_tdiv_get_rate,
311                         .set_rate       = clk_pwm_tdiv_set_rate,
312                         .round_rate     = clk_pwm_tdiv_round_rate,
313                 },
314         },
315         [4]     = {
316                 .clk    = {
317                         .name           = "pwm-tdiv",
318                         .parent         = &clk_timer_scaler[1],
319                         .get_rate       = clk_pwm_tdiv_get_rate,
320                         .set_rate       = clk_pwm_tdiv_set_rate,
321                         .round_rate     = clk_pwm_tdiv_round_rate,
322                 },
323         },
324 };
325
326 static int __init clk_pwm_tdiv_register(unsigned int id)
327 {
328         struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
329         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
330
331         tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
332         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
333
334         divclk->clk.id = id;
335         divclk->divisor = tcfg_to_divisor(tcfg1);
336
337         return s3c24xx_register_clock(&divclk->clk);
338 }
339
340 static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
341 {
342         return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
343 }
344
345 static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
346 {
347         return &clk_timer_tdiv[id].clk;
348 }
349
350 static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
351 {
352         unsigned int id = clk->id;
353         unsigned long tcfg1;
354         unsigned long flags;
355         unsigned long bits;
356         unsigned long shift = S3C2410_TCFG1_SHIFT(id);
357
358         if (parent == s3c24xx_pwmclk_tclk(id))
359                 bits = S3C2410_TCFG1_MUX_TCLK << shift;
360         else if (parent == s3c24xx_pwmclk_tdiv(id))
361                 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
362         else
363                 return -EINVAL;
364
365         clk->parent = parent;
366
367         local_irq_save(flags);
368
369         tcfg1 = __raw_readl(S3C2410_TCFG1);
370         tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
371         __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
372
373         local_irq_restore(flags);
374
375         return 0;
376 }
377
378 static struct clk clk_tin[] = {
379         [0]     = {
380                 .name           = "pwm-tin",
381                 .id             = 0,
382                 .set_parent     = clk_pwm_tin_set_parent,
383         },
384         [1]     = {
385                 .name           = "pwm-tin",
386                 .id             = 1,
387                 .set_parent     = clk_pwm_tin_set_parent,
388         },
389         [2]     = {
390                 .name           = "pwm-tin",
391                 .id             = 2,
392                 .set_parent     = clk_pwm_tin_set_parent,
393         },
394         [3]     = {
395                 .name           = "pwm-tin",
396                 .id             = 3,
397                 .set_parent     = clk_pwm_tin_set_parent,
398         },
399         [4]     = {
400                 .name           = "pwm-tin",
401                 .id             = 4,
402                 .set_parent     = clk_pwm_tin_set_parent,
403         },
404 };
405
406 static __init int clk_pwm_tin_register(struct clk *pwm)
407 {
408         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
409         unsigned int id = pwm->id;
410
411         struct clk *parent;
412         int ret;
413
414         ret = s3c24xx_register_clock(pwm);
415         if (ret < 0)
416                 return ret;
417
418         tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
419         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
420
421         if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
422                 parent = s3c24xx_pwmclk_tclk(id);
423         else
424                 parent = s3c24xx_pwmclk_tdiv(id);
425
426         return clk_set_parent(pwm, parent);
427 }
428
429 static __init int s3c24xx_pwmclk_init(void)
430 {
431         struct clk *clk_timers;
432         unsigned int clk;
433         int ret;
434
435         clk_timers = clk_get(NULL, "timers");
436         if (IS_ERR(clk_timers)) {
437                 printk(KERN_ERR "%s: no parent clock\n", __func__);
438                 return -EINVAL;
439         }
440
441         for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
442                 clk_timer_scaler[clk].parent = clk_timers;
443                 ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
444                 if (ret < 0) {
445                         printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
446                         goto err;
447                 }
448         }
449
450         for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
451                 ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
452                 if (ret < 0) {
453                         printk(KERN_ERR "error adding pww tclk%d\n", clk);
454                         goto err;
455                 }
456         }
457
458         for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
459                 ret = clk_pwm_tdiv_register(clk);
460                 if (ret < 0) {
461                         printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
462                         goto err;
463                 }
464         }
465
466         for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
467                 ret = clk_pwm_tin_register(&clk_tin[clk]);
468                 if (ret < 0) {
469                         printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
470                         goto err;
471                 }
472         }
473
474         return 0;
475
476  err:
477         return ret;
478 }
479
480 arch_initcall(s3c24xx_pwmclk_init);