Loading arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -266,6 +266,7 @@ config ARCH_IXP4XX bool "IXP4xx-based" depends on MMU select GENERIC_TIME select GENERIC_CLOCKEVENTS help Support for Intel's IXP4XX (XScale) family of processors. Loading arch/arm/mach-ixp4xx/common.c +74 −19 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/time.h> #include <linux/timex.h> #include <linux/clocksource.h> #include <linux/clockchips.h> #include <asm/arch/udc.h> #include <asm/hardware.h> Loading @@ -41,6 +42,8 @@ #include <asm/mach/time.h> static int __init ixp4xx_clocksource_init(void); static int __init ixp4xx_clockevent_init(void); static struct clock_event_device clockevent_ixp4xx; /************************************************************************* * IXP4xx chipset I/O mapping Loading Loading @@ -239,52 +242,40 @@ void __init ixp4xx_init_irq(void) * counter as a source of real clock ticks to account for missed jiffies. *************************************************************************/ static unsigned volatile last_jiffy_time; #define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); struct clock_event_device *evt = &clockevent_ixp4xx; /* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; /* * Catch up with the real idea of time */ while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) { timer_tick(); last_jiffy_time += LATCH; } write_sequnlock(&xtime_lock); evt->event_handler(evt); return IRQ_HANDLED; } static struct irqaction ixp4xx_timer_irq = { .name = "IXP4xx Timer Tick", .name = "timer1", .flags = IRQF_DISABLED | IRQF_TIMER, .handler = ixp4xx_timer_interrupt, }; static void __init ixp4xx_timer_init(void) { /* Reset/disable counter */ *IXP4XX_OSRT1 = 0; /* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; /* Setup the Timer counter value */ *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; /* Reset time-stamp counter */ *IXP4XX_OSTS = 0; last_jiffy_time = 0; /* Connect the interrupt handler and enable the interrupt */ setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq); ixp4xx_clocksource_init(); ixp4xx_clockevent_init(); } struct sys_timer ixp4xx_timer = { Loading Loading @@ -384,6 +375,9 @@ void __init ixp4xx_sys_init(void) ixp4xx_exp_bus_size >> 20); } /* * clocksource */ cycle_t ixp4xx_get_cycles(void) { return *IXP4XX_OSTS; Loading @@ -408,3 +402,64 @@ static int __init ixp4xx_clocksource_init(void) return 0; } /* * clockevents */ static int ixp4xx_set_next_event(unsigned long evt, struct clock_event_device *unused) { unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK; *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts; return 0; } static void ixp4xx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK; switch (mode) { case CLOCK_EVT_MODE_PERIODIC: osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK; opts = IXP4XX_OST_ENABLE; break; case CLOCK_EVT_MODE_ONESHOT: /* period set by 'set next_event' */ osrt = 0; opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT; break; case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: default: osrt = opts = 0; break; } *IXP4XX_OSRT1 = osrt | opts; } static struct clock_event_device clockevent_ixp4xx = { .name = "ixp4xx timer1", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .rating = 200, .shift = 24, .set_mode = ixp4xx_set_mode, .set_next_event = ixp4xx_set_next_event, }; static int __init ixp4xx_clockevent_init(void) { clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC, clockevent_ixp4xx.shift); clockevent_ixp4xx.max_delta_ns = clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx); clockevent_ixp4xx.min_delta_ns = clockevent_delta2ns(0xf, &clockevent_ixp4xx); clockevent_ixp4xx.cpumask = cpumask_of_cpu(0); clockevents_register_device(&clockevent_ixp4xx); return 0; } Loading
arch/arm/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -266,6 +266,7 @@ config ARCH_IXP4XX bool "IXP4xx-based" depends on MMU select GENERIC_TIME select GENERIC_CLOCKEVENTS help Support for Intel's IXP4XX (XScale) family of processors. Loading
arch/arm/mach-ixp4xx/common.c +74 −19 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <linux/time.h> #include <linux/timex.h> #include <linux/clocksource.h> #include <linux/clockchips.h> #include <asm/arch/udc.h> #include <asm/hardware.h> Loading @@ -41,6 +42,8 @@ #include <asm/mach/time.h> static int __init ixp4xx_clocksource_init(void); static int __init ixp4xx_clockevent_init(void); static struct clock_event_device clockevent_ixp4xx; /************************************************************************* * IXP4xx chipset I/O mapping Loading Loading @@ -239,52 +242,40 @@ void __init ixp4xx_init_irq(void) * counter as a source of real clock ticks to account for missed jiffies. *************************************************************************/ static unsigned volatile last_jiffy_time; #define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC) static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); struct clock_event_device *evt = &clockevent_ixp4xx; /* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; /* * Catch up with the real idea of time */ while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) { timer_tick(); last_jiffy_time += LATCH; } write_sequnlock(&xtime_lock); evt->event_handler(evt); return IRQ_HANDLED; } static struct irqaction ixp4xx_timer_irq = { .name = "IXP4xx Timer Tick", .name = "timer1", .flags = IRQF_DISABLED | IRQF_TIMER, .handler = ixp4xx_timer_interrupt, }; static void __init ixp4xx_timer_init(void) { /* Reset/disable counter */ *IXP4XX_OSRT1 = 0; /* Clear Pending Interrupt by writing '1' to it */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; /* Setup the Timer counter value */ *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; /* Reset time-stamp counter */ *IXP4XX_OSTS = 0; last_jiffy_time = 0; /* Connect the interrupt handler and enable the interrupt */ setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq); ixp4xx_clocksource_init(); ixp4xx_clockevent_init(); } struct sys_timer ixp4xx_timer = { Loading Loading @@ -384,6 +375,9 @@ void __init ixp4xx_sys_init(void) ixp4xx_exp_bus_size >> 20); } /* * clocksource */ cycle_t ixp4xx_get_cycles(void) { return *IXP4XX_OSTS; Loading @@ -408,3 +402,64 @@ static int __init ixp4xx_clocksource_init(void) return 0; } /* * clockevents */ static int ixp4xx_set_next_event(unsigned long evt, struct clock_event_device *unused) { unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK; *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts; return 0; } static void ixp4xx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK; switch (mode) { case CLOCK_EVT_MODE_PERIODIC: osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK; opts = IXP4XX_OST_ENABLE; break; case CLOCK_EVT_MODE_ONESHOT: /* period set by 'set next_event' */ osrt = 0; opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT; break; case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: default: osrt = opts = 0; break; } *IXP4XX_OSRT1 = osrt | opts; } static struct clock_event_device clockevent_ixp4xx = { .name = "ixp4xx timer1", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .rating = 200, .shift = 24, .set_mode = ixp4xx_set_mode, .set_next_event = ixp4xx_set_next_event, }; static int __init ixp4xx_clockevent_init(void) { clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC, clockevent_ixp4xx.shift); clockevent_ixp4xx.max_delta_ns = clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx); clockevent_ixp4xx.min_delta_ns = clockevent_delta2ns(0xf, &clockevent_ixp4xx); clockevent_ixp4xx.cpumask = cpumask_of_cpu(0); clockevents_register_device(&clockevent_ixp4xx); return 0; }