Commit 5e359bf2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer updates from Thomas Gleixner:
 "Rather large, but nothing exiting:

   - new range check for settimeofday() to prevent that boot time
     becomes negative.
   - fix for file time rounding
   - a few simplifications of the hrtimer code
   - fix for the proc/timerlist code so the output of clock realtime
     timers is accurate
   - more y2038 work
   - tree wide conversion of clockevent drivers to the new callbacks"

* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (88 commits)
  hrtimer: Handle failure of tick_init_highres() gracefully
  hrtimer: Unconfuse switch_hrtimer_base() a bit
  hrtimer: Simplify get_target_base() by returning current base
  hrtimer: Drop return code of hrtimer_switch_to_hres()
  time: Introduce timespec64_to_jiffies()/jiffies_to_timespec64()
  time: Introduce current_kernel_time64()
  time: Introduce struct itimerspec64
  time: Add the common weak version of update_persistent_clock()
  time: Always make sure wall_to_monotonic isn't positive
  time: Fix nanosecond file time rounding in timespec_trunc()
  timer_list: Add the base offset so remaining nsecs are accurate for non monotonic timers
  cris/time: Migrate to new 'set-state' interface
  kernel: broadcast-hrtimer: Migrate to new 'set-state' interface
  xtensa/time: Migrate to new 'set-state' interface
  unicore/time: Migrate to new 'set-state' interface
  um/time: Migrate to new 'set-state' interface
  sparc/time: Migrate to new 'set-state' interface
  sh/localtimer: Migrate to new 'set-state' interface
  score/time: Migrate to new 'set-state' interface
  s390/time: Migrate to new 'set-state' interface
  ...
