diff options
Diffstat (limited to 'drivers/clocksource/sun4i_timer.c')
-rw-r--r-- | drivers/clocksource/sun4i_timer.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 7123f654ce71..dd78b63f3a24 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c | |||
@@ -52,24 +52,46 @@ static void sun4i_clkevt_sync(void) | |||
52 | cpu_relax(); | 52 | cpu_relax(); |
53 | } | 53 | } |
54 | 54 | ||
55 | static void sun4i_clkevt_time_stop(u8 timer) | ||
56 | { | ||
57 | u32 val = readl(timer_base + TIMER_CTL_REG(timer)); | ||
58 | writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); | ||
59 | sun4i_clkevt_sync(); | ||
60 | } | ||
61 | |||
62 | static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay) | ||
63 | { | ||
64 | writel(delay, timer_base + TIMER_INTVAL_REG(timer)); | ||
65 | } | ||
66 | |||
67 | static void sun4i_clkevt_time_start(u8 timer, bool periodic) | ||
68 | { | ||
69 | u32 val = readl(timer_base + TIMER_CTL_REG(timer)); | ||
70 | |||
71 | if (periodic) | ||
72 | val &= ~TIMER_CTL_ONESHOT; | ||
73 | else | ||
74 | val |= TIMER_CTL_ONESHOT; | ||
75 | |||
76 | writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer)); | ||
77 | } | ||
78 | |||
55 | static void sun4i_clkevt_mode(enum clock_event_mode mode, | 79 | static void sun4i_clkevt_mode(enum clock_event_mode mode, |
56 | struct clock_event_device *clk) | 80 | struct clock_event_device *clk) |
57 | { | 81 | { |
58 | u32 u = readl(timer_base + TIMER_CTL_REG(0)); | ||
59 | |||
60 | switch (mode) { | 82 | switch (mode) { |
61 | case CLOCK_EVT_MODE_PERIODIC: | 83 | case CLOCK_EVT_MODE_PERIODIC: |
62 | u &= ~(TIMER_CTL_ONESHOT); | 84 | sun4i_clkevt_time_stop(0); |
63 | writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0)); | 85 | sun4i_clkevt_time_start(0, true); |
64 | break; | 86 | break; |
65 | |||
66 | case CLOCK_EVT_MODE_ONESHOT: | 87 | case CLOCK_EVT_MODE_ONESHOT: |
67 | writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0)); | 88 | sun4i_clkevt_time_stop(0); |
89 | sun4i_clkevt_time_start(0, false); | ||
68 | break; | 90 | break; |
69 | case CLOCK_EVT_MODE_UNUSED: | 91 | case CLOCK_EVT_MODE_UNUSED: |
70 | case CLOCK_EVT_MODE_SHUTDOWN: | 92 | case CLOCK_EVT_MODE_SHUTDOWN: |
71 | default: | 93 | default: |
72 | writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0)); | 94 | sun4i_clkevt_time_stop(0); |
73 | break; | 95 | break; |
74 | } | 96 | } |
75 | } | 97 | } |
@@ -77,15 +99,9 @@ static void sun4i_clkevt_mode(enum clock_event_mode mode, | |||
77 | static int sun4i_clkevt_next_event(unsigned long evt, | 99 | static int sun4i_clkevt_next_event(unsigned long evt, |
78 | struct clock_event_device *unused) | 100 | struct clock_event_device *unused) |
79 | { | 101 | { |
80 | u32 val = readl(timer_base + TIMER_CTL_REG(0)); | 102 | sun4i_clkevt_time_stop(0); |
81 | writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0)); | 103 | sun4i_clkevt_time_setup(0, evt); |
82 | sun4i_clkevt_sync(); | 104 | sun4i_clkevt_time_start(0, false); |
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, | ||
88 | timer_base + TIMER_CTL_REG(0)); | ||
89 | 105 | ||
90 | return 0; | 106 | return 0; |
91 | } | 107 | } |