diff options
-rw-r--r-- | arch/arm/mach-msm/timer.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 405e8a925202..9f3671a43314 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c | |||
@@ -81,11 +81,20 @@ enum { | |||
81 | 81 | ||
82 | static struct msm_clock msm_clocks[]; | 82 | static struct msm_clock msm_clocks[]; |
83 | 83 | ||
84 | static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt); | ||
85 | |||
84 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) | 86 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) |
85 | { | 87 | { |
86 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | 88 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; |
87 | if (evt->event_handler == NULL) | 89 | if (evt->event_handler == NULL) |
88 | return IRQ_HANDLED; | 90 | return IRQ_HANDLED; |
91 | /* Stop the timer tick */ | ||
92 | if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { | ||
93 | struct msm_clock *clock = clockevent_to_clock(evt); | ||
94 | u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); | ||
95 | ctrl &= ~TIMER_ENABLE_EN; | ||
96 | writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE); | ||
97 | } | ||
89 | evt->event_handler(evt); | 98 | evt->event_handler(evt); |
90 | return IRQ_HANDLED; | 99 | return IRQ_HANDLED; |
91 | } | 100 | } |
@@ -118,10 +127,12 @@ static int msm_timer_set_next_event(unsigned long cycles, | |||
118 | struct clock_event_device *evt) | 127 | struct clock_event_device *evt) |
119 | { | 128 | { |
120 | struct msm_clock *clock = clockevent_to_clock(evt); | 129 | struct msm_clock *clock = clockevent_to_clock(evt); |
121 | uint32_t now = readl(clock->local_counter); | 130 | u32 match = cycles << clock->shift; |
122 | uint32_t alarm = now + (cycles << clock->shift); | 131 | u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); |
123 | 132 | ||
124 | writel(alarm, clock->regbase + TIMER_MATCH_VAL); | 133 | writel_relaxed(0, clock->regbase + TIMER_CLEAR); |
134 | writel_relaxed(match, clock->regbase + TIMER_MATCH_VAL); | ||
135 | writel_relaxed(ctrl | TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); | ||
125 | return 0; | 136 | return 0; |
126 | } | 137 | } |
127 | 138 | ||
@@ -129,19 +140,23 @@ static void msm_timer_set_mode(enum clock_event_mode mode, | |||
129 | struct clock_event_device *evt) | 140 | struct clock_event_device *evt) |
130 | { | 141 | { |
131 | struct msm_clock *clock = clockevent_to_clock(evt); | 142 | struct msm_clock *clock = clockevent_to_clock(evt); |
143 | u32 ctrl; | ||
144 | |||
145 | ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); | ||
146 | ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); | ||
132 | 147 | ||
133 | switch (mode) { | 148 | switch (mode) { |
134 | case CLOCK_EVT_MODE_RESUME: | 149 | case CLOCK_EVT_MODE_RESUME: |
135 | case CLOCK_EVT_MODE_PERIODIC: | 150 | case CLOCK_EVT_MODE_PERIODIC: |
136 | break; | 151 | break; |
137 | case CLOCK_EVT_MODE_ONESHOT: | 152 | case CLOCK_EVT_MODE_ONESHOT: |
138 | writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); | 153 | /* Timer is enabled in set_next_event */ |
139 | break; | 154 | break; |
140 | case CLOCK_EVT_MODE_UNUSED: | 155 | case CLOCK_EVT_MODE_UNUSED: |
141 | case CLOCK_EVT_MODE_SHUTDOWN: | 156 | case CLOCK_EVT_MODE_SHUTDOWN: |
142 | writel(0, clock->regbase + TIMER_ENABLE); | ||
143 | break; | 157 | break; |
144 | } | 158 | } |
159 | writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE); | ||
145 | } | 160 | } |
146 | 161 | ||
147 | static struct msm_clock msm_clocks[] = { | 162 | static struct msm_clock msm_clocks[] = { |