openwrt/target/linux/s3c24xx/patches-2.6.24/1015-s3c2410-pwm.patch.patch

323 lines
7.9 KiB
Diff

From e9db29d62cbcef7974099c3a4deac69ad2a72190 Mon Sep 17 00:00:00 2001
From: mokopatches <mokopatches@openmoko.org>
Date: Fri, 4 Apr 2008 11:31:44 +0100
Subject: [PATCH] s3c2410-pwm.patch
This patch adds a PWM api abstraction for the S3C2410 SoC
Signed-off-by: Javi Roman <javiroman@kernel-labs.org>
Signed-off-by: Harald Welte <laforge@openmoko.org>
---
arch/arm/mach-s3c2410/Kconfig | 6 +
arch/arm/mach-s3c2410/Makefile | 1 +
arch/arm/mach-s3c2410/pwm.c | 214 ++++++++++++++++++++++++++++++++++++
include/asm-arm/arch-s3c2410/pwm.h | 40 +++++++
4 files changed, 261 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-s3c2410/pwm.c
create mode 100644 include/asm-arm/arch-s3c2410/pwm.h
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index ff339e1..e42195f 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -9,6 +9,7 @@ config CPU_S3C2410
depends on ARCH_S3C2410
select S3C2410_CLOCK
select S3C2410_GPIO
+ select S3C2410_PWM
select CPU_LLSERIAL_S3C2410
select S3C2410_PM if PM
help
@@ -37,6 +38,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 --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 8952a8d..bb577f4 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -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) += pwm.o
# Machine support
diff --git a/arch/arm/mach-s3c2410/pwm.c b/arch/arm/mach-s3c2410/pwm.c
new file mode 100644
index 0000000..8a07359
--- /dev/null
+++ b/arch/arm/mach-s3c2410/pwm.c
@@ -0,0 +1,214 @@
+/*
+ * arch/arm/mach-s3c2410/3c2410-pwm.c
+ *
+ * Copyright (c) by Javi Roman <javiroman@kernel-labs.org>
+ * for the OpenMoko Project.
+ *
+ * S3C2410A SoC PWM support
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <asm/hardware.h>
+#include <asm/plat-s3c/regs-timer.h>
+#include <asm/arch/pwm.h>
+
+int s3c2410_pwm_disable(struct s3c2410_pwm *pwm)
+{
+ unsigned long tcon;
+
+ /* stop timer */
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon &= 0xffffff00;
+ __raw_writel(tcon, S3C2410_TCON);
+
+ clk_disable(pwm->pclk);
+ clk_put(pwm->pclk);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2410_pwm_disable);
+
+int s3c2410_pwm_init(struct s3c2410_pwm *pwm)
+{
+ pwm->pclk = clk_get(NULL, "timers");
+ if (IS_ERR(pwm->pclk))
+ return PTR_ERR(pwm->pclk);
+
+ clk_enable(pwm->pclk);
+ pwm->pclk_rate = clk_get_rate(pwm->pclk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2410_pwm_init);
+
+int s3c2410_pwm_enable(struct s3c2410_pwm *pwm)
+{
+ unsigned long tcfg0, tcfg1, tcnt, tcmp;
+
+ /* control registers bits */
+ tcfg1 = __raw_readl(S3C2410_TCFG1);
+ tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+ /* divider & scaler slection */
+ switch (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:
+ /* timer four is not capable of doing PWM */
+ break;
+ default:
+ clk_disable(pwm->pclk);
+ clk_put(pwm->pclk);
+ return -1;
+ }
+
+ /* divider & scaler values */
+ tcfg1 |= pwm->divider;
+ __raw_writel(tcfg1, S3C2410_TCFG1);
+
+ switch (pwm->timerid) {
+ case PWM0:
+ case PWM1:
+ tcfg0 |= pwm->prescaler;
+ __raw_writel(tcfg0, S3C2410_TCFG0);
+ break;
+ default:
+ if ((tcfg0 | pwm->prescaler) != tcfg0) {
+ printk(KERN_WARNING "not changing prescaler of PWM %u,"
+ " since it's shared with timer4 (clock tick)\n",
+ pwm->timerid);
+ }
+ break;
+ }
+
+ /* timer count and compare buffer initial values */
+ tcnt = pwm->counter;
+ tcmp = pwm->comparer;
+
+ __raw_writel(tcnt, S3C2410_TCNTB(pwm->timerid));
+ __raw_writel(tcmp, S3C2410_TCMPB(pwm->timerid));
+
+ /* ensure timer is stopped */
+ s3c2410_pwm_stop(pwm);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2410_pwm_enable);
+
+int s3c2410_pwm_start(struct s3c2410_pwm *pwm)
+{
+ unsigned long tcon;
+
+ tcon = __raw_readl(S3C2410_TCON);
+
+ switch (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:
+ /* timer four is not capable of doing PWM */
+ default:
+ return -ENODEV;
+ }
+
+ __raw_writel(tcon, S3C2410_TCON);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2410_pwm_start);
+
+int s3c2410_pwm_stop(struct s3c2410_pwm *pwm)
+{
+ unsigned long tcon;
+
+ tcon = __raw_readl(S3C2410_TCON);
+
+ switch (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:
+ /* timer four is not capable of doing PWM */
+ default:
+ return -ENODEV;
+ }
+
+ __raw_writel(tcon, S3C2410_TCON);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2410_pwm_stop);
+
+int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *pwm)
+{
+ __raw_writel(reg_value, S3C2410_TCMPB(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 --git a/include/asm-arm/arch-s3c2410/pwm.h b/include/asm-arm/arch-s3c2410/pwm.h
new file mode 100644
index 0000000..a797ec3
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/pwm.h
@@ -0,0 +1,40 @@
+#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/plat-s3c/regs-timer.h>
+#include <asm/arch/gta01.h>
+
+enum pwm_timer {
+ PWM0,
+ PWM1,
+ PWM2,
+ PWM3,
+ PWM4
+};
+
+struct s3c2410_pwm {
+ enum pwm_timer timerid;
+ struct clk *pclk;
+ unsigned long pclk_rate;
+ unsigned long prescaler;
+ unsigned long divider;
+ unsigned long counter;
+ unsigned long comparer;
+};
+
+int s3c2410_pwm_init(struct s3c2410_pwm *s3c2410_pwm);
+int s3c2410_pwm_enable(struct s3c2410_pwm *s3c2410_pwm);
+int s3c2410_pwm_disable(struct s3c2410_pwm *s3c2410_pwm);
+int s3c2410_pwm_start(struct s3c2410_pwm *s3c2410_pwm);
+int s3c2410_pwm_stop(struct s3c2410_pwm *s3c2410_pwm);
+int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *s3c2410_pwm);
+int s3c2410_pwm_dumpregs(void);
+
+#endif /* __S3C2410_PWM_H */
--
1.5.6.5