aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/sun4i_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/sun4i_timer.c')
-rw-r--r--drivers/clocksource/sun4i_timer.c48
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
55static 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
62static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay)
63{
64 writel(delay, timer_base + TIMER_INTVAL_REG(timer));
65}
66
67static 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
55static void sun4i_clkevt_mode(enum clock_event_mode mode, 79static 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,
77static int sun4i_clkevt_next_event(unsigned long evt, 99static 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}