|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/clk.h>
|
|
|
#include <linux/io.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
|
|
|
#include <asm/system.h>
|
|
|
#include <asm/leds.h>
|
|
@@ -147,6 +148,10 @@ static struct irqaction s3c2410_timer_irq = {
|
|
|
machine_is_anubis() || \
|
|
|
machine_is_osiris())
|
|
|
|
|
|
+static struct clk *tin;
|
|
|
+static struct clk *tdiv;
|
|
|
+static struct clk *timerclk;
|
|
|
+
|
|
|
/*
|
|
|
* Set up timer interrupt, and return the current time in seconds.
|
|
|
*
|
|
@@ -162,12 +167,6 @@ static void s3c2410_timer_setup (void)
|
|
|
|
|
|
tcnt = TICK_MAX; /* default value for tcnt */
|
|
|
|
|
|
- /* read the current timer configuration bits */
|
|
|
-
|
|
|
- tcon = __raw_readl(S3C2410_TCON);
|
|
|
- tcfg1 = __raw_readl(S3C2410_TCFG1);
|
|
|
- tcfg0 = __raw_readl(S3C2410_TCFG0);
|
|
|
-
|
|
|
/* configure the system for whichever machine is in use */
|
|
|
|
|
|
if (use_tclk1_12()) {
|
|
@@ -175,11 +174,13 @@ static void s3c2410_timer_setup (void)
|
|
|
timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
|
|
|
tcnt = 12000000 / HZ;
|
|
|
|
|
|
+ tcfg1 = __raw_readl(S3C2410_TCFG1);
|
|
|
tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
|
|
|
tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
|
|
|
+ __raw_writel(tcfg1, S3C2410_TCFG1);
|
|
|
} else {
|
|
|
unsigned long pclk;
|
|
|
- struct clk *clk;
|
|
|
+ struct clk *tscaler;
|
|
|
|
|
|
/* for the h1940 (and others), we use the pclk from the core
|
|
|
* to generate the timer values. since values around 50 to
|
|
@@ -190,29 +191,25 @@ static void s3c2410_timer_setup (void)
|
|
|
* (8.45 ticks per usec)
|
|
|
*/
|
|
|
|
|
|
- /* this is used as default if no other timer can be found */
|
|
|
-
|
|
|
- clk = clk_get(NULL, "timers");
|
|
|
- if (IS_ERR(clk))
|
|
|
- panic("failed to get clock for system timer");
|
|
|
-
|
|
|
- clk_enable(clk);
|
|
|
-
|
|
|
- pclk = clk_get_rate(clk);
|
|
|
+ pclk = clk_get_rate(timerclk);
|
|
|
|
|
|
/* configure clock tick */
|
|
|
|
|
|
timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
|
|
|
|
|
|
- tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
|
|
|
- tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
|
|
|
+ tscaler = clk_get_parent(tdiv);
|
|
|
|
|
|
- tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
|
|
|
- tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
|
|
|
+ clk_set_rate(tscaler, pclk / 3);
|
|
|
+ clk_set_rate(tdiv, pclk / 6);
|
|
|
+ clk_set_parent(tin, tdiv);
|
|
|
|
|
|
- tcnt = (pclk / 6) / HZ;
|
|
|
+ tcnt = clk_get_rate(tin) / HZ;
|
|
|
}
|
|
|
|
|
|
+ tcon = __raw_readl(S3C2410_TCON);
|
|
|
+ tcfg0 = __raw_readl(S3C2410_TCFG0);
|
|
|
+ tcfg1 = __raw_readl(S3C2410_TCFG1);
|
|
|
+
|
|
|
/* timers reload after counting zero, so reduce the count by 1 */
|
|
|
|
|
|
tcnt--;
|
|
@@ -248,8 +245,35 @@ static void s3c2410_timer_setup (void)
|
|
|
__raw_writel(tcon, S3C2410_TCON);
|
|
|
}
|
|
|
|
|
|
+static void __init s3c2410_timer_resources(void)
|
|
|
+{
|
|
|
+ struct platform_device tmpdev;
|
|
|
+
|
|
|
+ tmpdev.dev.bus = &platform_bus_type;
|
|
|
+ tmpdev.id = 4;
|
|
|
+
|
|
|
+ timerclk = clk_get(NULL, "timers");
|
|
|
+ if (IS_ERR(timerclk))
|
|
|
+ panic("failed to get clock for system timer");
|
|
|
+
|
|
|
+ clk_enable(timerclk);
|
|
|
+
|
|
|
+ if (!use_tclk1_12()) {
|
|
|
+ tin = clk_get(&tmpdev.dev, "pwm-tin");
|
|
|
+ if (IS_ERR(tin))
|
|
|
+ panic("failed to get pwm-tin clock for system timer");
|
|
|
+
|
|
|
+ tdiv = clk_get(&tmpdev.dev, "pwm-tdiv");
|
|
|
+ if (IS_ERR(tdiv))
|
|
|
+ panic("failed to get pwm-tdiv clock for system timer");
|
|
|
+ }
|
|
|
+
|
|
|
+ clk_enable(tin);
|
|
|
+}
|
|
|
+
|
|
|
static void __init s3c2410_timer_init(void)
|
|
|
{
|
|
|
+ s3c2410_timer_resources();
|
|
|
s3c2410_timer_setup();
|
|
|
setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
|
|
|
}
|