Merge branch 'topic/cleanup' into for-linus
[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/log2.h>
18 #include <linux/clk.h>
19 #include <linux/err.h>
20 #include <linux/io.h>
21
22 #include <mach/hardware.h>
23 #include <mach/map.h>
24 #include <asm/irq.h>
25
26 #include <plat/clock.h>
27 #include <plat/cpu.h>
28
29 #include <plat/regs-timer.h>
30 #include <mach/pwm-clock.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 unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
172 {
173         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
174         unsigned int divisor;
175
176         tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
177         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
178
179         if (pwm_cfg_src_is_tclk(tcfg1))
180                 divisor = to_tdiv(clk)->divisor;
181         else
182                 divisor = tcfg_to_divisor(tcfg1);
183
184         return clk_get_rate(clk->parent) / divisor;
185 }
186
187 static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
188                                              unsigned long rate)
189 {
190         unsigned long parent_rate;
191         unsigned long divisor;
192
193         parent_rate = clk_get_rate(clk->parent);
194         divisor = parent_rate / rate;
195
196         if (divisor <= 1 && pwm_tdiv_has_div1())
197                 divisor = 1;
198         else if (divisor <= 2)
199                 divisor = 2;
200         else if (divisor <= 4)
201                 divisor = 4;
202         else if (divisor <= 8)
203                 divisor = 8;
204         else
205                 divisor = 16;
206
207         return parent_rate / divisor;
208 }
209
210 static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
211 {
212         return pwm_tdiv_div_bits(divclk->divisor);
213 }
214
215 static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
216 {
217         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
218         unsigned long bits = clk_pwm_tdiv_bits(divclk);
219         unsigned long flags;
220         unsigned long shift =  S3C2410_TCFG1_SHIFT(divclk->clk.id);
221
222         local_irq_save(flags);
223
224         tcfg1 = __raw_readl(S3C2410_TCFG1);
225         tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
226         tcfg1 |= bits << shift;
227         __raw_writel(tcfg1, S3C2410_TCFG1);
228
229         local_irq_restore(flags);
230 }
231
232 static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
233 {
234         struct pwm_tdiv_clk *divclk = to_tdiv(clk);
235         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
236         unsigned long parent_rate = clk_get_rate(clk->parent);
237         unsigned long divisor;
238
239         tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
240         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
241
242         rate = clk_round_rate(clk, rate);
243         divisor = parent_rate / rate;
244
245         if (divisor > 16)
246                 return -EINVAL;
247
248         divclk->divisor = divisor;
249
250         /* Update the current MUX settings if we are currently
251          * selected as the clock source for this clock. */
252
253         if (!pwm_cfg_src_is_tclk(tcfg1))
254                 clk_pwm_tdiv_update(divclk);
255
256         return 0;
257 }
258
259 static struct pwm_tdiv_clk clk_timer_tdiv[] = {
260         [0]     = {
261                 .clk    = {
262                         .name           = "pwm-tdiv",
263                         .parent         = &clk_timer_scaler[0],
264                         .get_rate       = clk_pwm_tdiv_get_rate,
265                         .set_rate       = clk_pwm_tdiv_set_rate,
266                         .round_rate     = clk_pwm_tdiv_round_rate,
267                 },
268         },
269         [1]     = {
270                 .clk    = {
271                         .name           = "pwm-tdiv",
272                         .parent         = &clk_timer_scaler[0],
273                         .get_rate       = clk_pwm_tdiv_get_rate,
274                         .set_rate       = clk_pwm_tdiv_set_rate,
275                         .round_rate     = clk_pwm_tdiv_round_rate,
276                 }
277         },
278         [2]     = {
279                 .clk    = {
280                         .name           = "pwm-tdiv",
281                         .parent         = &clk_timer_scaler[1],
282                         .get_rate       = clk_pwm_tdiv_get_rate,
283                         .set_rate       = clk_pwm_tdiv_set_rate,
284                         .round_rate     = clk_pwm_tdiv_round_rate,
285                 },
286         },
287         [3]     = {
288                 .clk    = {
289                         .name           = "pwm-tdiv",
290                         .parent         = &clk_timer_scaler[1],
291                         .get_rate       = clk_pwm_tdiv_get_rate,
292                         .set_rate       = clk_pwm_tdiv_set_rate,
293                         .round_rate     = clk_pwm_tdiv_round_rate,
294                 },
295         },
296         [4]     = {
297                 .clk    = {
298                         .name           = "pwm-tdiv",
299                         .parent         = &clk_timer_scaler[1],
300                         .get_rate       = clk_pwm_tdiv_get_rate,
301                         .set_rate       = clk_pwm_tdiv_set_rate,
302                         .round_rate     = clk_pwm_tdiv_round_rate,
303                 },
304         },
305 };
306
307 static int __init clk_pwm_tdiv_register(unsigned int id)
308 {
309         struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
310         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
311
312         tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
313         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
314
315         divclk->clk.id = id;
316         divclk->divisor = tcfg_to_divisor(tcfg1);
317
318         return s3c24xx_register_clock(&divclk->clk);
319 }
320
321 static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
322 {
323         return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
324 }
325
326 static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
327 {
328         return &clk_timer_tdiv[id].clk;
329 }
330
331 static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
332 {
333         unsigned int id = clk->id;
334         unsigned long tcfg1;
335         unsigned long flags;
336         unsigned long bits;
337         unsigned long shift = S3C2410_TCFG1_SHIFT(id);
338
339         if (parent == s3c24xx_pwmclk_tclk(id))
340                 bits = S3C_TCFG1_MUX_TCLK << shift;
341         else if (parent == s3c24xx_pwmclk_tdiv(id))
342                 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
343         else
344                 return -EINVAL;
345
346         clk->parent = parent;
347
348         local_irq_save(flags);
349
350         tcfg1 = __raw_readl(S3C2410_TCFG1);
351         tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
352         __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
353
354         local_irq_restore(flags);
355
356         return 0;
357 }
358
359 static struct clk clk_tin[] = {
360         [0]     = {
361                 .name           = "pwm-tin",
362                 .id             = 0,
363                 .set_parent     = clk_pwm_tin_set_parent,
364         },
365         [1]     = {
366                 .name           = "pwm-tin",
367                 .id             = 1,
368                 .set_parent     = clk_pwm_tin_set_parent,
369         },
370         [2]     = {
371                 .name           = "pwm-tin",
372                 .id             = 2,
373                 .set_parent     = clk_pwm_tin_set_parent,
374         },
375         [3]     = {
376                 .name           = "pwm-tin",
377                 .id             = 3,
378                 .set_parent     = clk_pwm_tin_set_parent,
379         },
380         [4]     = {
381                 .name           = "pwm-tin",
382                 .id             = 4,
383                 .set_parent     = clk_pwm_tin_set_parent,
384         },
385 };
386
387 static __init int clk_pwm_tin_register(struct clk *pwm)
388 {
389         unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
390         unsigned int id = pwm->id;
391
392         struct clk *parent;
393         int ret;
394
395         ret = s3c24xx_register_clock(pwm);
396         if (ret < 0)
397                 return ret;
398
399         tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
400         tcfg1 &= S3C2410_TCFG1_MUX_MASK;
401
402         if (pwm_cfg_src_is_tclk(tcfg1))
403                 parent = s3c24xx_pwmclk_tclk(id);
404         else
405                 parent = s3c24xx_pwmclk_tdiv(id);
406
407         return clk_set_parent(pwm, parent);
408 }
409
410 /**
411  * s3c_pwmclk_init() - initialise pwm clocks
412  *
413  * Initialise and register the clocks which provide the inputs for the
414  * pwm timer blocks.
415  *
416  * Note, this call is required by the time core, so must be called after
417  * the base clocks are added and before any of the initcalls are run.
418  */
419 __init void s3c_pwmclk_init(void)
420 {
421         struct clk *clk_timers;
422         unsigned int clk;
423         int ret;
424
425         clk_timers = clk_get(NULL, "timers");
426         if (IS_ERR(clk_timers)) {
427                 printk(KERN_ERR "%s: no parent clock\n", __func__);
428                 return;
429         }
430
431         for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
432                 clk_timer_scaler[clk].parent = clk_timers;
433                 ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
434                 if (ret < 0) {
435                         printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
436                         return;
437                 }
438         }
439
440         for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
441                 ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
442                 if (ret < 0) {
443                         printk(KERN_ERR "error adding pww tclk%d\n", clk);
444                         return;
445                 }
446         }
447
448         for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
449                 ret = clk_pwm_tdiv_register(clk);
450                 if (ret < 0) {
451                         printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
452                         return;
453                 }
454         }
455
456         for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
457                 ret = clk_pwm_tin_register(&clk_tin[clk]);
458                 if (ret < 0) {
459                         printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
460                         return;
461                 }
462         }
463 }