clocksource: exynos_mct: use (request/free)_irq calls for local timer registration
[linux-2.6-block.git] / drivers / clocksource / samsung_pwm_timer.c
index cb866156b8b0614779ebd93f0fb7b48163c16ed9..0234c8d2c8f26ccefc187be2385f103e8197f48c 100644 (file)
@@ -138,8 +138,6 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt)
 
        tcon = __raw_readl(pwm.base + REG_TCON);
 
-       tcnt--;
-
        tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan));
        tcon |= TCON_MANUALUPDATE(tcon_chan);
 
@@ -178,6 +176,19 @@ static void samsung_time_start(unsigned int channel, bool periodic)
 static int samsung_set_next_event(unsigned long cycles,
                                struct clock_event_device *evt)
 {
+       /*
+        * This check is needed to account for internal rounding
+        * errors inside clockevents core, which might result in
+        * passing cycles = 0, which in turn would not generate any
+        * timer interrupt and hang the system.
+        *
+        * Another solution would be to set up the clockevent device
+        * with min_delta = 2, but this would unnecessarily increase
+        * the minimum sleep period.
+        */
+       if (!cycles)
+               cycles = 1;
+
        samsung_time_setup(pwm.event_id, cycles);
        samsung_time_start(pwm.event_id, false);
 
@@ -187,7 +198,7 @@ static int samsung_set_next_event(unsigned long cycles,
 static void samsung_timer_resume(void)
 {
        /* event timer restart */
-       samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick);
+       samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1);
        samsung_time_start(pwm.event_id, true);
 
        /* source timer restart */
@@ -202,7 +213,7 @@ static void samsung_set_mode(enum clock_event_mode mode,
 
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
-               samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick);
+               samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1);
                samsung_time_start(pwm.event_id, true);
                break;