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