aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKevin Hilman <khilman@mvista.com>2007-03-08 14:23:59 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-04-21 16:02:30 -0400
commite32f1502be3fa459723b1e4105e014f0828f7513 (patch)
tree78040ca9d3a58b09f9214256738aa1c4abeba776 /arch
parent9e4559ddffc012a73ea0b54ed3b6a219c1483ae9 (diff)
[ARM] 4259/1: clockevent support for ixp4xx platform
Update ixp4xx timer support to use new clockevent infrastructure. Signed-off-by: Kevin Hilman <khilman@mvista.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mach-ixp4xx/common.c93
2 files changed, 75 insertions, 19 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2d13b0166121..2aadd0e1e586 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -266,6 +266,7 @@ config ARCH_IXP4XX
266 bool "IXP4xx-based" 266 bool "IXP4xx-based"
267 depends on MMU 267 depends on MMU
268 select GENERIC_TIME 268 select GENERIC_TIME
269 select GENERIC_CLOCKEVENTS
269 help 270 help
270 Support for Intel's IXP4XX (XScale) family of processors. 271 Support for Intel's IXP4XX (XScale) family of processors.
271 272
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 45068c3d8dcc..09edea9779e6 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -27,6 +27,7 @@
27#include <linux/time.h> 27#include <linux/time.h>
28#include <linux/timex.h> 28#include <linux/timex.h>
29#include <linux/clocksource.h> 29#include <linux/clocksource.h>
30#include <linux/clockchips.h>
30 31
31#include <asm/arch/udc.h> 32#include <asm/arch/udc.h>
32#include <asm/hardware.h> 33#include <asm/hardware.h>
@@ -41,6 +42,8 @@
41#include <asm/mach/time.h> 42#include <asm/mach/time.h>
42 43
43static int __init ixp4xx_clocksource_init(void); 44static int __init ixp4xx_clocksource_init(void);
45static int __init ixp4xx_clockevent_init(void);
46static struct clock_event_device clockevent_ixp4xx;
44 47
45/************************************************************************* 48/*************************************************************************
46 * IXP4xx chipset I/O mapping 49 * IXP4xx chipset I/O mapping
@@ -239,52 +242,40 @@ void __init ixp4xx_init_irq(void)
239 * counter as a source of real clock ticks to account for missed jiffies. 242 * counter as a source of real clock ticks to account for missed jiffies.
240 *************************************************************************/ 243 *************************************************************************/
241 244
242static unsigned volatile last_jiffy_time;
243
244#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
245
246static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) 245static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
247{ 246{
248 write_seqlock(&xtime_lock); 247 struct clock_event_device *evt = &clockevent_ixp4xx;
249 248
250 /* Clear Pending Interrupt by writing '1' to it */ 249 /* Clear Pending Interrupt by writing '1' to it */
251 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; 250 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
252 251
253 /* 252 evt->event_handler(evt);
254 * Catch up with the real idea of time
255 */
256 while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
257 timer_tick();
258 last_jiffy_time += LATCH;
259 }
260
261 write_sequnlock(&xtime_lock);
262 253
263 return IRQ_HANDLED; 254 return IRQ_HANDLED;
264} 255}
265 256
266static struct irqaction ixp4xx_timer_irq = { 257static struct irqaction ixp4xx_timer_irq = {
267 .name = "IXP4xx Timer Tick", 258 .name = "timer1",
268 .flags = IRQF_DISABLED | IRQF_TIMER, 259 .flags = IRQF_DISABLED | IRQF_TIMER,
269 .handler = ixp4xx_timer_interrupt, 260 .handler = ixp4xx_timer_interrupt,
270}; 261};
271 262
272static void __init ixp4xx_timer_init(void) 263static void __init ixp4xx_timer_init(void)
273{ 264{
265 /* Reset/disable counter */
266 *IXP4XX_OSRT1 = 0;
267
274 /* Clear Pending Interrupt by writing '1' to it */ 268 /* Clear Pending Interrupt by writing '1' to it */
275 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; 269 *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
276 270
277 /* Setup the Timer counter value */
278 *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
279
280 /* Reset time-stamp counter */ 271 /* Reset time-stamp counter */
281 *IXP4XX_OSTS = 0; 272 *IXP4XX_OSTS = 0;
282 last_jiffy_time = 0;
283 273
284 /* Connect the interrupt handler and enable the interrupt */ 274 /* Connect the interrupt handler and enable the interrupt */
285 setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq); 275 setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
286 276
287 ixp4xx_clocksource_init(); 277 ixp4xx_clocksource_init();
278 ixp4xx_clockevent_init();
288} 279}
289 280
290struct sys_timer ixp4xx_timer = { 281struct sys_timer ixp4xx_timer = {
@@ -384,6 +375,9 @@ void __init ixp4xx_sys_init(void)
384 ixp4xx_exp_bus_size >> 20); 375 ixp4xx_exp_bus_size >> 20);
385} 376}
386 377
378/*
379 * clocksource
380 */
387cycle_t ixp4xx_get_cycles(void) 381cycle_t ixp4xx_get_cycles(void)
388{ 382{
389 return *IXP4XX_OSTS; 383 return *IXP4XX_OSTS;
@@ -408,3 +402,64 @@ static int __init ixp4xx_clocksource_init(void)
408 402
409 return 0; 403 return 0;
410} 404}
405
406/*
407 * clockevents
408 */
409static int ixp4xx_set_next_event(unsigned long evt,
410 struct clock_event_device *unused)
411{
412 unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK;
413
414 *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts;
415
416 return 0;
417}
418
419static void ixp4xx_set_mode(enum clock_event_mode mode,
420 struct clock_event_device *evt)
421{
422 unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK;
423
424 switch (mode) {
425 case CLOCK_EVT_MODE_PERIODIC:
426 osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK;
427 opts = IXP4XX_OST_ENABLE;
428 break;
429 case CLOCK_EVT_MODE_ONESHOT:
430 /* period set by 'set next_event' */
431 osrt = 0;
432 opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT;
433 break;
434 case CLOCK_EVT_MODE_SHUTDOWN:
435 case CLOCK_EVT_MODE_UNUSED:
436 default:
437 osrt = opts = 0;
438 break;
439 }
440
441 *IXP4XX_OSRT1 = osrt | opts;
442}
443
444static struct clock_event_device clockevent_ixp4xx = {
445 .name = "ixp4xx timer1",
446 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
447 .rating = 200,
448 .shift = 24,
449 .set_mode = ixp4xx_set_mode,
450 .set_next_event = ixp4xx_set_next_event,
451};
452
453static int __init ixp4xx_clockevent_init(void)
454{
455 clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC,
456 clockevent_ixp4xx.shift);
457 clockevent_ixp4xx.max_delta_ns =
458 clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx);
459 clockevent_ixp4xx.min_delta_ns =
460 clockevent_delta2ns(0xf, &clockevent_ixp4xx);
461 clockevent_ixp4xx.cpumask = cpumask_of_cpu(0);
462
463 clockevents_register_device(&clockevent_ixp4xx);
464 return 0;
465}