All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zhong Hongbo <bocui107@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] =?yes?q?=5BV2=2004/15=5D=20S3C64XX=3A=20add=20pwm=20for=20s3c64xx=20support?=
Date: Sat, 14 Jul 2012 00:11:42 +0800	[thread overview]
Message-ID: <1342195913-25161-5-git-send-email-bocui107@gmail.com> (raw)
In-Reply-To: <1342195913-25161-1-git-send-email-bocui107@gmail.com>

From: Zhong Hongbo <bocui107@gmail.com>

Signed-off-by: Zhong Hongbo <bocui107@gmail.com>
---
Change for V2:
	- Change the type of the return value from unsinged int
	  to unsinged long for s3c64xx_get_base_nand function.
---
 arch/arm/cpu/arm1176/s3c64xx/Makefile       |    1 +
 arch/arm/cpu/arm1176/s3c64xx/pwm.c          |  189 +++++++++++++++++++++++++++
 arch/arm/include/asm/arch-s3c64xx/pwm.h     |   70 ++++++++++
 arch/arm/include/asm/arch-s3c64xx/s3c6400.h |   56 ++-------
 arch/arm/include/asm/arch-s3c64xx/s3c64x0.h |   59 ---------
 include/configs/smdk6400.h                  |    3 +
 6 files changed, 272 insertions(+), 106 deletions(-)
 create mode 100644 arch/arm/cpu/arm1176/s3c64xx/pwm.c
 create mode 100644 arch/arm/include/asm/arch-s3c64xx/pwm.h
 delete mode 100644 arch/arm/include/asm/arch-s3c64xx/s3c64x0.h

diff --git a/arch/arm/cpu/arm1176/s3c64xx/Makefile b/arch/arm/cpu/arm1176/s3c64xx/Makefile
index 0785b19..966663f 100644
--- a/arch/arm/cpu/arm1176/s3c64xx/Makefile
+++ b/arch/arm/cpu/arm1176/s3c64xx/Makefile
@@ -32,6 +32,7 @@ SOBJS	= reset.o
 
 COBJS-$(CONFIG_S3C6400)	+= cpu_init.o speed.o
 COBJS-y	+= timer.o
+COBJS-$(CONFIG_PWM) += pwm.o
 
 OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS-y))
 
