aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clocksource/sun4i_timer.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c
index 8e9c65136451..7123f654ce71 100644
--- a/drivers/clocksource/sun4i_timer.c
+++ b/drivers/clocksource/sun4i_timer.c
@@ -38,6 +38,20 @@
38 38
39static void __iomem *timer_base; 39static void __iomem *timer_base;
40 40
41/*
42 * When we disable a timer, we need to wait at least for 2 cycles of
43 * the timer source clock. We will use for that the clocksource timer
44 * that is already setup and runs at the same frequency than the other
45 * timers, and we never will be disabled.
46 */
47static void sun4i_clkevt_sync(void)
48{
49 u32 old = readl(timer_base + TIMER_CNTVAL_REG(1));
50
51 while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < 3)
52 cpu_relax();
53}
54
41static void sun4i_clkevt_mode(enum clock_event_mode mode, 55static void sun4i_clkevt_mode(enum clock_event_mode mode,
42 struct clock_event_device *clk) 56 struct clock_event_device *clk)
43{ 57{
@@ -63,9 +77,14 @@ static void sun4i_clkevt_mode(enum clock_event_mode mode,
63static int sun4i_clkevt_next_event(unsigned long evt, 77static int sun4i_clkevt_next_event(unsigned long evt,
64 struct clock_event_device *unused) 78 struct clock_event_device *unused)
65{ 79{
66 u32 u = readl(timer_base + TIMER_CTL_REG(0)); 80 u32 val = readl(timer_base + TIMER_CTL_REG(0));
67 writel(evt, timer_base + TIMER_CNTVAL_REG(0)); 81 writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0));
68 writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD, 82 sun4i_clkevt_sync();
83
84 writel(evt, timer_base + TIMER_INTVAL_REG(0));
85
86 val = readl(timer_base + TIMER_CTL_REG(0));
87 writel(val | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD,
69 timer_base + TIMER_CTL_REG(0)); 88 timer_base + TIMER_CTL_REG(0));
70 89
71 return 0; 90 return 0;