b9dfb81f2a
SVN-Revision: 13609
323 lines
8 KiB
Diff
Executable file
323 lines
8 KiB
Diff
Executable file
From 2b1ccb68bdc0e1454be0e769896862bf0c7f95f9 Mon Sep 17 00:00:00 2001
|
|
From: mokopatches <mokopatches@openmoko.org>
|
|
Date: Wed, 16 Jul 2008 14:44:49 +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 | 7 +
|
|
arch/arm/mach-s3c2410/Makefile | 1 +
|
|
arch/arm/mach-s3c2410/pwm.c | 214 ++++++++++++++++++++++++++++++++++++
|
|
include/asm-arm/arch-s3c2410/pwm.h | 40 +++++++
|
|
4 files changed, 262 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 58519e6..3e9ec50 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
|
|
@@ -38,6 +39,12 @@ config S3C2410_CLOCK
|
|
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"
|
|
|
|
config ARCH_SMDK2410
|
|
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
|
|
index b73562f..2a12a6a 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.3
|
|
|