diff --git a/arch/arm/cpu/arm1176/s3c64xx/pwm.c b/arch/arm/cpu/arm1176/s3c64xx/pwm.c
new file mode 100644
index 0000000..d1d70ff
--- /dev/null
+++ b/arch/arm/cpu/arm1176/s3c64xx/pwm.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012
+ *
+ * Zhong Hongbo <bocui107@gmail.com>
+ *
+ * based on arch/arm/cpu/armv7/s5p-common/sromc.c
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * 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 <common.h>
+#include <errno.h>
+#include <pwm.h>
+#include <asm/io.h>
+#include <asm/arch/s3c6400.h>
+#include <asm/arch/pwm.h>
+
+int pwm_enable(int pwm_id)
+{
+	const struct s3c_timer *pwm =
+			(struct s3c_timer *)s3c64xx_get_base_timer();
+	unsigned long tcon;
+
+	tcon = readl(&pwm->tcon);
+	tcon |= TCON_START(pwm_id);
+
+	writel(tcon, &pwm->tcon);
+
+	return 0;
+}
+
+void pwm_disable(int pwm_id)
+{
+	const struct s3c_timer *pwm =
+			(struct s3c_timer *)s3c64xx_get_base_timer();
+	unsigned long tcon;
+
+	tcon = readl(&pwm->tcon);
+	tcon &= ~TCON_START(pwm_id);
+
+	writel(tcon, &pwm->tcon);
+}
+
+static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
+{
+	unsigned long tin_parent_rate;
+	unsigned int div;
+
+	tin_parent_rate = get_PCLK();
+
+	for (div = 2; div <= 16; div *= 2) {
+		if ((tin_parent_rate / (div << 16)) < freq)
+			return tin_parent_rate / div;
+	}
+
+	return tin_parent_rate / 16;
+}
+
+#define NS_IN_HZ (1000000000UL)
+
+int pwm_config(int pwm_id, int duty_ns, int period_ns)
+{
+	const struct s3c_timer *pwm =
+			(struct s3c_timer *)s3c64xx_get_base_timer();
+	unsigned int offset;
+	unsigned long tin_rate;
+	unsigned long tin_ns;
+	unsigned long period;
+	unsigned long tcon;
+	unsigned long tcnt;
+	unsigned long tcmp;
+
+	/*
+	 * We currently avoid using 64bit arithmetic by using the
+	 * fact that anything faster than 1GHz is easily representable
+	 * by 32bits.
+	 */
+	if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ)
+		return -ERANGE;
+
+	if (duty_ns > period_ns)
+		return -EINVAL;
+
+	period = NS_IN_HZ / period_ns;
+
+	/* Check to see if we are changing the clock rate of the PWM */
+	tin_rate = pwm_calc_tin(pwm_id, period);
+
+	tin_ns = NS_IN_HZ / tin_rate;
+	tcnt = period_ns / tin_ns;
+
+	/* Note, counters count down */
+	tcmp = duty_ns / tin_ns;
+	tcmp = tcnt - tcmp;
+
+	/*
+	 * the pwm hw only checks the compare register after a decrement,
+	 * so the pin never toggles if tcmp = tcnt
+	 */
+	if (tcmp == tcnt)
+		tcmp--;
+
+	if (tcmp < 0)
+		tcmp = 0;
+
+	/* Update the PWM register block. */
+	offset = pwm_id * 3;
+	if (pwm_id < 4) {
+		writel(tcnt, &pwm->tcntb0 + offset);
+		writel(tcmp, &pwm->tcmpb0 + offset);
+	}
+
+	tcon = readl(&pwm->tcon);
+	tcon |= TCON_UPDATE(pwm_id);
+	if (pwm_id < 4)
+		tcon |= TCON_AUTO_RELOAD(pwm_id);
+	else
+		tcon |= TCON4_AUTO_RELOAD;
+	writel(tcon, &pwm->tcon);
+
+	tcon &= ~TCON_UPDATE(pwm_id);
+	writel(tcon, &pwm->tcon);
+
+	return 0;
+}
+
+int pwm_init(int pwm_id, int div, int invert)
+{
+	u32 val;
+	const struct s3c_timer *pwm =
+			(struct s3c_timer *)s3c64xx_get_base_timer();
+	unsigned long timer_rate_hz;
+	unsigned int offset, prescaler;
+
+	/*
+	 * Timer Freq(HZ) =
+	 *	PWM_CLK / { (prescaler_value + 1) * (divider_value) }
+	 */
+
+	val = readl(&pwm->tcfg0);
+	if (pwm_id < 2) {
+		prescaler = PRESCALER_0;
+		val &= ~0xff;
+		val |= (prescaler & 0xff);
+	} else {
+		prescaler = PRESCALER_1;
+		val &= ~(0xff << 8);
+		val |= (prescaler & 0xff) << 8;
+	}
+	writel(val, &pwm->tcfg0);
+	val = readl(&pwm->tcfg1);
+	val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
+	val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
+	writel(val, &pwm->tcfg1);
+
+	timer_rate_hz = get_PCLK() / ((prescaler + 1) *
+			(div + 1));
+
+	timer_rate_hz = timer_rate_hz / CONFIG_SYS_HZ;
+
+	/* set count value */
+	offset = pwm_id * 3;
+	writel(timer_rate_hz, &pwm->tcntb0 + offset);
+
+	val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
+	if (invert && (pwm_id < 4))
+		val |= TCON_INVERTER(pwm_id);
+	writel(val, &pwm->tcon);
+
+	pwm_enable(pwm_id);
+
+	return 0;
+}
diff --git a/arch/arm/include/asm/arch-s3c64xx/pwm.h b/arch/arm/include/asm/arch-s3c64xx/pwm.h
new file mode 100644
index 0000000..1e18f8c
--- /dev/null
+++ b/arch/arm/include/asm/arch-s3c64xx/pwm.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012
+ * Zhong Hongbo <bocui107@gmail.com>
+ *
+ * based on arch/arm/include/asm/arch-s5pc1xx/pwm.h
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ */
+
+#ifndef __ASM_ARM_ARCH_PWM_H_
+#define __ASM_ARM_ARCH_PWM_H_
+
+#define PRESCALER_0		(8 - 1)		/* prescaler of timer 0, 1 */
+#define PRESCALER_1		(16 - 1)	/* prescaler of timer 2, 3, 4 */
+
+/* Divider MUX */
+#define MUX_DIV_1		0		/* 1/1 period */
+#define MUX_DIV_2		1		/* 1/2 period */
+#define MUX_DIV_4		2		/* 1/4 period */
+#define MUX_DIV_8		3		/* 1/8 period */
+#define MUX_DIV_16		4		/* 1/16 period */
+
+#define MUX_DIV_SHIFT(x)	(x * 4)
+
+#define TCON_OFFSET(x)		((x + 1) * (!!x) << 2)
+
+#define TCON_START(x)		(1 << TCON_OFFSET(x))
+#define TCON_UPDATE(x)		(1 << (TCON_OFFSET(x) + 1))
+#define TCON_INVERTER(x)	(1 << (TCON_OFFSET(x) + 2))
+#define TCON_AUTO_RELOAD(x)	(1 << (TCON_OFFSET(x) + 3))
+#define TCON4_AUTO_RELOAD	(1 << 22)
+
+#define TCFG1_DMA(x)		(x << 20)
+
+#ifndef __ASSEMBLY__
+struct s3c_timer {
+	unsigned int	tcfg0;
+	unsigned int	tcfg1;
+	unsigned int	tcon;
+	unsigned int	tcntb0;
+	unsigned int	tcmpb0;
+	unsigned int	tcnto0;
+	unsigned int	tcntb1;
+	unsigned int	tcmpb1;
+	unsigned int	tcnto1;
+	unsigned int	tcntb2;
+	unsigned int	res1;
+	unsigned int	tcnto2;
+	unsigned int	tcntb3;
+	unsigned int	res2;
+	unsigned int	tcnto3;
+	unsigned int	tcntb4;
+	unsigned int	tcnto4;
+	unsigned int	tint_cstat;
+};
+#endif
+#endif
diff --git a/arch/arm/include/asm/arch-s3c64xx/s3c6400.h b/arch/arm/include/asm/arch-s3c64xx/s3c6400.h
index 77b9509..b884763 100644
--- a/arch/arm/include/asm/arch-s3c64xx/s3c6400.h
+++ b/arch/arm/include/asm/arch-s3c64xx/s3c6400.h
@@ -31,6 +31,10 @@
 #ifndef __S3C6400_H__
 #define __S3C6400_H__
 
