3 * by Hyok S. Choi <hyok.choi@samsung.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Based on linux/include/asm-arm/arch-s3c2410/time.h
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/init.h>
15 #include <linux/interrupt.h>
16 #include <asm/system.h>
18 #include <asm/mach-types.h>
22 #include <asm/mach/time.h>
23 #include <asm/arch/time.h>
25 /* copy from linux/arch/arm/kernel/time.c */
27 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
31 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
35 #define RTC_LEAP_YEAR 2000
38 extern spinlock_t rtc_lock
;
40 unsigned long elfin_get_rtc_time(void)
42 unsigned int year
, mon
, day
, hour
, min
, sec
;
44 spin_lock_irq(&rtc_lock
);
46 year
= BCDYEAR
& Msk_RTCYEAR
;
47 mon
= BCDMON
& Msk_RTCMON
;
48 day
= BCDDAY
& Msk_RTCDAY
;
49 hour
= BCDHOUR
& Msk_RTCHOUR
;
50 min
= BCDMIN
& Msk_RTCMIN
;
51 sec
= BCDSEC
& Msk_RTCSEC
;
53 /* If BCDSEC is zero, reread all bcd registers.
54 See Section 17.2 READ/WRITE REGISTERS for more info. */
55 goto read_rtc_bcd_time
;
57 spin_unlock_irq(&rtc_lock
);
66 year
+= RTC_LEAP_YEAR
;
68 return (mktime(year
, mon
, day
, hour
, min
, sec
));
72 * Copyed from drivers/char/sa1100-rtc.c.
76 static const unsigned char days_in_mo
[] =
77 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
80 #define is_leap(year) \
81 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
85 * Converts seconds since 1970-01-01 00:00:00 to Gregorian date.
87 static void decodetime (unsigned long t
, struct rtc_time
*tval
)
89 unsigned long days
, month
, year
, rem
;
93 tval
->tm_hour
= rem
/ 3600;
95 tval
->tm_min
= rem
/ 60;
96 tval
->tm_sec
= rem
% 60;
97 tval
->tm_wday
= (4 + days
) % 7;
99 #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
102 while (days
>= (365 + is_leap(year
))) {
103 unsigned long yg
= year
+ days
/ 365;
104 days
-= ((yg
- year
) * 365
105 + LEAPS_THRU_END_OF (yg
- 1)
106 - LEAPS_THRU_END_OF (year
- 1));
109 tval
->tm_year
= year
- 1900;
110 tval
->tm_yday
= days
+ 1;
116 if (days
>= (28 + is_leap(year
))) {
117 days
-= (28 + is_leap(year
));
119 while (days
>= days_in_mo
[month
]) {
120 days
-= days_in_mo
[month
];
125 tval
->tm_mon
= month
;
126 tval
->tm_mday
= days
+ 1;
129 int elfin_set_rtc(void)
131 unsigned long current_time
= xtime
.tv_sec
;
132 unsigned char year
, mon
, day
, hour
, min
, sec
;
134 struct rtc_time rtc_tm
;
136 decodetime(current_time
, &rtc_tm
);
138 yeardiff
= (rtc_tm
.tm_year
+ 1900) - RTC_LEAP_YEAR
;
140 /* S3C2410 RTC forces that the year must be higher or
141 equal than 2000, so initailize it. */
145 year
= (unsigned char) yeardiff
;
146 mon
= rtc_tm
.tm_mon
+ 1; /* tm_mon starts at zero */
147 day
= rtc_tm
.tm_mday
;
148 hour
= rtc_tm
.tm_hour
;
159 spin_lock_irq(&rtc_lock
);
161 BCDSEC
= sec
& Msk_RTCSEC
;
162 BCDMIN
= min
& Msk_RTCMIN
;
163 BCDHOUR
= hour
& Msk_RTCHOUR
;
164 BCDDAY
= day
& Msk_RTCDAY
;
165 BCDMON
= mon
& Msk_RTCMON
;
166 BCDYEAR
= year
& Msk_RTCYEAR
;
167 RTCCON
&= ~RTCCON_EN
;
168 spin_unlock_irq(&rtc_lock
);
173 static unsigned long elfin_gettimeoffset(void)
175 unsigned long elapsed
, usec
;
178 /* Use TCNTB4 as LATCH */
181 elapsed
= latch
- TCNTO4
;
182 usec
= (elapsed
* (tick_nsec
/ 1000)) / latch
; // hcyun
187 static irqreturn_t
elfin_timer_interrupt(int irq
, void *dev_id
)
197 static struct irqaction elfin_timer_irq
= {
198 .name
= "S3C24A0 Timer Tick",
199 .flags
= IRQF_DISABLED
| IRQF_TIMER
,
200 .handler
= elfin_timer_interrupt
203 #define TCON4_PRESCALER_VALUE 15
204 #define TCON4_DIVIDER_VALUE 2
205 #define TCON4_PERIOD 10 /* miliseconds */
206 void __init
elfin_time_init(void)
208 set_rtc
= elfin_set_rtc
;
209 xtime
.tv_sec
= elfin_get_rtc_time();
211 /* set timer interrupt */
212 TCFG0
= (TCFG0_DZONE(0) | TCFG0_PRE1(TCON4_PRESCALER_VALUE
) | TCFG0_PRE0(TCON4_PRESCALER_VALUE
));
215 * period = (prescaler value + 1) * (divider value) * buffer count / PCLK
216 * buffer count = period * PCLK / divider value / (prescaler value + 1)
220 * PCLK = 50700000 Hz, divider value = 2, prescaler value = 15
223 * buffer count = ((10 / 1000) * 50700000) / 2 / (15+1)
227 printk("DEBUG: PCLK=%d, Prescaler=%d, Divider=%d\n", elfin_get_bus_clk(GET_PCLK
), TCON4_PRESCALER_VALUE
+1, TCON4_DIVIDER_VALUE
);
228 TCNTB4
= ((TCON4_PERIOD
* ((elfin_get_bus_clk(GET_PCLK
))/1000)) / TCON4_DIVIDER_VALUE
) / (TCON4_PRESCALER_VALUE
+ 1);
229 printk("DEBUG: timer count %d\n", TCNTB4
);
231 TCON
= (TCON_4_AUTO
| TCON_4_UPDATE
| (0 << 20));
233 elfin_timer_irq
.handler
= elfin_timer_interrupt
;
235 printk("Timer Initialized.. IRQ=%d\n", IRQ_TIMER4
);
237 setup_irq(IRQ_TIMER4
, &elfin_timer_irq
);
239 TCON
= (TCON_4_AUTO
| (0 << 21) | TCON_4_ONOFF
);
242 struct sys_timer elfin_timer
= {
243 .init
= elfin_time_init
,
244 .offset
= elfin_gettimeoffset
,
247 EXPORT_SYMBOL(elfin_get_rtc_time
);
248 EXPORT_SYMBOL(elfin_set_rtc
);