kernel-ark/arch/arm/mach-sa1100/time.c
Shawn Guo 838a2ae80a ARM: use clockevents_config_and_register() where possible
The clockevent core is able to figure out the best mult and shift,
calculate min_delta_ns and max_delta_ns, with the necessary info passed
into clockevents_config_and_register().  Use this combined configure
and register function where possible to make the codes less error prone
and gain some positive diff stat.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Reviewed-by: Anton Vorontsov <cbouatmailru@gmail.com>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Tested-by: Roland Stigge <stigge@antcom.de>
Acked-by: Eric Miao <eric.y.miao@gmail.com>
Cc: Haojian Zhuang <haojian.zhuang@gmail.com>
Cc: David Brown <davidb@codeaurora.org>
Tested-by: Tony Lindgren <tony@atomide.com>
Acked-by: Barry Song <baohua.song@csr.com>
Tested-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Tony Prisk <linux@prisktech.co.nz>
Cc: Lennert Buytenhek <buytenh@wantstofly.org>
Cc: Wan ZongShun <mcuos.com@gmail.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Jason Cooper <jason@lakedaemon.net>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Olof Johansson <olof@lixom.net>
2013-01-14 10:12:42 -08:00

140 lines
3.3 KiB
C

/*
* linux/arch/arm/mach-sa1100/time.c
*
* Copyright (C) 1998 Deborah Wallach.
* Twiddles (C) 1999 Hugo Fiennes <hugo@empeg.com>
*
* 2000/03/29 (C) Nicolas Pitre <nico@fluxnic.net>
* Rewritten: big cleanup, much simpler, better HZ accuracy.
*
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/timex.h>
#include <linux/clockchips.h>
#include <asm/mach/time.h>
#include <asm/sched_clock.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
static u32 notrace sa1100_read_sched_clock(void)
{
return readl_relaxed(OSCR);
}
#define MIN_OSCR_DELTA 2
static irqreturn_t sa1100_ost0_interrupt(int irq, void *dev_id)
{
struct clock_event_device *c = dev_id;
/* Disarm the compare/match, signal the event. */
writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
writel_relaxed(OSSR_M0, OSSR);
c->event_handler(c);
return IRQ_HANDLED;
}
static int
sa1100_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
{
unsigned long next, oscr;
writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER);
next = readl_relaxed(OSCR) + delta;
writel_relaxed(next, OSMR0);
oscr = readl_relaxed(OSCR);
return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
}
static void
sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER);
writel_relaxed(OSSR_M0, OSSR);
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
}
}
static struct clock_event_device ckevt_sa1100_osmr0 = {
.name = "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 200,
.set_next_event = sa1100_osmr0_set_next_event,
.set_mode = sa1100_osmr0_set_mode,
};
static struct irqaction sa1100_timer_irq = {
.name = "ost0",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = sa1100_ost0_interrupt,
.dev_id = &ckevt_sa1100_osmr0,
};
static void __init sa1100_timer_init(void)
{
writel_relaxed(0, OIER);
writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
setup_sched_clock(sa1100_read_sched_clock, 32, 3686400);
ckevt_sa1100_osmr0.cpumask = cpumask_of(0);
setup_irq(IRQ_OST0, &sa1100_timer_irq);
clocksource_mmio_init(OSCR, "oscr", CLOCK_TICK_RATE, 200, 32,
clocksource_mmio_readl_up);
clockevents_config_and_register(&ckevt_sa1100_osmr0, 3686400,
MIN_OSCR_DELTA * 2, 0x7fffffff);
}
#ifdef CONFIG_PM
unsigned long osmr[4], oier;
static void sa1100_timer_suspend(void)
{
osmr[0] = readl_relaxed(OSMR0);
osmr[1] = readl_relaxed(OSMR1);
osmr[2] = readl_relaxed(OSMR2);
osmr[3] = readl_relaxed(OSMR3);
oier = readl_relaxed(OIER);
}
static void sa1100_timer_resume(void)
{
writel_relaxed(0x0f, OSSR);
writel_relaxed(osmr[0], OSMR0);
writel_relaxed(osmr[1], OSMR1);
writel_relaxed(osmr[2], OSMR2);
writel_relaxed(osmr[3], OSMR3);
writel_relaxed(oier, OIER);
/*
* OSMR0 is the system timer: make sure OSCR is sufficiently behind
*/
writel_relaxed(OSMR0 - LATCH, OSCR);
}
#else
#define sa1100_timer_suspend NULL
#define sa1100_timer_resume NULL
#endif
struct sys_timer sa1100_timer = {
.init = sa1100_timer_init,
.suspend = sa1100_timer_suspend,
.resume = sa1100_timer_resume,
};