+#if defined(CONFIG_SYNC_MODE) && defined(CONFIG_S3C6400)
+#error CONFIG_SYNC_MODE unavailable on S3C6400, please, fix your configuration!
+#endif
+
 #define S3C64XX_UART_CHANNELS	3
 #define S3C64XX_SPI_CHANNELS	2
 
@@ -587,51 +591,6 @@
  */
 #define ELFIN_TIMER_BASE	0x7F006000
 
-#define TCFG0_REG	__REG(0x7F006000)
-#define TCFG1_REG	__REG(0x7F006004)
-#define TCON_REG	__REG(0x7F006008)
-#define TCNTB0_REG	__REG(0x7F00600c)
-#define TCMPB0_REG	__REG(0x7F006010)
-#define TCNTO0_REG	__REG(0x7F006014)
-#define TCNTB1_REG	__REG(0x7F006018)
-#define TCMPB1_REG	__REG(0x7F00601c)
-#define TCNTO1_REG	__REG(0x7F006020)
-#define TCNTB2_REG	__REG(0x7F006024)
-#define TCMPB2_REG	__REG(0x7F006028)
-#define TCNTO2_REG	__REG(0x7F00602c)
-#define TCNTB3_REG	__REG(0x7F006030)
-#define TCMPB3_REG	__REG(0x7F006034)
-#define TCNTO3_REG	__REG(0x7F006038)
-#define TCNTB4_REG	__REG(0x7F00603c)
-#define TCNTO4_REG	__REG(0x7F006040)
-
-/* Fields */
-#define fTCFG0_DZONE		Fld(8, 16) /* the dead zone length (=timer 0) */
-#define fTCFG0_PRE1		Fld(8, 8)  /* prescaler value for time 2,3,4 */
-#define fTCFG0_PRE0		Fld(8, 0)  /* prescaler value for time 0,1 */
-#define fTCFG1_MUX4		Fld(4, 16)
-/* bits */
-#define TCFG0_DZONE(x)		FInsrt((x), fTCFG0_DZONE)
-#define TCFG0_PRE1(x)		FInsrt((x), fTCFG0_PRE1)
-#define TCFG0_PRE0(x)		FInsrt((x), fTCFG0_PRE0)
-#define TCON_4_AUTO		(1 << 22)  /* auto reload on/off for Timer 4 */
-#define TCON_4_UPDATE		(1 << 21)  /* manual Update TCNTB4 */
-#define TCON_4_ONOFF		(1 << 20)  /* 0: Stop, 1: start Timer 4 */
-#define COUNT_4_ON		(TCON_4_ONOFF * 1)
-#define COUNT_4_OFF		(TCON_4_ONOFF * 0)
-#define TCON_3_AUTO		(1 << 19)  /* auto reload on/off for Timer 3 */
-#define TIMER3_ATLOAD_ON	(TCON_3_AUTO * 1)
-#define TIMER3_ATLAOD_OFF	FClrBit(TCON, TCON_3_AUTO)
-#define TCON_3_INVERT		(1 << 18)  /* 1: Inverter on for TOUT3 */
-#define TIMER3_IVT_ON		(TCON_3_INVERT * 1)
-#define TIMER3_IVT_OFF		(FClrBit(TCON, TCON_3_INVERT))
-#define TCON_3_MAN		(1 << 17)  /* manual Update TCNTB3,TCMPB3 */
-#define TIMER3_MANUP		(TCON_3_MAN*1)
-#define TIMER3_NOP		(FClrBit(TCON, TCON_3_MAN))
-#define TCON_3_ONOFF		(1 << 16)  /* 0: Stop, 1: start Timer 3 */
-#define TIMER3_ON		(TCON_3_ONOFF * 1)
-#define TIMER3_OFF		(FClrBit(TCON, TCON_3_ONOFF))
-
 #if defined(CONFIG_CLK_400_100_50)
 #define STARTUP_AMDIV		400
 #define STARTUP_MDIV		400
