MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / arch / arm / mach-s3c24a0 / time.c
blob8384aa7c88b97c8cbfb55e074ee70a46a964bc16
1 /*
2 * time.c for smdk24a0
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>
17 #include <asm/leds.h>
18 #include <asm/mach-types.h>
20 #include <asm/io.h>
21 #include <asm/irq.h>
22 #include <asm/mach/time.h>
23 #include <asm/arch/time.h>
25 /* copy from linux/arch/arm/kernel/time.c */
26 #ifndef BCD_TO_BIN
27 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
28 #endif
30 #ifndef BIN_TO_BCD
31 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
32 #endif
34 #ifndef RTC_LEAP_YEAR
35 #define RTC_LEAP_YEAR 2000
36 #endif
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);
45 read_rtc_bcd_time:
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;
52 if (sec == 0) {
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);
59 BCD_TO_BIN(year);
60 BCD_TO_BIN(mon);
61 BCD_TO_BIN(day);
62 BCD_TO_BIN(hour);
63 BCD_TO_BIN(min);
64 BCD_TO_BIN(sec);
66 year += RTC_LEAP_YEAR;
68 return (mktime(year, mon, day, hour, min, sec));
72 * Copyed from drivers/char/sa1100-rtc.c.
74 #define epoch 1970
76 static const unsigned char days_in_mo[] =
77 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
79 #ifndef is_leap
80 #define is_leap(year) \
81 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
82 #endif
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;
91 days = t / 86400;
92 rem = t % 86400;
93 tval->tm_hour = rem / 3600;
94 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)
101 year = epoch;
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));
107 year = yg;
109 tval->tm_year = year - 1900;
110 tval->tm_yday = days + 1;
112 month = 0;
113 if (days >= 31) {
114 days -= 31;
115 month++;
116 if (days >= (28 + is_leap(year))) {
117 days -= (28 + is_leap(year));
118 month++;
119 while (days >= days_in_mo[month]) {
120 days -= days_in_mo[month];
121 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;
133 signed int yeardiff;
134 struct rtc_time rtc_tm;
136 decodetime(current_time, &rtc_tm);
138 yeardiff = (rtc_tm.tm_year + 1900) - RTC_LEAP_YEAR;
139 if (yeardiff < 0) {
140 /* S3C2410 RTC forces that the year must be higher or
141 equal than 2000, so initailize it. */
142 yeardiff = 0;
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;
149 min = rtc_tm.tm_min;
150 sec = rtc_tm.tm_sec;
152 BIN_TO_BCD(sec);
153 BIN_TO_BCD(min);
154 BIN_TO_BCD(hour);
155 BIN_TO_BCD(day);
156 BIN_TO_BCD(mon);
157 BIN_TO_BCD(year);
159 spin_lock_irq(&rtc_lock);
160 RTCCON |= RTCCON_EN;
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);
170 return 0;
173 static unsigned long elfin_gettimeoffset(void)
175 unsigned long elapsed, usec;
176 unsigned long latch;
178 /* Use TCNTB4 as LATCH */
179 latch = TCNTB4;
181 elapsed = latch - TCNTO4;
182 usec = (elapsed * (tick_nsec / 1000)) / latch; // hcyun
184 return usec;
187 static irqreturn_t elfin_timer_interrupt(int irq, void *dev_id)
190 // do_set_rtc();
191 timer_tick();
193 return IRQ_HANDLED;
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)
218 * e.g.)
220 * PCLK = 50700000 Hz, divider value = 2, prescaler value = 15
221 * period = 10ms
223 * buffer count = ((10 / 1000) * 50700000) / 2 / (15+1)
224 * = 15843.75
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);