1 From 2b1ccb68bdc0e1454be0e769896862bf0c7f95f9 Mon Sep 17 00:00:00 2001
2 From: mokopatches <mokopatches@openmoko.org>
3 Date: Wed, 16 Jul 2008 14:44:49 +0100
4 Subject: [PATCH] s3c2410-pwm.patch
5 This patch adds a PWM api abstraction for the S3C2410 SoC
7 Signed-off-by: Javi Roman <javiroman@kernel-labs.org>
8 Signed-off-by: Harald Welte <laforge@openmoko.org>
10 arch/arm/mach-s3c2410/Kconfig | 7 +
11 arch/arm/mach-s3c2410/Makefile | 1 +
12 arch/arm/mach-s3c2410/pwm.c | 214 ++++++++++++++++++++++++++++++++++++
13 include/asm-arm/arch-s3c2410/pwm.h | 40 +++++++
14 4 files changed, 262 insertions(+), 0 deletions(-)
15 create mode 100644 arch/arm/mach-s3c2410/pwm.c
16 create mode 100644 include/asm-arm/arch-s3c2410/pwm.h
18 diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
19 index 58519e6..3e9ec50 100644
20 --- a/arch/arm/mach-s3c2410/Kconfig
21 +++ b/arch/arm/mach-s3c2410/Kconfig
22 @@ -9,6 +9,7 @@ config CPU_S3C2410
23 depends on ARCH_S3C2410
27 select CPU_LLSERIAL_S3C2410
28 select S3C2410_PM if PM
30 @@ -38,6 +39,12 @@ config S3C2410_CLOCK
31 Clock code for the S3C2410, and similar processors
37 + PWM timer code for the S3C2410, and similar processors
40 menu "S3C2410 Machines"
43 diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
44 index b73562f..2a12a6a 100644
45 --- a/arch/arm/mach-s3c2410/Makefile
46 +++ b/arch/arm/mach-s3c2410/Makefile
47 @@ -16,6 +16,7 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
48 obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
49 obj-$(CONFIG_S3C2410_GPIO) += gpio.o
50 obj-$(CONFIG_S3C2410_CLOCK) += clock.o
51 +obj-$(CONFIG_S3C2410_PWM) += pwm.o
55 diff --git a/arch/arm/mach-s3c2410/pwm.c b/arch/arm/mach-s3c2410/pwm.c
57 index 0000000..8a07359
59 +++ b/arch/arm/mach-s3c2410/pwm.c
62 + * arch/arm/mach-s3c2410/3c2410-pwm.c
64 + * Copyright (c) by Javi Roman <javiroman@kernel-labs.org>
65 + * for the OpenMoko Project.
67 + * S3C2410A SoC PWM support
69 + * This program is free software; you can redistribute it and/or modify
70 + * it under the terms of the GNU General Public License as published by
71 + * the Free Software Foundation; either version 2 of the License, or
72 + * (at your option) any later version.
74 + * You should have received a copy of the GNU General Public License
75 + * along with this program; if not, write to the Free Software
76 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
80 +#include <linux/kernel.h>
81 +#include <linux/init.h>
82 +#include <linux/clk.h>
83 +#include <asm/hardware.h>
84 +#include <asm/plat-s3c/regs-timer.h>
85 +#include <asm/arch/pwm.h>
87 +int s3c2410_pwm_disable(struct s3c2410_pwm *pwm)
92 + tcon = __raw_readl(S3C2410_TCON);
94 + __raw_writel(tcon, S3C2410_TCON);
96 + clk_disable(pwm->pclk);
101 +EXPORT_SYMBOL_GPL(s3c2410_pwm_disable);
103 +int s3c2410_pwm_init(struct s3c2410_pwm *pwm)
105 + pwm->pclk = clk_get(NULL, "timers");
106 + if (IS_ERR(pwm->pclk))
107 + return PTR_ERR(pwm->pclk);
109 + clk_enable(pwm->pclk);
110 + pwm->pclk_rate = clk_get_rate(pwm->pclk);
113 +EXPORT_SYMBOL_GPL(s3c2410_pwm_init);
115 +int s3c2410_pwm_enable(struct s3c2410_pwm *pwm)
117 + unsigned long tcfg0, tcfg1, tcnt, tcmp;
119 + /* control registers bits */
120 + tcfg1 = __raw_readl(S3C2410_TCFG1);
121 + tcfg0 = __raw_readl(S3C2410_TCFG0);
123 + /* divider & scaler slection */
124 + switch (pwm->timerid) {
126 + tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
127 + tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
130 + tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK;
131 + tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
134 + tcfg1 &= ~S3C2410_TCFG1_MUX2_MASK;
135 + tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
138 + tcfg1 &= ~S3C2410_TCFG1_MUX3_MASK;
139 + tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
142 + /* timer four is not capable of doing PWM */
145 + clk_disable(pwm->pclk);
146 + clk_put(pwm->pclk);
150 + /* divider & scaler values */
151 + tcfg1 |= pwm->divider;
152 + __raw_writel(tcfg1, S3C2410_TCFG1);
154 + switch (pwm->timerid) {
157 + tcfg0 |= pwm->prescaler;
158 + __raw_writel(tcfg0, S3C2410_TCFG0);
161 + if ((tcfg0 | pwm->prescaler) != tcfg0) {
162 + printk(KERN_WARNING "not changing prescaler of PWM %u,"
163 + " since it's shared with timer4 (clock tick)\n",
169 + /* timer count and compare buffer initial values */
170 + tcnt = pwm->counter;
171 + tcmp = pwm->comparer;
173 + __raw_writel(tcnt, S3C2410_TCNTB(pwm->timerid));
174 + __raw_writel(tcmp, S3C2410_TCMPB(pwm->timerid));
176 + /* ensure timer is stopped */
177 + s3c2410_pwm_stop(pwm);
181 +EXPORT_SYMBOL_GPL(s3c2410_pwm_enable);
183 +int s3c2410_pwm_start(struct s3c2410_pwm *pwm)
185 + unsigned long tcon;
187 + tcon = __raw_readl(S3C2410_TCON);
189 + switch (pwm->timerid) {
191 + tcon |= S3C2410_TCON_T0START;
192 + tcon &= ~S3C2410_TCON_T0MANUALUPD;
195 + tcon |= S3C2410_TCON_T1START;
196 + tcon &= ~S3C2410_TCON_T1MANUALUPD;
199 + tcon |= S3C2410_TCON_T2START;
200 + tcon &= ~S3C2410_TCON_T2MANUALUPD;
203 + tcon |= S3C2410_TCON_T3START;
204 + tcon &= ~S3C2410_TCON_T3MANUALUPD;
207 + /* timer four is not capable of doing PWM */
212 + __raw_writel(tcon, S3C2410_TCON);
216 +EXPORT_SYMBOL_GPL(s3c2410_pwm_start);
218 +int s3c2410_pwm_stop(struct s3c2410_pwm *pwm)
220 + unsigned long tcon;
222 + tcon = __raw_readl(S3C2410_TCON);
224 + switch (pwm->timerid) {
226 + tcon &= ~0x00000000;
227 + tcon |= S3C2410_TCON_T0RELOAD;
228 + tcon |= S3C2410_TCON_T0MANUALUPD;
231 + tcon &= ~0x00000080;
232 + tcon |= S3C2410_TCON_T1RELOAD;
233 + tcon |= S3C2410_TCON_T1MANUALUPD;
236 + tcon &= ~0x00000800;
237 + tcon |= S3C2410_TCON_T2RELOAD;
238 + tcon |= S3C2410_TCON_T2MANUALUPD;
241 + tcon &= ~0x00008000;
242 + tcon |= S3C2410_TCON_T3RELOAD;
243 + tcon |= S3C2410_TCON_T3MANUALUPD;
246 + /* timer four is not capable of doing PWM */
251 + __raw_writel(tcon, S3C2410_TCON);
255 +EXPORT_SYMBOL_GPL(s3c2410_pwm_stop);
257 +int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *pwm)
259 + __raw_writel(reg_value, S3C2410_TCMPB(pwm->timerid));
263 +EXPORT_SYMBOL_GPL(s3c2410_pwm_duty_cycle);
265 +int s3c2410_pwm_dumpregs(void)
267 + printk(KERN_INFO "TCON: %08lx, TCFG0: %08lx, TCFG1: %08lx\n",
268 + (unsigned long) __raw_readl(S3C2410_TCON),
269 + (unsigned long) __raw_readl(S3C2410_TCFG0),
270 + (unsigned long) __raw_readl(S3C2410_TCFG1));
274 +EXPORT_SYMBOL_GPL(s3c2410_pwm_dumpregs);
275 diff --git a/include/asm-arm/arch-s3c2410/pwm.h b/include/asm-arm/arch-s3c2410/pwm.h
277 index 0000000..a797ec3
279 +++ b/include/asm-arm/arch-s3c2410/pwm.h
281 +#ifndef __S3C2410_PWM_H
282 +#define __S3C2410_PWM_H
284 +#include <linux/err.h>
285 +#include <linux/platform_device.h>
286 +#include <linux/clk.h>
288 +#include <asm-arm/io.h>
289 +#include <asm/arch/hardware.h>
290 +#include <asm/mach-types.h>
291 +#include <asm/plat-s3c/regs-timer.h>
292 +#include <asm/arch/gta01.h>
302 +struct s3c2410_pwm {
303 + enum pwm_timer timerid;
305 + unsigned long pclk_rate;
306 + unsigned long prescaler;
307 + unsigned long divider;
308 + unsigned long counter;
309 + unsigned long comparer;
312 +int s3c2410_pwm_init(struct s3c2410_pwm *s3c2410_pwm);
313 +int s3c2410_pwm_enable(struct s3c2410_pwm *s3c2410_pwm);
314 +int s3c2410_pwm_disable(struct s3c2410_pwm *s3c2410_pwm);
315 +int s3c2410_pwm_start(struct s3c2410_pwm *s3c2410_pwm);
316 +int s3c2410_pwm_stop(struct s3c2410_pwm *s3c2410_pwm);
317 +int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *s3c2410_pwm);
318 +int s3c2410_pwm_dumpregs(void);
320 +#endif /* __S3C2410_PWM_H */