disable IMQ on 2.6.28 as well -- people should use IFB..
[openwrt.git] / target / linux / s3c24xx / patches / 0011-s3c2410-pwm.patch.patch
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
6
7 Signed-off-by: Javi Roman <javiroman@kernel-labs.org>
8 Signed-off-by: Harald Welte <laforge@openmoko.org>
9 ---
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
17
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
24         select S3C2410_CLOCK
25         select S3C2410_GPIO
26 +       select S3C2410_PWM
27         select CPU_LLSERIAL_S3C2410
28         select S3C2410_PM if PM
29         help
30 @@ -38,6 +39,12 @@ config S3C2410_CLOCK
31           Clock code for the S3C2410, and similar processors
32  
33  
34 +config S3C2410_PWM
35 +       bool
36 +       help
37 +         PWM timer code for the S3C2410, and similar processors
38 +
39 +
40  menu "S3C2410 Machines"
41  
42  config ARCH_SMDK2410
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
52  
53  # Machine support
54  
55 diff --git a/arch/arm/mach-s3c2410/pwm.c b/arch/arm/mach-s3c2410/pwm.c
56 new file mode 100644
57 index 0000000..8a07359
58 --- /dev/null
59 +++ b/arch/arm/mach-s3c2410/pwm.c
60 @@ -0,0 +1,214 @@
61 +/*
62 + * arch/arm/mach-s3c2410/3c2410-pwm.c
63 + *
64 + * Copyright (c) by Javi Roman <javiroman@kernel-labs.org>
65 + *              for the OpenMoko Project.
66 + *
67 + *     S3C2410A SoC PWM support
68 + *
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.
73 + *
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
77 + *
78 + */
79 +
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>
86 +
87 +int s3c2410_pwm_disable(struct s3c2410_pwm *pwm)
88 +{
89 +       unsigned long tcon;
90 +
91 +       /* stop timer */
92 +       tcon = __raw_readl(S3C2410_TCON);
93 +       tcon &= 0xffffff00;
94 +       __raw_writel(tcon, S3C2410_TCON);
95 +
96 +       clk_disable(pwm->pclk);
97 +       clk_put(pwm->pclk);
98 +
99 +       return 0;
100 +}
101 +EXPORT_SYMBOL_GPL(s3c2410_pwm_disable);
102 +
103 +int s3c2410_pwm_init(struct s3c2410_pwm *pwm)
104 +{
105 +       pwm->pclk = clk_get(NULL, "timers");
106 +       if (IS_ERR(pwm->pclk))
107 +               return PTR_ERR(pwm->pclk);
108 +
109 +       clk_enable(pwm->pclk);
110 +       pwm->pclk_rate = clk_get_rate(pwm->pclk);
111 +       return 0;
112 +}
113 +EXPORT_SYMBOL_GPL(s3c2410_pwm_init);
114 +
115 +int s3c2410_pwm_enable(struct s3c2410_pwm *pwm)
116 +{
117 +       unsigned long tcfg0, tcfg1, tcnt, tcmp;
118 +
119 +       /* control registers bits */
120 +       tcfg1 = __raw_readl(S3C2410_TCFG1);
121 +       tcfg0 = __raw_readl(S3C2410_TCFG0);
122 +
123 +       /* divider & scaler slection */
124 +       switch (pwm->timerid) {
125 +       case PWM0:
126 +               tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
127 +               tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
128 +               break;
129 +       case PWM1:
130 +               tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK;
131 +               tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
132 +               break;
133 +       case PWM2:
134 +               tcfg1 &= ~S3C2410_TCFG1_MUX2_MASK;
135 +               tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
136 +               break;
137 +       case PWM3:
138 +               tcfg1 &= ~S3C2410_TCFG1_MUX3_MASK;
139 +               tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
140 +               break;
141 +       case PWM4:
142 +               /* timer four is not capable of doing PWM */
143 +               break;
144 +       default:
145 +               clk_disable(pwm->pclk);
146 +               clk_put(pwm->pclk);
147 +               return -1;
148 +       }
149 +
150 +       /* divider & scaler values */
151 +       tcfg1 |= pwm->divider;
152 +       __raw_writel(tcfg1, S3C2410_TCFG1);
153 +
154 +       switch (pwm->timerid) {
155 +       case PWM0:
156 +       case PWM1:
157 +               tcfg0 |= pwm->prescaler;
158 +               __raw_writel(tcfg0, S3C2410_TCFG0);
159 +               break;
160 +       default:
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",
164 +                              pwm->timerid);
165 +               }
166 +               break;
167 +       }
168 +
169 +       /* timer count and compare buffer initial values */
170 +       tcnt = pwm->counter;
171 +       tcmp = pwm->comparer;
172 +
173 +       __raw_writel(tcnt, S3C2410_TCNTB(pwm->timerid));
174 +       __raw_writel(tcmp, S3C2410_TCMPB(pwm->timerid));
175 +
176 +       /* ensure timer is stopped */
177 +       s3c2410_pwm_stop(pwm);
178 +
179 +       return 0;
180 +}
181 +EXPORT_SYMBOL_GPL(s3c2410_pwm_enable);
182 +
183 +int s3c2410_pwm_start(struct s3c2410_pwm *pwm)
184 +{
185 +       unsigned long tcon;
186 +
187 +       tcon = __raw_readl(S3C2410_TCON);
188 +
189 +       switch (pwm->timerid) {
190 +       case PWM0:
191 +               tcon |= S3C2410_TCON_T0START;
192 +               tcon &= ~S3C2410_TCON_T0MANUALUPD;
193 +               break;
194 +       case PWM1:
195 +               tcon |= S3C2410_TCON_T1START;
196 +               tcon &= ~S3C2410_TCON_T1MANUALUPD;
197 +               break;
198 +       case PWM2:
199 +               tcon |= S3C2410_TCON_T2START;
200 +               tcon &= ~S3C2410_TCON_T2MANUALUPD;
201 +               break;
202 +       case PWM3:
203 +               tcon |= S3C2410_TCON_T3START;
204 +               tcon &= ~S3C2410_TCON_T3MANUALUPD;
205 +               break;
206 +       case PWM4:
207 +               /* timer four is not capable of doing PWM */
208 +       default:
209 +               return -ENODEV;
210 +       }
211 +
212 +       __raw_writel(tcon, S3C2410_TCON);
213 +
214 +       return 0;
215 +}
216 +EXPORT_SYMBOL_GPL(s3c2410_pwm_start);
217 +
218 +int s3c2410_pwm_stop(struct s3c2410_pwm *pwm)
219 +{
220 +       unsigned long tcon;
221 +
222 +       tcon = __raw_readl(S3C2410_TCON);
223 +
224 +       switch (pwm->timerid) {
225 +       case PWM0:
226 +               tcon &= ~0x00000000;
227 +               tcon |= S3C2410_TCON_T0RELOAD;
228 +               tcon |= S3C2410_TCON_T0MANUALUPD;
229 +               break;
230 +       case PWM1:
231 +               tcon &= ~0x00000080;
232 +               tcon |= S3C2410_TCON_T1RELOAD;
233 +               tcon |= S3C2410_TCON_T1MANUALUPD;
234 +               break;
235 +       case PWM2:
236 +               tcon &= ~0x00000800;
237 +               tcon |= S3C2410_TCON_T2RELOAD;
238 +               tcon |= S3C2410_TCON_T2MANUALUPD;
239 +               break;
240 +       case PWM3:
241 +               tcon &= ~0x00008000;
242 +               tcon |= S3C2410_TCON_T3RELOAD;
243 +               tcon |= S3C2410_TCON_T3MANUALUPD;
244 +               break;
245 +       case PWM4:
246 +               /* timer four is not capable of doing PWM */
247 +       default:
248 +               return -ENODEV;
249 +       }
250 +
251 +       __raw_writel(tcon, S3C2410_TCON);
252 +
253 +       return 0;
254 +}
255 +EXPORT_SYMBOL_GPL(s3c2410_pwm_stop);
256 +
257 +int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *pwm)
258 +{
259 +       __raw_writel(reg_value, S3C2410_TCMPB(pwm->timerid));
260 +
261 +       return 0;
262 +}
263 +EXPORT_SYMBOL_GPL(s3c2410_pwm_duty_cycle);
264 +
265 +int s3c2410_pwm_dumpregs(void)
266 +{
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));
271 +
272 +       return 0;
273 +}
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
276 new file mode 100644
277 index 0000000..a797ec3
278 --- /dev/null
279 +++ b/include/asm-arm/arch-s3c2410/pwm.h
280 @@ -0,0 +1,40 @@
281 +#ifndef __S3C2410_PWM_H
282 +#define __S3C2410_PWM_H
283 +
284 +#include <linux/err.h>
285 +#include <linux/platform_device.h>
286 +#include <linux/clk.h>
287 +
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>
293 +
294 +enum pwm_timer {
295 +       PWM0,
296 +       PWM1,
297 +       PWM2,
298 +       PWM3,
299 +       PWM4
300 +};
301 +
302 +struct s3c2410_pwm {
303 +       enum pwm_timer timerid;
304 +       struct clk *pclk;
305 +       unsigned long pclk_rate;
306 +       unsigned long prescaler;
307 +       unsigned long divider;
308 +       unsigned long counter;
309 +       unsigned long comparer;
310 +};
311 +
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);
319 +
320 +#endif /* __S3C2410_PWM_H */
321 -- 
322 1.5.6.3
323