time.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:3k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright 2001 MontaVista Software Inc.
  3.  * Author: jsun@mvista.com or jsun@junsun.net
  4.  *
  5.  * rtc and time ops for vr4181.  Part of code is drived from 
  6.  * linux-vr, originally written  by Bradley D. LaRonde & Michael Klar.
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify it
  9.  * under  the terms of the GNU General  Public License as published by the
  10.  * Free Software Foundation;  either version 2 of the  License, or (at your
  11.  * option) any later version.
  12.  *
  13.  */
  14. #include <linux/kernel.h>
  15. #include <linux/spinlock.h>
  16. #include <linux/param.h> /* for HZ */
  17. #include <linux/time.h>
  18. #include <linux/interrupt.h>
  19. #include <asm/system.h>
  20. #include <asm/time.h>
  21. #include <asm/vr4181/vr4181.h>
  22. #define COUNTS_PER_JIFFY ((32768 + HZ/2) / HZ)
  23. /*
  24.  * RTC ops
  25.  */
  26. spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
  27. /* per VR41xx docs, bad data can be read if between 2 counts */
  28. static inline unsigned short 
  29. read_time_reg(volatile unsigned short *reg)
  30. {
  31. unsigned short value;
  32. do {
  33. value = *reg;
  34. barrier();
  35. } while (value != *reg);
  36. return value;
  37. }
  38. static unsigned long 
  39. vr4181_rtc_get_time(void)
  40. {
  41. unsigned short regh, regm, regl;
  42. // why this crazy order, you ask?  to guarantee that neither m
  43. // nor l wrap before all 3 read
  44. do {
  45. regm = read_time_reg(VR4181_ETIMEMREG);
  46. barrier();
  47. regh = read_time_reg(VR4181_ETIMEHREG);
  48. barrier();
  49. regl = read_time_reg(VR4181_ETIMELREG);
  50. } while (regm != read_time_reg(VR4181_ETIMEMREG));
  51. return ((regh << 17) | (regm << 1) | (regl >> 15));
  52. }
  53. static int 
  54. vr4181_rtc_set_time(unsigned long timeval)
  55. {
  56. unsigned short intreg;
  57. unsigned long flags;
  58. spin_lock_irqsave(&rtc_lock, flags);
  59. intreg = *VR4181_RTCINTREG & 0x05;
  60. barrier();
  61. *VR4181_ETIMELREG = timeval << 15;
  62. *VR4181_ETIMEMREG = timeval >> 1;
  63. *VR4181_ETIMEHREG = timeval >> 17;
  64. barrier();
  65. // assume that any ints that just triggered are invalid, since the
  66. // time value is written non-atomically in 3 separate regs
  67. *VR4181_RTCINTREG = 0x05 ^ intreg;
  68. spin_unlock_irqrestore(&rtc_lock, flags);
  69. return 0;
  70. }
  71. /* 
  72.  * timer interrupt routine (wrapper)
  73.  *
  74.  * we need our own interrupt routine because we need to clear
  75.  * RTC1 interrupt.
  76.  */
  77. static void 
  78. vr4181_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  79. {
  80. /* Clear the interrupt. */
  81. *VR4181_RTCINTREG = 0x2;
  82. /* call the generic one */
  83. timer_interrupt(irq, dev_id, regs);
  84. }
  85. /*
  86.  * vr4181_time_init:
  87.  *
  88.  * We pick the following choices:
  89.  *   . we use elapsed timer as the RTC.  We set some reasonable init data since
  90.  *     it does not persist across reset
  91.  *   . we use RTC1 as the system timer interrupt source.
  92.  *   . we use CPU counter for fast_gettimeoffset and we calivrate the cpu
  93.  *     frequency.  In other words, we use calibrate_div64_gettimeoffset().
  94.  *   . we use our own timer interrupt routine which clears the interrupt
  95.  *     and then calls the generic high-level timer interrupt routine.
  96.  *
  97.  */
  98. extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
  99. static void 
  100. vr4181_timer_setup(struct irqaction *irq)
  101. {
  102. /* over-write the handler to be our own one */
  103. irq->handler = vr4181_timer_interrupt;
  104. /* sets up the frequency */
  105. *VR4181_RTCL1LREG = COUNTS_PER_JIFFY;
  106. *VR4181_RTCL1HREG = 0;
  107. /* and ack any pending ints */
  108. *VR4181_RTCINTREG = 0x2;
  109. /* setup irqaction */
  110. setup_irq(VR4181_IRQ_INT1, irq);
  111. }
  112. void
  113. vr4181_init_time(void)
  114. {
  115. /* setup hookup functions */
  116. rtc_get_time = vr4181_rtc_get_time;
  117. rtc_set_time = vr4181_rtc_set_time;
  118. board_timer_setup = vr4181_timer_setup;
  119. }