@@ -749,8 +708,6 @@
 
 #ifndef __ASSEMBLY__
 
-#include "s3c64x0.h"
-
 static inline unsigned long s3c64xx_get_base_uart(void)
 {
 	return ELFIN_UART_BASE;
@@ -760,6 +717,11 @@ static inline unsigned long s3c64xx_get_base_nand(void)
 {
 	return ELFIN_NAND_BASE;
 }
+
+static inline unsigned long s3c64xx_get_base_timer(void)
+{
+	return ELFIN_TIMER_BASE;
+}
 #endif
 
 #endif /*__S3C6400_H__*/
diff --git a/arch/arm/include/asm/arch-s3c64xx/s3c64x0.h b/arch/arm/include/asm/arch-s3c64xx/s3c64x0.h
deleted file mode 100644
index 7add68c..0000000
--- a/arch/arm/include/asm/arch-s3c64xx/s3c64x0.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * (C) Copyright 2003
- * David M????ller ELSOFT AG Switzerland. d.mueller at elsoft.ch
- *
- * (C) Copyright 2008
- * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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
- */
-
-/************************************************
- * NAME	    : S3C64XX.h
- * Version  : 31.3.2003
- *
- * common stuff for SAMSUNG S3C64XX SoC
- ************************************************/
-
-#ifndef __S3C64XX_H__
-#define __S3C64XX_H__
-
-#if defined(CONFIG_SYNC_MODE) && defined(CONFIG_S3C6400)
-#error CONFIG_SYNC_MODE unavailable on S3C6400, please, fix your configuration!
-#endif
-
-#include <asm/types.h>
-
-/* PWM TIMER (see manual chapter 10) */
-typedef struct {
-	volatile u32	TCNTB;
-	volatile u32	TCMPB;
-	volatile u32	TCNTO;
-} s3c64xx_timer;
-
-typedef struct {
-	volatile u32	TCFG0;
-	volatile u32	TCFG1;
-	volatile u32	TCON;
-	s3c64xx_timer	ch[4];
-	volatile u32	TCNTB4;
-	volatile u32	TCNTO4;
-} s3c64xx_timers;
-
-#endif /*__S3C64XX_H__*/
diff --git a/include/configs/smdk6400.h b/include/configs/smdk6400.h
index 47326d6..3642a5c 100644
--- a/include/configs/smdk6400.h
+++ b/include/configs/smdk6400.h
@@ -141,6 +141,9 @@
 
 #define CONFIG_SYS_HZ			1000
 
+/* PWM */
+#define CONFIG_PWM                     1
+
 /*-----------------------------------------------------------------------
  * Stack sizes
  *
-- 
1.7.5.4

  parent reply	other threads:[~2012-07-13 16:11 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-13 16:11 [U-Boot] V2 S3c64xx: Switch all I/O to use readl/writel functio and Clear variable Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 01/15] SMDK6400: Move smdk6400 board from Makefile to boards.cfg Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 02/15] S3C64XX: Switch to use readl/writel to operate nand flash Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 03/15] S3C64XX: Use readl/writel to operate uart Zhong Hongbo
2012-07-13 16:11 ` Zhong Hongbo [this message]
2012-07-13 16:21   ` [U-Boot] [V2 04/15] S3C64XX: add pwm for s3c64xx support Zhong Hongbo
2012-07-19 22:04   ` Zhong Hongbo
2012-07-20  3:14     ` Minkyu Kang
2012-07-13 16:11 ` [U-Boot] [V2 05/15] S3C64XX: reference s5p cpu time system for s3c64xx timer Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 06/15] S3C64xx: mov cpu_init.S to the board directory Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 07/15] S3C6400: Delete nand_spl for S3C6400 Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 08/15] S3C6400: Adopt SPL framwork to support spl for nand flash Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 09/15] arm1176: Fixed No relocation Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 10/15] S3C64XX: Change SROM init to use read/write operation Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 11/15] S3C64XX: Switch to use read/writel to operation clock system Zhong Hongbo
2012-07-24  8:58   ` Minkyu Kang
2012-07-24 14:40     ` Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 12/15] S3c64xx: clear GPIO, Interrupt, Watchdog variable Zhong Hongbo
2012-07-24  8:47   ` Minkyu Kang
2012-07-13 16:11 ` [U-Boot] [V2 13/15] S3C6400: clear memory init variable Zhong Hongbo
2012-07-24  8:44   ` Minkyu Kang
2012-07-13 16:11 ` [U-Boot] [V2 14/15] S3C64XX: Move s3c6400.h to cpu.h to support s3c6410 board Zhong Hongbo
2012-07-24  2:38   ` Minkyu Kang
2012-07-24 14:45     ` Zhong Hongbo
2012-07-13 16:11 ` [U-Boot] [V2 15/15] S3C6400: Remove the unused variable for S3C6400 Zhong Hongbo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1342195913-25161-5-git-send-email-bocui107@gmail.com \
    --to=bocui107@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.