Skip to content

Commit

Permalink
ARM: u300: fix timekeeping when periodic mode is used
Browse files Browse the repository at this point in the history
To determine the value to write to the hardware's timer counter register
the symbol CLOCK_TICK_RATE is used. This value is a dummy value on u300
though. So instead use the clock rate that is used for oneshot mode.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Uwe Kleine-König authored and Linus Walleij committed Nov 26, 2013
1 parent 8ddd0f6 commit 6a79799
Showing 1 changed file with 24 additions and 14 deletions.
38 changes: 24 additions & 14 deletions arch/arm/mach-u300/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,13 @@
#define U300_TIMER_APP_CRC (0x100)
#define U300_TIMER_APP_CRC_CLOCK_REQUEST_ENABLE (0x00000001)

#define TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
#define US_PER_TICK ((1000000 + (HZ/2)) / HZ)

static void __iomem *u300_timer_base;

struct u300_clockevent_data {
struct clock_event_device cevd;
unsigned ticks_per_jiffy;
};

/*
* The u300_set_mode() function is always called first, if we
* have oneshot timer active, the oneshot scheduling function
Expand All @@ -197,6 +199,9 @@ static void __iomem *u300_timer_base;
static void u300_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
struct u300_clockevent_data *cevdata =
container_of(evt, struct u300_clockevent_data, cevd);

switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
/* Disable interrupts on GPT1 */
Expand All @@ -209,7 +214,7 @@ static void u300_set_mode(enum clock_event_mode mode,
* Set the periodic mode to a certain number of ticks per
* jiffy.
*/
writel(TICKS_PER_JIFFY,
writel(cevdata->ticks_per_jiffy,
u300_timer_base + U300_TIMER_APP_GPT1TC);
/*
* Set continuous mode, so the timer keeps triggering
Expand Down Expand Up @@ -305,20 +310,23 @@ static int u300_set_next_event(unsigned long cycles,
return 0;
}


/* Use general purpose timer 1 as clock event */
static struct clock_event_device clockevent_u300_1mhz = {
.name = "GPT1",
.rating = 300, /* Reasonably fast and accurate clock event */
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = u300_set_next_event,
.set_mode = u300_set_mode,
static struct u300_clockevent_data u300_clockevent_data = {
/* Use general purpose timer 1 as clock event */
.cevd = {
.name = "GPT1",
/* Reasonably fast and accurate clock event */
.rating = 300,
.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = u300_set_next_event,
.set_mode = u300_set_mode,
},
};

/* Clock event timer interrupt handler */
static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *evt = &clockevent_u300_1mhz;
struct clock_event_device *evt = &u300_clockevent_data.cevd;
/* ACK/Clear timer IRQ for the APP GPT1 Timer */

writel(U300_TIMER_APP_GPT1IA_IRQ_ACK,
Expand Down Expand Up @@ -379,6 +387,8 @@ static void __init u300_timer_init_of(struct device_node *np)
clk_prepare_enable(clk);
rate = clk_get_rate(clk);

u300_clockevent_data.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);

setup_sched_clock(u300_read_sched_clock, 32, rate);

u300_delay_timer.read_current_timer = &u300_read_current_timer;
Expand Down Expand Up @@ -428,7 +438,7 @@ static void __init u300_timer_init_of(struct device_node *np)
pr_err("timer: failed to initialize U300 clock source\n");

/* Configure and register the clockevent */
clockevents_config_and_register(&clockevent_u300_1mhz, rate,
clockevents_config_and_register(&u300_clockevent_data.cevd, rate,
1, 0xffffffff);

/*
Expand Down

0 comments on commit 6a79799

Please sign in to comment.