Commit 32f32d98 authored by Ezequiel Garcia's avatar Ezequiel Garcia Committed by Daniel Lezcano

clocksource/drivers/lpc32xx: Support periodic mode

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: default avatarEzequiel Garcia <ezequiel@vanguardiasur.com.ar>
Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
Reviewed-by: default avatarJoachim Eastwood <manabian@gmail.com>
Tested-by: default avatarJoachim Eastwood <manabian@gmail.com>
parent 751db1a6
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
struct lpc32xx_clock_event_ddata { struct lpc32xx_clock_event_ddata {
struct clock_event_device evtdev; struct clock_event_device evtdev;
void __iomem *base; void __iomem *base;
u32 ticks_per_jiffy;
}; };
/* Needed for the sched clock */ /* Needed for the sched clock */
...@@ -85,11 +86,39 @@ static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev) ...@@ -85,11 +86,39 @@ static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
static int lpc32xx_clkevt_oneshot(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 * When using oneshot, we must also disable the timer
* to wait for the first call to set_next_event(). * 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) static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id)
...@@ -107,11 +136,13 @@ static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id) ...@@ -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 = { static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
.evtdev = { .evtdev = {
.name = "lpc3220 clockevent", .name = "lpc3220 clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERIODIC,
.rating = 300, .rating = 300,
.set_next_event = lpc32xx_clkevt_next_event, .set_next_event = lpc32xx_clkevt_next_event,
.set_state_shutdown = lpc32xx_clkevt_shutdown, .set_state_shutdown = lpc32xx_clkevt_shutdown,
.set_state_oneshot = lpc32xx_clkevt_oneshot, .set_state_oneshot = lpc32xx_clkevt_oneshot,
.set_state_periodic = lpc32xx_clkevt_periodic,
}, },
}; };
...@@ -210,17 +241,15 @@ static int __init lpc32xx_clockevent_init(struct device_node *np) ...@@ -210,17 +241,15 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
/* /*
* Disable timer and clear any pending interrupt (IR) on match * Disable timer and clear any pending interrupt (IR) on match
* channel 0 (MR0). Clear the prescaler as it's not used. * 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_TCR);
writel_relaxed(0, base + LPC32XX_TIMER_PR); writel_relaxed(0, base + LPC32XX_TIMER_PR);
writel_relaxed(0, base + LPC32XX_TIMER_CTCR); writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR); 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); rate = clk_get_rate(clk);
lpc32xx_clk_event_ddata.base = base; 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, clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
rate, 1, -1); rate, 1, -1);
......
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