time.h
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/include/asm-arm/arch-s3c2410/time.h
  3.  *
  4.  * Copyright (C) 2002 MIZI Research, Inc.
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20. /*
  21.  * History
  22.  *
  23.  * 2002-05-20: Janghoon Lyu <nandy@mizi.com>
  24.  *    - Initial code
  25.  *
  26.  */
  27. #include <linux/time.h> /* for mktime() */
  28. #include <linux/rtc.h>  /* struct rtc_time */
  29. #include "cpu_s3c2410.h"
  30. /* copy from linux/arch/arm/kernel/time.c */
  31. #ifndef BCD_TO_BIN
  32. #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
  33. #endif
  34. #ifndef BIN_TO_BCD
  35. #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
  36. #endif
  37. #ifndef RTC_LEAP_YEAR
  38. #define RTC_LEAP_YEAR        2000
  39. #endif
  40. extern spinlock_t rtc_lock;
  41. unsigned long s3c2410_get_rtc_time(void)
  42. {
  43. 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;
  56. }
  57. spin_unlock_irq(&rtc_lock);
  58. BCD_TO_BIN(year);
  59. BCD_TO_BIN(mon);
  60. BCD_TO_BIN(day);
  61. BCD_TO_BIN(hour);
  62. BCD_TO_BIN(min);
  63. BCD_TO_BIN(sec);
  64. year += RTC_LEAP_YEAR;
  65. return (mktime(year, mon, day, hour, min, sec));
  66. }
  67. /* 
  68.  * Copyed from drivers/char/sa1100-rtc.c.
  69.  */
  70. #define epoch 1970
  71. static const unsigned char days_in_mo[] =
  72. {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  73. #ifndef is_leap
  74. #define is_leap(year) 
  75. ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
  76. #endif
  77. /*
  78.  * Converts seconds since 1970-01-01 00:00:00 to Gregorian date.
  79.  */
  80. static void decodetime (unsigned long t, struct rtc_time *tval)
  81. {
  82. unsigned long days, month, year, rem;
  83. days = t / 86400;
  84. rem = t % 86400;
  85. tval->tm_hour = rem / 3600;
  86. rem %= 3600;
  87. tval->tm_min = rem / 60;
  88. tval->tm_sec = rem % 60;
  89. tval->tm_wday = (4 + days) % 7;
  90. #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
  91. year = epoch;
  92. while (days >= (365 + is_leap(year))) {
  93. unsigned long yg = year + days / 365;
  94. days -= ((yg - year) * 365
  95. + LEAPS_THRU_END_OF (yg - 1)
  96. - LEAPS_THRU_END_OF (year - 1));
  97. year = yg;
  98. }
  99. tval->tm_year = year - 1900;
  100. tval->tm_yday = days + 1;
  101. month = 0;
  102. if (days >= 31) {
  103. days -= 31;
  104. month++;
  105. if (days >= (28 + is_leap(year))) {
  106. days -= (28 + is_leap(year));
  107. month++;
  108. while (days >= days_in_mo[month]) {
  109. days -= days_in_mo[month];
  110. month++;
  111. }
  112. }
  113. }
  114. tval->tm_mon = month;
  115. tval->tm_mday = days + 1;
  116. }
  117. int s3c2410_set_rtc(void)
  118. {
  119. unsigned long current_time = xtime.tv_sec;
  120. unsigned char year, mon, day, hour, min, sec;
  121. signed int yeardiff;
  122. struct rtc_time rtc_tm;
  123. decodetime(current_time, &rtc_tm);
  124. yeardiff = (rtc_tm.tm_year + 1900) - RTC_LEAP_YEAR;
  125. if (yeardiff < 0) {
  126. /* S3C2410 RTC forces that the year must be higher or 
  127.    equal than 2000, so initailize it. */
  128. yeardiff = 0;
  129. }
  130. year = (unsigned char) yeardiff;
  131. mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
  132. day = rtc_tm.tm_mday;
  133. hour = rtc_tm.tm_hour;
  134. min = rtc_tm.tm_min;
  135. sec = rtc_tm.tm_sec;
  136. BIN_TO_BCD(sec);
  137. BIN_TO_BCD(min);
  138. BIN_TO_BCD(hour);
  139. BIN_TO_BCD(day);
  140. BIN_TO_BCD(mon);
  141. BIN_TO_BCD(year);
  142. spin_lock_irq(&rtc_lock);
  143. RTCCON |= RTCCON_EN; 
  144. BCDSEC  = sec  & Msk_RTCSEC;
  145. BCDMIN  = min  & Msk_RTCMIN;
  146. BCDHOUR = hour & Msk_RTCHOUR;
  147. BCDDAY  = day  & Msk_RTCDAY;
  148. BCDMON  = mon  & Msk_RTCMON;
  149. BCDYEAR = year & Msk_RTCYEAR;
  150. RTCCON &= ~RTCCON_EN;
  151. spin_unlock_irq(&rtc_lock);
  152. return 0;
  153. }
  154. static unsigned long s3c2410_gettimeoffset(void)
  155. {
  156. unsigned long elapsed, usec;
  157. unsigned long latch;
  158. /* Use TCNTB4 as LATCH */
  159. latch = TCNTB4;
  160. elapsed = latch - TCNTO4;
  161. usec = (elapsed * tick) / latch;
  162. return usec;
  163. }
  164. static void s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  165. {
  166. long flags;
  167. do_leds();
  168. do_set_rtc();
  169. save_flags_cli(flags);
  170. do_timer(regs);
  171. restore_flags(flags);
  172. }
  173. /* Unit of 'freq' is khz */
  174. struct timer_counts {
  175. unsigned int freq;
  176. unsigned int count;
  177. };
  178. /*
  179.  * priod = (prescaler value + 1) * (divider value) * buffer count / PCLK = 10 ms
  180.  *
  181.  * e.g.; PCLK = 50 Mhz
  182.  * 10 ms = (15 + 1) * 2 * 15625 / (50000 * 1000)
  183.  * 15626 = 10 ms * (50000 * 1000) / 2 / (15 + 1)
  184.  *
  185.  * Other values
  186.  *  5156 = 10 ms * ( 16.5 * 1,000,000) / 2 / (15+1)
  187.  *  6250 = 10 ms * ( 20 * 1,000,000) / 2 / (15+1)
  188.  * 10312 = 10 ms * ( 33 * 1,000,000) / 2 / (15+1)
  189.  * 20625 = 10 ms * ( 66 * 1,000,000) / 2 / (15+1)
  190.  * 21875 = 10 ms * ( 70 * 1,000,000) / 2 / (15+1)
  191.  * 23437 = 10 ms * ( 75 * 1,000,000) / 2 / (15+1)
  192.  * 25000 = 10 ms * ( 80 * 1,000,000) / 2 / (15+1)
  193.  * 28125 = 10 ms * ( 90 * 1,000,000) / 2 / (15+1)
  194.  * 31250 = 10 ms * ( 100 * 1,000,000) / 2 / (15+1)
  195.  */
  196. struct timer_counts count_values[] = {
  197. {  16500,  5156 },
  198. {  20000,  6250 },
  199. {  33000, 10312 },
  200. {  50000, 15626 },
  201. {  66000, 20625 },
  202. {  70000, 21875 },
  203. {  75000, 23437 },
  204. {  80000, 25000 },
  205. {  90000, 28125 },
  206. { 100000, 31250 },
  207. {      0,     0 } /* last entry */
  208. };
  209. static inline void setup_timer(void)
  210. {
  211. struct timer_counts *timer_count = count_values; 
  212. unsigned long pclk;
  213. gettimeoffset = s3c2410_gettimeoffset;
  214. set_rtc = s3c2410_set_rtc;
  215. xtime.tv_sec = s3c2410_get_rtc_time();
  216. /* set timer interrupt */
  217. TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));
  218.  
  219. pclk = s3c2410_get_bus_clk(GET_PCLK)/1000;
  220. while (timer_count != 0) {
  221. if (pclk == timer_count->freq) {
  222. printk("DEBUG: timer count %dn", timer_count->count);
  223. TCNTB4 = timer_count->count;
  224. break;
  225. }
  226. timer_count++;
  227. }
  228. if (timer_count == 0) {
  229.      /* Error, assume that PCLK is 50 Mhz */
  230. TCNTB4 = 15626; /* down-counter, maximum value is 65535 (2^16) */
  231. }
  232. TCON = (TCON_4_AUTO | TCON_4_UPDATE | COUNT_4_OFF);
  233. timer_irq.handler = s3c2410_timer_interrupt;
  234. setup_arm_irq(IRQ_TIMER4, &timer_irq);
  235. TCON = (TCON_4_AUTO | COUNT_4_ON);
  236. }
  237. EXPORT_SYMBOL(s3c2410_get_rtc_time);
  238. EXPORT_SYMBOL(s3c2410_set_rtc);