aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2011-11-08 13:34:06 -0500
committerDavid Brown <davidb@codeaurora.org>2011-11-10 13:36:33 -0500
commita850c3f6446d30b47c984d3f9e45c935385fd592 (patch)
treea859b3efb8dbdfe7e6498f7b93028d39ef6c5397 /arch/arm/mach-msm
parentdd15ab814149df65187943c32ca09e4eeaac0047 (diff)
msm: timer: Fix ONESHOT mode interrupts
MSM timers don't support an interrupt enable/disable bit. Therefore, when the timer is free running it's possible for the count to wrap and the match value to match again even though a set_next_event() call hasn't been made since the last match. Workaround the lack of an interrupt enable bit by explicitly stopping the timer in the interrupt handler when the clockevent is in ONESHOT mode. This should prevent any possibility of the timer wrapping and matching more than once per set_next_event(). Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'arch/arm/mach-msm')
-rw-r--r--arch/arm/mach-msm/timer.c25
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
82static struct msm_clock msm_clocks[]; 82static struct msm_clock msm_clocks[];
83 83
84static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt);
85
84static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) 86static 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
147static struct msm_clock msm_clocks[] = { 162static struct msm_clock msm_clocks[] = {