parents 8d01b66b 85e1cd6e
...@@ -93,7 +93,7 @@ rtc_timer_interrupt(int irq, void *dev) ...@@ -93,7 +93,7 @@ rtc_timer_interrupt(int irq, void *dev)
struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);
/* Don't run the hook for UNUSED or SHUTDOWN. */ /* Don't run the hook for UNUSED or SHUTDOWN. */
if (likely(ce->mode == CLOCK_EVT_MODE_PERIODIC)) if (likely(clockevent_state_periodic(ce)))
ce->event_handler(ce); ce->event_handler(ce);
if (test_irq_work_pending()) { if (test_irq_work_pending()) {
...@@ -104,13 +104,6 @@ rtc_timer_interrupt(int irq, void *dev) ...@@ -104,13 +104,6 @@ rtc_timer_interrupt(int irq, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void
rtc_ce_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
{
/* The mode member of CE is updated in generic code.
Since we only support periodic events, nothing to do. */
}
static int static int
rtc_ce_set_next_event(unsigned long evt, struct clock_event_device *ce) rtc_ce_set_next_event(unsigned long evt, struct clock_event_device *ce)
{ {
...@@ -129,7 +122,6 @@ init_rtc_clockevent(void) ...@@ -129,7 +122,6 @@ init_rtc_clockevent(void)
.features = CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_PERIODIC,
.rating = 100, .rating = 100,
.cpumask = cpumask_of(cpu), .cpumask = cpumask_of(cpu),
.set_mode = rtc_ce_set_mode,
.set_next_event = rtc_ce_set_next_event, .set_next_event = rtc_ce_set_next_event,
}; };
...@@ -161,12 +153,12 @@ static struct clocksource qemu_cs = { ...@@ -161,12 +153,12 @@ static struct clocksource qemu_cs = {
* The QEMU alarm as a clock_event_device primitive. * The QEMU alarm as a clock_event_device primitive.
*/ */
static void static int qemu_ce_shutdown(struct clock_event_device *ce)
qemu_ce_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
{ {
/* The mode member of CE is updated for us in generic code. /* The mode member of CE is updated for us in generic code.
Just make sure that the event is disabled. */ Just make sure that the event is disabled. */
qemu_set_alarm_abs(0); qemu_set_alarm_abs(0);
return 0;
} }
static int static int
...@@ -197,7 +189,9 @@ init_qemu_clockevent(void) ...@@ -197,7 +189,9 @@ init_qemu_clockevent(void)
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 400, .rating = 400,
.cpumask = cpumask_of(cpu), .cpumask = cpumask_of(cpu),
.set_mode = qemu_ce_set_mode, .set_state_shutdown = qemu_ce_shutdown,
.set_state_oneshot = qemu_ce_shutdown,
.tick_resume = qemu_ce_shutdown,
.set_next_event = qemu_ce_set_next_event, .set_next_event = qemu_ce_set_next_event,
}; };
......
...@@ -136,44 +136,44 @@ static int bfin_gptmr0_set_next_event(unsigned long cycles, ...@@ -136,44 +136,44 @@ static int bfin_gptmr0_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static void bfin_gptmr0_set_mode(enum clock_event_mode mode, static int bfin_gptmr0_set_periodic(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: {
#ifndef CONFIG_BF60x #ifndef CONFIG_BF60x
set_gptimer_config(TIMER0_id, \ set_gptimer_config(TIMER0_id,
TIMER_OUT_DIS | TIMER_IRQ_ENA | \ TIMER_OUT_DIS | TIMER_IRQ_ENA |
TIMER_PERIOD_CNT | TIMER_MODE_PWM); TIMER_PERIOD_CNT | TIMER_MODE_PWM);
#else #else
set_gptimer_config(TIMER0_id, TIMER_OUT_DIS set_gptimer_config(TIMER0_id,
| TIMER_MODE_PWM_CONT | TIMER_PULSE_HI | TIMER_IRQ_PER); TIMER_OUT_DIS | TIMER_MODE_PWM_CONT |
TIMER_PULSE_HI | TIMER_IRQ_PER);
#endif #endif
set_gptimer_period(TIMER0_id, get_sclk() / HZ); set_gptimer_period(TIMER0_id, get_sclk() / HZ);
set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1); set_gptimer_pwidth(TIMER0_id, get_sclk() / HZ - 1);
enable_gptimers(TIMER0bit); enable_gptimers(TIMER0bit);
break; return 0;
} }
case CLOCK_EVT_MODE_ONESHOT:
disable_gptimers(TIMER0bit); static int bfin_gptmr0_set_oneshot(struct clock_event_device *evt)
{
disable_gptimers(TIMER0bit);
#ifndef CONFIG_BF60x #ifndef CONFIG_BF60x
set_gptimer_config(TIMER0_id, \ set_gptimer_config(TIMER0_id,
TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM); TIMER_OUT_DIS | TIMER_IRQ_ENA | TIMER_MODE_PWM);
#else #else
set_gptimer_config(TIMER0_id, TIMER_OUT_DIS | TIMER_MODE_PWM set_gptimer_config(TIMER0_id,
| TIMER_PULSE_HI | TIMER_IRQ_WID_DLY); TIMER_OUT_DIS | TIMER_MODE_PWM | TIMER_PULSE_HI |
TIMER_IRQ_WID_DLY);
#endif #endif
set_gptimer_period(TIMER0_id, 0); set_gptimer_period(TIMER0_id, 0);
break; return 0;
case CLOCK_EVT_MODE_UNUSED: }
case CLOCK_EVT_MODE_SHUTDOWN:
disable_gptimers(TIMER0bit); static int bfin_gptmr0_shutdown(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_RESUME: disable_gptimers(TIMER0bit);
break; return 0;
}
} }
static void bfin_gptmr0_ack(void) static void bfin_gptmr0_ack(void)
...@@ -211,13 +211,16 @@ static struct irqaction gptmr0_irq = { ...@@ -211,13 +211,16 @@ static struct irqaction gptmr0_irq = {
}; };
static struct clock_event_device clockevent_gptmr0 = { static struct clock_event_device clockevent_gptmr0 = {
.name = "bfin_gptimer0", .name = "bfin_gptimer0",
.rating = 300, .rating = 300,
.irq = IRQ_TIMER0, .irq = IRQ_TIMER0,
.shift = 32, .shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.set_next_event = bfin_gptmr0_set_next_event, CLOCK_EVT_FEAT_ONESHOT,
.set_mode = bfin_gptmr0_set_mode, .set_next_event = bfin_gptmr0_set_next_event,
.set_state_shutdown = bfin_gptmr0_shutdown,
.set_state_periodic = bfin_gptmr0_set_periodic,
.set_state_oneshot = bfin_gptmr0_set_oneshot,
}; };
static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt) static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
...@@ -250,36 +253,35 @@ static int bfin_coretmr_set_next_event(unsigned long cycles, ...@@ -250,36 +253,35 @@ static int bfin_coretmr_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static void bfin_coretmr_set_mode(enum clock_event_mode mode, static int bfin_coretmr_set_periodic(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
case CLOCK_EVT_MODE_PERIODIC: {
unsigned long tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1); bfin_write_TCNTL(TMPWR);
bfin_write_TCNTL(TMPWR); CSYNC();
CSYNC(); bfin_write_TSCALE(TIME_SCALE - 1);
bfin_write_TSCALE(TIME_SCALE - 1); bfin_write_TPERIOD(tcount);
bfin_write_TPERIOD(tcount); bfin_write_TCOUNT(tcount);
bfin_write_TCOUNT(tcount); CSYNC();
CSYNC(); bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD);
bfin_write_TCNTL(TMPWR | TMREN | TAUTORLD); return 0;
break; }
}
case CLOCK_EVT_MODE_ONESHOT: static int bfin_coretmr_set_oneshot(struct clock_event_device *evt)
bfin_write_TCNTL(TMPWR); {
CSYNC(); bfin_write_TCNTL(TMPWR);
bfin_write_TSCALE(TIME_SCALE - 1); CSYNC();
bfin_write_TPERIOD(0); bfin_write_TSCALE(TIME_SCALE - 1);
bfin_write_TCOUNT(0); bfin_write_TPERIOD(0);
break; bfin_write_TCOUNT(0);
case CLOCK_EVT_MODE_UNUSED: return 0;
case CLOCK_EVT_MODE_SHUTDOWN: }
bfin_write_TCNTL(0);
CSYNC(); static int bfin_coretmr_shutdown(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_RESUME: bfin_write_TCNTL(0);
break; CSYNC();
} return 0;
} }
void bfin_coretmr_init(void) void bfin_coretmr_init(void)
...@@ -335,7 +337,9 @@ void bfin_coretmr_clockevent_init(void) ...@@ -335,7 +337,9 @@ void bfin_coretmr_clockevent_init(void)
evt->shift = 32; evt->shift = 32;
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->set_next_event = bfin_coretmr_set_next_event; evt->set_next_event = bfin_coretmr_set_next_event;
evt->set_mode = bfin_coretmr_set_mode; evt->set_state_shutdown = bfin_coretmr_shutdown;
evt->set_state_periodic = bfin_coretmr_set_periodic;
evt->set_state_oneshot = bfin_coretmr_set_oneshot;
clock_tick = get_cclk() / TIME_SCALE; clock_tick = get_cclk() / TIME_SCALE;
evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift); evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift);
......
...@@ -126,35 +126,37 @@ static int next_event(unsigned long delta, ...@@ -126,35 +126,37 @@ static int next_event(unsigned long delta,
return 0; return 0;
} }
static void set_clock_mode(enum clock_event_mode mode, static int set_periodic(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { timer64_enable();
case CLOCK_EVT_MODE_PERIODIC: timer64_mode = TIMER64_MODE_PERIODIC;
timer64_enable(); timer64_config(TIMER64_RATE / HZ);
timer64_mode = TIMER64_MODE_PERIODIC; return 0;
timer64_config(TIMER64_RATE / HZ); }
break;
case CLOCK_EVT_MODE_ONESHOT: static int set_oneshot(struct clock_event_device *evt)
timer64_enable(); {
timer64_mode = TIMER64_MODE_ONE_SHOT; timer64_enable();
break; timer64_mode = TIMER64_MODE_ONE_SHOT;
case CLOCK_EVT_MODE_UNUSED: return 0;
case CLOCK_EVT_MODE_SHUTDOWN: }
timer64_mode = TIMER64_MODE_DISABLED;
timer64_disable(); static int shutdown(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_RESUME: timer64_mode = TIMER64_MODE_DISABLED;
break; timer64_disable();
} return 0;
} }
static struct clock_event_device t64_clockevent_device = { static struct clock_event_device t64_clockevent_device = {
.name = "TIMER64_EVT32_TIMER", .name = "TIMER64_EVT32_TIMER",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT |
.rating = 200, CLOCK_EVT_FEAT_PERIODIC,
.set_mode = set_clock_mode, .rating = 200,
.set_next_event = next_event, .set_state_shutdown = shutdown,
.set_state_periodic = set_periodic,
.set_state_oneshot = set_oneshot,
.set_next_event = next_event,
}; };
static irqreturn_t timer_interrupt(int irq, void *dev_id) static irqreturn_t timer_interrupt(int irq, void *dev_id)
......
...@@ -172,8 +172,7 @@ void handle_watchdog_bite(struct pt_regs *regs) ...@@ -172,8 +172,7 @@ void handle_watchdog_bite(struct pt_regs *regs)
extern void cris_profile_sample(struct pt_regs *regs); extern void cris_profile_sample(struct pt_regs *regs);
static void __iomem *timer_base; static void __iomem *timer_base;
static void crisv32_clkevt_mode(enum clock_event_mode mode, static int crisv32_clkevt_switch_state(struct clock_event_device *dev)
struct clock_event_device *dev)
{ {
reg_timer_rw_tmr0_ctrl ctrl = { reg_timer_rw_tmr0_ctrl ctrl = {
.op = regk_timer_hold, .op = regk_timer_hold,
...@@ -181,6 +180,7 @@ static void crisv32_clkevt_mode(enum clock_event_mode mode, ...@@ -181,6 +180,7 @@ static void crisv32_clkevt_mode(enum clock_event_mode mode,
}; };
REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl);
return 0;
} }
static int crisv32_clkevt_next_event(unsigned long evt, static int crisv32_clkevt_next_event(unsigned long evt,
...@@ -231,7 +231,9 @@ static struct clock_event_device crisv32_clockevent = { ...@@ -231,7 +231,9 @@ static struct clock_event_device crisv32_clockevent = {
.name = "crisv32-timer", .name = "crisv32-timer",
.rating = 300, .rating = 300,
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.set_mode = crisv32_clkevt_mode, .set_state_oneshot = crisv32_clkevt_switch_state,
.set_state_shutdown = crisv32_clkevt_switch_state,
.tick_resume = crisv32_clkevt_switch_state,
.set_next_event = crisv32_clkevt_next_event, .set_next_event = crisv32_clkevt_next_event,
}; };
......
...@@ -122,37 +122,29 @@ static int xilinx_timer_set_next_event(unsigned long delta, ...@@ -122,37 +122,29 @@ static int xilinx_timer_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void xilinx_timer_set_mode(enum clock_event_mode mode, static int xilinx_timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { pr_info("%s\n", __func__);
case CLOCK_EVT_MODE_PERIODIC: xilinx_timer0_stop();
pr_info("%s: periodic\n", __func__); return 0;
xilinx_timer0_start_periodic(freq_div_hz); }
break;
case CLOCK_EVT_MODE_ONESHOT: static int xilinx_timer_set_periodic(struct clock_event_device *evt)
pr_info("%s: oneshot\n", __func__); {
break; pr_info("%s\n", __func__);
case CLOCK_EVT_MODE_UNUSED: xilinx_timer0_start_periodic(freq_div_hz);
pr_info("%s: unused\n", __func__); return 0;
break;
case CLOCK_EVT_MODE_SHUTDOWN:
pr_info("%s: shutdown\n", __func__);
xilinx_timer0_stop();
break;
case CLOCK_EVT_MODE_RESUME:
pr_info("%s: resume\n", __func__);
break;
}
} }
static struct clock_event_device clockevent_xilinx_timer = { static struct clock_event_device clockevent_xilinx_timer = {
.name = "xilinx_clockevent", .name = "xilinx_clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT |
.shift = 8, CLOCK_EVT_FEAT_PERIODIC,
.rating = 300, .shift = 8,
.set_next_event = xilinx_timer_set_next_event, .rating = 300,
.set_mode = xilinx_timer_set_mode, .set_next_event = xilinx_timer_set_next_event,
.set_state_shutdown = xilinx_timer_shutdown,
.set_state_periodic = xilinx_timer_set_periodic,
}; };
static inline void timer_ack(void) static inline void timer_ack(void)
......
...@@ -41,12 +41,6 @@ static int next_event(unsigned long delta, ...@@ -41,12 +41,6 @@ static int next_event(unsigned long delta,
return 0; return 0;
} }
static void set_clock_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
/* Nothing to do ... */
}
static DEFINE_PER_CPU(struct clock_event_device, mn10300_clockevent_device); static DEFINE_PER_CPU(struct clock_event_device, mn10300_clockevent_device);
static DEFINE_PER_CPU(struct irqaction, timer_irq); static DEFINE_PER_CPU(struct irqaction, timer_irq);
...@@ -108,7 +102,6 @@ int __init init_clockevents(void) ...@@ -108,7 +102,6 @@ int __init init_clockevents(void)
cd->rating = 200; cd->rating = 200;
cd->cpumask = cpumask_of(smp_processor_id()); cd->cpumask = cpumask_of(smp_processor_id());
cd->set_mode = set_clock_mode;
cd->event_handler = event_handler; cd->event_handler = event_handler;
cd->set_next_event = next_event; cd->set_next_event = next_event;
......
...@@ -48,29 +48,6 @@ static int openrisc_timer_set_next_event(unsigned long delta, ...@@ -48,29 +48,6 @@ static int openrisc_timer_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void openrisc_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
pr_debug(KERN_INFO "%s: periodic\n", __func__);
BUG();
break;
case CLOCK_EVT_MODE_ONESHOT:
pr_debug(KERN_INFO "%s: oneshot\n", __func__);
break;
case CLOCK_EVT_MODE_UNUSED:
pr_debug(KERN_INFO "%s: unused\n", __func__);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
pr_debug(KERN_INFO "%s: shutdown\n", __func__);
break;
case CLOCK_EVT_MODE_RESUME:
pr_debug(KERN_INFO "%s: resume\n", __func__);
break;
}
}
/* This is the clock event device based on the OR1K tick timer. /* This is the clock event device based on the OR1K tick timer.
* As the timer is being used as a continuous clock-source (required for HR * As the timer is being used as a continuous clock-source (required for HR
* timers) we cannot enable the PERIODIC feature. The tick timer can run using * timers) we cannot enable the PERIODIC feature. The tick timer can run using
...@@ -82,7 +59,6 @@ static struct clock_event_device clockevent_openrisc_timer = { ...@@ -82,7 +59,6 @@ static struct clock_event_device clockevent_openrisc_timer = {
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 300, .rating = 300,
.set_next_event = openrisc_timer_set_next_event, .set_next_event = openrisc_timer_set_next_event,
.set_mode = openrisc_timer_set_mode,
}; };
static inline void timer_ack(void) static inline void timer_ack(void)
......
...@@ -99,16 +99,17 @@ static struct clocksource clocksource_timebase = { ...@@ -99,16 +99,17 @@ static struct clocksource clocksource_timebase = {
static int decrementer_set_next_event(unsigned long evt, static int decrementer_set_next_event(unsigned long evt,
struct clock_event_device *dev); struct clock_event_device *dev);
static void decrementer_set_mode(enum clock_event_mode mode, static int decrementer_shutdown(struct clock_event_device *evt);
struct clock_event_device *dev);
struct clock_event_device decrementer_clockevent = { struct clock_event_device decrementer_clockevent = {
.name = "decrementer", .name = "decrementer",
.rating = 200, .rating = 200,
.irq = 0, .irq = 0,
.set_next_event = decrementer_set_next_event, .set_next_event = decrementer_set_next_event,
.set_mode = decrementer_set_mode, .set_state_shutdown = decrementer_shutdown,
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP, .tick_resume = decrementer_shutdown,
.features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_C3STOP,
}; };
EXPORT_SYMBOL(decrementer_clockevent); EXPORT_SYMBOL(decrementer_clockevent);
...@@ -862,11 +863,10 @@ static int decrementer_set_next_event(unsigned long evt, ...@@ -862,11 +863,10 @@ static int decrementer_set_next_event(unsigned long evt,
return 0; return 0;
} }
static void decrementer_set_mode(enum clock_event_mode mode, static int decrementer_shutdown(struct clock_event_device *dev)
struct clock_event_device *dev)
{ {
if (mode != CLOCK_EVT_MODE_ONESHOT) decrementer_set_next_event(DECREMENTER_MAX, dev);
decrementer_set_next_event(DECREMENTER_MAX, dev); return 0;
} }
/* Interrupt handler for the timer broadcast IPI */ /* Interrupt handler for the timer broadcast IPI */
......
...@@ -120,11 +120,6 @@ static int s390_next_event(unsigned long delta, ...@@ -120,11 +120,6 @@ static int s390_next_event(unsigned long delta,
return 0; return 0;
} }
static void s390_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
}
/* /*
* Set up lowcore and control register of the current cpu to * Set up lowcore and control register of the current cpu to
* enable TOD clock and clock comparator interrupts. * enable TOD clock and clock comparator interrupts.
...@@ -148,7 +143,6 @@ void init_cpu_timer(void) ...@@ -148,7 +143,6 @@ void init_cpu_timer(void)
cd->rating = 400; cd->rating = 400;
cd->cpumask = cpumask_of(cpu); cd->cpumask = cpumask_of(cpu);
cd->set_next_event = s390_next_event; cd->set_next_event = s390_next_event;
cd->set_mode = s390_set_mode;
clockevents_register_device(cd); clockevents_register_device(cd);
......
...@@ -55,31 +55,20 @@ static int score_timer_set_next_event(unsigned long delta, ...@@ -55,31 +55,20 @@ static int score_timer_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void score_timer_set_mode(enum clock_event_mode mode, static int score_timer_set_periodic(struct clock_event_device *evt)
struct clock_event_device *evdev)
{ {
switch (mode) { outl((TMR_M_PERIODIC | TMR_IE_ENABLE), P_TIMER0_CTRL);
case CLOCK_EVT_MODE_PERIODIC: outl(SYSTEM_CLOCK / HZ, P_TIMER0_PRELOAD);
outl((TMR_M_PERIODIC | TMR_IE_ENABLE), P_TIMER0_CTRL); outl(inl(P_TIMER0_CTRL) | TMR_ENABLE, P_TIMER0_CTRL);
outl(SYSTEM_CLOCK/HZ, P_TIMER0_PRELOAD); return 0;
outl(inl(P_TIMER0_CTRL) | TMR_ENABLE, P_TIMER0_CTRL);
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_UNUSED:
break;
default:
BUG();
}
} }
static struct clock_event_device score_clockevent = { static struct clock_event_device score_clockevent = {
.name = "score_clockevent", .name = "score_clockevent",
.features = CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_PERIODIC,
.shift = 16, .shift = 16,
.set_next_event = score_timer_set_next_event, .set_next_event = score_timer_set_next_event,
.set_mode = score_timer_set_mode, .set_state_periodic = score_timer_set_periodic,
}; };
void __init time_init(void) void __init time_init(void)
......
...@@ -39,11 +39,6 @@ void local_timer_interrupt(void) ...@@ -39,11 +39,6 @@ void local_timer_interrupt(void)
irq_exit(); irq_exit();
} }
static void dummy_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *clk)
{
}
void local_timer_setup(unsigned int cpu) void local_timer_setup(unsigned int cpu)
{ {
struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
...@@ -54,7 +49,6 @@ void local_timer_setup(unsigned int cpu) ...@@ -54,7 +49,6 @@ void local_timer_setup(unsigned int cpu)
CLOCK_EVT_FEAT_DUMMY; CLOCK_EVT_FEAT_DUMMY;
clk->rating = 400; clk->rating = 400;
clk->mult = 1; clk->mult = 1;
clk->set_mode = dummy_timer_set_mode;
clk->broadcast = smp_timer_broadcast; clk->broadcast = smp_timer_broadcast;
clk->cpumask = cpumask_of(cpu); clk->cpumask = cpumask_of(cpu);
......
...@@ -247,7 +247,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) ...@@ -247,7 +247,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
ce = &per_cpu(sparc32_clockevent, cpu); ce = &per_cpu(sparc32_clockevent, cpu);
if (ce->mode & CLOCK_EVT_MODE_PERIODIC) if (clockevent_state_periodic(ce))
sun4m_clear_profile_irq(cpu); sun4m_clear_profile_irq(cpu);
else else
sparc_config.load_profile_irq(cpu, 0); /* Is this needless? */ sparc_config.load_profile_irq(cpu, 0); /* Is this needless? */
......
...@@ -101,21 +101,18 @@ irqreturn_t notrace timer_interrupt(int dummy, void *dev_id) ...@@ -101,21 +101,18 @@ irqreturn_t notrace timer_interrupt(int dummy, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void timer_ce_set_mode(enum clock_event_mode mode, static int timer_ce_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { timer_ce_enabled = 0;
case CLOCK_EVT_MODE_PERIODIC: smp_mb();
case CLOCK_EVT_MODE_RESUME: return 0;
timer_ce_enabled = 1; }
break;
case CLOCK_EVT_MODE_SHUTDOWN: static int timer_ce_set_periodic(struct clock_event_device *evt)
timer_ce_enabled = 0; {
break; timer_ce_enabled = 1;
default:
break;
}
smp_mb(); smp_mb();
return 0;
} }
static __init void setup_timer_ce(void) static __init void setup_timer_ce(void)
...@@ -127,7 +124,9 @@ static __init void setup_timer_ce(void) ...@@ -127,7 +124,9 @@ static __init void setup_timer_ce(void)
ce->name = "timer_ce"; ce->name = "timer_ce";
ce->rating = 100; ce->rating = 100;
ce->features = CLOCK_EVT_FEAT_PERIODIC; ce->features = CLOCK_EVT_FEAT_PERIODIC;
ce->set_mode = timer_ce_set_mode; ce->set_state_shutdown = timer_ce_shutdown;
ce->set_state_periodic = timer_ce_set_periodic;
ce->tick_resume = timer_ce_set_periodic;
ce->cpumask = cpu_possible_mask; ce->cpumask = cpu_possible_mask;
ce->shift = 32; ce->shift = 32;
ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC, ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC,
...@@ -183,24 +182,20 @@ static __init int setup_timer_cs(void) ...@@ -183,24 +182,20 @@ static __init int setup_timer_cs(void)
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void percpu_ce_setup(enum clock_event_mode mode, static int percpu_ce_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
int cpu = cpumask_first(evt->cpumask); int cpu = cpumask_first(evt->cpumask);
switch (mode) { sparc_config.load_profile_irq(cpu, 0);
case CLOCK_EVT_MODE_PERIODIC: return 0;
sparc_config.load_profile_irq(cpu, }
SBUS_CLOCK_RATE / HZ);
break; static int percpu_ce_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_ONESHOT: {
case CLOCK_EVT_MODE_SHUTDOWN: int cpu = cpumask_first(evt->cpumask);
case CLOCK_EVT_MODE_UNUSED:
sparc_config.load_profile_irq(cpu, 0); sparc_config.load_profile_irq(cpu, SBUS_CLOCK_RATE / HZ);
break; return 0;
default:
break;
}
} }
static int percpu_ce_set_next_event(unsigned long delta, static int percpu_ce_set_next_event(unsigned long delta,
...@@ -224,7 +219,9 @@ void register_percpu_ce(int cpu) ...@@ -224,7 +219,9 @@ void register_percpu_ce(int cpu)
ce->name = "percpu_ce"; ce->name = "percpu_ce";
ce->rating = 200; ce->rating = 200;
ce->features = features; ce->features = features;
ce->set_mode = percpu_ce_setup; ce->set_state_shutdown = percpu_ce_shutdown;
ce->set_state_periodic = percpu_ce_set_periodic;
ce->set_state_oneshot = percpu_ce_shutdown;
ce->set_next_event = percpu_ce_set_next_event; ce->set_next_event = percpu_ce_set_next_event;
ce->cpumask = cpumask_of(cpu); ce->cpumask = cpumask_of(cpu);
ce->shift = 32; ce->shift = 32;
......
...@@ -674,32 +674,19 @@ static int sparc64_next_event(unsigned long delta, ...@@ -674,32 +674,19 @@ static int sparc64_next_event(unsigned long delta,
return tick_ops->add_compare(delta) ? -ETIME : 0; return tick_ops->add_compare(delta) ? -ETIME : 0;
} }
static void sparc64_timer_setup(enum clock_event_mode mode, static int sparc64_timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt) {
{ tick_ops->disable_irq();
switch (mode) { return 0;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_RESUME:
break;
case CLOCK_EVT_MODE_SHUTDOWN:
tick_ops->disable_irq();
break;
case CLOCK_EVT_MODE_PERIODIC:
case CLOCK_EVT_MODE_UNUSED:
WARN_ON(1);
break;
}
} }
static struct clock_event_device sparc64_clockevent = { static struct clock_event_device sparc64_clockevent = {
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.set_mode = sparc64_timer_setup, .set_state_shutdown = sparc64_timer_shutdown,
.set_next_event = sparc64_next_event, .set_next_event = sparc64_next_event,
.rating = 100, .rating = 100,
.shift = 30, .shift = 30,
.irq = -1, .irq = -1,
}; };
static DEFINE_PER_CPU(struct clock_event_device, sparc64_events); static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
......
...@@ -22,23 +22,16 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) ...@@ -22,23 +22,16 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
local_irq_restore(flags); local_irq_restore(flags);
} }
static void itimer_set_mode(enum clock_event_mode mode, static int itimer_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { disable_timer();
case CLOCK_EVT_MODE_PERIODIC: return 0;
set_interval(); }
break;
static int itimer_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_SHUTDOWN: {
case CLOCK_EVT_MODE_UNUSED: set_interval();
case CLOCK_EVT_MODE_ONESHOT: return 0;
disable_timer();
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
} }
static int itimer_next_event(unsigned long delta, static int itimer_next_event(unsigned long delta,
...@@ -48,14 +41,17 @@ static int itimer_next_event(unsigned long delta, ...@@ -48,14 +41,17 @@ static int itimer_next_event(unsigned long delta,
} }
static struct clock_event_device itimer_clockevent = { static struct clock_event_device itimer_clockevent = {
.name = "itimer", .name = "itimer",
.rating = 250, .rating = 250,
.cpumask = cpu_all_mask, .cpumask = cpu_all_mask,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.set_mode = itimer_set_mode, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = itimer_next_event, .set_state_shutdown = itimer_shutdown,
.shift = 32, .set_state_periodic = itimer_set_periodic,
.irq = 0, .set_state_oneshot = itimer_shutdown,
.set_next_event = itimer_next_event,
.shift = 32,
.irq = 0,
}; };
static irqreturn_t um_timer(int irq, void *dev) static irqreturn_t um_timer(int irq, void *dev)
......
...@@ -46,29 +46,20 @@ puv3_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c) ...@@ -46,29 +46,20 @@ puv3_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
} }
static void static int puv3_osmr0_shutdown(struct clock_event_device *evt)
puv3_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
{ {
switch (mode) { writel(readl(OST_OIER) & ~OST_OIER_E0, OST_OIER);
case CLOCK_EVT_MODE_ONESHOT: writel(readl(OST_OSSR) & ~OST_OSSR_M0, OST_OSSR);
case CLOCK_EVT_MODE_UNUSED: return 0;
case CLOCK_EVT_MODE_SHUTDOWN:
writel(readl(OST_OIER) & ~OST_OIER_E0, OST_OIER);
writel(readl(OST_OSSR) & ~OST_OSSR_M0, OST_OSSR);
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
}
} }
static struct clock_event_device ckevt_puv3_osmr0 = { static struct clock_event_device ckevt_puv3_osmr0 = {
.name = "osmr0", .name = "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 200, .rating = 200,
.set_next_event = puv3_osmr0_set_next_event, .set_next_event = puv3_osmr0_set_next_event,
.set_mode = puv3_osmr0_set_mode, .set_state_shutdown = puv3_osmr0_shutdown,
.set_state_oneshot = puv3_osmr0_shutdown,
}; };
static cycle_t puv3_read_oscr(struct clocksource *cs) static cycle_t puv3_read_oscr(struct clocksource *cs)
......
...@@ -34,7 +34,7 @@ static int __init init_pit_clocksource(void) ...@@ -34,7 +34,7 @@ static int __init init_pit_clocksource(void)
* - when local APIC timer is active (PIT is switched off) * - when local APIC timer is active (PIT is switched off)
*/ */
if (num_possible_cpus() > 1 || is_hpet_enabled() || if (num_possible_cpus() > 1 || is_hpet_enabled() ||
i8253_clockevent.mode != CLOCK_EVT_MODE_PERIODIC) !clockevent_state_periodic(&i8253_clockevent))
return 0; return 0;
return clocksource_i8253_init(); return clocksource_i8253_init();
......
...@@ -52,8 +52,6 @@ static struct clocksource ccount_clocksource = { ...@@ -52,8 +52,6 @@ static struct clocksource ccount_clocksource = {
static int ccount_timer_set_next_event(unsigned long delta, static int ccount_timer_set_next_event(unsigned long delta,
struct clock_event_device *dev); struct clock_event_device *dev);
static void ccount_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt);
struct ccount_timer { struct ccount_timer {
struct clock_event_device evt; struct clock_event_device evt;
int irq_enabled; int irq_enabled;
...@@ -77,35 +75,34 @@ static int ccount_timer_set_next_event(unsigned long delta, ...@@ -77,35 +75,34 @@ static int ccount_timer_set_next_event(unsigned long delta,
return ret; return ret;
} }
static void ccount_timer_set_mode(enum clock_event_mode mode, /*
struct clock_event_device *evt) * There is no way to disable the timer interrupt at the device level,
* only at the intenable register itself. Since enable_irq/disable_irq
* calls are nested, we need to make sure that these calls are
* balanced.
*/
static int ccount_timer_shutdown(struct clock_event_device *evt)
{
struct ccount_timer *timer =
container_of(evt, struct ccount_timer, evt);
if (timer->irq_enabled) {
disable_irq(evt->irq);
timer->irq_enabled = 0;
}
return 0;
}
static int ccount_timer_set_oneshot(struct clock_event_device *evt)
{ {
struct ccount_timer *timer = struct ccount_timer *timer =
container_of(evt, struct ccount_timer, evt); container_of(evt, struct ccount_timer, evt);
/* if (!timer->irq_enabled) {
* There is no way to disable the timer interrupt at the device level, enable_irq(evt->irq);
* only at the intenable register itself. Since enable_irq/disable_irq timer->irq_enabled = 1;
* calls are nested, we need to make sure that these calls are
* balanced.
*/
switch (mode) {
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
if (timer->irq_enabled) {
disable_irq(evt->irq);
timer->irq_enabled = 0;
}
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_ONESHOT:
if (!timer->irq_enabled) {
enable_irq(evt->irq);
timer->irq_enabled = 1;
}
default:
break;
} }
return 0;
} }
static irqreturn_t timer_interrupt(int irq, void *dev_id); static irqreturn_t timer_interrupt(int irq, void *dev_id);
...@@ -126,7 +123,9 @@ void local_timer_setup(unsigned cpu) ...@@ -126,7 +123,9 @@ void local_timer_setup(unsigned cpu)
clockevent->features = CLOCK_EVT_FEAT_ONESHOT; clockevent->features = CLOCK_EVT_FEAT_ONESHOT;
clockevent->rating = 300; clockevent->rating = 300;
clockevent->set_next_event = ccount_timer_set_next_event; clockevent->set_next_event = ccount_timer_set_next_event;
clockevent->set_mode = ccount_timer_set_mode; clockevent->set_state_shutdown = ccount_timer_shutdown;
clockevent->set_state_oneshot = ccount_timer_set_oneshot;
clockevent->tick_resume = ccount_timer_set_oneshot;
clockevent->cpumask = cpumask_of(cpu); clockevent->cpumask = cpumask_of(cpu);
clockevent->irq = irq_create_mapping(NULL, LINUX_TIMER_INT); clockevent->irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
if (WARN(!clockevent->irq, "error: can't map timer irq")) if (WARN(!clockevent->irq, "error: can't map timer irq"))
......
...@@ -277,7 +277,7 @@ config CLKSRC_MIPS_GIC ...@@ -277,7 +277,7 @@ config CLKSRC_MIPS_GIC
config CLKSRC_PXA config CLKSRC_PXA
def_bool y if ARCH_PXA || ARCH_SA1100 def_bool y if ARCH_PXA || ARCH_SA1100
select CLKSRC_OF if USE_OF select CLKSRC_OF if OF
help help
This enables OST0 support available on PXA and SA-11x0 This enables OST0 support available on PXA and SA-11x0
platforms. platforms.
......
...@@ -181,44 +181,36 @@ static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) ...@@ -181,44 +181,36 @@ static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id)
return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt);
} }
static __always_inline void timer_set_mode(const int access, int mode, static __always_inline int timer_shutdown(const int access,
struct clock_event_device *clk) struct clock_event_device *clk)
{ {
unsigned long ctrl; unsigned long ctrl;
switch (mode) {
case CLOCK_EVT_MODE_UNUSED: ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk);
case CLOCK_EVT_MODE_SHUTDOWN: ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); return 0;
break;
default:
break;
}
} }
static void arch_timer_set_mode_virt(enum clock_event_mode mode, static int arch_timer_shutdown_virt(struct clock_event_device *clk)
struct clock_event_device *clk)
{ {
timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode, clk); return timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk);
} }
static void arch_timer_set_mode_phys(enum clock_event_mode mode, static int arch_timer_shutdown_phys(struct clock_event_device *clk)
struct clock_event_device *clk)
{ {
timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode, clk); return timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk);
} }
static void arch_timer_set_mode_virt_mem(enum clock_event_mode mode, static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk)
struct clock_event_device *clk)
{ {
timer_set_mode(ARCH_TIMER_MEM_VIRT_ACCESS, mode, clk); return timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk);
} }
static void arch_timer_set_mode_phys_mem(enum clock_event_mode mode, static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk)
struct clock_event_device *clk)
{ {
timer_set_mode(ARCH_TIMER_MEM_PHYS_ACCESS, mode, clk); return timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk);
} }
static __always_inline void set_next_event(const int access, unsigned long evt, static __always_inline void set_next_event(const int access, unsigned long evt,
...@@ -273,11 +265,11 @@ static void __arch_timer_setup(unsigned type, ...@@ -273,11 +265,11 @@ static void __arch_timer_setup(unsigned type,
clk->cpumask = cpumask_of(smp_processor_id()); clk->cpumask = cpumask_of(smp_processor_id());
if (arch_timer_use_virtual) { if (arch_timer_use_virtual) {
clk->irq = arch_timer_ppi[VIRT_PPI]; clk->irq = arch_timer_ppi[VIRT_PPI];
clk->set_mode = arch_timer_set_mode_virt; clk->set_state_shutdown = arch_timer_shutdown_virt;
clk->set_next_event = arch_timer_set_next_event_virt; clk->set_next_event = arch_timer_set_next_event_virt;
} else { } else {
clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
clk->set_mode = arch_timer_set_mode_phys; clk->set_state_shutdown = arch_timer_shutdown_phys;
clk->set_next_event = arch_timer_set_next_event_phys; clk->set_next_event = arch_timer_set_next_event_phys;
} }
} else { } else {
...@@ -286,17 +278,17 @@ static void __arch_timer_setup(unsigned type, ...@@ -286,17 +278,17 @@ static void __arch_timer_setup(unsigned type,
clk->rating = 400; clk->rating = 400;
clk->cpumask = cpu_all_mask; clk->cpumask = cpu_all_mask;
if (arch_timer_mem_use_virtual) { if (arch_timer_mem_use_virtual) {
clk->set_mode = arch_timer_set_mode_virt_mem; clk->set_state_shutdown = arch_timer_shutdown_virt_mem;
clk->set_next_event = clk->set_next_event =
arch_timer_set_next_event_virt_mem; arch_timer_set_next_event_virt_mem;
} else { } else {
clk->set_mode = arch_timer_set_mode_phys_mem; clk->set_state_shutdown = arch_timer_shutdown_phys_mem;
clk->set_next_event = clk->set_next_event =
arch_timer_set_next_event_phys_mem; arch_timer_set_next_event_phys_mem;
} }
} }
clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, clk); clk->set_state_shutdown(clk);
clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff);
} }
...@@ -506,7 +498,7 @@ static void arch_timer_stop(struct clock_event_device *clk) ...@@ -506,7 +498,7 @@ static void arch_timer_stop(struct clock_event_device *clk)
disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]); disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]);
} }
clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk); clk->set_state_shutdown(clk);
} }
static int arch_timer_cpu_notify(struct notifier_block *self, static int arch_timer_cpu_notify(struct notifier_block *self,
......
...@@ -107,26 +107,21 @@ static void gt_compare_set(unsigned long delta, int periodic) ...@@ -107,26 +107,21 @@ static void gt_compare_set(unsigned long delta, int periodic)
writel(ctrl, gt_base + GT_CONTROL); writel(ctrl, gt_base + GT_CONTROL);
} }
static void gt_clockevent_set_mode(enum clock_event_mode mode, static int gt_clockevent_shutdown(struct clock_event_device *evt)
struct clock_event_device *clk)
{ {
unsigned long ctrl; unsigned long ctrl;
switch (mode) { ctrl = readl(gt_base + GT_CONTROL);
case CLOCK_EVT_MODE_PERIODIC: ctrl &= ~(GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE |
gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1); GT_CONTROL_AUTO_INC);
break; writel(ctrl, gt_base + GT_CONTROL);
case CLOCK_EVT_MODE_ONESHOT: return 0;
case CLOCK_EVT_MODE_UNUSED: }
case CLOCK_EVT_MODE_SHUTDOWN:
ctrl = readl(gt_base + GT_CONTROL); static int gt_clockevent_set_periodic(struct clock_event_device *evt)
ctrl &= ~(GT_CONTROL_COMP_ENABLE | {
GT_CONTROL_IRQ_ENABLE | GT_CONTROL_AUTO_INC); gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1);
writel(ctrl, gt_base + GT_CONTROL); return 0;
break;
default:
break;
}
} }
static int gt_clockevent_set_next_event(unsigned long evt, static int gt_clockevent_set_next_event(unsigned long evt,
...@@ -155,7 +150,7 @@ static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id) ...@@ -155,7 +150,7 @@ static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
* the Global Timer flag _after_ having incremented * the Global Timer flag _after_ having incremented
* the Comparator register value to a higher value. * the Comparator register value to a higher value.
*/ */
if (evt->mode == CLOCK_EVT_MODE_ONESHOT) if (clockevent_state_oneshot(evt))
gt_compare_set(ULONG_MAX, 0); gt_compare_set(ULONG_MAX, 0);
writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS); writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS);
...@@ -171,7 +166,9 @@ static int gt_clockevents_init(struct clock_event_device *clk) ...@@ -171,7 +166,9 @@ static int gt_clockevents_init(struct clock_event_device *clk)
clk->name = "arm_global_timer"; clk->name = "arm_global_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERCPU; CLOCK_EVT_FEAT_PERCPU;
clk->set_mode = gt_clockevent_set_mode; clk->set_state_shutdown = gt_clockevent_shutdown;
clk->set_state_periodic = gt_clockevent_set_periodic;
clk->set_state_oneshot = gt_clockevent_shutdown;
clk->set_next_event = gt_clockevent_set_next_event; clk->set_next_event = gt_clockevent_set_next_event;
clk->cpumask = cpumask_of(cpu); clk->cpumask = cpumask_of(cpu);
clk->rating = 300; clk->rating = 300;
...@@ -184,7 +181,7 @@ static int gt_clockevents_init(struct clock_event_device *clk) ...@@ -184,7 +181,7 @@ static int gt_clockevents_init(struct clock_event_device *clk)
static void gt_clockevents_stop(struct clock_event_device *clk) static void gt_clockevents_stop(struct clock_event_device *clk)
{ {
gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk); gt_clockevent_shutdown(clk);
disable_percpu_irq(clk->irq); disable_percpu_irq(clk->irq);
} }
......
...@@ -120,38 +120,52 @@ static int asm9260_timer_set_next_event(unsigned long delta, ...@@ -120,38 +120,52 @@ static int asm9260_timer_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void asm9260_timer_set_mode(enum clock_event_mode mode, static inline void __asm9260_timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
/* stop timer0 */ /* stop timer0 */
writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG); writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG);
}
static int asm9260_timer_shutdown(struct clock_event_device *evt)
{
__asm9260_timer_shutdown(evt);
return 0;
}
static int asm9260_timer_set_oneshot(struct clock_event_device *evt)
{
__asm9260_timer_shutdown(evt);
/* enable reset and stop on match */
writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
priv.base + HW_MCR + SET_REG);
return 0;
}
static int asm9260_timer_set_periodic(struct clock_event_device *evt)
{
__asm9260_timer_shutdown(evt);
switch (mode) { /* disable reset and stop on match */
case CLOCK_EVT_MODE_PERIODIC: writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
/* disable reset and stop on match */ priv.base + HW_MCR + CLR_REG);
writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), /* configure match count for TC0 */
priv.base + HW_MCR + CLR_REG); writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0);
/* configure match count for TC0 */ /* enable TC0 */
writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0); writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
/* enable TC0 */ return 0;
writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
break;
case CLOCK_EVT_MODE_ONESHOT:
/* enable reset and stop on match */
writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
priv.base + HW_MCR + SET_REG);
break;
default:
break;
}
} }
static struct clock_event_device event_dev = { static struct clock_event_device event_dev = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.rating = 200, .rating = 200,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.set_next_event = asm9260_timer_set_next_event, CLOCK_EVT_FEAT_ONESHOT,
.set_mode = asm9260_timer_set_mode, .set_next_event = asm9260_timer_set_next_event,
.set_state_shutdown = asm9260_timer_shutdown,
.set_state_periodic = asm9260_timer_set_periodic,
.set_state_oneshot = asm9260_timer_set_oneshot,
.tick_resume = asm9260_timer_shutdown,
}; };
static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id) static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id)
......
...@@ -54,21 +54,6 @@ static u64 notrace bcm2835_sched_read(void) ...@@ -54,21 +54,6 @@ static u64 notrace bcm2835_sched_read(void)
return readl_relaxed(system_clock); return readl_relaxed(system_clock);
} }
static void bcm2835_time_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt_dev)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
break;
default:
WARN(1, "%s: unhandled event mode %d\n", __func__, mode);
break;
}
}
static int bcm2835_time_set_next_event(unsigned long event, static int bcm2835_time_set_next_event(unsigned long event,
struct clock_event_device *evt_dev) struct clock_event_device *evt_dev)
{ {
...@@ -129,7 +114,6 @@ static void __init bcm2835_timer_init(struct device_node *node) ...@@ -129,7 +114,6 @@ static void __init bcm2835_timer_init(struct device_node *node)
timer->evt.name = node->name; timer->evt.name = node->name;
timer->evt.rating = 300; timer->evt.rating = 300;
timer->evt.features = CLOCK_EVT_FEAT_ONESHOT; timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
timer->evt.set_mode = bcm2835_time_set_mode;
timer->evt.set_next_event = bcm2835_time_set_next_event; timer->evt.set_next_event = bcm2835_time_set_next_event;
timer->evt.cpumask = cpumask_of(0); timer->evt.cpumask = cpumask_of(0);
timer->act.name = node->name; timer->act.name = node->name;
......
...@@ -127,25 +127,18 @@ static int kona_timer_set_next_event(unsigned long clc, ...@@ -127,25 +127,18 @@ static int kona_timer_set_next_event(unsigned long clc,
return 0; return 0;
} }
static void kona_timer_set_mode(enum clock_event_mode mode, static int kona_timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *unused)
{ {
switch (mode) { kona_timer_disable_and_clear(timers.tmr_regs);
case CLOCK_EVT_MODE_ONESHOT: return 0;
/* by default mode is one shot don't do any thing */
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
default:
kona_timer_disable_and_clear(timers.tmr_regs);
}
} }
static struct clock_event_device kona_clockevent_timer = { static struct clock_event_device kona_clockevent_timer = {
.name = "timer 1", .name = "timer 1",
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = kona_timer_set_next_event, .set_next_event = kona_timer_set_next_event,
.set_mode = kona_timer_set_mode .set_state_shutdown = kona_timer_shutdown,
.tick_resume = kona_timer_shutdown,
}; };
static void __init kona_timer_clockevents_init(void) static void __init kona_timer_clockevents_init(void)
......
...@@ -190,40 +190,42 @@ static int ttc_set_next_event(unsigned long cycles, ...@@ -190,40 +190,42 @@ static int ttc_set_next_event(unsigned long cycles,
} }
/** /**
* ttc_set_mode - Sets the mode of timer * ttc_set_{shutdown|oneshot|periodic} - Sets the state of timer
* *
* @mode: Mode to be set
* @evt: Address of clock event instance * @evt: Address of clock event instance
**/ **/
static void ttc_set_mode(enum clock_event_mode mode, static int ttc_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
struct ttc_timer *timer = &ttce->ttc; struct ttc_timer *timer = &ttce->ttc;
u32 ctrl_reg; u32 ctrl_reg;
switch (mode) { ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET);
case CLOCK_EVT_MODE_PERIODIC: ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK;
ttc_set_interval(timer, DIV_ROUND_CLOSEST(ttce->ttc.freq, writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET);
PRESCALE * HZ)); return 0;
break; }
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED: static int ttc_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_SHUTDOWN: {
ctrl_reg = readl_relaxed(timer->base_addr + struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
TTC_CNT_CNTRL_OFFSET); struct ttc_timer *timer = &ttce->ttc;
ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK;
writel_relaxed(ctrl_reg, ttc_set_interval(timer,
timer->base_addr + TTC_CNT_CNTRL_OFFSET); DIV_ROUND_CLOSEST(ttce->ttc.freq, PRESCALE * HZ));
break; return 0;
case CLOCK_EVT_MODE_RESUME: }
ctrl_reg = readl_relaxed(timer->base_addr +
TTC_CNT_CNTRL_OFFSET); static int ttc_resume(struct clock_event_device *evt)
ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; {
writel_relaxed(ctrl_reg, struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
timer->base_addr + TTC_CNT_CNTRL_OFFSET); struct ttc_timer *timer = &ttce->ttc;
break; u32 ctrl_reg;
}
ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET);
ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK;
writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET);
return 0;
} }
static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, static int ttc_rate_change_clocksource_cb(struct notifier_block *nb,
...@@ -429,7 +431,10 @@ static void __init ttc_setup_clockevent(struct clk *clk, ...@@ -429,7 +431,10 @@ static void __init ttc_setup_clockevent(struct clk *clk,
ttcce->ce.name = "ttc_clockevent"; ttcce->ce.name = "ttc_clockevent";
ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
ttcce->ce.set_next_event = ttc_set_next_event; ttcce->ce.set_next_event = ttc_set_next_event;
ttcce->ce.set_mode = ttc_set_mode; ttcce->ce.set_state_shutdown = ttc_shutdown;
ttcce->ce.set_state_periodic = ttc_set_periodic;
ttcce->ce.set_state_oneshot = ttc_shutdown;
ttcce->ce.tick_resume = ttc_resume;
ttcce->ce.rating = 200; ttcce->ce.rating = 200;
ttcce->ce.irq = irq; ttcce->ce.irq = irq;
ttcce->ce.cpumask = cpu_possible_mask; ttcce->ce.cpumask = cpu_possible_mask;
......
...@@ -61,11 +61,6 @@ static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) ...@@ -61,11 +61,6 @@ static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void clps711x_clockevent_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
}
static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base,
unsigned int irq) unsigned int irq)
{ {
...@@ -91,7 +86,6 @@ static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, ...@@ -91,7 +86,6 @@ static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base,
clkevt->name = "clps711x-clockevent"; clkevt->name = "clps711x-clockevent";
clkevt->rating = 300; clkevt->rating = 300;
clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP; clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP;
clkevt->set_mode = clps711x_clockevent_set_mode;
clkevt->cpumask = cpumask_of(0); clkevt->cpumask = cpumask_of(0);
clockevents_config_and_register(clkevt, HZ, 0, 0); clockevents_config_and_register(clkevt, HZ, 0, 0);
......
...@@ -42,7 +42,6 @@ MODULE_PARM_DESC(irq, "Which IRQ to use for the clock source MFGPT ticks."); ...@@ -42,7 +42,6 @@ MODULE_PARM_DESC(irq, "Which IRQ to use for the clock source MFGPT ticks.");
* 256 128 .125 512.000 * 256 128 .125 512.000
*/ */
static unsigned int cs5535_tick_mode = CLOCK_EVT_MODE_SHUTDOWN;
static struct cs5535_mfgpt_timer *cs5535_event_clock; static struct cs5535_mfgpt_timer *cs5535_event_clock;
/* Selected from the table above */ /* Selected from the table above */
...@@ -77,15 +76,17 @@ static void start_timer(struct cs5535_mfgpt_timer *timer, uint16_t delta) ...@@ -77,15 +76,17 @@ static void start_timer(struct cs5535_mfgpt_timer *timer, uint16_t delta)
MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
} }
static void mfgpt_set_mode(enum clock_event_mode mode, static int mfgpt_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
disable_timer(cs5535_event_clock); disable_timer(cs5535_event_clock);
return 0;
}
if (mode == CLOCK_EVT_MODE_PERIODIC) static int mfgpt_set_periodic(struct clock_event_device *evt)
start_timer(cs5535_event_clock, MFGPT_PERIODIC); {
disable_timer(cs5535_event_clock);
cs5535_tick_mode = mode; start_timer(cs5535_event_clock, MFGPT_PERIODIC);
return 0;
} }
static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
...@@ -97,7 +98,10 @@ static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) ...@@ -97,7 +98,10 @@ static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
static struct clock_event_device cs5535_clockevent = { static struct clock_event_device cs5535_clockevent = {
.name = DRV_NAME, .name = DRV_NAME,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = mfgpt_set_mode, .set_state_shutdown = mfgpt_shutdown,
.set_state_periodic = mfgpt_set_periodic,
.set_state_oneshot = mfgpt_shutdown,
.tick_resume = mfgpt_shutdown,
.set_next_event = mfgpt_next_event, .set_next_event = mfgpt_next_event,
.rating = 250, .rating = 250,
}; };
...@@ -113,7 +117,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) ...@@ -113,7 +117,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
/* Turn off the clock (and clear the event) */ /* Turn off the clock (and clear the event) */
disable_timer(cs5535_event_clock); disable_timer(cs5535_event_clock);
if (cs5535_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) if (clockevent_state_shutdown(&cs5535_clockevent))
return IRQ_HANDLED; return IRQ_HANDLED;
/* Clear the counter */ /* Clear the counter */
...@@ -121,7 +125,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) ...@@ -121,7 +125,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
/* Restart the clock in periodic mode */ /* Restart the clock in periodic mode */
if (cs5535_tick_mode == CLOCK_EVT_MODE_PERIODIC) if (clockevent_state_periodic(&cs5535_clockevent))
cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP,
MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
......
...@@ -16,15 +16,6 @@ ...@@ -16,15 +16,6 @@
static DEFINE_PER_CPU(struct clock_event_device, dummy_timer_evt); static DEFINE_PER_CPU(struct clock_event_device, dummy_timer_evt);
static void dummy_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
/*
* Core clockevents code will call this when exchanging timer devices.
* We don't need to do anything here.
*/
}
static void dummy_timer_setup(void) static void dummy_timer_setup(void)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
...@@ -35,7 +26,6 @@ static void dummy_timer_setup(void) ...@@ -35,7 +26,6 @@ static void dummy_timer_setup(void)
CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_DUMMY; CLOCK_EVT_FEAT_DUMMY;
evt->rating = 100; evt->rating = 100;
evt->set_mode = dummy_timer_set_mode;
evt->cpumask = cpumask_of(cpu); evt->cpumask = cpumask_of(cpu);
clockevents_register_device(evt); clockevents_register_device(evt);
......
...@@ -110,71 +110,87 @@ static void apbt_enable_int(struct dw_apb_timer *timer) ...@@ -110,71 +110,87 @@ static void apbt_enable_int(struct dw_apb_timer *timer)
apbt_writel(timer, ctrl, APBTMR_N_CONTROL); apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
} }
static void apbt_set_mode(enum clock_event_mode mode, static int apbt_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
unsigned long ctrl; unsigned long ctrl;
unsigned long period;
pr_debug("%s CPU %d state=shutdown\n", __func__,
cpumask_first(evt->cpumask));
ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
ctrl &= ~APBTMR_CONTROL_ENABLE;
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
return 0;
}
static int apbt_set_oneshot(struct clock_event_device *evt)
{
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
unsigned long ctrl;
pr_debug("%s CPU %d mode=%d\n", __func__, pr_debug("%s CPU %d state=oneshot\n", __func__,
cpumask_first(evt->cpumask), cpumask_first(evt->cpumask));
mode);
ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
switch (mode) { /*
case CLOCK_EVT_MODE_PERIODIC: * set free running mode, this mode will let timer reload max
period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); * timeout which will give time (3min on 25MHz clock) to rearm
ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); * the next event, therefore emulate the one-shot mode.
ctrl |= APBTMR_CONTROL_MODE_PERIODIC; */
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); ctrl &= ~APBTMR_CONTROL_ENABLE;
/* ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC;
* DW APB p. 46, have to disable timer before load counter,
* may cause sync problem. apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
*/ /* write again to set free running mode */
ctrl &= ~APBTMR_CONTROL_ENABLE; apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
udelay(1); /*
pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); * DW APB p. 46, load counter with all 1s before starting free
apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); * running mode.
ctrl |= APBTMR_CONTROL_ENABLE; */
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT);
break; ctrl &= ~APBTMR_CONTROL_INT;
ctrl |= APBTMR_CONTROL_ENABLE;
case CLOCK_EVT_MODE_ONESHOT: apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); return 0;
/* }
* set free running mode, this mode will let timer reload max
* timeout which will give time (3min on 25MHz clock) to rearm static int apbt_set_periodic(struct clock_event_device *evt)
* the next event, therefore emulate the one-shot mode. {
*/ struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
ctrl &= ~APBTMR_CONTROL_ENABLE; unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ);
ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; unsigned long ctrl;
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); pr_debug("%s CPU %d state=periodic\n", __func__,
/* write again to set free running mode */ cpumask_first(evt->cpumask));
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
/* ctrl |= APBTMR_CONTROL_MODE_PERIODIC;
* DW APB p. 46, load counter with all 1s before starting free apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
* running mode. /*
*/ * DW APB p. 46, have to disable timer before load counter,
apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); * may cause sync problem.
ctrl &= ~APBTMR_CONTROL_INT; */
ctrl |= APBTMR_CONTROL_ENABLE; ctrl &= ~APBTMR_CONTROL_ENABLE;
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
break; udelay(1);
pr_debug("Setting clock period %lu for HZ %d\n", period, HZ);
case CLOCK_EVT_MODE_UNUSED: apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT);
case CLOCK_EVT_MODE_SHUTDOWN: ctrl |= APBTMR_CONTROL_ENABLE;
ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
ctrl &= ~APBTMR_CONTROL_ENABLE; return 0;
apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); }
break;
static int apbt_resume(struct clock_event_device *evt)
case CLOCK_EVT_MODE_RESUME: {
apbt_enable_int(&dw_ced->timer); struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
break;
} pr_debug("%s CPU %d state=resume\n", __func__,
cpumask_first(evt->cpumask));
apbt_enable_int(&dw_ced->timer);
return 0;
} }
static int apbt_next_event(unsigned long delta, static int apbt_next_event(unsigned long delta,
...@@ -232,8 +248,12 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, ...@@ -232,8 +248,12 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
&dw_ced->ced); &dw_ced->ced);
dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced);
dw_ced->ced.cpumask = cpumask_of(cpu); dw_ced->ced.cpumask = cpumask_of(cpu);
dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC |
dw_ced->ced.set_mode = apbt_set_mode; CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
dw_ced->ced.set_state_shutdown = apbt_shutdown;
dw_ced->ced.set_state_periodic = apbt_set_periodic;
dw_ced->ced.set_state_oneshot = apbt_set_oneshot;
dw_ced->ced.tick_resume = apbt_resume;
dw_ced->ced.set_next_event = apbt_next_event; dw_ced->ced.set_next_event = apbt_next_event;
dw_ced->ced.irq = dw_ced->timer.irq; dw_ced->ced.irq = dw_ced->timer.irq;
dw_ced->ced.rating = rating; dw_ced->ced.rating = rating;
......
...@@ -251,33 +251,21 @@ static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced) ...@@ -251,33 +251,21 @@ static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced)
return container_of(ced, struct em_sti_priv, ced); return container_of(ced, struct em_sti_priv, ced);
} }
static void em_sti_clock_event_mode(enum clock_event_mode mode, static int em_sti_clock_event_shutdown(struct clock_event_device *ced)
struct clock_event_device *ced)
{ {
struct em_sti_priv *p = ced_to_em_sti(ced); struct em_sti_priv *p = ced_to_em_sti(ced);
em_sti_stop(p, USER_CLOCKEVENT);
return 0;
}
/* deal with old setting first */ static int em_sti_clock_event_set_oneshot(struct clock_event_device *ced)
switch (ced->mode) { {
case CLOCK_EVT_MODE_ONESHOT: struct em_sti_priv *p = ced_to_em_sti(ced);
em_sti_stop(p, USER_CLOCKEVENT);
break;
default:
break;
}
switch (mode) { dev_info(&p->pdev->dev, "used for oneshot clock events\n");
case CLOCK_EVT_MODE_ONESHOT: em_sti_start(p, USER_CLOCKEVENT);
dev_info(&p->pdev->dev, "used for oneshot clock events\n"); clockevents_config(&p->ced, p->rate);
em_sti_start(p, USER_CLOCKEVENT); return 0;
clockevents_config(&p->ced, p->rate);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
em_sti_stop(p, USER_CLOCKEVENT);
break;
default:
break;
}
} }
static int em_sti_clock_event_next(unsigned long delta, static int em_sti_clock_event_next(unsigned long delta,
...@@ -303,11 +291,12 @@ static void em_sti_register_clockevent(struct em_sti_priv *p) ...@@ -303,11 +291,12 @@ static void em_sti_register_clockevent(struct em_sti_priv *p)
ced->rating = 200; ced->rating = 200;
ced->cpumask = cpu_possible_mask; ced->cpumask = cpu_possible_mask;
ced->set_next_event = em_sti_clock_event_next; ced->set_next_event = em_sti_clock_event_next;
ced->set_mode = em_sti_clock_event_mode; ced->set_state_shutdown = em_sti_clock_event_shutdown;
ced->set_state_oneshot = em_sti_clock_event_set_oneshot;
dev_info(&p->pdev->dev, "used for clock events\n"); dev_info(&p->pdev->dev, "used for clock events\n");
/* Register with dummy 1 Hz value, gets updated in ->set_mode() */ /* Register with dummy 1 Hz value, gets updated in ->set_state_oneshot() */
clockevents_config_and_register(ced, 1, 2, 0xffffffff); clockevents_config_and_register(ced, 1, 2, 0xffffffff);
} }
......
...@@ -257,15 +257,14 @@ static void exynos4_mct_comp0_stop(void) ...@@ -257,15 +257,14 @@ static void exynos4_mct_comp0_stop(void)
exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB); exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
} }
static void exynos4_mct_comp0_start(enum clock_event_mode mode, static void exynos4_mct_comp0_start(bool periodic, unsigned long cycles)
unsigned long cycles)
{ {
unsigned int tcon; unsigned int tcon;
cycle_t comp_cycle; cycle_t comp_cycle;
tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON);
if (mode == CLOCK_EVT_MODE_PERIODIC) { if (periodic) {
tcon |= MCT_G_TCON_COMP0_AUTO_INC; tcon |= MCT_G_TCON_COMP0_AUTO_INC;
exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR); exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
} }
...@@ -283,38 +282,38 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, ...@@ -283,38 +282,38 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode,
static int exynos4_comp_set_next_event(unsigned long cycles, static int exynos4_comp_set_next_event(unsigned long cycles,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
exynos4_mct_comp0_start(evt->mode, cycles); exynos4_mct_comp0_start(false, cycles);
return 0; return 0;
} }
static void exynos4_comp_set_mode(enum clock_event_mode mode, static int mct_set_state_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
unsigned long cycles_per_jiffy;
exynos4_mct_comp0_stop(); exynos4_mct_comp0_stop();
return 0;
}
switch (mode) { static int mct_set_state_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_PERIODIC: {
cycles_per_jiffy = unsigned long cycles_per_jiffy;
(((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
exynos4_mct_comp0_start(mode, cycles_per_jiffy);
break;
case CLOCK_EVT_MODE_ONESHOT: cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult)
case CLOCK_EVT_MODE_UNUSED: >> evt->shift);
case CLOCK_EVT_MODE_SHUTDOWN: exynos4_mct_comp0_stop();
case CLOCK_EVT_MODE_RESUME: exynos4_mct_comp0_start(true, cycles_per_jiffy);
break; return 0;
}
} }
static struct clock_event_device mct_comp_device = { static struct clock_event_device mct_comp_device = {
.name = "mct-comp", .name = "mct-comp",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.rating = 250, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = exynos4_comp_set_next_event, .rating = 250,
.set_mode = exynos4_comp_set_mode, .set_next_event = exynos4_comp_set_next_event,
.set_state_periodic = mct_set_state_periodic,
.set_state_shutdown = mct_set_state_shutdown,
.set_state_oneshot = mct_set_state_shutdown,
.tick_resume = mct_set_state_shutdown,
}; };
static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id) static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
...@@ -390,39 +389,32 @@ static int exynos4_tick_set_next_event(unsigned long cycles, ...@@ -390,39 +389,32 @@ static int exynos4_tick_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static inline void exynos4_tick_set_mode(enum clock_event_mode mode, static int set_state_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt) {
exynos4_mct_tick_stop(this_cpu_ptr(&percpu_mct_tick));
return 0;
}
static int set_state_periodic(struct clock_event_device *evt)
{ {
struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
unsigned long cycles_per_jiffy; unsigned long cycles_per_jiffy;
cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult)
>> evt->shift);
exynos4_mct_tick_stop(mevt); exynos4_mct_tick_stop(mevt);
exynos4_mct_tick_start(cycles_per_jiffy, mevt);
switch (mode) { return 0;
case CLOCK_EVT_MODE_PERIODIC:
cycles_per_jiffy =
(((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
exynos4_mct_tick_start(cycles_per_jiffy, mevt);
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
break;
}
} }
static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
{ {
struct clock_event_device *evt = &mevt->evt;
/* /*
* This is for supporting oneshot mode. * This is for supporting oneshot mode.
* Mct would generate interrupt periodically * Mct would generate interrupt periodically
* without explicit stopping. * without explicit stopping.
*/ */
if (evt->mode != CLOCK_EVT_MODE_PERIODIC) if (!clockevent_state_periodic(&mevt->evt))
exynos4_mct_tick_stop(mevt); exynos4_mct_tick_stop(mevt);
/* Clear the MCT tick interrupt */ /* Clear the MCT tick interrupt */
...@@ -442,20 +434,21 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) ...@@ -442,20 +434,21 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int exynos4_local_timer_setup(struct clock_event_device *evt) static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt)
{ {
struct mct_clock_event_device *mevt; struct clock_event_device *evt = &mevt->evt;
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
mevt = container_of(evt, struct mct_clock_event_device, evt);
mevt->base = EXYNOS4_MCT_L_BASE(cpu); mevt->base = EXYNOS4_MCT_L_BASE(cpu);
snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu); snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
evt->name = mevt->name; evt->name = mevt->name;
evt->cpumask = cpumask_of(cpu); evt->cpumask = cpumask_of(cpu);
evt->set_next_event = exynos4_tick_set_next_event; evt->set_next_event = exynos4_tick_set_next_event;
evt->set_mode = exynos4_tick_set_mode; evt->set_state_periodic = set_state_periodic;
evt->set_state_shutdown = set_state_shutdown;
evt->set_state_oneshot = set_state_shutdown;
evt->tick_resume = set_state_shutdown;
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->rating = 450; evt->rating = 450;
...@@ -477,9 +470,11 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt) ...@@ -477,9 +470,11 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt)
return 0; return 0;
} }
static void exynos4_local_timer_stop(struct clock_event_device *evt) static void exynos4_local_timer_stop(struct mct_clock_event_device *mevt)
{ {
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); struct clock_event_device *evt = &mevt->evt;
evt->set_state_shutdown(evt);
if (mct_int_type == MCT_INT_SPI) { if (mct_int_type == MCT_INT_SPI) {
if (evt->irq != -1) if (evt->irq != -1)
disable_irq_nosync(evt->irq); disable_irq_nosync(evt->irq);
...@@ -500,11 +495,11 @@ static int exynos4_mct_cpu_notify(struct notifier_block *self, ...@@ -500,11 +495,11 @@ static int exynos4_mct_cpu_notify(struct notifier_block *self,
switch (action & ~CPU_TASKS_FROZEN) { switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING: case CPU_STARTING:
mevt = this_cpu_ptr(&percpu_mct_tick); mevt = this_cpu_ptr(&percpu_mct_tick);
exynos4_local_timer_setup(&mevt->evt); exynos4_local_timer_setup(mevt);
break; break;
case CPU_DYING: case CPU_DYING:
mevt = this_cpu_ptr(&percpu_mct_tick); mevt = this_cpu_ptr(&percpu_mct_tick);
exynos4_local_timer_stop(&mevt->evt); exynos4_local_timer_stop(mevt);
break; break;
} }
...@@ -570,7 +565,7 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem ...@@ -570,7 +565,7 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem
goto out_irq; goto out_irq;
/* Immediately configure the timer on the boot CPU */ /* Immediately configure the timer on the boot CPU */
exynos4_local_timer_setup(&mevt->evt); exynos4_local_timer_setup(mevt);
return; return;
out_irq: out_irq:
......
...@@ -153,19 +153,16 @@ static int ftm_set_next_event(unsigned long delta, ...@@ -153,19 +153,16 @@ static int ftm_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void ftm_set_mode(enum clock_event_mode mode, static int ftm_set_oneshot(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { ftm_counter_disable(priv->clkevt_base);
case CLOCK_EVT_MODE_PERIODIC: return 0;
ftm_set_next_event(priv->periodic_cyc, evt); }
break;
case CLOCK_EVT_MODE_ONESHOT: static int ftm_set_periodic(struct clock_event_device *evt)
ftm_counter_disable(priv->clkevt_base); {
break; ftm_set_next_event(priv->periodic_cyc, evt);
default: return 0;
return;
}
} }
static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id)
...@@ -174,7 +171,7 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) ...@@ -174,7 +171,7 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id)
ftm_irq_acknowledge(priv->clkevt_base); ftm_irq_acknowledge(priv->clkevt_base);
if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) { if (likely(clockevent_state_oneshot(evt))) {
ftm_irq_disable(priv->clkevt_base); ftm_irq_disable(priv->clkevt_base);
ftm_counter_disable(priv->clkevt_base); ftm_counter_disable(priv->clkevt_base);
} }
...@@ -185,11 +182,13 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) ...@@ -185,11 +182,13 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id)
} }
static struct clock_event_device ftm_clockevent = { static struct clock_event_device ftm_clockevent = {
.name = "Freescale ftm timer", .name = "Freescale ftm timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.set_mode = ftm_set_mode, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = ftm_set_next_event, .set_state_periodic = ftm_set_periodic,
.rating = 300, .set_state_oneshot = ftm_set_oneshot,
.set_next_event = ftm_set_next_event,
.rating = 300,
}; };
static struct irqaction ftm_timer_irq = { static struct irqaction ftm_timer_irq = {
......
...@@ -81,7 +81,7 @@ static irqreturn_t timer8_interrupt(int irq, void *dev_id) ...@@ -81,7 +81,7 @@ static irqreturn_t timer8_interrupt(int irq, void *dev_id)
p->flags |= FLAG_IRQCONTEXT; p->flags |= FLAG_IRQCONTEXT;
ctrl_outw(p->tcora, p->mapbase + TCORA); ctrl_outw(p->tcora, p->mapbase + TCORA);
if (!(p->flags & FLAG_SKIPEVENT)) { if (!(p->flags & FLAG_SKIPEVENT)) {
if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) if (clockevent_state_oneshot(&p->ced))
ctrl_outw(0x0000, p->mapbase + _8TCR); ctrl_outw(0x0000, p->mapbase + _8TCR);
p->ced.event_handler(&p->ced); p->ced.event_handler(&p->ced);
} }
...@@ -169,29 +169,32 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic) ...@@ -169,29 +169,32 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000); timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000);
} }
static void timer8_clock_event_mode(enum clock_event_mode mode, static int timer8_clock_event_shutdown(struct clock_event_device *ced)
struct clock_event_device *ced) {
timer8_stop(ced_to_priv(ced));
return 0;
}
static int timer8_clock_event_periodic(struct clock_event_device *ced)
{ {
struct timer8_priv *p = ced_to_priv(ced); struct timer8_priv *p = ced_to_priv(ced);
switch (mode) { dev_info(&p->pdev->dev, "used for periodic clock events\n");
case CLOCK_EVT_MODE_PERIODIC: timer8_stop(p);
dev_info(&p->pdev->dev, "used for periodic clock events\n"); timer8_clock_event_start(p, PERIODIC);
timer8_stop(p);
timer8_clock_event_start(p, PERIODIC); return 0;
break; }
case CLOCK_EVT_MODE_ONESHOT:
dev_info(&p->pdev->dev, "used for oneshot clock events\n"); static int timer8_clock_event_oneshot(struct clock_event_device *ced)
timer8_stop(p); {
timer8_clock_event_start(p, ONESHOT); struct timer8_priv *p = ced_to_priv(ced);
break;
case CLOCK_EVT_MODE_SHUTDOWN: dev_info(&p->pdev->dev, "used for oneshot clock events\n");
case CLOCK_EVT_MODE_UNUSED: timer8_stop(p);
timer8_stop(p); timer8_clock_event_start(p, ONESHOT);
break;
default: return 0;
break;
}
} }
static int timer8_clock_event_next(unsigned long delta, static int timer8_clock_event_next(unsigned long delta,
...@@ -199,7 +202,7 @@ static int timer8_clock_event_next(unsigned long delta, ...@@ -199,7 +202,7 @@ static int timer8_clock_event_next(unsigned long delta,
{ {
struct timer8_priv *p = ced_to_priv(ced); struct timer8_priv *p = ced_to_priv(ced);
BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); BUG_ON(!clockevent_state_oneshot(ced));
timer8_set_next(p, delta - 1); timer8_set_next(p, delta - 1);
return 0; return 0;
...@@ -246,7 +249,9 @@ static int timer8_setup(struct timer8_priv *p, ...@@ -246,7 +249,9 @@ static int timer8_setup(struct timer8_priv *p,
p->ced.rating = 200; p->ced.rating = 200;
p->ced.cpumask = cpumask_of(0); p->ced.cpumask = cpumask_of(0);
p->ced.set_next_event = timer8_clock_event_next; p->ced.set_next_event = timer8_clock_event_next;
p->ced.set_mode = timer8_clock_event_mode; p->ced.set_state_shutdown = timer8_clock_event_shutdown;
p->ced.set_state_periodic = timer8_clock_event_periodic;
p->ced.set_state_oneshot = timer8_clock_event_oneshot;
ret = setup_irq(irq, &p->irqaction); ret = setup_irq(irq, &p->irqaction);
if (ret < 0) { if (ret < 0) {
......
...@@ -100,44 +100,40 @@ int __init clocksource_i8253_init(void) ...@@ -100,44 +100,40 @@ int __init clocksource_i8253_init(void)
#endif #endif
#ifdef CONFIG_CLKEVT_I8253 #ifdef CONFIG_CLKEVT_I8253
/* static int pit_shutdown(struct clock_event_device *evt)
* Initialize the PIT timer.
*
* This is also called after resume to bring the PIT into operation again.
*/
static void init_pit_timer(enum clock_event_mode mode,
struct clock_event_device *evt)
{ {
if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt))
return 0;
raw_spin_lock(&i8253_lock); raw_spin_lock(&i8253_lock);
switch (mode) { outb_p(0x30, PIT_MODE);
case CLOCK_EVT_MODE_PERIODIC: outb_p(0, PIT_CH0);
/* binary, mode 2, LSB/MSB, ch 0 */ outb_p(0, PIT_CH0);
outb_p(0x34, PIT_MODE);
outb_p(PIT_LATCH & 0xff , PIT_CH0); /* LSB */ raw_spin_unlock(&i8253_lock);
outb_p(PIT_LATCH >> 8 , PIT_CH0); /* MSB */ return 0;
break; }
case CLOCK_EVT_MODE_SHUTDOWN: static int pit_set_oneshot(struct clock_event_device *evt)
case CLOCK_EVT_MODE_UNUSED: {
if (evt->mode == CLOCK_EVT_MODE_PERIODIC || raw_spin_lock(&i8253_lock);
evt->mode == CLOCK_EVT_MODE_ONESHOT) { outb_p(0x38, PIT_MODE);
outb_p(0x30, PIT_MODE); raw_spin_unlock(&i8253_lock);
outb_p(0, PIT_CH0); return 0;
outb_p(0, PIT_CH0); }
}
break; static int pit_set_periodic(struct clock_event_device *evt)
{
case CLOCK_EVT_MODE_ONESHOT: raw_spin_lock(&i8253_lock);
/* One shot setup */
outb_p(0x38, PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */
break; outb_p(0x34, PIT_MODE);
outb_p(PIT_LATCH & 0xff, PIT_CH0); /* LSB */
case CLOCK_EVT_MODE_RESUME: outb_p(PIT_LATCH >> 8, PIT_CH0); /* MSB */
/* Nothing to do here */
break;
}
raw_spin_unlock(&i8253_lock); raw_spin_unlock(&i8253_lock);
return 0;
} }
/* /*
...@@ -160,10 +156,11 @@ static int pit_next_event(unsigned long delta, struct clock_event_device *evt) ...@@ -160,10 +156,11 @@ static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
* it can be solely used for the global tick. * it can be solely used for the global tick.
*/ */
struct clock_event_device i8253_clockevent = { struct clock_event_device i8253_clockevent = {
.name = "pit", .name = "pit",
.features = CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_PERIODIC,
.set_mode = init_pit_timer, .set_state_shutdown = pit_shutdown,
.set_next_event = pit_next_event, .set_state_periodic = pit_set_periodic,
.set_next_event = pit_next_event,
}; };
/* /*
...@@ -172,8 +169,10 @@ struct clock_event_device i8253_clockevent = { ...@@ -172,8 +169,10 @@ struct clock_event_device i8253_clockevent = {
*/ */
void __init clockevent_i8253_init(bool oneshot) void __init clockevent_i8253_init(bool oneshot)
{ {
if (oneshot) if (oneshot) {
i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT; i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT;
i8253_clockevent.set_state_oneshot = pit_set_oneshot;
}
/* /*
* Start pit with the boot cpu mask. x86 might make it global * Start pit with the boot cpu mask. x86 might make it global
* when it is used as broadcast device later. * when it is used as broadcast device later.
......
...@@ -67,25 +67,25 @@ static void meson6_clkevt_time_start(unsigned char timer, bool periodic) ...@@ -67,25 +67,25 @@ static void meson6_clkevt_time_start(unsigned char timer, bool periodic)
writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX);
} }
static void meson6_clkevt_mode(enum clock_event_mode mode, static int meson6_shutdown(struct clock_event_device *evt)
struct clock_event_device *clk)
{ {
switch (mode) { meson6_clkevt_time_stop(CED_ID);
case CLOCK_EVT_MODE_PERIODIC: return 0;
meson6_clkevt_time_stop(CED_ID); }
meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC/HZ - 1);
meson6_clkevt_time_start(CED_ID, true); static int meson6_set_oneshot(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_ONESHOT: meson6_clkevt_time_stop(CED_ID);
meson6_clkevt_time_stop(CED_ID); meson6_clkevt_time_start(CED_ID, false);
meson6_clkevt_time_start(CED_ID, false); return 0;
break; }
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN: static int meson6_set_periodic(struct clock_event_device *evt)
default: {
meson6_clkevt_time_stop(CED_ID); meson6_clkevt_time_stop(CED_ID);
break; meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC / HZ - 1);
} meson6_clkevt_time_start(CED_ID, true);
return 0;
} }
static int meson6_clkevt_next_event(unsigned long evt, static int meson6_clkevt_next_event(unsigned long evt,
...@@ -99,11 +99,15 @@ static int meson6_clkevt_next_event(unsigned long evt, ...@@ -99,11 +99,15 @@ static int meson6_clkevt_next_event(unsigned long evt,
} }
static struct clock_event_device meson6_clockevent = { static struct clock_event_device meson6_clockevent = {
.name = "meson6_tick", .name = "meson6_tick",
.rating = 400, .rating = 400,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.set_mode = meson6_clkevt_mode, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = meson6_clkevt_next_event, .set_state_shutdown = meson6_shutdown,
.set_state_periodic = meson6_set_periodic,
.set_state_oneshot = meson6_set_oneshot,
.tick_resume = meson6_shutdown,
.set_next_event = meson6_clkevt_next_event,
}; };
static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id)
......
...@@ -56,25 +56,6 @@ static int metag_timer_set_next_event(unsigned long delta, ...@@ -56,25 +56,6 @@ static int metag_timer_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void metag_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_RESUME:
break;
case CLOCK_EVT_MODE_SHUTDOWN:
/* We should disable the IRQ here */
break;
case CLOCK_EVT_MODE_PERIODIC:
case CLOCK_EVT_MODE_UNUSED:
WARN_ON(1);
break;
};
}
static cycle_t metag_clocksource_read(struct clocksource *cs) static cycle_t metag_clocksource_read(struct clocksource *cs)
{ {
return __core_reg_get(TXTIMER); return __core_reg_get(TXTIMER);
...@@ -129,7 +110,6 @@ static void arch_timer_setup(unsigned int cpu) ...@@ -129,7 +110,6 @@ static void arch_timer_setup(unsigned int cpu)
clk->rating = 200, clk->rating = 200,
clk->shift = 12, clk->shift = 12,
clk->irq = tbisig_map(TBID_SIGNUM_TRT), clk->irq = tbisig_map(TBID_SIGNUM_TRT),
clk->set_mode = metag_timer_set_mode,
clk->set_next_event = metag_timer_set_next_event, clk->set_next_event = metag_timer_set_next_event,
clk->mult = div_sc(hwtimer_freq, NSEC_PER_SEC, clk->shift); clk->mult = div_sc(hwtimer_freq, NSEC_PER_SEC, clk->shift);
......
...@@ -33,12 +33,6 @@ static int gic_next_event(unsigned long delta, struct clock_event_device *evt) ...@@ -33,12 +33,6 @@ static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
return res; return res;
} }
static void gic_set_clock_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
/* Nothing to do ... */
}
static irqreturn_t gic_compare_interrupt(int irq, void *dev_id) static irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
{ {
struct clock_event_device *cd = dev_id; struct clock_event_device *cd = dev_id;
...@@ -67,7 +61,6 @@ static void gic_clockevent_cpu_init(struct clock_event_device *cd) ...@@ -67,7 +61,6 @@ static void gic_clockevent_cpu_init(struct clock_event_device *cd)
cd->irq = gic_timer_irq; cd->irq = gic_timer_irq;
cd->cpumask = cpumask_of(cpu); cd->cpumask = cpumask_of(cpu);
cd->set_next_event = gic_next_event; cd->set_next_event = gic_next_event;
cd->set_mode = gic_set_clock_mode;
clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff); clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff);
......
...@@ -58,25 +58,24 @@ ...@@ -58,25 +58,24 @@
static void __iomem *base; static void __iomem *base;
static unsigned int clock_count_per_tick; static unsigned int clock_count_per_tick;
static void moxart_clkevt_mode(enum clock_event_mode mode, static int moxart_shutdown(struct clock_event_device *evt)
struct clock_event_device *clk)
{ {
switch (mode) { writel(TIMER1_DISABLE, base + TIMER_CR);
case CLOCK_EVT_MODE_RESUME: return 0;
case CLOCK_EVT_MODE_ONESHOT: }
writel(TIMER1_DISABLE, base + TIMER_CR);
writel(~0, base + TIMER1_BASE + REG_LOAD); static int moxart_set_oneshot(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_PERIODIC: writel(TIMER1_DISABLE, base + TIMER_CR);
writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); writel(~0, base + TIMER1_BASE + REG_LOAD);
writel(TIMER1_ENABLE, base + TIMER_CR); return 0;
break; }
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN: static int moxart_set_periodic(struct clock_event_device *evt)
default: {
writel(TIMER1_DISABLE, base + TIMER_CR); writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD);
break; writel(TIMER1_ENABLE, base + TIMER_CR);
} return 0;
} }
static int moxart_clkevt_next_event(unsigned long cycles, static int moxart_clkevt_next_event(unsigned long cycles,
...@@ -95,11 +94,15 @@ static int moxart_clkevt_next_event(unsigned long cycles, ...@@ -95,11 +94,15 @@ static int moxart_clkevt_next_event(unsigned long cycles,
} }
static struct clock_event_device moxart_clockevent = { static struct clock_event_device moxart_clockevent = {
.name = "moxart_timer", .name = "moxart_timer",
.rating = 200, .rating = 200,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.set_mode = moxart_clkevt_mode, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = moxart_clkevt_next_event, .set_state_shutdown = moxart_shutdown,
.set_state_periodic = moxart_set_periodic,
.set_state_oneshot = moxart_set_oneshot,
.tick_resume = moxart_set_oneshot,
.set_next_event = moxart_clkevt_next_event,
}; };
static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id) static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
......
...@@ -102,27 +102,20 @@ static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt, ...@@ -102,27 +102,20 @@ static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt,
evt->gpt_base + TIMER_CTRL_REG(timer)); evt->gpt_base + TIMER_CTRL_REG(timer));
} }
static void mtk_clkevt_mode(enum clock_event_mode mode, static int mtk_clkevt_shutdown(struct clock_event_device *clk)
struct clock_event_device *clk) {
mtk_clkevt_time_stop(to_mtk_clk(clk), GPT_CLK_EVT);
return 0;
}
static int mtk_clkevt_set_periodic(struct clock_event_device *clk)
{ {
struct mtk_clock_event_device *evt = to_mtk_clk(clk); struct mtk_clock_event_device *evt = to_mtk_clk(clk);
mtk_clkevt_time_stop(evt, GPT_CLK_EVT); mtk_clkevt_time_stop(evt, GPT_CLK_EVT);
mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT);
switch (mode) { mtk_clkevt_time_start(evt, true, GPT_CLK_EVT);
case CLOCK_EVT_MODE_PERIODIC: return 0;
mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT);
mtk_clkevt_time_start(evt, true, GPT_CLK_EVT);
break;
case CLOCK_EVT_MODE_ONESHOT:
/* Timer is enabled in set_next_event */
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
default:
/* No more interrupts will occur as source is disabled */
break;
}
} }
static int mtk_clkevt_next_event(unsigned long event, static int mtk_clkevt_next_event(unsigned long event,
...@@ -196,7 +189,10 @@ static void __init mtk_timer_init(struct device_node *node) ...@@ -196,7 +189,10 @@ static void __init mtk_timer_init(struct device_node *node)
evt->dev.name = "mtk_tick"; evt->dev.name = "mtk_tick";
evt->dev.rating = 300; evt->dev.rating = 300;
evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->dev.set_mode = mtk_clkevt_mode; evt->dev.set_state_shutdown = mtk_clkevt_shutdown;
evt->dev.set_state_periodic = mtk_clkevt_set_periodic;
evt->dev.set_state_oneshot = mtk_clkevt_shutdown;
evt->dev.tick_resume = mtk_clkevt_shutdown;
evt->dev.set_next_event = mtk_clkevt_next_event; evt->dev.set_next_event = mtk_clkevt_next_event;
evt->dev.cpumask = cpu_possible_mask; evt->dev.cpumask = cpu_possible_mask;
......
...@@ -77,7 +77,6 @@ ...@@ -77,7 +77,6 @@
#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS 0xf #define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS 0xf
static struct clock_event_device mxs_clockevent_device; static struct clock_event_device mxs_clockevent_device;
static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED;
static void __iomem *mxs_timrot_base; static void __iomem *mxs_timrot_base;
static u32 timrot_major_version; static u32 timrot_major_version;
...@@ -141,64 +140,49 @@ static struct irqaction mxs_timer_irq = { ...@@ -141,64 +140,49 @@ static struct irqaction mxs_timer_irq = {
.handler = mxs_timer_interrupt, .handler = mxs_timer_interrupt,
}; };
#ifdef DEBUG static void mxs_irq_clear(char *state)
static const char *clock_event_mode_label[] const = {
[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
[CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
[CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED"
};
#endif /* DEBUG */
static void mxs_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{ {
/* Disable interrupt in timer module */ /* Disable interrupt in timer module */
timrot_irq_disable(); timrot_irq_disable();
if (mode != mxs_clockevent_mode) { /* Set event time into the furthest future */
/* Set event time into the furthest future */ if (timrot_is_v1())
if (timrot_is_v1()) __raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
__raw_writel(0xffff, else
mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); __raw_writel(0xffffffff,
else mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
__raw_writel(0xffffffff,
mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); /* Clear pending interrupt */
timrot_irq_acknowledge();
/* Clear pending interrupt */
timrot_irq_acknowledge();
}
#ifdef DEBUG #ifdef DEBUG
pr_info("%s: changing mode from %s to %s\n", __func__, pr_info("%s: changing mode to %s\n", __func__, state)
clock_event_mode_label[mxs_clockevent_mode],
clock_event_mode_label[mode]);
#endif /* DEBUG */ #endif /* DEBUG */
}
/* Remember timer mode */ static int mxs_shutdown(struct clock_event_device *evt)
mxs_clockevent_mode = mode; {
mxs_irq_clear("shutdown");
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: return 0;
pr_err("%s: Periodic mode is not implemented\n", __func__); }
break;
case CLOCK_EVT_MODE_ONESHOT: static int mxs_set_oneshot(struct clock_event_device *evt)
timrot_irq_enable(); {
break; if (clockevent_state_oneshot(evt))
case CLOCK_EVT_MODE_SHUTDOWN: mxs_irq_clear("oneshot");
case CLOCK_EVT_MODE_UNUSED: timrot_irq_enable();
case CLOCK_EVT_MODE_RESUME: return 0;
/* Left event sources disabled, no more interrupts appear */
break;
}
} }
static struct clock_event_device mxs_clockevent_device = { static struct clock_event_device mxs_clockevent_device = {
.name = "mxs_timrot", .name = "mxs_timrot",
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.set_mode = mxs_set_mode, .set_state_shutdown = mxs_shutdown,
.set_next_event = timrotv2_set_next_event, .set_state_oneshot = mxs_set_oneshot,
.rating = 200, .tick_resume = mxs_shutdown,
.set_next_event = timrotv2_set_next_event,
.rating = 200,
}; };
static int __init mxs_clockevent_init(struct clk *timer_clk) static int __init mxs_clockevent_init(struct clk *timer_clk)
......
...@@ -119,28 +119,27 @@ static void nmdk_clkevt_reset(void) ...@@ -119,28 +119,27 @@ static void nmdk_clkevt_reset(void)
} }
} }
static void nmdk_clkevt_mode(enum clock_event_mode mode, static int nmdk_clkevt_shutdown(struct clock_event_device *evt)
struct clock_event_device *dev)
{ {
switch (mode) { writel(0, mtu_base + MTU_IMSC);
case CLOCK_EVT_MODE_PERIODIC: /* disable timer */
clkevt_periodic = true; writel(0, mtu_base + MTU_CR(1));
nmdk_clkevt_reset(); /* load some high default value */
break; writel(0xffffffff, mtu_base + MTU_LR(1));
case CLOCK_EVT_MODE_ONESHOT: return 0;
clkevt_periodic = false; }
break;
case CLOCK_EVT_MODE_SHUTDOWN: static int nmdk_clkevt_set_oneshot(struct clock_event_device *evt)
case CLOCK_EVT_MODE_UNUSED: {
writel(0, mtu_base + MTU_IMSC); clkevt_periodic = false;
/* disable timer */ return 0;
writel(0, mtu_base + MTU_CR(1)); }
/* load some high default value */
writel(0xffffffff, mtu_base + MTU_LR(1)); static int nmdk_clkevt_set_periodic(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_RESUME: clkevt_periodic = true;
break; nmdk_clkevt_reset();
} return 0;
} }
static void nmdk_clksrc_reset(void) static void nmdk_clksrc_reset(void)
...@@ -163,13 +162,16 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) ...@@ -163,13 +162,16 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev)
} }
static struct clock_event_device nmdk_clkevt = { static struct clock_event_device nmdk_clkevt = {
.name = "mtu_1", .name = "mtu_1",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | .features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_DYNIRQ, CLOCK_EVT_FEAT_PERIODIC |
.rating = 200, CLOCK_EVT_FEAT_DYNIRQ,
.set_mode = nmdk_clkevt_mode, .rating = 200,
.set_next_event = nmdk_clkevt_next, .set_state_shutdown = nmdk_clkevt_shutdown,
.resume = nmdk_clkevt_resume, .set_state_periodic = nmdk_clkevt_set_periodic,
.set_state_oneshot = nmdk_clkevt_set_oneshot,
.set_next_event = nmdk_clkevt_next,
.resume = nmdk_clkevt_resume,
}; };
/* /*
......
...@@ -88,26 +88,12 @@ pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) ...@@ -88,26 +88,12 @@ pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
} }
static void static int pxa_osmr0_shutdown(struct clock_event_device *evt)
pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{ {
switch (mode) { /* initializing, released, or preparing for suspend */
case CLOCK_EVT_MODE_ONESHOT: timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); timer_writel(OSSR_M0, OSSR);
timer_writel(OSSR_M0, OSSR); return 0;
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* initializing, released, or preparing for suspend */
timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
timer_writel(OSSR_M0, OSSR);
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
}
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -147,13 +133,14 @@ static void pxa_timer_resume(struct clock_event_device *cedev) ...@@ -147,13 +133,14 @@ static void pxa_timer_resume(struct clock_event_device *cedev)
#endif #endif
static struct clock_event_device ckevt_pxa_osmr0 = { static struct clock_event_device ckevt_pxa_osmr0 = {
.name = "osmr0", .name = "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 200, .rating = 200,
.set_next_event = pxa_osmr0_set_next_event, .set_next_event = pxa_osmr0_set_next_event,
.set_mode = pxa_osmr0_set_mode, .set_state_shutdown = pxa_osmr0_shutdown,
.suspend = pxa_timer_suspend, .set_state_oneshot = pxa_osmr0_shutdown,
.resume = pxa_timer_resume, .suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
}; };
static struct irqaction pxa_ost0_irq = { static struct irqaction pxa_ost0_irq = {
......
...@@ -47,7 +47,7 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) ...@@ -47,7 +47,7 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
{ {
struct clock_event_device *evt = dev_id; struct clock_event_device *evt = dev_id;
/* Stop the timer tick */ /* Stop the timer tick */
if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { if (clockevent_state_oneshot(evt)) {
u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
ctrl &= ~TIMER_ENABLE_EN; ctrl &= ~TIMER_ENABLE_EN;
writel_relaxed(ctrl, event_base + TIMER_ENABLE); writel_relaxed(ctrl, event_base + TIMER_ENABLE);
...@@ -75,26 +75,14 @@ static int msm_timer_set_next_event(unsigned long cycles, ...@@ -75,26 +75,14 @@ static int msm_timer_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static void msm_timer_set_mode(enum clock_event_mode mode, static int msm_timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
u32 ctrl; u32 ctrl;
ctrl = readl_relaxed(event_base + TIMER_ENABLE); ctrl = readl_relaxed(event_base + TIMER_ENABLE);
ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN);
switch (mode) {
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
case CLOCK_EVT_MODE_ONESHOT:
/* Timer is enabled in set_next_event */
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
break;
}
writel_relaxed(ctrl, event_base + TIMER_ENABLE); writel_relaxed(ctrl, event_base + TIMER_ENABLE);
return 0;
} }
static struct clock_event_device __percpu *msm_evt; static struct clock_event_device __percpu *msm_evt;
...@@ -126,7 +114,9 @@ static int msm_local_timer_setup(struct clock_event_device *evt) ...@@ -126,7 +114,9 @@ static int msm_local_timer_setup(struct clock_event_device *evt)
evt->name = "msm_timer"; evt->name = "msm_timer";
evt->features = CLOCK_EVT_FEAT_ONESHOT; evt->features = CLOCK_EVT_FEAT_ONESHOT;
evt->rating = 200; evt->rating = 200;
evt->set_mode = msm_timer_set_mode; evt->set_state_shutdown = msm_timer_shutdown;
evt->set_state_oneshot = msm_timer_shutdown;
evt->tick_resume = msm_timer_shutdown;
evt->set_next_event = msm_timer_set_next_event; evt->set_next_event = msm_timer_set_next_event;
evt->cpumask = cpumask_of(cpu); evt->cpumask = cpumask_of(cpu);
...@@ -147,7 +137,7 @@ static int msm_local_timer_setup(struct clock_event_device *evt) ...@@ -147,7 +137,7 @@ static int msm_local_timer_setup(struct clock_event_device *evt)
static void msm_local_timer_stop(struct clock_event_device *evt) static void msm_local_timer_stop(struct clock_event_device *evt)
{ {
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); evt->set_state_shutdown(evt);
disable_percpu_irq(evt->irq); disable_percpu_irq(evt->irq);
} }
......
...@@ -82,23 +82,18 @@ static inline int rk_timer_set_next_event(unsigned long cycles, ...@@ -82,23 +82,18 @@ static inline int rk_timer_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static inline void rk_timer_set_mode(enum clock_event_mode mode, static int rk_timer_shutdown(struct clock_event_device *ce)
struct clock_event_device *ce)
{ {
switch (mode) { rk_timer_disable(ce);
case CLOCK_EVT_MODE_PERIODIC: return 0;
rk_timer_disable(ce); }
rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING); static int rk_timer_set_periodic(struct clock_event_device *ce)
break; {
case CLOCK_EVT_MODE_ONESHOT: rk_timer_disable(ce);
case CLOCK_EVT_MODE_RESUME: rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
break; rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
case CLOCK_EVT_MODE_UNUSED: return 0;
case CLOCK_EVT_MODE_SHUTDOWN:
rk_timer_disable(ce);
break;
}
} }
static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
...@@ -107,7 +102,7 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) ...@@ -107,7 +102,7 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
rk_timer_interrupt_clear(ce); rk_timer_interrupt_clear(ce);
if (ce->mode == CLOCK_EVT_MODE_ONESHOT) if (clockevent_state_oneshot(ce))
rk_timer_disable(ce); rk_timer_disable(ce);
ce->event_handler(ce); ce->event_handler(ce);
...@@ -161,7 +156,8 @@ static void __init rk_timer_init(struct device_node *np) ...@@ -161,7 +156,8 @@ static void __init rk_timer_init(struct device_node *np)
ce->name = TIMER_NAME; ce->name = TIMER_NAME;
ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
ce->set_next_event = rk_timer_set_next_event; ce->set_next_event = rk_timer_set_next_event;
ce->set_mode = rk_timer_set_mode; ce->set_state_shutdown = rk_timer_shutdown;
ce->set_state_periodic = rk_timer_set_periodic;
ce->irq = irq; ce->irq = irq;
ce->cpumask = cpumask_of(0); ce->cpumask = cpumask_of(0);
ce->rating = 250; ce->rating = 250;
......
...@@ -207,25 +207,18 @@ static int samsung_set_next_event(unsigned long cycles, ...@@ -207,25 +207,18 @@ static int samsung_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static void samsung_set_mode(enum clock_event_mode mode, static int samsung_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
samsung_time_stop(pwm.event_id); samsung_time_stop(pwm.event_id);
return 0;
}
switch (mode) { static int samsung_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_PERIODIC: {
samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); samsung_time_stop(pwm.event_id);
samsung_time_start(pwm.event_id, true); samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1);
break; samsung_time_start(pwm.event_id, true);
return 0;
case CLOCK_EVT_MODE_ONESHOT:
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
break;
}
} }
static void samsung_clockevent_resume(struct clock_event_device *cev) static void samsung_clockevent_resume(struct clock_event_device *cev)
...@@ -240,12 +233,16 @@ static void samsung_clockevent_resume(struct clock_event_device *cev) ...@@ -240,12 +233,16 @@ static void samsung_clockevent_resume(struct clock_event_device *cev)
} }
static struct clock_event_device time_event_device = { static struct clock_event_device time_event_device = {
.name = "samsung_event_timer", .name = "samsung_event_timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.rating = 200, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = samsung_set_next_event, .rating = 200,
.set_mode = samsung_set_mode, .set_next_event = samsung_set_next_event,
.resume = samsung_clockevent_resume, .set_state_shutdown = samsung_shutdown,
.set_state_periodic = samsung_set_periodic,
.set_state_oneshot = samsung_shutdown,
.tick_resume = samsung_shutdown,
.resume = samsung_clockevent_resume,
}; };
static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
......
...@@ -538,7 +538,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) ...@@ -538,7 +538,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
if (ch->flags & FLAG_CLOCKEVENT) { if (ch->flags & FLAG_CLOCKEVENT) {
if (!(ch->flags & FLAG_SKIPEVENT)) { if (!(ch->flags & FLAG_SKIPEVENT)) {
if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) { if (clockevent_state_oneshot(&ch->ced)) {
ch->next_match_value = ch->max_match_value; ch->next_match_value = ch->max_match_value;
ch->flags |= FLAG_REPROGRAM; ch->flags |= FLAG_REPROGRAM;
} }
...@@ -554,7 +554,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) ...@@ -554,7 +554,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
sh_cmt_clock_event_program_verify(ch, 1); sh_cmt_clock_event_program_verify(ch, 1);
if (ch->flags & FLAG_CLOCKEVENT) if (ch->flags & FLAG_CLOCKEVENT)
if ((ch->ced.mode == CLOCK_EVT_MODE_SHUTDOWN) if ((clockevent_state_shutdown(&ch->ced))
|| (ch->match_value == ch->next_match_value)) || (ch->match_value == ch->next_match_value))
ch->flags &= ~FLAG_REPROGRAM; ch->flags &= ~FLAG_REPROGRAM;
} }
...@@ -726,39 +726,37 @@ static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic) ...@@ -726,39 +726,37 @@ static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
sh_cmt_set_next(ch, ch->max_match_value); sh_cmt_set_next(ch, ch->max_match_value);
} }
static void sh_cmt_clock_event_mode(enum clock_event_mode mode, static int sh_cmt_clock_event_shutdown(struct clock_event_device *ced)
struct clock_event_device *ced) {
struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
sh_cmt_stop(ch, FLAG_CLOCKEVENT);
return 0;
}
static int sh_cmt_clock_event_set_state(struct clock_event_device *ced,
int periodic)
{ {
struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
/* deal with old setting first */ /* deal with old setting first */
switch (ced->mode) { if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
case CLOCK_EVT_MODE_PERIODIC:
case CLOCK_EVT_MODE_ONESHOT:
sh_cmt_stop(ch, FLAG_CLOCKEVENT); sh_cmt_stop(ch, FLAG_CLOCKEVENT);
break;
default:
break;
}
switch (mode) { dev_info(&ch->cmt->pdev->dev, "ch%u: used for %s clock events\n",
case CLOCK_EVT_MODE_PERIODIC: ch->index, periodic ? "periodic" : "oneshot");
dev_info(&ch->cmt->pdev->dev, sh_cmt_clock_event_start(ch, periodic);
"ch%u: used for periodic clock events\n", ch->index); return 0;
sh_cmt_clock_event_start(ch, 1); }
break;
case CLOCK_EVT_MODE_ONESHOT: static int sh_cmt_clock_event_set_oneshot(struct clock_event_device *ced)
dev_info(&ch->cmt->pdev->dev, {
"ch%u: used for oneshot clock events\n", ch->index); return sh_cmt_clock_event_set_state(ced, 0);
sh_cmt_clock_event_start(ch, 0); }
break;
case CLOCK_EVT_MODE_SHUTDOWN: static int sh_cmt_clock_event_set_periodic(struct clock_event_device *ced)
case CLOCK_EVT_MODE_UNUSED: {
sh_cmt_stop(ch, FLAG_CLOCKEVENT); return sh_cmt_clock_event_set_state(ced, 1);
break;
default:
break;
}
} }
static int sh_cmt_clock_event_next(unsigned long delta, static int sh_cmt_clock_event_next(unsigned long delta,
...@@ -766,7 +764,7 @@ static int sh_cmt_clock_event_next(unsigned long delta, ...@@ -766,7 +764,7 @@ static int sh_cmt_clock_event_next(unsigned long delta,
{ {
struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); BUG_ON(!clockevent_state_oneshot(ced));
if (likely(ch->flags & FLAG_IRQCONTEXT)) if (likely(ch->flags & FLAG_IRQCONTEXT))
ch->next_match_value = delta - 1; ch->next_match_value = delta - 1;
else else
...@@ -820,7 +818,9 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch, ...@@ -820,7 +818,9 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
ced->rating = 125; ced->rating = 125;
ced->cpumask = cpu_possible_mask; ced->cpumask = cpu_possible_mask;
ced->set_next_event = sh_cmt_clock_event_next; ced->set_next_event = sh_cmt_clock_event_next;
ced->set_mode = sh_cmt_clock_event_mode; ced->set_state_shutdown = sh_cmt_clock_event_shutdown;
ced->set_state_periodic = sh_cmt_clock_event_set_periodic;
ced->set_state_oneshot = sh_cmt_clock_event_set_oneshot;
ced->suspend = sh_cmt_clock_event_suspend; ced->suspend = sh_cmt_clock_event_suspend;
ced->resume = sh_cmt_clock_event_resume; ced->resume = sh_cmt_clock_event_resume;
...@@ -935,9 +935,6 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt) ...@@ -935,9 +935,6 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt)
static const struct platform_device_id sh_cmt_id_table[] = { static const struct platform_device_id sh_cmt_id_table[] = {
{ "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] },
{ "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] },
{ "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] },
{ "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] },
{ "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] },
{ } { }
}; };
MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); MODULE_DEVICE_TABLE(platform, sh_cmt_id_table);
......
...@@ -276,36 +276,25 @@ static struct sh_mtu2_channel *ced_to_sh_mtu2(struct clock_event_device *ced) ...@@ -276,36 +276,25 @@ static struct sh_mtu2_channel *ced_to_sh_mtu2(struct clock_event_device *ced)
return container_of(ced, struct sh_mtu2_channel, ced); return container_of(ced, struct sh_mtu2_channel, ced);
} }
static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, static int sh_mtu2_clock_event_shutdown(struct clock_event_device *ced)
struct clock_event_device *ced)
{ {
struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced); struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced);
int disabled = 0;
/* deal with old setting first */ sh_mtu2_disable(ch);
switch (ced->mode) { return 0;
case CLOCK_EVT_MODE_PERIODIC: }
static int sh_mtu2_clock_event_set_periodic(struct clock_event_device *ced)
{
struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced);
if (clockevent_state_periodic(ced))
sh_mtu2_disable(ch); sh_mtu2_disable(ch);
disabled = 1;
break;
default:
break;
}
switch (mode) { dev_info(&ch->mtu->pdev->dev, "ch%u: used for periodic clock events\n",
case CLOCK_EVT_MODE_PERIODIC: ch->index);
dev_info(&ch->mtu->pdev->dev, sh_mtu2_enable(ch);
"ch%u: used for periodic clock events\n", ch->index); return 0;
sh_mtu2_enable(ch);
break;
case CLOCK_EVT_MODE_UNUSED:
if (!disabled)
sh_mtu2_disable(ch);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
default:
break;
}
} }
static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced) static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced)
...@@ -327,7 +316,8 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, ...@@ -327,7 +316,8 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,
ced->features = CLOCK_EVT_FEAT_PERIODIC; ced->features = CLOCK_EVT_FEAT_PERIODIC;
ced->rating = 200; ced->rating = 200;
ced->cpumask = cpu_possible_mask; ced->cpumask = cpu_possible_mask;
ced->set_mode = sh_mtu2_clock_event_mode; ced->set_state_shutdown = sh_mtu2_clock_event_shutdown;
ced->set_state_periodic = sh_mtu2_clock_event_set_periodic;
ced->suspend = sh_mtu2_clock_event_suspend; ced->suspend = sh_mtu2_clock_event_suspend;
ced->resume = sh_mtu2_clock_event_resume; ced->resume = sh_mtu2_clock_event_resume;
......
...@@ -240,7 +240,7 @@ static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id) ...@@ -240,7 +240,7 @@ static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id)
struct sh_tmu_channel *ch = dev_id; struct sh_tmu_channel *ch = dev_id;
/* disable or acknowledge interrupt */ /* disable or acknowledge interrupt */
if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) if (clockevent_state_oneshot(&ch->ced))
sh_tmu_write(ch, TCR, TCR_TPSC_CLK4); sh_tmu_write(ch, TCR, TCR_TPSC_CLK4);
else else
sh_tmu_write(ch, TCR, TCR_UNIE | TCR_TPSC_CLK4); sh_tmu_write(ch, TCR, TCR_UNIE | TCR_TPSC_CLK4);
...@@ -358,42 +358,38 @@ static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic) ...@@ -358,42 +358,38 @@ static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic)
} }
} }
static void sh_tmu_clock_event_mode(enum clock_event_mode mode, static int sh_tmu_clock_event_shutdown(struct clock_event_device *ced)
struct clock_event_device *ced) {
struct sh_tmu_channel *ch = ced_to_sh_tmu(ced);
if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
sh_tmu_disable(ch);
return 0;
}
static int sh_tmu_clock_event_set_state(struct clock_event_device *ced,
int periodic)
{ {
struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); struct sh_tmu_channel *ch = ced_to_sh_tmu(ced);
int disabled = 0;
/* deal with old setting first */ /* deal with old setting first */
switch (ced->mode) { if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
case CLOCK_EVT_MODE_PERIODIC:
case CLOCK_EVT_MODE_ONESHOT:
sh_tmu_disable(ch); sh_tmu_disable(ch);
disabled = 1;
break;
default:
break;
}
switch (mode) { dev_info(&ch->tmu->pdev->dev, "ch%u: used for %s clock events\n",
case CLOCK_EVT_MODE_PERIODIC: ch->index, periodic ? "periodic" : "oneshot");
dev_info(&ch->tmu->pdev->dev, sh_tmu_clock_event_start(ch, periodic);
"ch%u: used for periodic clock events\n", ch->index); return 0;
sh_tmu_clock_event_start(ch, 1); }
break;
case CLOCK_EVT_MODE_ONESHOT: static int sh_tmu_clock_event_set_oneshot(struct clock_event_device *ced)
dev_info(&ch->tmu->pdev->dev, {
"ch%u: used for oneshot clock events\n", ch->index); return sh_tmu_clock_event_set_state(ced, 0);
sh_tmu_clock_event_start(ch, 0); }
break;
case CLOCK_EVT_MODE_UNUSED: static int sh_tmu_clock_event_set_periodic(struct clock_event_device *ced)
if (!disabled) {
sh_tmu_disable(ch); return sh_tmu_clock_event_set_state(ced, 1);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
default:
break;
}
} }
static int sh_tmu_clock_event_next(unsigned long delta, static int sh_tmu_clock_event_next(unsigned long delta,
...@@ -401,7 +397,7 @@ static int sh_tmu_clock_event_next(unsigned long delta, ...@@ -401,7 +397,7 @@ static int sh_tmu_clock_event_next(unsigned long delta,
{ {
struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); struct sh_tmu_channel *ch = ced_to_sh_tmu(ced);
BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); BUG_ON(!clockevent_state_oneshot(ced));
/* program new delta value */ /* program new delta value */
sh_tmu_set_next(ch, delta, 0); sh_tmu_set_next(ch, delta, 0);
...@@ -430,7 +426,9 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, ...@@ -430,7 +426,9 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch,
ced->rating = 200; ced->rating = 200;
ced->cpumask = cpu_possible_mask; ced->cpumask = cpu_possible_mask;
ced->set_next_event = sh_tmu_clock_event_next; ced->set_next_event = sh_tmu_clock_event_next;
ced->set_mode = sh_tmu_clock_event_mode; ced->set_state_shutdown = sh_tmu_clock_event_shutdown;
ced->set_state_periodic = sh_tmu_clock_event_set_periodic;
ced->set_state_oneshot = sh_tmu_clock_event_set_oneshot;
ced->suspend = sh_tmu_clock_event_suspend; ced->suspend = sh_tmu_clock_event_suspend;
ced->resume = sh_tmu_clock_event_resume; ced->resume = sh_tmu_clock_event_resume;
......
...@@ -81,25 +81,25 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic) ...@@ -81,25 +81,25 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic)
timer_base + TIMER_CTL_REG(timer)); timer_base + TIMER_CTL_REG(timer));
} }
static void sun4i_clkevt_mode(enum clock_event_mode mode, static int sun4i_clkevt_shutdown(struct clock_event_device *evt)
struct clock_event_device *clk)
{ {
switch (mode) { sun4i_clkevt_time_stop(0);
case CLOCK_EVT_MODE_PERIODIC: return 0;
sun4i_clkevt_time_stop(0); }
sun4i_clkevt_time_setup(0, ticks_per_jiffy);
sun4i_clkevt_time_start(0, true); static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_ONESHOT: sun4i_clkevt_time_stop(0);
sun4i_clkevt_time_stop(0); sun4i_clkevt_time_start(0, false);
sun4i_clkevt_time_start(0, false); return 0;
break; }
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN: static int sun4i_clkevt_set_periodic(struct clock_event_device *evt)
default: {
sun4i_clkevt_time_stop(0); sun4i_clkevt_time_stop(0);
break; sun4i_clkevt_time_setup(0, ticks_per_jiffy);
} sun4i_clkevt_time_start(0, true);
return 0;
} }
static int sun4i_clkevt_next_event(unsigned long evt, static int sun4i_clkevt_next_event(unsigned long evt,
...@@ -116,7 +116,10 @@ static struct clock_event_device sun4i_clockevent = { ...@@ -116,7 +116,10 @@ static struct clock_event_device sun4i_clockevent = {
.name = "sun4i_tick", .name = "sun4i_tick",
.rating = 350, .rating = 350,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = sun4i_clkevt_mode, .set_state_shutdown = sun4i_clkevt_shutdown,
.set_state_periodic = sun4i_clkevt_set_periodic,
.set_state_oneshot = sun4i_clkevt_set_oneshot,
.tick_resume = sun4i_clkevt_shutdown,
.set_next_event = sun4i_clkevt_next_event, .set_next_event = sun4i_clkevt_next_event,
}; };
......
...@@ -91,55 +91,62 @@ static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt) ...@@ -91,55 +91,62 @@ static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
*/ */
static u32 timer_clock; static u32 timer_clock;
static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) static int tc_shutdown(struct clock_event_device *d)
{ {
struct tc_clkevt_device *tcd = to_tc_clkevt(d); struct tc_clkevt_device *tcd = to_tc_clkevt(d);
void __iomem *regs = tcd->regs; void __iomem *regs = tcd->regs;
if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR));
|| tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) { __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
__raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); clk_disable(tcd->clk);
__raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
clk_disable(tcd->clk);
}
switch (m) { return 0;
}
/* By not making the gentime core emulate periodic mode on top static int tc_set_oneshot(struct clock_event_device *d)
* of oneshot, we get lower overhead and improved accuracy. {
*/ struct tc_clkevt_device *tcd = to_tc_clkevt(d);
case CLOCK_EVT_MODE_PERIODIC: void __iomem *regs = tcd->regs;
clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and restart */ if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))
__raw_writel(timer_clock tc_shutdown(d);
| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
regs + ATMEL_TC_REG(2, CMR));
__raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
/* Enable clock and interrupts on RC compare */ clk_enable(tcd->clk);
__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
/* go go gadget! */ /* slow clock, count up to RC, then irq and stop */
__raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, __raw_writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE |
regs + ATMEL_TC_REG(2, CCR)); ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR));
break; __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
case CLOCK_EVT_MODE_ONESHOT: /* set_next_event() configures and starts the timer */
clk_enable(tcd->clk); return 0;
}
/* slow clock, count up to RC, then irq and stop */ static int tc_set_periodic(struct clock_event_device *d)
__raw_writel(timer_clock | ATMEL_TC_CPCSTOP {
| ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, struct tc_clkevt_device *tcd = to_tc_clkevt(d);
regs + ATMEL_TC_REG(2, CMR)); void __iomem *regs = tcd->regs;
__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
/* set_next_event() configures and starts the timer */ if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))
break; tc_shutdown(d);
default: /* By not making the gentime core emulate periodic mode on top
break; * of oneshot, we get lower overhead and improved accuracy.
} */
clk_enable(tcd->clk);
/* slow clock, count up to RC, then irq and restart */
__raw_writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
regs + ATMEL_TC_REG(2, CMR));
__raw_writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
/* Enable clock and interrupts on RC compare */
__raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
/* go go gadget! */
__raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs +
ATMEL_TC_REG(2, CCR));
return 0;
} }
static int tc_next_event(unsigned long delta, struct clock_event_device *d) static int tc_next_event(unsigned long delta, struct clock_event_device *d)
...@@ -154,13 +161,15 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d) ...@@ -154,13 +161,15 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d)
static struct tc_clkevt_device clkevt = { static struct tc_clkevt_device clkevt = {
.clkevt = { .clkevt = {
.name = "tc_clkevt", .name = "tc_clkevt",
.features = CLOCK_EVT_FEAT_PERIODIC .features = CLOCK_EVT_FEAT_PERIODIC |
| CLOCK_EVT_FEAT_ONESHOT, CLOCK_EVT_FEAT_ONESHOT,
/* Should be lower than at91rm9200's system timer */ /* Should be lower than at91rm9200's system timer */
.rating = 125, .rating = 125,
.set_next_event = tc_next_event, .set_next_event = tc_next_event,
.set_mode = tc_mode, .set_state_shutdown = tc_shutdown,
.set_state_periodic = tc_set_periodic,
.set_state_oneshot = tc_set_oneshot,
}, },
}; };
......
...@@ -72,33 +72,36 @@ static int tegra_timer_set_next_event(unsigned long cycles, ...@@ -72,33 +72,36 @@ static int tegra_timer_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static void tegra_timer_set_mode(enum clock_event_mode mode, static inline void timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
u32 reg;
timer_writel(0, TIMER3_BASE + TIMER_PTV); timer_writel(0, TIMER3_BASE + TIMER_PTV);
}
switch (mode) { static int tegra_timer_shutdown(struct clock_event_device *evt)
case CLOCK_EVT_MODE_PERIODIC: {
reg = 0xC0000000 | ((1000000/HZ)-1); timer_shutdown(evt);
timer_writel(reg, TIMER3_BASE + TIMER_PTV); return 0;
break; }
case CLOCK_EVT_MODE_ONESHOT:
break; static int tegra_timer_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_UNUSED: {
case CLOCK_EVT_MODE_SHUTDOWN: u32 reg = 0xC0000000 | ((1000000 / HZ) - 1);
case CLOCK_EVT_MODE_RESUME:
break; timer_shutdown(evt);
} timer_writel(reg, TIMER3_BASE + TIMER_PTV);
return 0;
} }
static struct clock_event_device tegra_clockevent = { static struct clock_event_device tegra_clockevent = {
.name = "timer0", .name = "timer0",
.rating = 300, .rating = 300,
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT |
.set_next_event = tegra_timer_set_next_event, CLOCK_EVT_FEAT_PERIODIC,
.set_mode = tegra_timer_set_mode, .set_next_event = tegra_timer_set_next_event,
.set_state_shutdown = tegra_timer_shutdown,
.set_state_periodic = tegra_timer_set_periodic,
.set_state_oneshot = tegra_timer_shutdown,
.tick_resume = tegra_timer_shutdown,
}; };
static u64 notrace tegra_read_sched_clock(void) static u64 notrace tegra_read_sched_clock(void)
......
...@@ -121,33 +121,33 @@ armada_370_xp_clkevt_next_event(unsigned long delta, ...@@ -121,33 +121,33 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
return 0; return 0;
} }
static void static int armada_370_xp_clkevt_shutdown(struct clock_event_device *evt)
armada_370_xp_clkevt_mode(enum clock_event_mode mode,
struct clock_event_device *dev)
{ {
if (mode == CLOCK_EVT_MODE_PERIODIC) { /*
* Disable timer.
*/
local_timer_ctrl_clrset(TIMER0_EN, 0);
/* /*
* Setup timer to fire at 1/HZ intervals. * ACK pending timer interrupt.
*/ */
writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF); writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS);
writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF); return 0;
}
/* static int armada_370_xp_clkevt_set_periodic(struct clock_event_device *evt)
* Enable timer. {
*/ /*
local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask); * Setup timer to fire at 1/HZ intervals.
} else { */
/* writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF);
* Disable timer. writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF);
*/
local_timer_ctrl_clrset(TIMER0_EN, 0);
/* /*
* ACK pending timer interrupt. * Enable timer.
*/ */
writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask);
} return 0;
} }
static int armada_370_xp_clkevt_irq; static int armada_370_xp_clkevt_irq;
...@@ -185,7 +185,10 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt) ...@@ -185,7 +185,10 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt)
evt->shift = 32, evt->shift = 32,
evt->rating = 300, evt->rating = 300,
evt->set_next_event = armada_370_xp_clkevt_next_event, evt->set_next_event = armada_370_xp_clkevt_next_event,
evt->set_mode = armada_370_xp_clkevt_mode, evt->set_state_shutdown = armada_370_xp_clkevt_shutdown;
evt->set_state_periodic = armada_370_xp_clkevt_set_periodic;
evt->set_state_oneshot = armada_370_xp_clkevt_shutdown;
evt->tick_resume = armada_370_xp_clkevt_shutdown;
evt->irq = armada_370_xp_clkevt_irq; evt->irq = armada_370_xp_clkevt_irq;
evt->cpumask = cpumask_of(cpu); evt->cpumask = cpumask_of(cpu);
...@@ -197,7 +200,7 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt) ...@@ -197,7 +200,7 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt)
static void armada_370_xp_timer_stop(struct clock_event_device *evt) static void armada_370_xp_timer_stop(struct clock_event_device *evt)
{ {
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); evt->set_state_shutdown(evt);
disable_percpu_irq(evt->irq); disable_percpu_irq(evt->irq);
} }
......
...@@ -48,40 +48,42 @@ struct efm32_clock_event_ddata { ...@@ -48,40 +48,42 @@ struct efm32_clock_event_ddata {
unsigned periodic_top; unsigned periodic_top;
}; };
static void efm32_clock_event_set_mode(enum clock_event_mode mode, static int efm32_clock_event_shutdown(struct clock_event_device *evtdev)
struct clock_event_device *evtdev)
{ {
struct efm32_clock_event_ddata *ddata = struct efm32_clock_event_ddata *ddata =
container_of(evtdev, struct efm32_clock_event_ddata, evtdev); container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
switch (mode) { writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
case CLOCK_EVT_MODE_PERIODIC: return 0;
writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); }
writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP);
writel_relaxed(TIMERn_CTRL_PRESC_1024 | static int efm32_clock_event_set_oneshot(struct clock_event_device *evtdev)
TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | {
TIMERn_CTRL_MODE_DOWN, struct efm32_clock_event_ddata *ddata =
ddata->base + TIMERn_CTRL); container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD);
break; writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
writel_relaxed(TIMERn_CTRL_PRESC_1024 |
case CLOCK_EVT_MODE_ONESHOT: TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); TIMERn_CTRL_OSMEN |
writel_relaxed(TIMERn_CTRL_PRESC_1024 | TIMERn_CTRL_MODE_DOWN,
TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | ddata->base + TIMERn_CTRL);
TIMERn_CTRL_OSMEN | return 0;
TIMERn_CTRL_MODE_DOWN, }
ddata->base + TIMERn_CTRL);
break; static int efm32_clock_event_set_periodic(struct clock_event_device *evtdev)
{
case CLOCK_EVT_MODE_UNUSED: struct efm32_clock_event_ddata *ddata =
case CLOCK_EVT_MODE_SHUTDOWN: container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
break; writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP);
case CLOCK_EVT_MODE_RESUME: writel_relaxed(TIMERn_CTRL_PRESC_1024 |
break; TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
} TIMERn_CTRL_MODE_DOWN,
ddata->base + TIMERn_CTRL);
writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD);
return 0;
} }
static int efm32_clock_event_set_next_event(unsigned long evt, static int efm32_clock_event_set_next_event(unsigned long evt,
...@@ -112,7 +114,9 @@ static struct efm32_clock_event_ddata clock_event_ddata = { ...@@ -112,7 +114,9 @@ static struct efm32_clock_event_ddata clock_event_ddata = {
.evtdev = { .evtdev = {
.name = "efm32 clockevent", .name = "efm32 clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.set_mode = efm32_clock_event_set_mode, .set_state_shutdown = efm32_clock_event_shutdown,
.set_state_periodic = efm32_clock_event_set_periodic,
.set_state_oneshot = efm32_clock_event_set_oneshot,
.set_next_event = efm32_clock_event_set_next_event, .set_next_event = efm32_clock_event_set_next_event,
.rating = 200, .rating = 200,
}, },
......
...@@ -60,30 +60,36 @@ static int orion_clkevt_next_event(unsigned long delta, ...@@ -60,30 +60,36 @@ static int orion_clkevt_next_event(unsigned long delta,
return 0; return 0;
} }
static void orion_clkevt_mode(enum clock_event_mode mode, static int orion_clkevt_shutdown(struct clock_event_device *dev)
struct clock_event_device *dev)
{ {
if (mode == CLOCK_EVT_MODE_PERIODIC) { /* disable timer */
/* setup and enable periodic timer at 1/HZ intervals */ atomic_io_modify(timer_base + TIMER_CTRL,
writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD); TIMER1_RELOAD_EN | TIMER1_EN, 0);
writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL); return 0;
atomic_io_modify(timer_base + TIMER_CTRL, }
TIMER1_RELOAD_EN | TIMER1_EN,
TIMER1_RELOAD_EN | TIMER1_EN); static int orion_clkevt_set_periodic(struct clock_event_device *dev)
} else { {
/* disable timer */ /* setup and enable periodic timer at 1/HZ intervals */
atomic_io_modify(timer_base + TIMER_CTRL, writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
TIMER1_RELOAD_EN | TIMER1_EN, 0); writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
} atomic_io_modify(timer_base + TIMER_CTRL,
TIMER1_RELOAD_EN | TIMER1_EN,
TIMER1_RELOAD_EN | TIMER1_EN);
return 0;
} }
static struct clock_event_device orion_clkevt = { static struct clock_event_device orion_clkevt = {
.name = "orion_event", .name = "orion_event",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT |
.shift = 32, CLOCK_EVT_FEAT_PERIODIC,
.rating = 300, .shift = 32,
.set_next_event = orion_clkevt_next_event, .rating = 300,
.set_mode = orion_clkevt_mode, .set_next_event = orion_clkevt_next_event,
.set_state_shutdown = orion_clkevt_shutdown,
.set_state_periodic = orion_clkevt_set_periodic,
.set_state_oneshot = orion_clkevt_shutdown,
.tick_resume = orion_clkevt_shutdown,
}; };
static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id) static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
......
...@@ -76,7 +76,7 @@ static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) ...@@ -76,7 +76,7 @@ static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
/* clear timer interrupt */ /* clear timer interrupt */
writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
if (ce->mode == CLOCK_EVT_MODE_ONESHOT) if (clockevent_state_oneshot(ce))
sirfsoc_timer_count_disable(cpu); sirfsoc_timer_count_disable(cpu);
ce->event_handler(ce); ce->event_handler(ce);
...@@ -117,18 +117,11 @@ static int sirfsoc_timer_set_next_event(unsigned long delta, ...@@ -117,18 +117,11 @@ static int sirfsoc_timer_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void sirfsoc_timer_set_mode(enum clock_event_mode mode, /* Oneshot is enabled in set_next_event */
struct clock_event_device *ce) static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
{ {
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
/* enable in set_next_event */
break;
default:
break;
}
sirfsoc_timer_count_disable(smp_processor_id()); sirfsoc_timer_count_disable(smp_processor_id());
return 0;
} }
static void sirfsoc_clocksource_suspend(struct clocksource *cs) static void sirfsoc_clocksource_suspend(struct clocksource *cs)
...@@ -193,7 +186,9 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce) ...@@ -193,7 +186,9 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
ce->name = "local_timer"; ce->name = "local_timer";
ce->features = CLOCK_EVT_FEAT_ONESHOT; ce->features = CLOCK_EVT_FEAT_ONESHOT;
ce->rating = 200; ce->rating = 200;
ce->set_mode = sirfsoc_timer_set_mode; ce->set_state_shutdown = sirfsoc_timer_shutdown;
ce->set_state_oneshot = sirfsoc_timer_shutdown;
ce->tick_resume = sirfsoc_timer_shutdown;
ce->set_next_event = sirfsoc_timer_set_next_event; ce->set_next_event = sirfsoc_timer_set_next_event;
clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60); clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
ce->max_delta_ns = clockevent_delta2ns(-2, ce); ce->max_delta_ns = clockevent_delta2ns(-2, ce);
......
...@@ -90,33 +90,27 @@ static cycle_t read_pit_clk(struct clocksource *cs) ...@@ -90,33 +90,27 @@ static cycle_t read_pit_clk(struct clocksource *cs)
return elapsed; return elapsed;
} }
static int pit_clkevt_shutdown(struct clock_event_device *dev)
{
struct pit_data *data = clkevt_to_pit_data(dev);
/* disable irq, leaving the clocksource active */
pit_write(data->base, AT91_PIT_MR, (data->cycle - 1) | AT91_PIT_PITEN);
return 0;
}
/* /*
* Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16)
*/ */
static void static int pit_clkevt_set_periodic(struct clock_event_device *dev)
pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{ {
struct pit_data *data = clkevt_to_pit_data(dev); struct pit_data *data = clkevt_to_pit_data(dev);
switch (mode) { /* update clocksource counter */
case CLOCK_EVT_MODE_PERIODIC: data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR));
/* update clocksource counter */ pit_write(data->base, AT91_PIT_MR,
data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN);
pit_write(data->base, AT91_PIT_MR, return 0;
(data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN);
break;
case CLOCK_EVT_MODE_ONESHOT:
BUG();
/* FALLTHROUGH */
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
/* disable irq, leaving the clocksource active */
pit_write(data->base, AT91_PIT_MR,
(data->cycle - 1) | AT91_PIT_PITEN);
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
} }
static void at91sam926x_pit_suspend(struct clock_event_device *cedev) static void at91sam926x_pit_suspend(struct clock_event_device *cedev)
...@@ -162,7 +156,7 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) ...@@ -162,7 +156,7 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
WARN_ON_ONCE(!irqs_disabled()); WARN_ON_ONCE(!irqs_disabled());
/* The PIT interrupt may be disabled, and is shared */ /* The PIT interrupt may be disabled, and is shared */
if ((data->clkevt.mode == CLOCK_EVT_MODE_PERIODIC) && if (clockevent_state_periodic(&data->clkevt) &&
(pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) { (pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) {
unsigned nr_ticks; unsigned nr_ticks;
...@@ -208,8 +202,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) ...@@ -208,8 +202,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data)
data->clksrc.mask = CLOCKSOURCE_MASK(bits); data->clksrc.mask = CLOCKSOURCE_MASK(bits);
data->clksrc.name = "pit"; data->clksrc.name = "pit";
data->clksrc.rating = 175; data->clksrc.rating = 175;
data->clksrc.read = read_pit_clk, data->clksrc.read = read_pit_clk;
data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS, data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
clocksource_register_hz(&data->clksrc, pit_rate); clocksource_register_hz(&data->clksrc, pit_rate);
/* Set up irq handler */ /* Set up irq handler */
...@@ -227,7 +221,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) ...@@ -227,7 +221,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data)
data->clkevt.rating = 100; data->clkevt.rating = 100;
data->clkevt.cpumask = cpumask_of(0); data->clkevt.cpumask = cpumask_of(0);
data->clkevt.set_mode = pit_clkevt_mode; data->clkevt.set_state_shutdown = pit_clkevt_shutdown;
data->clkevt.set_state_periodic = pit_clkevt_set_periodic;
data->clkevt.resume = at91sam926x_pit_resume; data->clkevt.resume = at91sam926x_pit_resume;
data->clkevt.suspend = at91sam926x_pit_suspend; data->clkevt.suspend = at91sam926x_pit_suspend;
clockevents_register_device(&data->clkevt); clockevents_register_device(&data->clkevt);
......
...@@ -106,36 +106,47 @@ static struct clocksource clk32k = { ...@@ -106,36 +106,47 @@ static struct clocksource clk32k = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
static void static void clkdev32k_disable_and_flush_irq(void)
clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{ {
unsigned int val; unsigned int val;
/* Disable and flush pending timer interrupts */ /* Disable and flush pending timer interrupts */
regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS); regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
regmap_read(regmap_st, AT91_ST_SR, &val); regmap_read(regmap_st, AT91_ST_SR, &val);
last_crtr = read_CRTR(); last_crtr = read_CRTR();
switch (mode) { }
case CLOCK_EVT_MODE_PERIODIC:
/* PIT for periodic irqs; fixed rate of 1/HZ */ static int clkevt32k_shutdown(struct clock_event_device *evt)
irqmask = AT91_ST_PITS; {
regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH); clkdev32k_disable_and_flush_irq();
break; irqmask = 0;
case CLOCK_EVT_MODE_ONESHOT: regmap_write(regmap_st, AT91_ST_IER, irqmask);
/* ALM for oneshot irqs, set by next_event() return 0;
* before 32 seconds have passed }
*/
irqmask = AT91_ST_ALMS; static int clkevt32k_set_oneshot(struct clock_event_device *dev)
regmap_write(regmap_st, AT91_ST_RTAR, last_crtr); {
break; clkdev32k_disable_and_flush_irq();
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED: /*
case CLOCK_EVT_MODE_RESUME: * ALM for oneshot irqs, set by next_event()
irqmask = 0; * before 32 seconds have passed.
break; */
} irqmask = AT91_ST_ALMS;
regmap_write(regmap_st, AT91_ST_RTAR, last_crtr);
regmap_write(regmap_st, AT91_ST_IER, irqmask); regmap_write(regmap_st, AT91_ST_IER, irqmask);
return 0;
}
static int clkevt32k_set_periodic(struct clock_event_device *dev)
{
clkdev32k_disable_and_flush_irq();
/* PIT for periodic irqs; fixed rate of 1/HZ */
irqmask = AT91_ST_PITS;
regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH);
regmap_write(regmap_st, AT91_ST_IER, irqmask);
return 0;
} }
static int static int
...@@ -170,11 +181,15 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev) ...@@ -170,11 +181,15 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
} }
static struct clock_event_device clkevt = { static struct clock_event_device clkevt = {
.name = "at91_tick", .name = "at91_tick",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.rating = 150, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = clkevt32k_next_event, .rating = 150,
.set_mode = clkevt32k_mode, .set_next_event = clkevt32k_next_event,
.set_state_shutdown = clkevt32k_shutdown,
.set_state_periodic = clkevt32k_set_periodic,
.set_state_oneshot = clkevt32k_set_oneshot,
.tick_resume = clkevt32k_shutdown,
}; };
/* /*
......
...@@ -87,27 +87,27 @@ static inline void dc_timer_set_count(struct clock_event_device *ce, ...@@ -87,27 +87,27 @@ static inline void dc_timer_set_count(struct clock_event_device *ce,
writel(count, dt->base + COUNT(dt->timer_id)); writel(count, dt->base + COUNT(dt->timer_id));
} }
static void digicolor_clkevt_mode(enum clock_event_mode mode, static int digicolor_clkevt_shutdown(struct clock_event_device *ce)
struct clock_event_device *ce) {
dc_timer_disable(ce);
return 0;
}
static int digicolor_clkevt_set_oneshot(struct clock_event_device *ce)
{
dc_timer_disable(ce);
dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
return 0;
}
static int digicolor_clkevt_set_periodic(struct clock_event_device *ce)
{ {
struct digicolor_timer *dt = dc_timer(ce); struct digicolor_timer *dt = dc_timer(ce);
switch (mode) { dc_timer_disable(ce);
case CLOCK_EVT_MODE_PERIODIC: dc_timer_set_count(ce, dt->ticks_per_jiffy);
dc_timer_disable(ce); dc_timer_enable(ce, CONTROL_MODE_PERIODIC);
dc_timer_set_count(ce, dt->ticks_per_jiffy); return 0;
dc_timer_enable(ce, CONTROL_MODE_PERIODIC);
break;
case CLOCK_EVT_MODE_ONESHOT:
dc_timer_disable(ce);
dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
default:
dc_timer_disable(ce);
break;
}
} }
static int digicolor_clkevt_next_event(unsigned long evt, static int digicolor_clkevt_next_event(unsigned long evt,
...@@ -125,7 +125,10 @@ static struct digicolor_timer dc_timer_dev = { ...@@ -125,7 +125,10 @@ static struct digicolor_timer dc_timer_dev = {
.name = "digicolor_tick", .name = "digicolor_tick",
.rating = 340, .rating = 340,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = digicolor_clkevt_mode, .set_state_shutdown = digicolor_clkevt_shutdown,
.set_state_periodic = digicolor_clkevt_set_periodic,
.set_state_oneshot = digicolor_clkevt_set_oneshot,
.tick_resume = digicolor_clkevt_shutdown,
.set_next_event = digicolor_clkevt_next_event, .set_next_event = digicolor_clkevt_next_event,
}, },
.timer_id = TIMER_C, .timer_id = TIMER_C,
......
...@@ -83,7 +83,6 @@ struct imx_timer { ...@@ -83,7 +83,6 @@ struct imx_timer {
struct clk *clk_ipg; struct clk *clk_ipg;
const struct imx_gpt_data *gpt; const struct imx_gpt_data *gpt;
struct clock_event_device ced; struct clock_event_device ced;
enum clock_event_mode cem;
struct irqaction act; struct irqaction act;
}; };
...@@ -212,18 +211,38 @@ static int v2_set_next_event(unsigned long evt, ...@@ -212,18 +211,38 @@ static int v2_set_next_event(unsigned long evt,
-ETIME : 0; -ETIME : 0;
} }
static int mxc_shutdown(struct clock_event_device *ced)
{
struct imx_timer *imxtm = to_imx_timer(ced);
unsigned long flags;
u32 tcn;
/*
* The timer interrupt generation is disabled at least
* for enough time to call mxc_set_next_event()
*/
local_irq_save(flags);
/* Disable interrupt in GPT module */
imxtm->gpt->gpt_irq_disable(imxtm);
tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn);
/* Set event time into far-far future */
writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp);
/* Clear pending interrupt */
imxtm->gpt->gpt_irq_acknowledge(imxtm);
#ifdef DEBUG #ifdef DEBUG
static const char *clock_event_mode_label[] = { printk(KERN_INFO "%s: changing mode\n", __func__);
[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
[CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
[CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED",
[CLOCK_EVT_MODE_RESUME] = "CLOCK_EVT_MODE_RESUME",
};
#endif /* DEBUG */ #endif /* DEBUG */
static void mxc_set_mode(enum clock_event_mode mode, local_irq_restore(flags);
struct clock_event_device *ced)
return 0;
}
static int mxc_set_oneshot(struct clock_event_device *ced)
{ {
struct imx_timer *imxtm = to_imx_timer(ced); struct imx_timer *imxtm = to_imx_timer(ced);
unsigned long flags; unsigned long flags;
...@@ -237,7 +256,7 @@ static void mxc_set_mode(enum clock_event_mode mode, ...@@ -237,7 +256,7 @@ static void mxc_set_mode(enum clock_event_mode mode,
/* Disable interrupt in GPT module */ /* Disable interrupt in GPT module */
imxtm->gpt->gpt_irq_disable(imxtm); imxtm->gpt->gpt_irq_disable(imxtm);
if (mode != imxtm->cem) { if (!clockevent_state_oneshot(ced)) {
u32 tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn); u32 tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn);
/* Set event time into far-far future */ /* Set event time into far-far future */
writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp); writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp);
...@@ -247,37 +266,19 @@ static void mxc_set_mode(enum clock_event_mode mode, ...@@ -247,37 +266,19 @@ static void mxc_set_mode(enum clock_event_mode mode,
} }
#ifdef DEBUG #ifdef DEBUG
printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n", printk(KERN_INFO "%s: changing mode\n", __func__);
clock_event_mode_label[imxtm->cem],
clock_event_mode_label[mode]);
#endif /* DEBUG */ #endif /* DEBUG */
/* Remember timer mode */
imxtm->cem = mode;
local_irq_restore(flags);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
"supported for i.MX\n");
break;
case CLOCK_EVT_MODE_ONESHOT:
/* /*
* Do not put overhead of interrupt enable/disable into * Do not put overhead of interrupt enable/disable into
* mxc_set_next_event(), the core has about 4 minutes * mxc_set_next_event(), the core has about 4 minutes
* to call mxc_set_next_event() or shutdown clock after * to call mxc_set_next_event() or shutdown clock after
* mode switching * mode switching
*/ */
local_irq_save(flags); imxtm->gpt->gpt_irq_enable(imxtm);
imxtm->gpt->gpt_irq_enable(imxtm); local_irq_restore(flags);
local_irq_restore(flags);
break; return 0;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_RESUME:
/* Left event sources disabled, no more interrupts appear */
break;
}
} }
/* /*
...@@ -303,11 +304,11 @@ static int __init mxc_clockevent_init(struct imx_timer *imxtm) ...@@ -303,11 +304,11 @@ static int __init mxc_clockevent_init(struct imx_timer *imxtm)
struct clock_event_device *ced = &imxtm->ced; struct clock_event_device *ced = &imxtm->ced;
struct irqaction *act = &imxtm->act; struct irqaction *act = &imxtm->act;
imxtm->cem = CLOCK_EVT_MODE_UNUSED;
ced->name = "mxc_timer1"; ced->name = "mxc_timer1";
ced->features = CLOCK_EVT_FEAT_ONESHOT; ced->features = CLOCK_EVT_FEAT_ONESHOT;
ced->set_mode = mxc_set_mode; ced->set_state_shutdown = mxc_shutdown;
ced->set_state_oneshot = mxc_set_oneshot;
ced->tick_resume = mxc_shutdown;
ced->set_next_event = imxtm->gpt->set_next_event; ced->set_next_event = imxtm->gpt->set_next_event;
ced->rating = 200; ced->rating = 200;
ced->cpumask = cpumask_of(0); ced->cpumask = cpumask_of(0);
......
...@@ -75,33 +75,37 @@ static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) ...@@ -75,33 +75,37 @@ static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) static int clkevt_shutdown(struct clock_event_device *evt)
{ {
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
/* Disable timer */ /* Disable timer */
writel(ctrl, clkevt_base + TIMER_CTRL); writel(ctrl, clkevt_base + TIMER_CTRL);
return 0;
}
switch (mode) { static int clkevt_set_oneshot(struct clock_event_device *evt)
case CLOCK_EVT_MODE_PERIODIC: {
/* Enable the timer and start the periodic tick */ u32 ctrl = readl(clkevt_base + TIMER_CTRL) &
writel(timer_reload, clkevt_base + TIMER_LOAD); ~(TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC);
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
writel(ctrl, clkevt_base + TIMER_CTRL); /* Leave the timer disabled, .set_next_event will enable it */
break; writel(ctrl, clkevt_base + TIMER_CTRL);
case CLOCK_EVT_MODE_ONESHOT: return 0;
/* Leave the timer disabled, .set_next_event will enable it */ }
ctrl &= ~TIMER_CTRL_PERIODIC;
writel(ctrl, clkevt_base + TIMER_CTRL);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_RESUME:
default:
/* Just leave in disabled state */
break;
}
static int clkevt_set_periodic(struct clock_event_device *evt)
{
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
/* Disable timer */
writel(ctrl, clkevt_base + TIMER_CTRL);
/* Enable the timer and start the periodic tick */
writel(timer_reload, clkevt_base + TIMER_LOAD);
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
writel(ctrl, clkevt_base + TIMER_CTRL);
return 0;
} }
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
...@@ -116,11 +120,15 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device * ...@@ -116,11 +120,15 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device *
} }
static struct clock_event_device integrator_clockevent = { static struct clock_event_device integrator_clockevent = {
.name = "timer1", .name = "timer1",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC |
.set_mode = clkevt_set_mode, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = clkevt_set_next_event, .set_state_shutdown = clkevt_shutdown,
.rating = 300, .set_state_periodic = clkevt_set_periodic,
.set_state_oneshot = clkevt_set_oneshot,
.tick_resume = clkevt_shutdown,
.set_next_event = clkevt_set_next_event,
.rating = 300,
}; };
static struct irqaction integrator_timer_irq = { static struct irqaction integrator_timer_irq = {
......
...@@ -72,10 +72,10 @@ static inline void keystone_timer_barrier(void) ...@@ -72,10 +72,10 @@ static inline void keystone_timer_barrier(void)
/** /**
* keystone_timer_config: configures timer to work in oneshot/periodic modes. * keystone_timer_config: configures timer to work in oneshot/periodic modes.
* @ mode: mode to configure * @ mask: mask of the mode to configure
* @ period: cycles number to configure for * @ period: cycles number to configure for
*/ */
static int keystone_timer_config(u64 period, enum clock_event_mode mode) static int keystone_timer_config(u64 period, int mask)
{ {
u32 tcr; u32 tcr;
u32 off; u32 off;
...@@ -84,16 +84,7 @@ static int keystone_timer_config(u64 period, enum clock_event_mode mode) ...@@ -84,16 +84,7 @@ static int keystone_timer_config(u64 period, enum clock_event_mode mode)
off = tcr & ~(TCR_ENAMODE_MASK); off = tcr & ~(TCR_ENAMODE_MASK);
/* set enable mode */ /* set enable mode */
switch (mode) { tcr |= mask;
case CLOCK_EVT_MODE_ONESHOT:
tcr |= TCR_ENAMODE_ONESHOT_MASK;
break;
case CLOCK_EVT_MODE_PERIODIC:
tcr |= TCR_ENAMODE_PERIODIC_MASK;
break;
default:
return -1;
}
/* disable timer */ /* disable timer */
keystone_timer_writel(off, TCR); keystone_timer_writel(off, TCR);
...@@ -138,24 +129,19 @@ static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id) ...@@ -138,24 +129,19 @@ static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id)
static int keystone_set_next_event(unsigned long cycles, static int keystone_set_next_event(unsigned long cycles,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
return keystone_timer_config(cycles, evt->mode); return keystone_timer_config(cycles, TCR_ENAMODE_ONESHOT_MASK);
} }
static void keystone_set_mode(enum clock_event_mode mode, static int keystone_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { keystone_timer_disable();
case CLOCK_EVT_MODE_PERIODIC: return 0;
keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC); }
break;
case CLOCK_EVT_MODE_UNUSED: static int keystone_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_SHUTDOWN: {
case CLOCK_EVT_MODE_ONESHOT: keystone_timer_config(timer.hz_period, TCR_ENAMODE_PERIODIC_MASK);
keystone_timer_disable(); return 0;
break;
default:
break;
}
} }
static void __init keystone_timer_init(struct device_node *np) static void __init keystone_timer_init(struct device_node *np)
...@@ -222,7 +208,9 @@ static void __init keystone_timer_init(struct device_node *np) ...@@ -222,7 +208,9 @@ static void __init keystone_timer_init(struct device_node *np)
/* setup clockevent */ /* setup clockevent */
event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
event_dev->set_next_event = keystone_set_next_event; event_dev->set_next_event = keystone_set_next_event;
event_dev->set_mode = keystone_set_mode; event_dev->set_state_shutdown = keystone_shutdown;
event_dev->set_state_periodic = keystone_set_periodic;
event_dev->set_state_oneshot = keystone_shutdown;
event_dev->cpumask = cpu_all_mask; event_dev->cpumask = cpu_all_mask;
event_dev->owner = THIS_MODULE; event_dev->owner = THIS_MODULE;
event_dev->name = TIMER_NAME; event_dev->name = TIMER_NAME;
......
...@@ -104,26 +104,21 @@ static int sirfsoc_timer_set_next_event(unsigned long delta, ...@@ -104,26 +104,21 @@ static int sirfsoc_timer_set_next_event(unsigned long delta,
return next - now > delta ? -ETIME : 0; return next - now > delta ? -ETIME : 0;
} }
static void sirfsoc_timer_set_mode(enum clock_event_mode mode, static int sirfsoc_timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *ce)
{ {
u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: writel_relaxed(val & ~BIT(0),
WARN_ON(1); sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
break; return 0;
case CLOCK_EVT_MODE_ONESHOT: }
writel_relaxed(val | BIT(0),
sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); static int sirfsoc_timer_set_oneshot(struct clock_event_device *evt)
break; {
case CLOCK_EVT_MODE_SHUTDOWN: u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
writel_relaxed(val & ~BIT(0),
sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
break; return 0;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_RESUME:
break;
}
} }
static void sirfsoc_clocksource_suspend(struct clocksource *cs) static void sirfsoc_clocksource_suspend(struct clocksource *cs)
...@@ -157,7 +152,8 @@ static struct clock_event_device sirfsoc_clockevent = { ...@@ -157,7 +152,8 @@ static struct clock_event_device sirfsoc_clockevent = {
.name = "sirfsoc_clockevent", .name = "sirfsoc_clockevent",
.rating = 200, .rating = 200,
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.set_mode = sirfsoc_timer_set_mode, .set_state_shutdown = sirfsoc_timer_shutdown,
.set_state_oneshot = sirfsoc_timer_set_oneshot,
.set_next_event = sirfsoc_timer_set_next_event, .set_next_event = sirfsoc_timer_set_next_event,
}; };
......
...@@ -133,50 +133,50 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) ...@@ -133,50 +133,50 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void sp804_set_mode(enum clock_event_mode mode, static inline void timer_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; writel(0, clkevt_base + TIMER_CTRL);
}
writel(ctrl, clkevt_base + TIMER_CTRL); static int sp804_shutdown(struct clock_event_device *evt)
{
timer_shutdown(evt);
return 0;
}
switch (mode) { static int sp804_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_PERIODIC: {
writel(clkevt_reload, clkevt_base + TIMER_LOAD); unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
break;
case CLOCK_EVT_MODE_ONESHOT:
/* period set, and timer enabled in 'next_event' hook */
ctrl |= TIMER_CTRL_ONESHOT;
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
default:
break;
}
timer_shutdown(evt);
writel(clkevt_reload, clkevt_base + TIMER_LOAD);
writel(ctrl, clkevt_base + TIMER_CTRL); writel(ctrl, clkevt_base + TIMER_CTRL);
return 0;
} }
static int sp804_set_next_event(unsigned long next, static int sp804_set_next_event(unsigned long next,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE |
TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE;
writel(next, clkevt_base + TIMER_LOAD); writel(next, clkevt_base + TIMER_LOAD);
writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); writel(ctrl, clkevt_base + TIMER_CTRL);
return 0; return 0;
} }
static struct clock_event_device sp804_clockevent = { static struct clock_event_device sp804_clockevent = {
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | .features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_DYNIRQ, CLOCK_EVT_FEAT_ONESHOT |
.set_mode = sp804_set_mode, CLOCK_EVT_FEAT_DYNIRQ,
.set_next_event = sp804_set_next_event, .set_state_shutdown = sp804_shutdown,
.rating = 300, .set_state_periodic = sp804_set_periodic,
.set_state_oneshot = sp804_shutdown,
.tick_resume = sp804_shutdown,
.set_next_event = sp804_set_next_event,
.rating = 300,
}; };
static struct irqaction sp804_timer_irq = { static struct irqaction sp804_timer_irq = {
......
...@@ -40,24 +40,25 @@ struct stm32_clock_event_ddata { ...@@ -40,24 +40,25 @@ struct stm32_clock_event_ddata {
void __iomem *base; void __iomem *base;
}; };
static void stm32_clock_event_set_mode(enum clock_event_mode mode, static int stm32_clock_event_shutdown(struct clock_event_device *evtdev)
struct clock_event_device *evtdev)
{ {
struct stm32_clock_event_ddata *data = struct stm32_clock_event_ddata *data =
container_of(evtdev, struct stm32_clock_event_ddata, evtdev); container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
void *base = data->base; void *base = data->base;
switch (mode) { writel_relaxed(0, base + TIM_CR1);
case CLOCK_EVT_MODE_PERIODIC: return 0;
writel_relaxed(data->periodic_top, base + TIM_ARR); }
writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
break;
case CLOCK_EVT_MODE_ONESHOT: static int stm32_clock_event_set_periodic(struct clock_event_device *evtdev)
default: {
writel_relaxed(0, base + TIM_CR1); struct stm32_clock_event_ddata *data =
break; container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
} void *base = data->base;
writel_relaxed(data->periodic_top, base + TIM_ARR);
writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
return 0;
} }
static int stm32_clock_event_set_next_event(unsigned long evt, static int stm32_clock_event_set_next_event(unsigned long evt,
...@@ -88,7 +89,10 @@ static struct stm32_clock_event_ddata clock_event_ddata = { ...@@ -88,7 +89,10 @@ static struct stm32_clock_event_ddata clock_event_ddata = {
.evtdev = { .evtdev = {
.name = "stm32 clockevent", .name = "stm32 clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.set_mode = stm32_clock_event_set_mode, .set_state_shutdown = stm32_clock_event_shutdown,
.set_state_periodic = stm32_clock_event_set_periodic,
.set_state_oneshot = stm32_clock_event_shutdown,
.tick_resume = stm32_clock_event_shutdown,
.set_next_event = stm32_clock_event_set_next_event, .set_next_event = stm32_clock_event_set_next_event,
.rating = 200, .rating = 200,
}, },
......
...@@ -103,27 +103,31 @@ static void sun5i_clkevt_time_start(struct sun5i_timer_clkevt *ce, u8 timer, boo ...@@ -103,27 +103,31 @@ static void sun5i_clkevt_time_start(struct sun5i_timer_clkevt *ce, u8 timer, boo
ce->timer.base + TIMER_CTL_REG(timer)); ce->timer.base + TIMER_CTL_REG(timer));
} }
static void sun5i_clkevt_mode(enum clock_event_mode mode, static int sun5i_clkevt_shutdown(struct clock_event_device *clkevt)
struct clock_event_device *clkevt)
{ {
struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
switch (mode) { sun5i_clkevt_time_stop(ce, 0);
case CLOCK_EVT_MODE_PERIODIC: return 0;
sun5i_clkevt_time_stop(ce, 0); }
sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy);
sun5i_clkevt_time_start(ce, 0, true); static int sun5i_clkevt_set_oneshot(struct clock_event_device *clkevt)
break; {
case CLOCK_EVT_MODE_ONESHOT: struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
sun5i_clkevt_time_stop(ce, 0);
sun5i_clkevt_time_start(ce, 0, false); sun5i_clkevt_time_stop(ce, 0);
break; sun5i_clkevt_time_start(ce, 0, false);
case CLOCK_EVT_MODE_UNUSED: return 0;
case CLOCK_EVT_MODE_SHUTDOWN: }
default:
sun5i_clkevt_time_stop(ce, 0); static int sun5i_clkevt_set_periodic(struct clock_event_device *clkevt)
break; {
} struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
sun5i_clkevt_time_stop(ce, 0);
sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy);
sun5i_clkevt_time_start(ce, 0, true);
return 0;
} }
static int sun5i_clkevt_next_event(unsigned long evt, static int sun5i_clkevt_next_event(unsigned long evt,
...@@ -286,7 +290,10 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem ...@@ -286,7 +290,10 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem
ce->clkevt.name = node->name; ce->clkevt.name = node->name;
ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
ce->clkevt.set_next_event = sun5i_clkevt_next_event; ce->clkevt.set_next_event = sun5i_clkevt_next_event;
ce->clkevt.set_mode = sun5i_clkevt_mode; ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown;
ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic;
ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot;
ce->clkevt.tick_resume = sun5i_clkevt_shutdown;
ce->clkevt.rating = 340; ce->clkevt.rating = 340;
ce->clkevt.irq = irq; ce->clkevt.irq = irq;
ce->clkevt.cpumask = cpu_possible_mask; ce->clkevt.cpumask = cpu_possible_mask;
......
...@@ -187,85 +187,82 @@ struct u300_clockevent_data { ...@@ -187,85 +187,82 @@ struct u300_clockevent_data {
unsigned ticks_per_jiffy; unsigned ticks_per_jiffy;
}; };
static int u300_shutdown(struct clock_event_device *evt)
{
/* Disable interrupts on GP1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
return 0;
}
/* /*
* The u300_set_mode() function is always called first, if we * If we have oneshot timer active, the oneshot scheduling function
* have oneshot timer active, the oneshot scheduling function
* u300_set_next_event() is called immediately after. * u300_set_next_event() is called immediately after.
*/ */
static void u300_set_mode(enum clock_event_mode mode, static int u300_set_oneshot(struct clock_event_device *evt)
struct clock_event_device *evt) {
/* Just return; here? */
/*
* The actual event will be programmed by the next event hook,
* so we just set a dummy value somewhere at the end of the
* universe here.
*/
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
/*
* Expire far in the future, u300_set_next_event() will be
* called soon...
*/
writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC);
/* We run one shot per tick here! */
writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
u300_timer_base + U300_TIMER_APP_SGPT1M);
/* Enable interrupts for this timer */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Enable timer */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
u300_timer_base + U300_TIMER_APP_EGPT1);
return 0;
}
static int u300_set_periodic(struct clock_event_device *evt)
{ {
struct u300_clockevent_data *cevdata = struct u300_clockevent_data *cevdata =
container_of(evt, struct u300_clockevent_data, cevd); container_of(evt, struct u300_clockevent_data, cevd);
switch (mode) { /* Disable interrupts on GPT1 */
case CLOCK_EVT_MODE_PERIODIC: writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
/* Disable interrupts on GPT1 */ u300_timer_base + U300_TIMER_APP_GPT1IE);
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, /* Disable GP1 while we're reprogramming it. */
u300_timer_base + U300_TIMER_APP_GPT1IE); writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
/* Disable GP1 while we're reprogramming it. */ u300_timer_base + U300_TIMER_APP_DGPT1);
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, /*
u300_timer_base + U300_TIMER_APP_DGPT1); * Set the periodic mode to a certain number of ticks per
/* * jiffy.
* Set the periodic mode to a certain number of ticks per */
* jiffy. writel(cevdata->ticks_per_jiffy,
*/ u300_timer_base + U300_TIMER_APP_GPT1TC);
writel(cevdata->ticks_per_jiffy, /*
u300_timer_base + U300_TIMER_APP_GPT1TC); * Set continuous mode, so the timer keeps triggering
/* * interrupts.
* Set continuous mode, so the timer keeps triggering */
* interrupts. writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS,
*/ u300_timer_base + U300_TIMER_APP_SGPT1M);
writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS, /* Enable timer interrupts */
u300_timer_base + U300_TIMER_APP_SGPT1M); writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
/* Enable timer interrupts */ u300_timer_base + U300_TIMER_APP_GPT1IE);
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, /* Then enable the OS timer again */
u300_timer_base + U300_TIMER_APP_GPT1IE); writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
/* Then enable the OS timer again */ u300_timer_base + U300_TIMER_APP_EGPT1);
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, return 0;
u300_timer_base + U300_TIMER_APP_EGPT1);
break;
case CLOCK_EVT_MODE_ONESHOT:
/* Just break; here? */
/*
* The actual event will be programmed by the next event hook,
* so we just set a dummy value somewhere at the end of the
* universe here.
*/
/* Disable interrupts on GPT1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 while we're reprogramming it. */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
/*
* Expire far in the future, u300_set_next_event() will be
* called soon...
*/
writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC);
/* We run one shot per tick here! */
writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT,
u300_timer_base + U300_TIMER_APP_SGPT1M);
/* Enable interrupts for this timer */
writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Enable timer */
writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE,
u300_timer_base + U300_TIMER_APP_EGPT1);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* Disable interrupts on GP1 */
writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE,
u300_timer_base + U300_TIMER_APP_GPT1IE);
/* Disable GP1 */
writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE,
u300_timer_base + U300_TIMER_APP_DGPT1);
break;
case CLOCK_EVT_MODE_RESUME:
/* Ignore this call */
break;
}
} }
/* /*
...@@ -309,13 +306,15 @@ static int u300_set_next_event(unsigned long cycles, ...@@ -309,13 +306,15 @@ static int u300_set_next_event(unsigned long cycles,
static struct u300_clockevent_data u300_clockevent_data = { static struct u300_clockevent_data u300_clockevent_data = {
/* Use general purpose timer 1 as clock event */ /* Use general purpose timer 1 as clock event */
.cevd = { .cevd = {
.name = "GPT1", .name = "GPT1",
/* Reasonably fast and accurate clock event */ /* Reasonably fast and accurate clock event */
.rating = 300, .rating = 300,
.features = CLOCK_EVT_FEAT_PERIODIC | .features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT, CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = u300_set_next_event, .set_next_event = u300_set_next_event,
.set_mode = u300_set_mode, .set_state_shutdown = u300_shutdown,
.set_state_periodic = u300_set_periodic,
.set_state_oneshot = u300_set_oneshot,
}, },
}; };
......
...@@ -86,20 +86,16 @@ static int pit_set_next_event(unsigned long delta, ...@@ -86,20 +86,16 @@ static int pit_set_next_event(unsigned long delta,
return 0; return 0;
} }
static void pit_set_mode(enum clock_event_mode mode, static int pit_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { pit_timer_disable();
case CLOCK_EVT_MODE_PERIODIC: return 0;
pit_set_next_event(cycle_per_jiffy, evt); }
break;
case CLOCK_EVT_MODE_SHUTDOWN: static int pit_set_periodic(struct clock_event_device *evt)
case CLOCK_EVT_MODE_UNUSED: {
pit_timer_disable(); pit_set_next_event(cycle_per_jiffy, evt);
break; return 0;
default:
break;
}
} }
static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
...@@ -114,7 +110,7 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) ...@@ -114,7 +110,7 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
* and start the counter again. So software need to disable the timer * and start the counter again. So software need to disable the timer
* to stop the counter loop in ONESHOT mode. * to stop the counter loop in ONESHOT mode.
*/ */
if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) if (likely(clockevent_state_oneshot(evt)))
pit_timer_disable(); pit_timer_disable();
evt->event_handler(evt); evt->event_handler(evt);
...@@ -125,7 +121,8 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) ...@@ -125,7 +121,8 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
static struct clock_event_device clockevent_pit = { static struct clock_event_device clockevent_pit = {
.name = "VF pit timer", .name = "VF pit timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = pit_set_mode, .set_state_shutdown = pit_shutdown,
.set_state_periodic = pit_set_periodic,
.set_next_event = pit_set_next_event, .set_next_event = pit_set_next_event,
.rating = 300, .rating = 300,
}; };
......
...@@ -88,29 +88,20 @@ static int vt8500_timer_set_next_event(unsigned long cycles, ...@@ -88,29 +88,20 @@ static int vt8500_timer_set_next_event(unsigned long cycles,
return 0; return 0;
} }
static void vt8500_timer_set_mode(enum clock_event_mode mode, static int vt8500_shutdown(struct clock_event_device *evt)
struct clock_event_device *evt)
{ {
switch (mode) { writel(readl(regbase + TIMER_CTRL_VAL) | 1, regbase + TIMER_CTRL_VAL);
case CLOCK_EVT_MODE_RESUME: writel(0, regbase + TIMER_IER_VAL);
case CLOCK_EVT_MODE_PERIODIC: return 0;
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
writel(readl(regbase + TIMER_CTRL_VAL) | 1,
regbase + TIMER_CTRL_VAL);
writel(0, regbase + TIMER_IER_VAL);
break;
}
} }
static struct clock_event_device clockevent = { static struct clock_event_device clockevent = {
.name = "vt8500_timer", .name = "vt8500_timer",
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 200, .rating = 200,
.set_next_event = vt8500_timer_set_next_event, .set_next_event = vt8500_timer_set_next_event,
.set_mode = vt8500_timer_set_mode, .set_state_shutdown = vt8500_shutdown,
.set_state_oneshot = vt8500_shutdown,
}; };
static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id)
......
...@@ -76,32 +76,28 @@ static int zevio_timer_set_event(unsigned long delta, ...@@ -76,32 +76,28 @@ static int zevio_timer_set_event(unsigned long delta,
return 0; return 0;
} }
static void zevio_timer_set_mode(enum clock_event_mode mode, static int zevio_timer_shutdown(struct clock_event_device *dev)
struct clock_event_device *dev)
{ {
struct zevio_timer *timer = container_of(dev, struct zevio_timer, struct zevio_timer *timer = container_of(dev, struct zevio_timer,
clkevt); clkevt);
switch (mode) { /* Disable timer interrupts */
case CLOCK_EVT_MODE_RESUME: writel(0, timer->interrupt_regs + IO_INTR_MSK);
case CLOCK_EVT_MODE_ONESHOT: writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK);
/* Enable timer interrupts */ /* Stop timer */
writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK); writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL);
writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); return 0;
break; }
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED: static int zevio_timer_set_oneshot(struct clock_event_device *dev)
/* Disable timer interrupts */ {
writel(0, timer->interrupt_regs + IO_INTR_MSK); struct zevio_timer *timer = container_of(dev, struct zevio_timer,
writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); clkevt);
/* Stop timer */
writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL); /* Enable timer interrupts */
break; writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK);
case CLOCK_EVT_MODE_PERIODIC: writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK);
default: return 0;
/* Unsupported */
break;
}
} }
static irqreturn_t zevio_timer_interrupt(int irq, void *dev_id) static irqreturn_t zevio_timer_interrupt(int irq, void *dev_id)
...@@ -162,7 +158,9 @@ static int __init zevio_timer_add(struct device_node *node) ...@@ -162,7 +158,9 @@ static int __init zevio_timer_add(struct device_node *node)
if (timer->interrupt_regs && irqnr) { if (timer->interrupt_regs && irqnr) {
timer->clkevt.name = timer->clockevent_name; timer->clkevt.name = timer->clockevent_name;
timer->clkevt.set_next_event = zevio_timer_set_event; timer->clkevt.set_next_event = zevio_timer_set_event;
timer->clkevt.set_mode = zevio_timer_set_mode; timer->clkevt.set_state_shutdown = zevio_timer_shutdown;
timer->clkevt.set_state_oneshot = zevio_timer_set_oneshot;
timer->clkevt.tick_resume = zevio_timer_set_oneshot;
timer->clkevt.rating = 200; timer->clkevt.rating = 200;
timer->clkevt.cpumask = cpu_all_mask; timer->clkevt.cpumask = cpu_all_mask;
timer->clkevt.features = CLOCK_EVT_FEAT_ONESHOT; timer->clkevt.features = CLOCK_EVT_FEAT_ONESHOT;
......
...@@ -234,13 +234,10 @@ static inline int tick_check_broadcast_expired(void) { return 0; } ...@@ -234,13 +234,10 @@ static inline int tick_check_broadcast_expired(void) { return 0; }
static inline void tick_setup_hrtimer_broadcast(void) { } static inline void tick_setup_hrtimer_broadcast(void) { }
# endif # endif
extern int clockevents_notify(unsigned long reason, void *arg);
#else /* !CONFIG_GENERIC_CLOCKEVENTS: */ #else /* !CONFIG_GENERIC_CLOCKEVENTS: */
static inline void clockevents_suspend(void) { } static inline void clockevents_suspend(void) { }
static inline void clockevents_resume(void) { } static inline void clockevents_resume(void) { }
static inline int clockevents_notify(unsigned long reason, void *arg) { return 0; }
static inline int tick_check_broadcast_expired(void) { return 0; } static inline int tick_check_broadcast_expired(void) { return 0; }
static inline void tick_setup_hrtimer_broadcast(void) { } static inline void tick_setup_hrtimer_broadcast(void) { }
......
...@@ -409,9 +409,25 @@ static __always_inline unsigned long usecs_to_jiffies(const unsigned int u) ...@@ -409,9 +409,25 @@ static __always_inline unsigned long usecs_to_jiffies(const unsigned int u)
} }
} }
extern unsigned long timespec_to_jiffies(const struct timespec *value); extern unsigned long timespec64_to_jiffies(const struct timespec64 *value);
extern void jiffies_to_timespec(const unsigned long jiffies, extern void jiffies_to_timespec64(const unsigned long jiffies,
struct timespec *value); struct timespec64 *value);
static inline unsigned long timespec_to_jiffies(const struct timespec *value)
{
struct timespec64 ts = timespec_to_timespec64(*value);
return timespec64_to_jiffies(&ts);
}
static inline void jiffies_to_timespec(const unsigned long jiffies,
struct timespec *value)
{
struct timespec64 ts;
jiffies_to_timespec64(jiffies, &ts);
*value = timespec64_to_timespec(ts);
}
extern unsigned long timeval_to_jiffies(const struct timeval *value); extern unsigned long timeval_to_jiffies(const struct timeval *value);
extern void jiffies_to_timeval(const unsigned long jiffies, extern void jiffies_to_timeval(const unsigned long jiffies,
struct timeval *value); struct timeval *value);
......
...@@ -12,11 +12,18 @@ typedef __s64 time64_t; ...@@ -12,11 +12,18 @@ typedef __s64 time64_t;
*/ */
#if __BITS_PER_LONG == 64 #if __BITS_PER_LONG == 64
# define timespec64 timespec # define timespec64 timespec
#define itimerspec64 itimerspec
#else #else
struct timespec64 { struct timespec64 {
time64_t tv_sec; /* seconds */ time64_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */ long tv_nsec; /* nanoseconds */
}; };
struct itimerspec64 {
struct timespec64 it_interval;
struct timespec64 it_value;
};
#endif #endif
/* Parameters used to convert the timespec values: */ /* Parameters used to convert the timespec values: */
...@@ -45,6 +52,16 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) ...@@ -45,6 +52,16 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
return ts; return ts;
} }
static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64)
{
return *its64;
}
static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its)
{
return *its;
}
# define timespec64_equal timespec_equal # define timespec64_equal timespec_equal
# define timespec64_compare timespec_compare # define timespec64_compare timespec_compare
# define set_normalized_timespec64 set_normalized_timespec # define set_normalized_timespec64 set_normalized_timespec
...@@ -77,6 +94,24 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) ...@@ -77,6 +94,24 @@ static inline struct timespec64 timespec_to_timespec64(const struct timespec ts)
return ret; return ret;
} }
static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64)
{
struct itimerspec ret;
ret.it_interval = timespec64_to_timespec(its64->it_interval);
ret.it_value = timespec64_to_timespec(its64->it_value);
return ret;
}
static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its)
{
struct itimerspec64 ret;
ret.it_interval = timespec_to_timespec64(its->it_interval);
ret.it_value = timespec_to_timespec64(its->it_value);
return ret;
}
static inline int timespec64_equal(const struct timespec64 *a, static inline int timespec64_equal(const struct timespec64 *a,
const struct timespec64 *b) const struct timespec64 *b)
{ {
......
...@@ -18,10 +18,17 @@ extern int do_sys_settimeofday(const struct timespec *tv, ...@@ -18,10 +18,17 @@ extern int do_sys_settimeofday(const struct timespec *tv,
* Kernel time accessors * Kernel time accessors
*/ */
unsigned long get_seconds(void); unsigned long get_seconds(void);
struct timespec current_kernel_time(void); struct timespec64 current_kernel_time64(void);
/* does not take xtime_lock */ /* does not take xtime_lock */
struct timespec __current_kernel_time(void); struct timespec __current_kernel_time(void);
static inline struct timespec current_kernel_time(void)
{
struct timespec64 now = current_kernel_time64();
return timespec64_to_timespec(now);
}
/* /*
* timespec based interfaces * timespec based interfaces
*/ */
......
...@@ -183,7 +183,7 @@ struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, ...@@ -183,7 +183,7 @@ struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base,
int pinned) int pinned)
{ {
if (pinned || !base->migration_enabled) if (pinned || !base->migration_enabled)
return this_cpu_ptr(&hrtimer_bases); return base;
return &per_cpu(hrtimer_bases, get_nohz_timer_target()); return &per_cpu(hrtimer_bases, get_nohz_timer_target());
} }
#else #else
...@@ -191,23 +191,32 @@ static inline ...@@ -191,23 +191,32 @@ static inline
struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base,
int pinned) int pinned)
{ {
return this_cpu_ptr(&hrtimer_bases); return base;
} }
#endif #endif
/* /*
* Switch the timer base to the current CPU when possible. * We switch the timer base to a power-optimized selected CPU target,
* if:
* - NO_HZ_COMMON is enabled
* - timer migration is enabled
* - the timer callback is not running
* - the timer is not the first expiring timer on the new target
*
* If one of the above requirements is not fulfilled we move the timer
* to the current CPU or leave it on the previously assigned CPU if
* the timer callback is currently running.
*/ */
static inline struct hrtimer_clock_base * static inline struct hrtimer_clock_base *
switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
int pinned) int pinned)
{ {
struct hrtimer_cpu_base *new_cpu_base, *this_base; struct hrtimer_cpu_base *new_cpu_base, *this_cpu_base;
struct hrtimer_clock_base *new_base; struct hrtimer_clock_base *new_base;
int basenum = base->index; int basenum = base->index;
this_base = this_cpu_ptr(&hrtimer_bases); this_cpu_base = this_cpu_ptr(&hrtimer_bases);
new_cpu_base = get_target_base(this_base, pinned); new_cpu_base = get_target_base(this_cpu_base, pinned);
again: again:
new_base = &new_cpu_base->clock_base[basenum]; new_base = &new_cpu_base->clock_base[basenum];
...@@ -229,19 +238,19 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, ...@@ -229,19 +238,19 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
raw_spin_unlock(&base->cpu_base->lock); raw_spin_unlock(&base->cpu_base->lock);
raw_spin_lock(&new_base->cpu_base->lock); raw_spin_lock(&new_base->cpu_base->lock);
if (new_cpu_base != this_base && if (new_cpu_base != this_cpu_base &&
hrtimer_check_target(timer, new_base)) { hrtimer_check_target(timer, new_base)) {
raw_spin_unlock(&new_base->cpu_base->lock); raw_spin_unlock(&new_base->cpu_base->lock);
raw_spin_lock(&base->cpu_base->lock); raw_spin_lock(&base->cpu_base->lock);
new_cpu_base = this_base; new_cpu_base = this_cpu_base;
timer->base = base; timer->base = base;
goto again; goto again;
} }
timer->base = new_base; timer->base = new_base;
} else { } else {
if (new_cpu_base != this_base && if (new_cpu_base != this_cpu_base &&
hrtimer_check_target(timer, new_base)) { hrtimer_check_target(timer, new_base)) {
new_cpu_base = this_base; new_cpu_base = this_cpu_base;
goto again; goto again;
} }
} }
...@@ -679,14 +688,14 @@ static void retrigger_next_event(void *arg) ...@@ -679,14 +688,14 @@ static void retrigger_next_event(void *arg)
/* /*
* Switch to high resolution mode * Switch to high resolution mode
*/ */
static int hrtimer_switch_to_hres(void) static void hrtimer_switch_to_hres(void)
{ {
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases); struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
if (tick_init_highres()) { if (tick_init_highres()) {
printk(KERN_WARNING "Could not switch to high resolution " printk(KERN_WARNING "Could not switch to high resolution "
"mode on CPU %d\n", base->cpu); "mode on CPU %d\n", base->cpu);
return 0; return;
} }
base->hres_active = 1; base->hres_active = 1;
hrtimer_resolution = HIGH_RES_NSEC; hrtimer_resolution = HIGH_RES_NSEC;
...@@ -694,7 +703,6 @@ static int hrtimer_switch_to_hres(void) ...@@ -694,7 +703,6 @@ static int hrtimer_switch_to_hres(void)
tick_setup_sched_timer(); tick_setup_sched_timer();
/* "Retrigger" the interrupt to get things going */ /* "Retrigger" the interrupt to get things going */
retrigger_next_event(NULL); retrigger_next_event(NULL);
return 1;
} }
static void clock_was_set_work(struct work_struct *work) static void clock_was_set_work(struct work_struct *work)
...@@ -718,7 +726,7 @@ void clock_was_set_delayed(void) ...@@ -718,7 +726,7 @@ void clock_was_set_delayed(void)
static inline int __hrtimer_hres_active(struct hrtimer_cpu_base *b) { return 0; } static inline int __hrtimer_hres_active(struct hrtimer_cpu_base *b) { return 0; }
static inline int hrtimer_hres_active(void) { return 0; } static inline int hrtimer_hres_active(void) { return 0; }
static inline int hrtimer_is_hres_enabled(void) { return 0; } static inline int hrtimer_is_hres_enabled(void) { return 0; }
static inline int hrtimer_switch_to_hres(void) { return 0; } static inline void hrtimer_switch_to_hres(void) { }
static inline void static inline void
hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
static inline int hrtimer_reprogram(struct hrtimer *timer, static inline int hrtimer_reprogram(struct hrtimer *timer,
......
...@@ -487,6 +487,11 @@ int second_overflow(unsigned long secs) ...@@ -487,6 +487,11 @@ int second_overflow(unsigned long secs)
} }
#ifdef CONFIG_GENERIC_CMOS_UPDATE #ifdef CONFIG_GENERIC_CMOS_UPDATE
int __weak update_persistent_clock(struct timespec now)
{
return -ENODEV;
}
int __weak update_persistent_clock64(struct timespec64 now64) int __weak update_persistent_clock64(struct timespec64 now64)
{ {
struct timespec now; struct timespec now;
......
...@@ -18,30 +18,23 @@ ...@@ -18,30 +18,23 @@
static struct hrtimer bctimer; static struct hrtimer bctimer;
static void bc_set_mode(enum clock_event_mode mode, static int bc_shutdown(struct clock_event_device *evt)
struct clock_event_device *bc)
{ {
switch (mode) { /*
case CLOCK_EVT_MODE_UNUSED: * Note, we cannot cancel the timer here as we might
case CLOCK_EVT_MODE_SHUTDOWN: * run into the following live lock scenario:
/* *
* Note, we cannot cancel the timer here as we might * cpu 0 cpu1
* run into the following live lock scenario: * lock(broadcast_lock);
* * hrtimer_interrupt()
* cpu 0 cpu1 * bc_handler()
* lock(broadcast_lock); * tick_handle_oneshot_broadcast();
* hrtimer_interrupt() * lock(broadcast_lock);
* bc_handler() * hrtimer_cancel()
* tick_handle_oneshot_broadcast(); * wait_for_callback()
* lock(broadcast_lock); */
* hrtimer_cancel() hrtimer_try_to_cancel(&bctimer);
* wait_for_callback() return 0;
*/
hrtimer_try_to_cancel(&bctimer);
break;
default:
break;
}
} }
/* /*
...@@ -82,7 +75,7 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc) ...@@ -82,7 +75,7 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
} }
static struct clock_event_device ce_broadcast_hrtimer = { static struct clock_event_device ce_broadcast_hrtimer = {
.set_mode = bc_set_mode, .set_state_shutdown = bc_shutdown,
.set_next_ktime = bc_set_next, .set_next_ktime = bc_set_next,
.features = CLOCK_EVT_FEAT_ONESHOT | .features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_KTIME | CLOCK_EVT_FEAT_KTIME |
...@@ -102,13 +95,11 @@ static enum hrtimer_restart bc_handler(struct hrtimer *t) ...@@ -102,13 +95,11 @@ static enum hrtimer_restart bc_handler(struct hrtimer *t)
{ {
ce_broadcast_hrtimer.event_handler(&ce_broadcast_hrtimer); ce_broadcast_hrtimer.event_handler(&ce_broadcast_hrtimer);
switch (ce_broadcast_hrtimer.mode) { if (clockevent_state_oneshot(&ce_broadcast_hrtimer))
case CLOCK_EVT_MODE_ONESHOT:
if (ce_broadcast_hrtimer.next_event.tv64 != KTIME_MAX) if (ce_broadcast_hrtimer.next_event.tv64 != KTIME_MAX)
return HRTIMER_RESTART; return HRTIMER_RESTART;
default:
return HRTIMER_NORESTART; return HRTIMER_NORESTART;
}
} }
void tick_setup_hrtimer_broadcast(void) void tick_setup_hrtimer_broadcast(void)
......
...@@ -304,9 +304,6 @@ void tick_check_new_device(struct clock_event_device *newdev) ...@@ -304,9 +304,6 @@ void tick_check_new_device(struct clock_event_device *newdev)
int cpu; int cpu;
cpu = smp_processor_id(); cpu = smp_processor_id();
if (!cpumask_test_cpu(cpu, newdev->cpumask))
goto out_bc;
td = &per_cpu(tick_cpu_device, cpu); td = &per_cpu(tick_cpu_device, cpu);
curdev = td->evtdev; curdev = td->evtdev;
......
...@@ -291,26 +291,20 @@ EXPORT_SYMBOL(jiffies_to_usecs); ...@@ -291,26 +291,20 @@ EXPORT_SYMBOL(jiffies_to_usecs);
* @t: Timespec * @t: Timespec
* @gran: Granularity in ns. * @gran: Granularity in ns.
* *
* Truncate a timespec to a granularity. gran must be smaller than a second. * Truncate a timespec to a granularity. Always rounds down. gran must
* Always rounds down. * not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns).
*
* This function should be only used for timestamps returned by
* current_kernel_time() or CURRENT_TIME, not with do_gettimeofday() because
* it doesn't handle the better resolution of the latter.
*/ */
struct timespec timespec_trunc(struct timespec t, unsigned gran) struct timespec timespec_trunc(struct timespec t, unsigned gran)
{ {
/* /* Avoid division in the common cases 1 ns and 1 s. */
* Division is pretty slow so avoid it for common cases. if (gran == 1) {
* Currently current_kernel_time() never returns better than
* jiffies resolution. Exploit that.
*/
if (gran <= jiffies_to_usecs(1) * 1000) {
/* nothing */ /* nothing */
} else if (gran == 1000000000) { } else if (gran == NSEC_PER_SEC) {
t.tv_nsec = 0; t.tv_nsec = 0;
} else { } else if (gran > 1 && gran < NSEC_PER_SEC) {
t.tv_nsec -= t.tv_nsec % gran; t.tv_nsec -= t.tv_nsec % gran;
} else {
WARN(1, "illegal file time granularity: %u", gran);
} }
return t; return t;
} }
...@@ -550,7 +544,7 @@ EXPORT_SYMBOL(__usecs_to_jiffies); ...@@ -550,7 +544,7 @@ EXPORT_SYMBOL(__usecs_to_jiffies);
* value to a scaled second value. * value to a scaled second value.
*/ */
static unsigned long static unsigned long
__timespec_to_jiffies(unsigned long sec, long nsec) __timespec64_to_jiffies(u64 sec, long nsec)
{ {
nsec = nsec + TICK_NSEC - 1; nsec = nsec + TICK_NSEC - 1;
...@@ -558,22 +552,27 @@ __timespec_to_jiffies(unsigned long sec, long nsec) ...@@ -558,22 +552,27 @@ __timespec_to_jiffies(unsigned long sec, long nsec)
sec = MAX_SEC_IN_JIFFIES; sec = MAX_SEC_IN_JIFFIES;
nsec = 0; nsec = 0;
} }
return (((u64)sec * SEC_CONVERSION) + return ((sec * SEC_CONVERSION) +
(((u64)nsec * NSEC_CONVERSION) >> (((u64)nsec * NSEC_CONVERSION) >>
(NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
} }
unsigned long static unsigned long
timespec_to_jiffies(const struct timespec *value) __timespec_to_jiffies(unsigned long sec, long nsec)
{ {
return __timespec_to_jiffies(value->tv_sec, value->tv_nsec); return __timespec64_to_jiffies((u64)sec, nsec);
} }
EXPORT_SYMBOL(timespec_to_jiffies); unsigned long
timespec64_to_jiffies(const struct timespec64 *value)
{
return __timespec64_to_jiffies(value->tv_sec, value->tv_nsec);
}
EXPORT_SYMBOL(timespec64_to_jiffies);
void void
jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) jiffies_to_timespec64(const unsigned long jiffies, struct timespec64 *value)
{ {
/* /*
* Convert jiffies to nanoseconds and separate with * Convert jiffies to nanoseconds and separate with
...@@ -584,7 +583,7 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value) ...@@ -584,7 +583,7 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
NSEC_PER_SEC, &rem); NSEC_PER_SEC, &rem);
value->tv_nsec = rem; value->tv_nsec = rem;
} }
EXPORT_SYMBOL(jiffies_to_timespec); EXPORT_SYMBOL(jiffies_to_timespec64);
/* /*
* We could use a similar algorithm to timespec_to_jiffies (with a * We could use a similar algorithm to timespec_to_jiffies (with a
......
...@@ -911,6 +911,7 @@ int do_settimeofday64(const struct timespec64 *ts) ...@@ -911,6 +911,7 @@ int do_settimeofday64(const struct timespec64 *ts)
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 ts_delta, xt; struct timespec64 ts_delta, xt;
unsigned long flags; unsigned long flags;
int ret = 0;
if (!timespec64_valid_strict(ts)) if (!timespec64_valid_strict(ts))
return -EINVAL; return -EINVAL;
...@@ -924,10 +925,15 @@ int do_settimeofday64(const struct timespec64 *ts) ...@@ -924,10 +925,15 @@ int do_settimeofday64(const struct timespec64 *ts)
ts_delta.tv_sec = ts->tv_sec - xt.tv_sec; ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec; ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
ret = -EINVAL;
goto out;
}
tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta)); tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));
tk_set_xtime(tk, ts); tk_set_xtime(tk, ts);
out:
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
write_seqcount_end(&tk_core.seq); write_seqcount_end(&tk_core.seq);
...@@ -936,7 +942,7 @@ int do_settimeofday64(const struct timespec64 *ts) ...@@ -936,7 +942,7 @@ int do_settimeofday64(const struct timespec64 *ts)
/* signal hrtimers about time change */ /* signal hrtimers about time change */
clock_was_set(); clock_was_set();
return 0; return ret;
} }
EXPORT_SYMBOL(do_settimeofday64); EXPORT_SYMBOL(do_settimeofday64);
...@@ -965,7 +971,8 @@ int timekeeping_inject_offset(struct timespec *ts) ...@@ -965,7 +971,8 @@ int timekeeping_inject_offset(struct timespec *ts)
/* Make sure the proposed value is valid */ /* Make sure the proposed value is valid */
tmp = timespec64_add(tk_xtime(tk), ts64); tmp = timespec64_add(tk_xtime(tk), ts64);
if (!timespec64_valid_strict(&tmp)) { if (timespec64_compare(&tk->wall_to_monotonic, &ts64) > 0 ||
!timespec64_valid_strict(&tmp)) {
ret = -EINVAL; ret = -EINVAL;
goto error; goto error;
} }
...@@ -1874,7 +1881,7 @@ struct timespec __current_kernel_time(void) ...@@ -1874,7 +1881,7 @@ struct timespec __current_kernel_time(void)
return timespec64_to_timespec(tk_xtime(tk)); return timespec64_to_timespec(tk_xtime(tk));
} }
struct timespec current_kernel_time(void) struct timespec64 current_kernel_time64(void)
{ {
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 now; struct timespec64 now;
...@@ -1886,9 +1893,9 @@ struct timespec current_kernel_time(void) ...@@ -1886,9 +1893,9 @@ struct timespec current_kernel_time(void)
now = tk_xtime(tk); now = tk_xtime(tk);
} while (read_seqcount_retry(&tk_core.seq, seq)); } while (read_seqcount_retry(&tk_core.seq, seq));
return timespec64_to_timespec(now); return now;
} }
EXPORT_SYMBOL(current_kernel_time); EXPORT_SYMBOL(current_kernel_time64);
struct timespec64 get_monotonic_coarse64(void) struct timespec64 get_monotonic_coarse64(void)
{ {
......
...@@ -137,7 +137,7 @@ print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now) ...@@ -137,7 +137,7 @@ print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
(unsigned long long) ktime_to_ns(base->offset)); (unsigned long long) ktime_to_ns(base->offset));
#endif #endif
SEQ_printf(m, "active timers:\n"); SEQ_printf(m, "active timers:\n");
print_active_timers(m, base, now); print_active_timers(m, base, now + ktime_to_ns(base->offset));
} }
static void print_cpu(struct seq_file *m, int cpu, u64 now) static void print_cpu(struct seq_file *m, int cpu, u64 now)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment