1 From 4b35af38b03658e6031fdca45c98e488d6cf3f34 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Tue, 21 Jul 2009 12:06:29 +0200
4 Subject: [PATCH] 011-s3c-pwm.patch
7 arch/arm/plat-s3c/Kconfig | 5 +
8 arch/arm/plat-s3c/Makefile | 1 +
9 arch/arm/plat-s3c/include/plat/pwm.h | 45 ++++
10 arch/arm/plat-s3c/pwm.c | 288 ++++++++++++++++++++++
11 arch/arm/plat-s3c24xx/pwm-clock.c | 437 ++++++++++++++++++++++++++++++++++
12 5 files changed, 776 insertions(+), 0 deletions(-)
13 create mode 100644 arch/arm/plat-s3c/include/plat/pwm.h
14 create mode 100644 arch/arm/plat-s3c/pwm.c
15 create mode 100644 arch/arm/plat-s3c24xx/pwm-clock.c
17 diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
18 index 935c755..bae4b95 100644
19 --- a/arch/arm/plat-s3c/Kconfig
20 +++ b/arch/arm/plat-s3c/Kconfig
21 @@ -166,6 +166,11 @@ config S3C_DMA
23 Internal configuration for S3C DMA core
28 + PWM timer code for the S3C2410, and similar processors
30 # device definitions to compile in
33 diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
34 index f32f183..ab60855 100644
35 --- a/arch/arm/plat-s3c/Makefile
36 +++ b/arch/arm/plat-s3c/Makefile
37 @@ -38,3 +38,4 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += dev-audio.o
38 obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o
39 obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
40 obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o
41 +obj-$(CONFIG_S3C_PWM) += pwm.o
42 diff --git a/arch/arm/plat-s3c/include/plat/pwm.h b/arch/arm/plat-s3c/include/plat/pwm.h
44 index 0000000..6a41b0a
46 +++ b/arch/arm/plat-s3c/include/plat/pwm.h
48 +#ifndef __S3C2410_PWM_H
49 +#define __S3C2410_PWM_H
51 +#include <linux/err.h>
52 +#include <linux/platform_device.h>
53 +#include <linux/clk.h>
56 +#include <mach/hardware.h>
57 +#include <asm/mach-types.h>
58 +#include <plat/regs-timer.h>
69 + enum pwm_timer timerid;
71 + unsigned long pclk_rate;
72 + unsigned long prescaler;
73 + unsigned long divider;
74 + unsigned long counter;
75 + unsigned long comparer;
78 +struct s3c24xx_pwm_platform_data{
79 + /* callback to attach platform children (to enforce suspend / resume
81 + void (*attach_child_devices)(struct device *parent_device);
84 +int s3c2410_pwm_init(struct s3c2410_pwm *s3c2410_pwm);
85 +int s3c2410_pwm_enable(struct s3c2410_pwm *s3c2410_pwm);
86 +int s3c2410_pwm_disable(struct s3c2410_pwm *s3c2410_pwm);
87 +int s3c2410_pwm_start(struct s3c2410_pwm *s3c2410_pwm);
88 +int s3c2410_pwm_stop(struct s3c2410_pwm *s3c2410_pwm);
89 +int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *s3c2410_pwm);
90 +int s3c2410_pwm_dumpregs(void);
92 +#endif /* __S3C2410_PWM_H */
93 diff --git a/arch/arm/plat-s3c/pwm.c b/arch/arm/plat-s3c/pwm.c
95 index 0000000..250bd2b
97 +++ b/arch/arm/plat-s3c/pwm.c
100 + * arch/arm/plat-s3c/pwm.c
102 + * Copyright (c) by Javi Roman <javiroman@kernel-labs.org>
103 + * for the Openmoko Project.
105 + * S3C2410A SoC PWM support
107 + * This program is free software; you can redistribute it and/or modify
108 + * it under the terms of the GNU General Public License as published by
109 + * the Free Software Foundation; either version 2 of the License, or
110 + * (at your option) any later version.
112 + * You should have received a copy of the GNU General Public License
113 + * along with this program; if not, write to the Free Software
114 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
118 +#include <linux/kernel.h>
119 +#include <linux/init.h>
120 +#include <linux/clk.h>
121 +#include <linux/device.h>
122 +#include <mach/hardware.h>
123 +#include <plat/regs-timer.h>
124 +#include <plat/pwm.h>
128 + static unsigned long standby_reg_tcon;
129 + static unsigned long standby_reg_tcfg0;
130 + static unsigned long standby_reg_tcfg1;
133 +int s3c2410_pwm_disable(struct s3c2410_pwm *pwm)
135 + unsigned long tcon;
138 + tcon = __raw_readl(S3C2410_TCON);
139 + tcon &= 0xffffff00;
140 + __raw_writel(tcon, S3C2410_TCON);
142 + clk_disable(pwm->pclk);
143 + clk_put(pwm->pclk);
147 +EXPORT_SYMBOL_GPL(s3c2410_pwm_disable);
149 +int s3c2410_pwm_init(struct s3c2410_pwm *pwm)
151 + pwm->pclk = clk_get(NULL, "timers");
152 + if (IS_ERR(pwm->pclk))
153 + return PTR_ERR(pwm->pclk);
155 + clk_enable(pwm->pclk);
156 + pwm->pclk_rate = clk_get_rate(pwm->pclk);
159 +EXPORT_SYMBOL_GPL(s3c2410_pwm_init);
161 +int s3c2410_pwm_enable(struct s3c2410_pwm *pwm)
163 + unsigned long tcfg0, tcfg1, tcnt, tcmp;
165 + /* control registers bits */
166 + tcfg1 = __raw_readl(S3C2410_TCFG1);
167 + tcfg0 = __raw_readl(S3C2410_TCFG0);
169 + /* divider & scaler slection */
170 + switch (pwm->timerid) {
172 + tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
173 + tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
176 + tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK;
177 + tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
180 + tcfg1 &= ~S3C2410_TCFG1_MUX2_MASK;
181 + tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
184 + tcfg1 &= ~S3C2410_TCFG1_MUX3_MASK;
185 + tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
188 + /* timer four is not capable of doing PWM */
191 + clk_disable(pwm->pclk);
192 + clk_put(pwm->pclk);
196 + /* divider & scaler values */
197 + tcfg1 |= pwm->divider;
198 + __raw_writel(tcfg1, S3C2410_TCFG1);
200 + switch (pwm->timerid) {
203 + tcfg0 |= pwm->prescaler;
204 + __raw_writel(tcfg0, S3C2410_TCFG0);
207 + if ((tcfg0 | pwm->prescaler) != tcfg0) {
208 + printk(KERN_WARNING "not changing prescaler of PWM %u,"
209 + " since it's shared with timer4 (clock tick)\n",
215 + /* timer count and compare buffer initial values */
216 + tcnt = pwm->counter;
217 + tcmp = pwm->comparer;
219 + __raw_writel(tcnt, S3C2410_TCNTB(pwm->timerid));
220 + __raw_writel(tcmp, S3C2410_TCMPB(pwm->timerid));
222 + /* ensure timer is stopped */
223 + s3c2410_pwm_stop(pwm);
227 +EXPORT_SYMBOL_GPL(s3c2410_pwm_enable);
229 +int s3c2410_pwm_start(struct s3c2410_pwm *pwm)
231 + unsigned long tcon;
233 + tcon = __raw_readl(S3C2410_TCON);
235 + switch (pwm->timerid) {
237 + tcon |= S3C2410_TCON_T0START;
238 + tcon &= ~S3C2410_TCON_T0MANUALUPD;
241 + tcon |= S3C2410_TCON_T1START;
242 + tcon &= ~S3C2410_TCON_T1MANUALUPD;
245 + tcon |= S3C2410_TCON_T2START;
246 + tcon &= ~S3C2410_TCON_T2MANUALUPD;
249 + tcon |= S3C2410_TCON_T3START;
250 + tcon &= ~S3C2410_TCON_T3MANUALUPD;
253 + /* timer four is not capable of doing PWM */
258 + __raw_writel(tcon, S3C2410_TCON);
262 +EXPORT_SYMBOL_GPL(s3c2410_pwm_start);
264 +int s3c2410_pwm_stop(struct s3c2410_pwm *pwm)
266 + unsigned long tcon;
268 + tcon = __raw_readl(S3C2410_TCON);
270 + switch (pwm->timerid) {
272 + tcon &= ~0x00000000;
273 + tcon |= S3C2410_TCON_T0RELOAD;
274 + tcon |= S3C2410_TCON_T0MANUALUPD;
277 + tcon &= ~0x00000080;
278 + tcon |= S3C2410_TCON_T1RELOAD;
279 + tcon |= S3C2410_TCON_T1MANUALUPD;
282 + tcon &= ~0x00000800;
283 + tcon |= S3C2410_TCON_T2RELOAD;
284 + tcon |= S3C2410_TCON_T2MANUALUPD;
287 + tcon &= ~0x00008000;
288 + tcon |= S3C2410_TCON_T3RELOAD;
289 + tcon |= S3C2410_TCON_T3MANUALUPD;
292 + /* timer four is not capable of doing PWM */
297 + __raw_writel(tcon, S3C2410_TCON);
301 +EXPORT_SYMBOL_GPL(s3c2410_pwm_stop);
303 +int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *pwm)
305 + __raw_writel(reg_value, S3C2410_TCMPB(pwm->timerid));
309 +EXPORT_SYMBOL_GPL(s3c2410_pwm_duty_cycle);
311 +int s3c2410_pwm_dumpregs(void)
313 + printk(KERN_INFO "TCON: %08lx, TCFG0: %08lx, TCFG1: %08lx\n",
314 + (unsigned long) __raw_readl(S3C2410_TCON),
315 + (unsigned long) __raw_readl(S3C2410_TCFG0),
316 + (unsigned long) __raw_readl(S3C2410_TCFG1));
320 +EXPORT_SYMBOL_GPL(s3c2410_pwm_dumpregs);
322 +static int __init s3c24xx_pwm_probe(struct platform_device *pdev)
324 + struct s3c24xx_pwm_platform_data *pdata = pdev->dev.platform_data;
326 + dev_info(&pdev->dev, "s3c24xx_pwm is registered \n");
328 + /* if platform was interested, give him a chance to register
329 + * platform devices that switch power with us as the parent
330 + * at registration time -- ensures suspend / resume ordering
333 + if (pdata->attach_child_devices)
334 + (pdata->attach_child_devices)(&pdev->dev);
340 +static int s3c24xx_pwm_suspend(struct platform_device *pdev, pm_message_t state)
342 + /* PWM config should be kept in suspending */
343 + standby_reg_tcon = __raw_readl(S3C2410_TCON);
344 + standby_reg_tcfg0 = __raw_readl(S3C2410_TCFG0);
345 + standby_reg_tcfg1 = __raw_readl(S3C2410_TCFG1);
350 +static int s3c24xx_pwm_resume(struct platform_device *pdev)
352 + __raw_writel(standby_reg_tcon, S3C2410_TCON);
353 + __raw_writel(standby_reg_tcfg0, S3C2410_TCFG0);
354 + __raw_writel(standby_reg_tcfg1, S3C2410_TCFG1);
359 +#define s3c24xx_pwm_suspend NULL
360 +#define s3c24xx_pwm_resume NULL
363 +static struct platform_driver s3c24xx_pwm_driver = {
365 + .name = "s3c24xx_pwm",
366 + .owner = THIS_MODULE,
368 + .probe = s3c24xx_pwm_probe,
369 + .suspend = s3c24xx_pwm_suspend,
370 + .resume = s3c24xx_pwm_resume,
373 +static int __init s3c24xx_pwm_init(void)
375 + return platform_driver_register(&s3c24xx_pwm_driver);
378 +static void __exit s3c24xx_pwm_exit(void)
382 +MODULE_AUTHOR("Javi Roman <javiroman@kernel-labs.org>");
383 +MODULE_LICENSE("GPL");
385 +module_init(s3c24xx_pwm_init);
386 +module_exit(s3c24xx_pwm_exit);
387 diff --git a/arch/arm/plat-s3c24xx/pwm-clock.c b/arch/arm/plat-s3c24xx/pwm-clock.c
389 index 0000000..d41cccd
391 +++ b/arch/arm/plat-s3c24xx/pwm-clock.c
393 +/* linux/arch/arm/plat-s3c24xx/pwm-clock.c
395 + * Copyright (c) 2007 Simtec Electronics
396 + * Copyright (c) 2007, 2008 Ben Dooks
397 + * Ben Dooks <ben-linux@fluff.org>
399 + * This program is free software; you can redistribute it and/or modify
400 + * it under the terms of the GNU General Public License as published by
401 + * the Free Software Foundation; either version 2 of the License.
404 +#include <linux/init.h>
405 +#include <linux/module.h>
406 +#include <linux/kernel.h>
407 +#include <linux/list.h>
408 +#include <linux/errno.h>
409 +#include <linux/clk.h>
410 +#include <linux/err.h>
411 +#include <linux/io.h>
413 +#include <mach/hardware.h>
414 +#include <asm/irq.h>
416 +#include <mach/regs-clock.h>
417 +#include <mach/regs-gpio.h>
419 +#include <asm/plat-s3c24xx/clock.h>
420 +#include <asm/plat-s3c24xx/cpu.h>
422 +#include <asm/plat-s3c/regs-timer.h>
424 +/* Each of the timers 0 through 5 go through the following
425 + * clock tree, with the inputs depending on the timers.
427 + * pclk ---- [ prescaler 0 ] -+---> timer 0
430 + * pclk ---- [ prescaler 1 ] -+---> timer 2
434 + * Which are fed into the timers as so:
436 + * prescaled 0 ---- [ div 2,4,8,16 ] ---\
438 + * tclk 0 ------------------------------/
440 + * prescaled 0 ---- [ div 2,4,8,16 ] ---\
442 + * tclk 0 ------------------------------/
445 + * prescaled 1 ---- [ div 2,4,8,16 ] ---\
447 + * tclk 1 ------------------------------/
449 + * prescaled 1 ---- [ div 2,4,8,16 ] ---\
451 + * tclk 1 ------------------------------/
453 + * prescaled 1 ---- [ div 2,4,8, 16 ] --\
455 + * tclk 1 ------------------------------/
457 + * Since the mux and the divider are tied together in the
458 + * same register space, it is impossible to set the parent
459 + * and the rate at the same time. To avoid this, we add an
460 + * intermediate 'prescaled-and-divided' clock to select
461 + * as the parent for the timer input clock called tdiv.
463 + * prescaled clk --> pwm-tdiv ---\
464 + * [ mux ] --> timer X
465 + * tclk -------------------------/
468 +static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
470 + unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
472 + if (clk->id == 1) {
473 + tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
474 + tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
476 + tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK;
479 + return clk_get_rate(clk->parent) / (tcfg0 + 1);
482 +/* TODO - add set rate calls. */
484 +static struct clk clk_timer_scaler[] = {
486 + .name = "pwm-scaler0",
488 + .get_rate = clk_pwm_scaler_getrate,
491 + .name = "pwm-scaler1",
493 + .get_rate = clk_pwm_scaler_getrate,
497 +static struct clk clk_timer_tclk[] = {
499 + .name = "pwm-tclk0",
503 + .name = "pwm-tclk1",
508 +struct pwm_tdiv_clk {
510 + unsigned int divisor;
513 +static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
515 + return container_of(clk, struct pwm_tdiv_clk, clk);
518 +static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
520 + return 1 << (1 + tcfg1);
523 +static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
525 + unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
526 + unsigned int divisor;
528 + tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
529 + tcfg1 &= S3C2410_TCFG1_MUX_MASK;
531 + if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
532 + divisor = to_tdiv(clk)->divisor;
534 + divisor = tcfg_to_divisor(tcfg1);
536 + return clk_get_rate(clk->parent) / divisor;
539 +static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
540 + unsigned long rate)
542 + unsigned long parent_rate;
543 + unsigned long divisor;
545 + parent_rate = clk_get_rate(clk->parent);
546 + divisor = parent_rate / rate;
550 + else if (divisor <= 4)
552 + else if (divisor <= 8)
557 + return parent_rate / divisor;
560 +static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
562 + unsigned long bits;
564 + switch (divclk->divisor) {
566 + bits = S3C2410_TCFG1_MUX_DIV2;
569 + bits = S3C2410_TCFG1_MUX_DIV4;
572 + bits = S3C2410_TCFG1_MUX_DIV8;
576 + bits = S3C2410_TCFG1_MUX_DIV16;
583 +static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
585 + unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
586 + unsigned long bits = clk_pwm_tdiv_bits(divclk);
587 + unsigned long flags;
588 + unsigned long shift = S3C2410_TCFG1_SHIFT(divclk->clk.id);
590 + local_irq_save(flags);
592 + tcfg1 = __raw_readl(S3C2410_TCFG1);
593 + tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
594 + tcfg1 |= bits << shift;
595 + __raw_writel(tcfg1, S3C2410_TCFG1);
597 + local_irq_restore(flags);
600 +static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
602 + struct pwm_tdiv_clk *divclk = to_tdiv(clk);
603 + unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
604 + unsigned long parent_rate = clk_get_rate(clk->parent);
605 + unsigned long divisor;
607 + tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
608 + tcfg1 &= S3C2410_TCFG1_MUX_MASK;
610 + rate = clk_round_rate(clk, rate);
611 + divisor = parent_rate / rate;
616 + divclk->divisor = divisor;
618 + /* Update the current MUX settings if we are currently
619 + * selected as the clock source for this clock. */
621 + if (tcfg1 != S3C2410_TCFG1_MUX_TCLK)
622 + clk_pwm_tdiv_update(divclk);
627 +static struct pwm_tdiv_clk clk_timer_tdiv[] = {
630 + .name = "pwm-tdiv",
631 + .parent = &clk_timer_scaler[0],
632 + .get_rate = clk_pwm_tdiv_get_rate,
633 + .set_rate = clk_pwm_tdiv_set_rate,
634 + .round_rate = clk_pwm_tdiv_round_rate,
639 + .name = "pwm-tdiv",
640 + .parent = &clk_timer_scaler[0],
641 + .get_rate = clk_pwm_tdiv_get_rate,
642 + .set_rate = clk_pwm_tdiv_set_rate,
643 + .round_rate = clk_pwm_tdiv_round_rate,
648 + .name = "pwm-tdiv",
649 + .parent = &clk_timer_scaler[1],
650 + .get_rate = clk_pwm_tdiv_get_rate,
651 + .set_rate = clk_pwm_tdiv_set_rate,
652 + .round_rate = clk_pwm_tdiv_round_rate,
657 + .name = "pwm-tdiv",
658 + .parent = &clk_timer_scaler[1],
659 + .get_rate = clk_pwm_tdiv_get_rate,
660 + .set_rate = clk_pwm_tdiv_set_rate,
661 + .round_rate = clk_pwm_tdiv_round_rate,
666 + .name = "pwm-tdiv",
667 + .parent = &clk_timer_scaler[1],
668 + .get_rate = clk_pwm_tdiv_get_rate,
669 + .set_rate = clk_pwm_tdiv_set_rate,
670 + .round_rate = clk_pwm_tdiv_round_rate,
675 +static int __init clk_pwm_tdiv_register(unsigned int id)
677 + struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
678 + unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
680 + tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
681 + tcfg1 &= S3C2410_TCFG1_MUX_MASK;
683 + divclk->clk.id = id;
684 + divclk->divisor = tcfg_to_divisor(tcfg1);
686 + return s3c24xx_register_clock(&divclk->clk);
689 +static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
691 + return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
694 +static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
696 + return &clk_timer_tdiv[id].clk;
699 +static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
701 + unsigned int id = clk->id;
702 + unsigned long tcfg1;
703 + unsigned long flags;
704 + unsigned long bits;
705 + unsigned long shift = S3C2410_TCFG1_SHIFT(id);
707 + if (parent == s3c24xx_pwmclk_tclk(id))
708 + bits = S3C2410_TCFG1_MUX_TCLK << shift;
709 + else if (parent == s3c24xx_pwmclk_tdiv(id))
710 + bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
714 + clk->parent = parent;
716 + local_irq_save(flags);
718 + tcfg1 = __raw_readl(S3C2410_TCFG1);
719 + tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
720 + __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
722 + local_irq_restore(flags);
727 +static struct clk clk_tin[] = {
731 + .set_parent = clk_pwm_tin_set_parent,
736 + .set_parent = clk_pwm_tin_set_parent,
741 + .set_parent = clk_pwm_tin_set_parent,
746 + .set_parent = clk_pwm_tin_set_parent,
751 + .set_parent = clk_pwm_tin_set_parent,
755 +static __init int clk_pwm_tin_register(struct clk *pwm)
757 + unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
758 + unsigned int id = pwm->id;
760 + struct clk *parent;
763 + ret = s3c24xx_register_clock(pwm);
767 + tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
768 + tcfg1 &= S3C2410_TCFG1_MUX_MASK;
770 + if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
771 + parent = s3c24xx_pwmclk_tclk(id);
773 + parent = s3c24xx_pwmclk_tdiv(id);
775 + return clk_set_parent(pwm, parent);
778 +static __init int s3c24xx_pwmclk_init(void)
780 + struct clk *clk_timers;
784 + clk_timers = clk_get(NULL, "timers");
785 + if (IS_ERR(clk_timers)) {
786 + printk(KERN_ERR "%s: no parent clock\n", __func__);
790 + for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
791 + clk_timer_scaler[clk].parent = clk_timers;
792 + ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
794 + printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
799 + for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
800 + ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
802 + printk(KERN_ERR "error adding pww tclk%d\n", clk);
807 + for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
808 + ret = clk_pwm_tdiv_register(clk);
810 + printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
815 + for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
816 + ret = clk_pwm_tin_register(&clk_tin[clk]);
818 + printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
829 +arch_initcall(s3c24xx_pwmclk_init);