diff options
-rw-r--r-- | drivers/clocksource/sun4i_timer.c | 25 |
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 | ||
39 | static void __iomem *timer_base; | 39 | static 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 | */ | ||
47 | static 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 | |||
41 | static void sun4i_clkevt_mode(enum clock_event_mode mode, | 55 | static 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, | |||
63 | static int sun4i_clkevt_next_event(unsigned long evt, | 77 | static 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; |