Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pwm-clock.c
Go to the documentation of this file.
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 <[email protected]>
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 <plat/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]) {
85  } else {
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]) {
121  tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
122  } else {
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_ops clk_pwm_scaler_ops = {
134  .get_rate = clk_pwm_scaler_get_rate,
135  .set_rate = clk_pwm_scaler_set_rate,
136  .round_rate = clk_pwm_scaler_round_rate,
137 };
138 
139 static struct clk clk_timer_scaler[] = {
140  [0] = {
141  .name = "pwm-scaler0",
142  .id = -1,
143  .ops = &clk_pwm_scaler_ops,
144  },
145  [1] = {
146  .name = "pwm-scaler1",
147  .id = -1,
148  .ops = &clk_pwm_scaler_ops,
149  },
150 };
151 
152 static struct clk clk_timer_tclk[] = {
153  [0] = {
154  .name = "pwm-tclk0",
155  .id = -1,
156  },
157  [1] = {
158  .name = "pwm-tclk1",
159  .id = -1,
160  },
161 };
162 
163 struct pwm_tdiv_clk {
164  struct clk clk;
165  unsigned int divisor;
166 };
167 
168 static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
169 {
170  return container_of(clk, struct pwm_tdiv_clk, clk);
171 }
172 
173 static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
174 {
175  unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
176  unsigned int divisor;
177 
178  tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
179  tcfg1 &= S3C2410_TCFG1_MUX_MASK;
180 
181  if (pwm_cfg_src_is_tclk(tcfg1))
182  divisor = to_tdiv(clk)->divisor;
183  else
184  divisor = tcfg_to_divisor(tcfg1);
185 
186  return clk_get_rate(clk->parent) / divisor;
187 }
188 
189 static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
190  unsigned long rate)
191 {
192  unsigned long parent_rate;
193  unsigned long divisor;
194 
195  parent_rate = clk_get_rate(clk->parent);
196  divisor = parent_rate / rate;
197 
198  if (divisor <= 1 && pwm_tdiv_has_div1())
199  divisor = 1;
200  else if (divisor <= 2)
201  divisor = 2;
202  else if (divisor <= 4)
203  divisor = 4;
204  else if (divisor <= 8)
205  divisor = 8;
206  else
207  divisor = 16;
208 
209  return parent_rate / divisor;
210 }
211 
212 static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
213 {
214  return pwm_tdiv_div_bits(divclk->divisor);
215 }
216 
217 static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
218 {
219  unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
220  unsigned long bits = clk_pwm_tdiv_bits(divclk);
221  unsigned long flags;
222  unsigned long shift = S3C2410_TCFG1_SHIFT(divclk->clk.id);
223 
224  local_irq_save(flags);
225 
226  tcfg1 = __raw_readl(S3C2410_TCFG1);
227  tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
228  tcfg1 |= bits << shift;
229  __raw_writel(tcfg1, S3C2410_TCFG1);
230 
231  local_irq_restore(flags);
232 }
233 
234 static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
235 {
236  struct pwm_tdiv_clk *divclk = to_tdiv(clk);
237  unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
238  unsigned long parent_rate = clk_get_rate(clk->parent);
239  unsigned long divisor;
240 
241  tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
242  tcfg1 &= S3C2410_TCFG1_MUX_MASK;
243 
244  rate = clk_round_rate(clk, rate);
245  divisor = parent_rate / rate;
246 
247  if (divisor > 16)
248  return -EINVAL;
249 
250  divclk->divisor = divisor;
251 
252  /* Update the current MUX settings if we are currently
253  * selected as the clock source for this clock. */
254 
255  if (!pwm_cfg_src_is_tclk(tcfg1))
256  clk_pwm_tdiv_update(divclk);
257 
258  return 0;
259 }
260 
261 static struct clk_ops clk_tdiv_ops = {
262  .get_rate = clk_pwm_tdiv_get_rate,
263  .set_rate = clk_pwm_tdiv_set_rate,
264  .round_rate = clk_pwm_tdiv_round_rate,
265 };
266 
267 static struct pwm_tdiv_clk clk_timer_tdiv[] = {
268  [0] = {
269  .clk = {
270  .name = "pwm-tdiv",
271  .devname = "s3c24xx-pwm.0",
272  .ops = &clk_tdiv_ops,
273  .parent = &clk_timer_scaler[0],
274  },
275  },
276  [1] = {
277  .clk = {
278  .name = "pwm-tdiv",
279  .devname = "s3c24xx-pwm.1",
280  .ops = &clk_tdiv_ops,
281  .parent = &clk_timer_scaler[0],
282  }
283  },
284  [2] = {
285  .clk = {
286  .name = "pwm-tdiv",
287  .devname = "s3c24xx-pwm.2",
288  .ops = &clk_tdiv_ops,
289  .parent = &clk_timer_scaler[1],
290  },
291  },
292  [3] = {
293  .clk = {
294  .name = "pwm-tdiv",
295  .devname = "s3c24xx-pwm.3",
296  .ops = &clk_tdiv_ops,
297  .parent = &clk_timer_scaler[1],
298  },
299  },
300  [4] = {
301  .clk = {
302  .name = "pwm-tdiv",
303  .devname = "s3c24xx-pwm.4",
304  .ops = &clk_tdiv_ops,
305  .parent = &clk_timer_scaler[1],
306  },
307  },
308 };
309 
310 static int __init clk_pwm_tdiv_register(unsigned int id)
311 {
312  struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
313  unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
314 
315  tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
316  tcfg1 &= S3C2410_TCFG1_MUX_MASK;
317 
318  divclk->clk.id = id;
319  divclk->divisor = tcfg_to_divisor(tcfg1);
320 
321  return s3c24xx_register_clock(&divclk->clk);
322 }
323 
324 static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
325 {
326  return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
327 }
328 
329 static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
330 {
331  return &clk_timer_tdiv[id].clk;
332 }
333 
334 static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
335 {
336  unsigned int id = clk->id;
337  unsigned long tcfg1;
338  unsigned long flags;
339  unsigned long bits;
340  unsigned long shift = S3C2410_TCFG1_SHIFT(id);
341 
342  unsigned long mux_tclk;
343 
344  if (soc_is_s3c24xx())
345  mux_tclk = S3C2410_TCFG1_MUX_TCLK;
346  else if (soc_is_s5p6440() || soc_is_s5p6450())
347  mux_tclk = 0;
348  else
349  mux_tclk = S3C64XX_TCFG1_MUX_TCLK;
350 
351  if (parent == s3c24xx_pwmclk_tclk(id))
352  bits = mux_tclk << shift;
353  else if (parent == s3c24xx_pwmclk_tdiv(id))
354  bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
355  else
356  return -EINVAL;
357 
358  clk->parent = parent;
359 
360  local_irq_save(flags);
361 
362  tcfg1 = __raw_readl(S3C2410_TCFG1);
363  tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
364  __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
365 
366  local_irq_restore(flags);
367 
368  return 0;
369 }
370 
371 static struct clk_ops clk_tin_ops = {
372  .set_parent = clk_pwm_tin_set_parent,
373 };
374 
375 static struct clk clk_tin[] = {
376  [0] = {
377  .name = "pwm-tin",
378  .devname = "s3c24xx-pwm.0",
379  .id = 0,
380  .ops = &clk_tin_ops,
381  },
382  [1] = {
383  .name = "pwm-tin",
384  .devname = "s3c24xx-pwm.1",
385  .id = 1,
386  .ops = &clk_tin_ops,
387  },
388  [2] = {
389  .name = "pwm-tin",
390  .devname = "s3c24xx-pwm.2",
391  .id = 2,
392  .ops = &clk_tin_ops,
393  },
394  [3] = {
395  .name = "pwm-tin",
396  .devname = "s3c24xx-pwm.3",
397  .id = 3,
398  .ops = &clk_tin_ops,
399  },
400  [4] = {
401  .name = "pwm-tin",
402  .devname = "s3c24xx-pwm.4",
403  .id = 4,
404  .ops = &clk_tin_ops,
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 (pwm_cfg_src_is_tclk(tcfg1))
424  parent = s3c24xx_pwmclk_tclk(id);
425  else
426  parent = s3c24xx_pwmclk_tdiv(id);
427 
428  return clk_set_parent(pwm, parent);
429 }
430 
441 {
442  struct clk *clk_timers;
443  unsigned int clk;
444  int ret;
445 
446  clk_timers = clk_get(NULL, "timers");
447  if (IS_ERR(clk_timers)) {
448  printk(KERN_ERR "%s: no parent clock\n", __func__);
449  return;
450  }
451 
452  for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++)
453  clk_timer_scaler[clk].parent = clk_timers;
454 
455  s3c_register_clocks(clk_timer_scaler, ARRAY_SIZE(clk_timer_scaler));
456  s3c_register_clocks(clk_timer_tclk, ARRAY_SIZE(clk_timer_tclk));
457 
458  for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
459  ret = clk_pwm_tdiv_register(clk);
460 
461  if (ret < 0) {
462  printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
463  return;
464  }
465  }
466 
467  for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
468  ret = clk_pwm_tin_register(&clk_tin[clk]);
469  if (ret < 0) {
470  printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
471  return;
472  }
473  }
474 }