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 */
+ 

Reply via email to