Hi all,
this is a generic interface for s3c2410 PWM timers. This patche may
not be complete, but it works properly for our necessities right now:
leds-gta01 and gta01_bl drivers.
-Javi
diff -uprN -X dontdiff linux-2.6.22.5/arch/arm/mach-s3c2410/Kconfig linux-2.6.22.5.new/arch/arm/mach-s3c2410/Kconfig
--- linux-2.6.22.5/arch/arm/mach-s3c2410/Kconfig 2007-09-15 10:37:48.000000000 +0200
+++ linux-2.6.22.5.new/arch/arm/mach-s3c2410/Kconfig 2007-09-15 11:33:00.000000000 +0200
@@ -9,6 +9,7 @@ config CPU_S3C2410
depends on ARCH_S3C2410
select S3C2410_CLOCK
select S3C2410_GPIO
+ select S3C2410_PWM
select S3C2410_PM if PM
help
Support for S3C2410 and S3C2410A family from the S3C24XX line
@@ -36,6 +37,11 @@ config S3C2410_CLOCK
help
Clock code for the S3C2410, and similar processors
+config S3C2410_PWM
+ bool
+ help
+ PWM timer code for the S3C2410, and similar processors
+
menu "S3C2410 Machines"
diff -uprN -X dontdiff linux-2.6.22.5/arch/arm/mach-s3c2410/Makefile linux-2.6.22.5.new/arch/arm/mach-s3c2410/Makefile
--- linux-2.6.22.5/arch/arm/mach-s3c2410/Makefile 2007-09-15 10:35:39.000000000 +0200
+++ linux-2.6.22.5.new/arch/arm/mach-s3c2410/Makefile 2007-09-15 11:33:00.000000000 +0200
@@ -16,6 +16,7 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
obj-$(CONFIG_S3C2410_GPIO) += gpio.o
obj-$(CONFIG_S3C2410_CLOCK) += clock.o
+obj-$(CONFIG_S3C2410_PWM) += s3c2410-pwm.o
# Machine support
diff -uprN -X dontdiff linux-2.6.22.5/arch/arm/mach-s3c2410/s3c2410-pwm.c linux-2.6.22.5.new/arch/arm/mach-s3c2410/s3c2410-pwm.c
--- linux-2.6.22.5/arch/arm/mach-s3c2410/s3c2410-pwm.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22.5.new/arch/arm/mach-s3c2410/s3c2410-pwm.c 2007-09-16 19:41:44.000000000 +0200
@@ -0,0 +1,217 @@
+/*
+ * arch/arm/mach-s3c2410/3c2410-pwm.c
+ *
+ * Copyright (c) by Javi Roman <[EMAIL PROTECTED]>
+ * for the Openmoko Project.
+ *
+ * SoC 3c2410a PWM generic support for GTA01
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <asm/arch/s3c2410-pwm.h>
+
+struct s3c2410_pwm_t *s3c2410_pwm_alloc(void)
+{
+ struct s3c2410_pwm_t *s3c2410_pwm;
+
+ s3c2410_pwm = kzalloc(sizeof(*s3c2410_pwm), GFP_KERNEL);
+ if (!s3c2410_pwm)
+ /*return -ENOMEM;*/
+ return NULL;
+
+ s3c2410_pwm->pclk = clk_get(NULL, "timers");
+
+ if (IS_ERR(s3c2410_pwm->pclk)) {
+ /*return PTR_ERR(clk);*/
+ kfree(s3c2410_pwm);
+ return NULL;
+ }
+
+ clk_enable(s3c2410_pwm->pclk);
+
+ s3c2410_pwm->pclk_rate = clk_get_rate(s3c2410_pwm->pclk);
+
+ return s3c2410_pwm;
+}
+
+EXPORT_SYMBOL_GPL(s3c2410_pwm_alloc);
+
+int s3c2410_pwm_disable(struct s3c2410_pwm_t *s3c2410_pwm)
+{
+ unsigned long tcon;
+
+ /* stop timer */
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon &= 0xffffff00;
+ __raw_writel(tcon, S3C2410_TCON);
+
+ clk_disable(s3c2410_pwm->pclk);
+ clk_put(s3c2410_pwm->pclk);
+
+ kfree(s3c2410_pwm);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c2410_pwm_disable);
+
+int s3c2410_pwm_enable(struct s3c2410_pwm_t *s3c2410_pwm)
+{
+ unsigned long tcfg0, tcfg1, tcnt, tcmp;
+
+ /* control registers bits */
+ tcfg1 = __raw_readl(S3C2410_TCFG1);
+ tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+ /* divider & scaler slection */
+ switch(s3c2410_pwm->timerid) {
+ case PWM0:
+ tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
+ tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
+ break;
+ case PWM1:
+ tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK;
+ tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
+ break;
+ case PWM2:
+ tcfg1 &= ~S3C2410_TCFG1_MUX2_MASK;
+ tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+ break;
+ case PWM3:
+ tcfg1 &= ~S3C2410_TCFG1_MUX3_MASK;
+ tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+ break;
+ case PWM4:
+ tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
+ tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+ break;
+ default:
+ return -1;
+ }
+
+ /* divider & scaler values */
+ tcfg1 |= s3c2410_pwm->divider;
+ tcfg0 |= s3c2410_pwm->prescaler;
+
+ __raw_writel(tcfg1, S3C2410_TCFG1);
+ __raw_writel(tcfg0, S3C2410_TCFG0);
+
+ /* timer count and compare buffer initial values */
+ tcnt = s3c2410_pwm->counter;
+ tcmp = s3c2410_pwm->comparer;
+
+ __raw_writel(tcnt, S3C2410_TCNTB(s3c2410_pwm->timerid));
+ __raw_writel(tcmp, S3C2410_TCMPB(s3c2410_pwm->timerid));
+
+ /* ensure timer is stopped */
+ s3c2410_pwm_stop(s3c2410_pwm);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c2410_pwm_enable);
+
+int s3c2410_pwm_start(struct s3c2410_pwm_t *s3c2410_pwm)
+{
+ unsigned long tcon;
+
+ tcon = __raw_readl(S3C2410_TCON);
+
+ switch (s3c2410_pwm->timerid) {
+ case PWM0:
+ tcon |= S3C2410_TCON_T0START;
+ tcon &= ~S3C2410_TCON_T0MANUALUPD;
+ break;
+ case PWM1:
+ tcon |= S3C2410_TCON_T1START;
+ tcon &= ~S3C2410_TCON_T1MANUALUPD;
+ break;
+ case PWM2:
+ tcon |= S3C2410_TCON_T2START;
+ tcon &= ~S3C2410_TCON_T2MANUALUPD;
+ break;
+ case PWM3:
+ tcon |= S3C2410_TCON_T3START;
+ tcon &= ~S3C2410_TCON_T3MANUALUPD;
+ break;
+ case PWM4:
+ tcon |= S3C2410_TCON_T4START;
+ tcon &= ~S3C2410_TCON_T4MANUALUPD;
+ }
+
+ __raw_writel(tcon, S3C2410_TCON);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c2410_pwm_start);
+
+int s3c2410_pwm_stop(struct s3c2410_pwm_t *s3c2410_pwm)
+{
+ unsigned long tcon;
+
+ tcon = __raw_readl(S3C2410_TCON);
+
+ switch (s3c2410_pwm->timerid) {
+ case PWM0:
+ tcon &= ~0x00000000;
+ tcon |= S3C2410_TCON_T0RELOAD;
+ tcon |= S3C2410_TCON_T0MANUALUPD;
+ break;
+ case PWM1:
+ tcon &= ~0x00000080;
+ tcon |= S3C2410_TCON_T1RELOAD;
+ tcon |= S3C2410_TCON_T1MANUALUPD;
+ break;
+ case PWM2:
+ tcon &= ~0x00000800;
+ tcon |= S3C2410_TCON_T2RELOAD;
+ tcon |= S3C2410_TCON_T2MANUALUPD;
+ break;
+ case PWM3:
+ tcon &= ~0x00008000;
+ tcon |= S3C2410_TCON_T3RELOAD;
+ tcon |= S3C2410_TCON_T3MANUALUPD;
+ break;
+ case PWM4:
+ tcon &= ~0x00080000;
+ tcon |= S3C2410_TCON_T4RELOAD;
+ tcon |= S3C2410_TCON_T3MANUALUPD;
+ }
+
+ __raw_writel(tcon, S3C2410_TCON);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c2410_pwm_stop);
+
+int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm_t *s3c2410_pwm)
+{
+ __raw_writel(reg_value, S3C2410_TCMPB(s3c2410_pwm->timerid));
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c2410_pwm_duty_cycle);
+
+int s3c2410_pwm_dumpregs(void)
+{
+ printk(KERN_INFO "TCON: %08lx, TCFG0: %08lx, TCFG1: %08lx\n",
+ (unsigned long) __raw_readl(S3C2410_TCON),
+ (unsigned long) __raw_readl(S3C2410_TCFG0),
+ (unsigned long) __raw_readl(S3C2410_TCFG1));
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c2410_pwm_dumpregs);
+
diff -uprN -X dontdiff linux-2.6.22.5/include/asm-arm/arch-s3c2410/s3c2410-pwm.h linux-2.6.22.5.new/include/asm-arm/arch-s3c2410/s3c2410-pwm.h
--- linux-2.6.22.5/include/asm-arm/arch-s3c2410/s3c2410-pwm.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22.5.new/include/asm-arm/arch-s3c2410/s3c2410-pwm.h 2007-09-16 10:59:22.000000000 +0200
@@ -0,0 +1,41 @@
+#ifndef __S3C2410_PWM_H
+#define __S3C2410_PWM_H
+
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm-arm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/regs-timer.h>
+#include <asm/arch/gta01.h>
+
+enum pwm_timer {
+ PWM0,
+ PWM1,
+ PWM2,
+ PWM3,
+ PWM4
+};
+
+struct s3c2410_pwm_t {
+ enum pwm_timer timerid;
+ struct clk *pclk;
+ unsigned long pclk_rate;
+ unsigned long prescaler;
+ unsigned long divider;
+ unsigned long counter;
+ unsigned long comparer;
+};
+
+struct s3c2410_pwm_t *s3c2410_pwm_alloc(void);
+int s3c2410_pwm_enable(struct s3c2410_pwm_t *s3c2410_pwm);
+int s3c2410_pwm_disable(struct s3c2410_pwm_t *s3c2410_pwm);
+int s3c2410_pwm_start(struct s3c2410_pwm_t *s3c2410_pwm);
+int s3c2410_pwm_stop(struct s3c2410_pwm_t *s3c2410_pwm);
+int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm_t *s3c2410_pwm);
+int s3c2410_pwm_dumpregs(void);
+
+#endif /* __S3C2410_PWM_H */
+