2 * arch/sh/kernel/timers/timer-cmt.c - CMT Timer Support
4 * Copyright (C) 2005 Yoshinori Sato
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/interrupt.h>
14 #include <linux/spinlock.h>
15 #include <linux/seqlock.h>
16 #include <asm/timer.h>
20 #include <asm/clock.h>
22 #if defined(CONFIG_CPU_SUBTYPE_SH7619)
23 #define CMT_CMSTR 0xf84a0070
24 #define CMT_CMCSR_0 0xf84a0072
25 #define CMT_CMCNT_0 0xf84a0074
26 #define CMT_CMCOR_0 0xf84a0076
27 #define CMT_CMCSR_1 0xf84a0078
28 #define CMT_CMCNT_1 0xf84a007a
29 #define CMT_CMCOR_1 0xf84a007c
31 #define STBCR3 0xf80a0000
32 #define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR3) & ~0x10, STBCR3); } while(0)
33 #define CMT_CMCSR_INIT 0x0040
34 #define CMT_CMCSR_CALIB 0x0000
35 #elif defined(CONFIG_CPU_SUBTYPE_SH7206)
36 #define CMT_CMSTR 0xfffec000
37 #define CMT_CMCSR_0 0xfffec002
38 #define CMT_CMCNT_0 0xfffec004
39 #define CMT_CMCOR_0 0xfffec006
41 #define STBCR4 0xfffe040c
42 #define cmt_clock_enable() do { ctrl_outb(ctrl_inb(STBCR4) & ~0x04, STBCR4); } while(0)
43 #define CMT_CMCSR_INIT 0x0040
44 #define CMT_CMCSR_CALIB 0x0000
46 #error "Unknown CPU SUBTYPE"
49 static DEFINE_SPINLOCK(cmt0_lock
);
51 static unsigned long cmt_timer_get_offset(void)
56 static unsigned short count_p
= 0xffff; /* for the first call after boot */
57 static unsigned long jiffies_p
= 0;
60 * cache volatile jiffies temporarily; we have IRQs turned off.
62 unsigned long jiffies_t
;
64 spin_lock_irqsave(&cmt0_lock
, flags
);
65 /* timer count may underflow right here */
66 count
= ctrl_inw(CMT_CMCOR_0
);
67 count
-= ctrl_inw(CMT_CMCNT_0
);
72 * avoiding timer inconsistencies (they are rare, but they happen)...
73 * there is one kind of problem that must be avoided here:
74 * 1. the timer counter underflows
77 if (jiffies_t
== jiffies_p
) {
78 if (count
> count_p
) {
80 if (ctrl_inw(CMT_CMCSR_0
) & 0x80) { /* Check CMF bit */
83 printk("%s (): hardware timer problem?\n",
88 jiffies_p
= jiffies_t
;
91 spin_unlock_irqrestore(&cmt0_lock
, flags
);
93 count
= ((LATCH
-1) - count
) * TICK_SIZE
;
94 count
= (count
+ LATCH
/2) / LATCH
;
99 static irqreturn_t
cmt_timer_interrupt(int irq
, void *dev_id
,
100 struct pt_regs
*regs
)
102 unsigned long timer_status
;
105 timer_status
= ctrl_inw(CMT_CMCSR_0
);
106 timer_status
&= ~0x80;
107 ctrl_outw(timer_status
, CMT_CMCSR_0
);
110 * Here we are in the timer irq handler. We just have irqs locally
111 * disabled but we don't know if the timer_bh is running on the other
112 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
113 * the irq version of write_lock because as just said we have irq
114 * locally disabled. -arca
116 write_seqlock(&xtime_lock
);
117 handle_timer_tick(regs
);
118 write_sequnlock(&xtime_lock
);
123 static struct irqaction cmt_irq
= {
125 .handler
= cmt_timer_interrupt
,
126 .flags
= SA_INTERRUPT
,
127 .mask
= CPU_MASK_NONE
,
131 * Hah! We'll see if this works (switching from usecs to nsecs).
133 static unsigned long cmt_timer_get_frequency(void)
136 struct timespec ts1
, ts2
;
137 unsigned long diff_nsec
;
138 unsigned long factor
;
140 /* Setup the timer: We don't want to generate interrupts, just
141 * have it count down at its natural rate.
144 ctrl_outw(ctrl_inw(CMT_CMSTR
) & ~0x01, CMT_CMSTR
);
145 ctrl_outw(CMT_CMCSR_CALIB
, CMT_CMCSR_0
);
146 ctrl_outw(0xffff, CMT_CMCOR_0
);
147 ctrl_outw(0xffff, CMT_CMCNT_0
);
149 rtc_sh_get_time(&ts2
);
152 rtc_sh_get_time(&ts1
);
153 } while (ts1
.tv_nsec
== ts2
.tv_nsec
&& ts1
.tv_sec
== ts2
.tv_sec
);
155 /* actually start the timer */
156 ctrl_outw(ctrl_inw(CMT_CMSTR
) | 0x01, CMT_CMSTR
);
159 rtc_sh_get_time(&ts2
);
160 } while (ts1
.tv_nsec
== ts2
.tv_nsec
&& ts1
.tv_sec
== ts2
.tv_sec
);
162 freq
= 0xffff - ctrl_inw(CMT_CMCNT_0
);
163 if (ts2
.tv_nsec
< ts1
.tv_nsec
) {
164 ts2
.tv_nsec
+= 1000000000;
168 diff_nsec
= (ts2
.tv_sec
- ts1
.tv_sec
) * 1000000000 + (ts2
.tv_nsec
- ts1
.tv_nsec
);
170 /* this should work well if the RTC has a precision of n Hz, where
171 * n is an integer. I don't think we have to worry about the other
173 factor
= (1000000000 + diff_nsec
/2) / diff_nsec
;
175 if (factor
* diff_nsec
> 1100000000 ||
176 factor
* diff_nsec
< 900000000)
177 panic("weird RTC (diff_nsec %ld)", diff_nsec
);
179 return freq
* factor
;
182 static void cmt_clk_init(struct clk
*clk
)
184 u8 divisor
= CMT_CMCSR_INIT
& 0x3;
185 ctrl_inw(CMT_CMCSR_0
);
186 ctrl_outw(CMT_CMCSR_INIT
, CMT_CMCSR_0
);
187 clk
->parent
= clk_get("module_clk");
188 clk
->rate
= clk
->parent
->rate
/ (8 << (divisor
<< 1));
191 static void cmt_clk_recalc(struct clk
*clk
)
193 u8 divisor
= ctrl_inw(CMT_CMCSR_0
) & 0x3;
194 clk
->rate
= clk
->parent
->rate
/ (8 << (divisor
<< 1));
197 static struct clk_ops cmt_clk_ops
= {
198 .init
= cmt_clk_init
,
199 .recalc
= cmt_clk_recalc
,
202 static struct clk cmt0_clk
= {
207 static int cmt_timer_start(void)
209 ctrl_outw(ctrl_inw(CMT_CMSTR
) | 0x01, CMT_CMSTR
);
213 static int cmt_timer_stop(void)
215 ctrl_outw(ctrl_inw(CMT_CMSTR
) & ~0x01, CMT_CMSTR
);
219 static int cmt_timer_init(void)
221 unsigned long interval
;
225 setup_irq(TIMER_IRQ
, &cmt_irq
);
227 cmt0_clk
.parent
= clk_get("module_clk");
231 interval
= cmt0_clk
.parent
->rate
/ 8 / HZ
;
232 printk(KERN_INFO
"Interval = %ld\n", interval
);
234 ctrl_outw(interval
, CMT_CMCOR_0
);
236 clk_register(&cmt0_clk
);
237 clk_enable(&cmt0_clk
);
244 struct sys_timer_ops cmt_timer_ops
= {
245 .init
= cmt_timer_init
,
246 .start
= cmt_timer_start
,
247 .stop
= cmt_timer_stop
,
248 .get_frequency
= cmt_timer_get_frequency
,
249 .get_offset
= cmt_timer_get_offset
,
252 struct sys_timer cmt_timer
= {
254 .ops
= &cmt_timer_ops
,