Skip to content

Commit

Permalink
clocksource/drivers/lpc32xx: Support periodic mode
Browse files Browse the repository at this point in the history
This commit adds the support for periodic mode. This is done by not
setting the MR0S (Stop on TnMR0) bit on MCR, thus allowing
interrupts to be periodically generated on MR0 matches.

In order to do this, move the initial configuration that is specific to
the one-shot mode to set_state_oneshot().

Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Reviewed-by: Joachim Eastwood <manabian@gmail.com>
Tested-by: Joachim Eastwood <manabian@gmail.com>
  • Loading branch information
Ezequiel Garcia authored and Daniel Lezcano committed Feb 25, 2016
1 parent 751db1a commit 32f32d9
Showing 1 changed file with 34 additions and 5 deletions.
39 changes: 34 additions & 5 deletions drivers/clocksource/time-lpc32xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
struct lpc32xx_clock_event_ddata {
struct clock_event_device evtdev;
void __iomem *base;
u32 ticks_per_jiffy;
};

/* Needed for the sched clock */
Expand Down Expand Up @@ -85,11 +86,39 @@ static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)

static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
{
struct lpc32xx_clock_event_ddata *ddata =
container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);

/*
* When using oneshot, we must also disable the timer
* to wait for the first call to set_next_event().
*/
return lpc32xx_clkevt_shutdown(evtdev);
writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);

/* Enable interrupt, reset on match and stop on match (MCR). */
writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
LPC32XX_TIMER_MCR_MR0S, ddata->base + LPC32XX_TIMER_MCR);
return 0;
}

static int lpc32xx_clkevt_periodic(struct clock_event_device *evtdev)
{
struct lpc32xx_clock_event_ddata *ddata =
container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);

/* Enable interrupt and reset on match. */
writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R,
ddata->base + LPC32XX_TIMER_MCR);

/*
* Place timer in reset and program the delta in the match
* channel 0 (MR0).
*/
writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
writel_relaxed(ddata->ticks_per_jiffy, ddata->base + LPC32XX_TIMER_MR0);
writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);

return 0;
}

static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
Expand All @@ -107,11 +136,13 @@ static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
.evtdev = {
.name = "lpc3220 clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT,
.features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERIODIC,
.rating = 300,
.set_next_event = lpc32xx_clkevt_next_event,
.set_state_shutdown = lpc32xx_clkevt_shutdown,
.set_state_oneshot = lpc32xx_clkevt_oneshot,
.set_state_periodic = lpc32xx_clkevt_periodic,
},
};

Expand Down Expand Up @@ -210,17 +241,15 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
/*
* Disable timer and clear any pending interrupt (IR) on match
* channel 0 (MR0). Clear the prescaler as it's not used.
* Enable interrupt, reset on match and stop on match (MCR).
*/
writel_relaxed(0, base + LPC32XX_TIMER_TCR);
writel_relaxed(0, base + LPC32XX_TIMER_PR);
writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR);
writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
LPC32XX_TIMER_MCR_MR0S, base + LPC32XX_TIMER_MCR);

rate = clk_get_rate(clk);
lpc32xx_clk_event_ddata.base = base;
lpc32xx_clk_event_ddata.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
rate, 1, -1);

Expand Down

0 comments on commit 32f32d9

Please sign in to comment.