static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
/* Clock event handling */
-static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
+static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt, int force)
{
unsigned long tmp;
- unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
- unsigned long offset = mevt->base + MCT_L_TCON_OFFSET;
- tmp = readl_relaxed(reg_base + offset);
- if (tmp & mask) {
- tmp &= ~mask;
- exynos4_mct_write(tmp, offset);
+ /* clear MCT local interrupt */
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
+
+ if (force || !clockevent_state_periodic(&mevt->evt)) {
+ tmp = readl_relaxed(reg_base + mevt->base + MCT_L_TCON_OFFSET);
+ tmp &= ~(MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START | MCT_L_TCON_INTERVAL_MODE);
+ exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
}
}
-static void exynos4_mct_tick_start(unsigned long cycles,
+static void exynos4_mct_tick_start(unsigned long cycles, int periodic,
struct mct_clock_event_device *mevt)
{
unsigned long tmp;
- exynos4_mct_tick_stop(mevt);
-
tmp = (1 << 31) | cycles; /* MCT_L_UPDATE_ICNTB */
/* update interrupt count buffer */
/* enable MCT tick interrupt */
exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
- tmp = readl_relaxed(reg_base + mevt->base + MCT_L_TCON_OFFSET);
- tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START |
- MCT_L_TCON_INTERVAL_MODE;
+ tmp = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
+
+ if (periodic || clockevent_state_periodic(&mevt->evt))
+ tmp |= MCT_L_TCON_INTERVAL_MODE;
+
exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
}
struct mct_clock_event_device *mevt;
mevt = container_of(evt, struct mct_clock_event_device, evt);
- exynos4_mct_tick_start(cycles, mevt);
+ exynos4_mct_tick_start(cycles, 0, mevt);
return 0;
}
struct mct_clock_event_device *mevt;
mevt = container_of(evt, struct mct_clock_event_device, evt);
- exynos4_mct_tick_stop(mevt);
+ exynos4_mct_tick_stop(mevt, 1);
return 0;
}
mevt = container_of(evt, struct mct_clock_event_device, evt);
cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult)
>> evt->shift);
- exynos4_mct_tick_stop(mevt);
- exynos4_mct_tick_start(cycles_per_jiffy, mevt);
+ exynos4_mct_tick_stop(mevt, 1);
+ exynos4_mct_tick_start(cycles_per_jiffy, 1, mevt);
return 0;
}
-static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
-{
- /*
- * This is for supporting oneshot mode.
- * Mct would generate interrupt periodically
- * without explicit stopping.
- */
- if (!clockevent_state_periodic(&mevt->evt))
- exynos4_mct_tick_stop(mevt);
-
- /* Clear the MCT tick interrupt */
- if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1)
- exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
-}
-
static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
{
struct mct_clock_event_device *mevt = dev_id;
struct clock_event_device *evt = &mevt->evt;
- exynos4_mct_tick_clear(mevt);
+ exynos4_mct_tick_stop(mevt, 0);
evt->event_handler(evt);