[PATCH 10/14] MACH SAMSUNG/S3C: Re-work the S3C family timer driver

Juergen Beisert jbe at pengutronix.de
Mon Jan 2 06:43:58 EST 2012


After separation and after all S3C macros are now present, change the driver
to be more generic for future additions.

The timer registers in the S3C24XX family are only 16 bit wide. But these
registers can be read and written in a 32 bit manner. This is important to share
code with more recent CPUs which comes with 32 bit registers.

Signed-off-by: Juergen Beisert <jbe at pengutronix.de>
---
 arch/arm/mach-samsung/s3c-timer.c |   78 ++++++++++++++++++++++++++++--------
 1 files changed, 60 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mach-samsung/s3c-timer.c b/arch/arm/mach-samsung/s3c-timer.c
index d9dae55..6665c8c 100644
--- a/arch/arm/mach-samsung/s3c-timer.c
+++ b/arch/arm/mach-samsung/s3c-timer.c
@@ -37,36 +37,78 @@
 #define S3C_TCNTB4 (S3C_TIMER_BASE + 0x3c)
 #define S3C_TCNTO4 (S3C_TIMER_BASE + 0x40)
 
+#define TIMER_WIDTH 16
+#define TIMER_SHIFT 10
+#define PRE_MUX 3
+#define PRE_MUX_ADD 1
+static const uint32_t max = 0x0000ffff;
 
-static uint64_t s3c24xx_clocksource_read(void)
+static void s3c_init_t4_clk_source(void)
+{
+	unsigned reg;
+
+	reg = readl(S3C_TCON) & ~S3C_TCON_T4MASK; /* stop timer 4 */
+	writel(reg, S3C_TCON);
+	reg = readl(S3C_TCFG0) & ~S3C_TCFG0_T4MASK;
+	reg |= S3C_TCFG0_SET_PSCL234(0); /* 0 means pre scaler is '256' */
+	writel(reg, S3C_TCFG0);
+	reg = readl(S3C_TCFG1) & ~S3C_TCFG1_T4MASK;
+	reg |= S3C_TCFG1_SET_T4MUX(PRE_MUX); /* / 16 */
+	writel(reg, S3C_TCFG1);
+}
+
+static unsigned s3c_get_t4_clk(void)
+{
+	unsigned clk = s3c_get_pclk();
+	unsigned pre = S3C_TCFG0_GET_PSCL234(readl(S3C_TCFG0)) + 1;
+	unsigned div = S3C_TCFG1_GET_T4MUX(readl(S3C_TCFG1)) + PRE_MUX_ADD;
+
+	return clk / pre / (1 << div);
+}
+
+static void s3c_timer_init(void)
+{
+	unsigned tcon;
+
+	tcon = readl(S3C_TCON) & ~S3C_TCON_T4MASK;
+
+	writel(max, S3C_TCNTB4);	/* reload value */
+	/* force a manual counter update */
+	writel(tcon | S3C_TCON_T4MANUALUPD, S3C_TCON);
+}
+
+static void s3c_timer_start(void)
+{
+	unsigned tcon;
+
+	tcon  = readl(S3C_TCON) & ~S3C_TCON_T4MANUALUPD;
+	tcon |= S3C_TCON_T4START | S3C_TCON_T4RELOAD;
+	writel(tcon, S3C_TCON);
+}
+
+static uint64_t s3c_clocksource_read(void)
 {
 	/* note: its a down counter */
-	return 0xFFFF - readw(S3C_TCNTO4);
+	return max - readl(S3C_TCNTO4);
 }
 
 static struct clocksource cs = {
-	.read	= s3c24xx_clocksource_read,
-	.mask	= CLOCKSOURCE_MASK(16),
-	.shift	= 10,
+	.read = s3c_clocksource_read,
+	.mask = CLOCKSOURCE_MASK(TIMER_WIDTH),
+	.shift = TIMER_SHIFT,
 };
 
-static int clocksource_init(void)
+static int s3c_clk_src_init(void)
 {
-	uint32_t p_clk = s3c_get_pclk();
-
-	writel(0x00000000, S3C_TCON);	/* stop all timers */
-	writel(0x00ffffff, S3C_TCFG0);	/* PCLK / (255 + 1) for timer 4 */
-	writel(0x00030000, S3C_TCFG1);	/* /16 */
-
-	writew(0xffff, S3C_TCNTB4);	/* reload value is TOP */
+	/* select its clock source first */
+	s3c_init_t4_clk_source();
 
-	writel(0x00600000, S3C_TCON);	/* force a first reload */
-	writel(0x00400000, S3C_TCON);
-	writel(0x00500000, S3C_TCON);	/* enable timer 4 with auto reload */
+	s3c_timer_init();
+	s3c_timer_start();
 
-	cs.mult = clocksource_hz2mult(p_clk / ((255 + 1) * 16), cs.shift);
+	cs.mult = clocksource_hz2mult(s3c_get_t4_clk(), cs.shift);
 	init_clock(&cs);
 
 	return 0;
 }
-core_initcall(clocksource_init);
+core_initcall(s3c_clk_src_init);
-- 
1.7.7.3




More information about the barebox mailing list