diff options
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-versatile/core.c | 68 |
2 files changed, 59 insertions, 10 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cddd054676c0..d1f24aa89deb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -167,6 +167,7 @@ config ARCH_VERSATILE | |||
167 | select ARM_VIC | 167 | select ARM_VIC |
168 | select ICST307 | 168 | select ICST307 |
169 | select GENERIC_TIME | 169 | select GENERIC_TIME |
170 | select GENERIC_CLOCKEVENTS | ||
170 | help | 171 | help |
171 | This enables support for ARM Ltd Versatile board. | 172 | This enables support for ARM Ltd Versatile board. |
172 | 173 | ||
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 08a9fe6eeadb..1275aa7d2eb1 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/amba/bus.h> | 27 | #include <linux/amba/bus.h> |
28 | #include <linux/amba/clcd.h> | 28 | #include <linux/amba/clcd.h> |
29 | #include <linux/clocksource.h> | 29 | #include <linux/clocksource.h> |
30 | #include <linux/clockchips.h> | ||
30 | 31 | ||
31 | #include <asm/cnt32_to_63.h> | 32 | #include <asm/cnt32_to_63.h> |
32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
@@ -829,19 +830,61 @@ void __init versatile_init(void) | |||
829 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) | 830 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) |
830 | #endif | 831 | #endif |
831 | 832 | ||
833 | static void timer_set_mode(enum clock_event_mode mode, | ||
834 | struct clock_event_device *clk) | ||
835 | { | ||
836 | unsigned long ctrl; | ||
837 | |||
838 | switch(mode) { | ||
839 | case CLOCK_EVT_MODE_PERIODIC: | ||
840 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); | ||
841 | |||
842 | ctrl = TIMER_CTRL_PERIODIC; | ||
843 | ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE; | ||
844 | break; | ||
845 | case CLOCK_EVT_MODE_ONESHOT: | ||
846 | /* period set, and timer enabled in 'next_event' hook */ | ||
847 | ctrl = TIMER_CTRL_ONESHOT; | ||
848 | ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE; | ||
849 | break; | ||
850 | case CLOCK_EVT_MODE_UNUSED: | ||
851 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
852 | default: | ||
853 | ctrl = 0; | ||
854 | } | ||
855 | |||
856 | writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL); | ||
857 | } | ||
858 | |||
859 | static int timer_set_next_event(unsigned long evt, | ||
860 | struct clock_event_device *unused) | ||
861 | { | ||
862 | unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL); | ||
863 | |||
864 | writel(evt, TIMER0_VA_BASE + TIMER_LOAD); | ||
865 | writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL); | ||
866 | |||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static struct clock_event_device timer0_clockevent = { | ||
871 | .name = "timer0", | ||
872 | .shift = 32, | ||
873 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
874 | .set_mode = timer_set_mode, | ||
875 | .set_next_event = timer_set_next_event, | ||
876 | }; | ||
877 | |||
832 | /* | 878 | /* |
833 | * IRQ handler for the timer | 879 | * IRQ handler for the timer |
834 | */ | 880 | */ |
835 | static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id) | 881 | static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id) |
836 | { | 882 | { |
837 | write_seqlock(&xtime_lock); | 883 | struct clock_event_device *evt = &timer0_clockevent; |
838 | 884 | ||
839 | // ...clear the interrupt | ||
840 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); | 885 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); |
841 | 886 | ||
842 | timer_tick(); | 887 | evt->event_handler(evt); |
843 | |||
844 | write_sequnlock(&xtime_lock); | ||
845 | 888 | ||
846 | return IRQ_HANDLED; | 889 | return IRQ_HANDLED; |
847 | } | 890 | } |
@@ -909,17 +952,22 @@ static void __init versatile_timer_init(void) | |||
909 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | 952 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); |
910 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | 953 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); |
911 | 954 | ||
912 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); | ||
913 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); | ||
914 | writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | | ||
915 | TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); | ||
916 | |||
917 | /* | 955 | /* |
918 | * Make irqs happen for the system timer | 956 | * Make irqs happen for the system timer |
919 | */ | 957 | */ |
920 | setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); | 958 | setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); |
921 | 959 | ||
922 | versatile_clocksource_init(); | 960 | versatile_clocksource_init(); |
961 | |||
962 | timer0_clockevent.mult = | ||
963 | div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift); | ||
964 | timer0_clockevent.max_delta_ns = | ||
965 | clockevent_delta2ns(0xffffffff, &timer0_clockevent); | ||
966 | timer0_clockevent.min_delta_ns = | ||
967 | clockevent_delta2ns(0xf, &timer0_clockevent); | ||
968 | |||
969 | timer0_clockevent.cpumask = cpumask_of_cpu(0); | ||
970 | clockevents_register_device(&timer0_clockevent); | ||
923 | } | 971 | } |
924 | 972 | ||
925 | struct sys_timer versatile_timer = { | 973 | struct sys_timer versatile_timer = { |