aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel@vanguardiasur.com.ar>2016-02-09 20:54:26 -0500
committerDaniel Lezcano <daniel.lezcano@linaro.org>2016-02-25 08:30:20 -0500
commit32f32d982f655dd191858406b11e50219a0ee01e (patch)
treeac1c176915488da0d354ee1ba4b4848769b41109
parent751db1a6eaec3d266ccfe3f0d11323b7c82486bf (diff)
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: 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>
-rw-r--r--drivers/clocksource/time-lpc32xx.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c
index 50d1a63cbe1e..5694eddade15 100644
--- a/drivers/clocksource/time-lpc32xx.c
+++ b/drivers/clocksource/time-lpc32xx.c
@@ -43,6 +43,7 @@
43struct lpc32xx_clock_event_ddata { 43struct lpc32xx_clock_event_ddata {
44 struct clock_event_device evtdev; 44 struct clock_event_device evtdev;
45 void __iomem *base; 45 void __iomem *base;
46 u32 ticks_per_jiffy;
46}; 47};
47 48
48/* Needed for the sched clock */ 49/* Needed for the sched clock */
@@ -85,11 +86,39 @@ static int lpc32xx_clkevt_shutdown(struct clock_event_device *evtdev)
85 86
86static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev) 87static int lpc32xx_clkevt_oneshot(struct clock_event_device *evtdev)
87{ 88{
89 struct lpc32xx_clock_event_ddata *ddata =
90 container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
91
88 /* 92 /*
89 * When using oneshot, we must also disable the timer 93 * When using oneshot, we must also disable the timer
90 * to wait for the first call to set_next_event(). 94 * to wait for the first call to set_next_event().
91 */ 95 */
92 return lpc32xx_clkevt_shutdown(evtdev); 96 writel_relaxed(0, ddata->base + LPC32XX_TIMER_TCR);
97
98 /* Enable interrupt, reset on match and stop on match (MCR). */
99 writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
100 LPC32XX_TIMER_MCR_MR0S, ddata->base + LPC32XX_TIMER_MCR);
101 return 0;
102}
103
104static int lpc32xx_clkevt_periodic(struct clock_event_device *evtdev)
105{
106 struct lpc32xx_clock_event_ddata *ddata =
107 container_of(evtdev, struct lpc32xx_clock_event_ddata, evtdev);
108
109 /* Enable interrupt and reset on match. */
110 writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R,
111 ddata->base + LPC32XX_TIMER_MCR);
112
113 /*
114 * Place timer in reset and program the delta in the match
115 * channel 0 (MR0).
116 */
117 writel_relaxed(LPC32XX_TIMER_TCR_CRST, ddata->base + LPC32XX_TIMER_TCR);
118 writel_relaxed(ddata->ticks_per_jiffy, ddata->base + LPC32XX_TIMER_MR0);
119 writel_relaxed(LPC32XX_TIMER_TCR_CEN, ddata->base + LPC32XX_TIMER_TCR);
120
121 return 0;
93} 122}
94 123
95static irqreturn_t lpc32xx_clock_event_handler(int irq, void *dev_id) 124static 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)
107static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = { 136static struct lpc32xx_clock_event_ddata lpc32xx_clk_event_ddata = {
108 .evtdev = { 137 .evtdev = {
109 .name = "lpc3220 clockevent", 138 .name = "lpc3220 clockevent",
110 .features = CLOCK_EVT_FEAT_ONESHOT, 139 .features = CLOCK_EVT_FEAT_ONESHOT |
140 CLOCK_EVT_FEAT_PERIODIC,
111 .rating = 300, 141 .rating = 300,
112 .set_next_event = lpc32xx_clkevt_next_event, 142 .set_next_event = lpc32xx_clkevt_next_event,
113 .set_state_shutdown = lpc32xx_clkevt_shutdown, 143 .set_state_shutdown = lpc32xx_clkevt_shutdown,
114 .set_state_oneshot = lpc32xx_clkevt_oneshot, 144 .set_state_oneshot = lpc32xx_clkevt_oneshot,
145 .set_state_periodic = lpc32xx_clkevt_periodic,
115 }, 146 },
116}; 147};
117 148
@@ -210,17 +241,15 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
210 /* 241 /*
211 * Disable timer and clear any pending interrupt (IR) on match 242 * Disable timer and clear any pending interrupt (IR) on match
212 * channel 0 (MR0). Clear the prescaler as it's not used. 243 * channel 0 (MR0). Clear the prescaler as it's not used.
213 * Enable interrupt, reset on match and stop on match (MCR).
214 */ 244 */
215 writel_relaxed(0, base + LPC32XX_TIMER_TCR); 245 writel_relaxed(0, base + LPC32XX_TIMER_TCR);
216 writel_relaxed(0, base + LPC32XX_TIMER_PR); 246 writel_relaxed(0, base + LPC32XX_TIMER_PR);
217 writel_relaxed(0, base + LPC32XX_TIMER_CTCR); 247 writel_relaxed(0, base + LPC32XX_TIMER_CTCR);
218 writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR); 248 writel_relaxed(LPC32XX_TIMER_IR_MR0INT, base + LPC32XX_TIMER_IR);
219 writel_relaxed(LPC32XX_TIMER_MCR_MR0I | LPC32XX_TIMER_MCR_MR0R |
220 LPC32XX_TIMER_MCR_MR0S, base + LPC32XX_TIMER_MCR);
221 249
222 rate = clk_get_rate(clk); 250 rate = clk_get_rate(clk);
223 lpc32xx_clk_event_ddata.base = base; 251 lpc32xx_clk_event_ddata.base = base;
252 lpc32xx_clk_event_ddata.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
224 clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev, 253 clockevents_config_and_register(&lpc32xx_clk_event_ddata.evtdev,
225 rate, 1, -1); 254 rate, 1, -1);
226 255