aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ks8695/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ks8695/time.c')
-rw-r--r--arch/arm/mach-ks8695/time.c105
1 files changed, 67 insertions, 38 deletions
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
index 6974c2355601..46c84bc7792c 100644
--- a/arch/arm/mach-ks8695/time.c
+++ b/arch/arm/mach-ks8695/time.c
@@ -25,6 +25,7 @@
25#include <linux/kernel.h> 25#include <linux/kernel.h>
26#include <linux/sched.h> 26#include <linux/sched.h>
27#include <linux/io.h> 27#include <linux/io.h>
28#include <linux/clockchips.h>
28 29
29#include <asm/mach/time.h> 30#include <asm/mach/time.h>
30#include <asm/system_misc.h> 31#include <asm/system_misc.h>
@@ -53,44 +54,69 @@
53/* Timer0 Timeout Counter Register */ 54/* Timer0 Timeout Counter Register */
54#define T0TC_WATCHDOG (0xff) /* Enable watchdog mode */ 55#define T0TC_WATCHDOG (0xff) /* Enable watchdog mode */
55 56
56/* 57static void ks8695_set_mode(enum clock_event_mode mode,
57 * Returns number of ms since last clock interrupt. Note that interrupts 58 struct clock_event_device *evt)
58 * will have been disabled by do_gettimeoffset()
59 */
60static unsigned long ks8695_gettimeoffset (void)
61{ 59{
62 unsigned long elapsed, tick2, intpending; 60 u32 tmcon;
63 61
64 /* 62 if (mode == CLOCK_EVT_FEAT_PERIODIC) {
65 * Get the current number of ticks. Note that there is a race 63 u32 rate = DIV_ROUND_CLOSEST(KS8695_CLOCK_RATE, HZ);
66 * condition between us reading the timer and checking for an 64 u32 half = DIV_ROUND_CLOSEST(rate, 2);
67 * interrupt. We solve this by ensuring that the counter has not 65
68 * reloaded between our two reads. 66 /* Disable timer 1 */
69 */ 67 tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON);
70 elapsed = readl_relaxed(KS8695_TMR_VA + KS8695_T1TC) + readl_relaxed(KS8695_TMR_VA + KS8695_T1PD); 68 tmcon &= ~TMCON_T1EN;
71 do { 69 writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
72 tick2 = elapsed; 70
73 intpending = readl_relaxed(KS8695_IRQ_VA + KS8695_INTST) & (1 << KS8695_IRQ_TIMER1); 71 /* Both registers need to count down */
74 elapsed = readl_relaxed(KS8695_TMR_VA + KS8695_T1TC) + readl_relaxed(KS8695_TMR_VA + KS8695_T1PD); 72 writel_relaxed(half, KS8695_TMR_VA + KS8695_T1TC);
75 } while (elapsed > tick2); 73 writel_relaxed(half, KS8695_TMR_VA + KS8695_T1PD);
76 74
77 /* Convert to number of ticks expired (not remaining) */ 75 /* Re-enable timer1 */
78 elapsed = (CLOCK_TICK_RATE / HZ) - elapsed; 76 tmcon |= TMCON_T1EN;
79 77 writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
80 /* Is interrupt pending? If so, then timer has been reloaded already. */ 78 }
81 if (intpending) 79}
82 elapsed += (CLOCK_TICK_RATE / HZ); 80
83 81static int ks8695_set_next_event(unsigned long cycles,
84 /* Convert ticks to usecs */ 82 struct clock_event_device *evt)
85 return (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH; 83
84{
85 u32 half = DIV_ROUND_CLOSEST(cycles, 2);
86 u32 tmcon;
87
88 /* Disable timer 1 */
89 tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON);
90 tmcon &= ~TMCON_T1EN;
91 writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
92
93 /* Both registers need to count down */
94 writel_relaxed(half, KS8695_TMR_VA + KS8695_T1TC);
95 writel_relaxed(half, KS8695_TMR_VA + KS8695_T1PD);
96
97 /* Re-enable timer1 */
98 tmcon |= TMCON_T1EN;
99 writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
100
101 return 0;
86} 102}
87 103
104static struct clock_event_device clockevent_ks8695 = {
105 .name = "ks8695_t1tc",
106 .rating = 300, /* Reasonably fast and accurate clock event */
107 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
108 .set_next_event = ks8695_set_next_event,
109 .set_mode = ks8695_set_mode,
110};
111
88/* 112/*
89 * IRQ handler for the timer. 113 * IRQ handler for the timer.
90 */ 114 */
91static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id) 115static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id)
92{ 116{
93 timer_tick(); 117 struct clock_event_device *evt = &clockevent_ks8695;
118
119 evt->event_handler(evt);
94 return IRQ_HANDLED; 120 return IRQ_HANDLED;
95} 121}
96 122
@@ -102,18 +128,22 @@ static struct irqaction ks8695_timer_irq = {
102 128
103static void ks8695_timer_setup(void) 129static void ks8695_timer_setup(void)
104{ 130{
105 unsigned long tmout = CLOCK_TICK_RATE / HZ;
106 unsigned long tmcon; 131 unsigned long tmcon;
107 132
108 /* disable timer1 */ 133 /* Disable timer 0 and 1 */
109 tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON); 134 tmcon = readl_relaxed(KS8695_TMR_VA + KS8695_TMCON);
110 writel_relaxed(tmcon & ~TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON); 135 tmcon &= ~TMCON_T0EN;
111 136 tmcon &= ~TMCON_T1EN;
112 writel_relaxed(tmout / 2, KS8695_TMR_VA + KS8695_T1TC); 137 writel_relaxed(tmcon, KS8695_TMR_VA + KS8695_TMCON);
113 writel_relaxed(tmout / 2, KS8695_TMR_VA + KS8695_T1PD);
114 138
115 /* re-enable timer1 */ 139 /*
116 writel_relaxed(tmcon | TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON); 140 * Use timer 1 to fire IRQs on the timeline, minimum 2 cycles
141 * (one on each counter) maximum 2*2^32, but the API will only
142 * accept up to a 32bit full word (0xFFFFFFFFU).
143 */
144 clockevents_config_and_register(&clockevent_ks8695,
145 KS8695_CLOCK_RATE, 2,
146 0xFFFFFFFFU);
117} 147}
118 148
119static void __init ks8695_timer_init (void) 149static void __init ks8695_timer_init (void)
@@ -126,7 +156,6 @@ static void __init ks8695_timer_init (void)
126 156
127struct sys_timer ks8695_timer = { 157struct sys_timer ks8695_timer = {
128 .init = ks8695_timer_init, 158 .init = ks8695_timer_init,
129 .offset = ks8695_gettimeoffset,
130}; 159};
131 160
132void ks8695_restart(char mode, const char *cmd) 161void ks8695_restart(char mode, const char *cmd)