rtc.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /*
  2. * arch/sh/boards/landisk/rtc.c -- RTC support
  3. *
  4. * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
  5. * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
  6. */
  7. /*
  8. * modifed by kogiidena
  9. * 2005.09.16
  10. */
  11. #include <linux/config.h>
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/sched.h>
  15. #include <linux/time.h>
  16. #include <linux/delay.h>
  17. #include <linux/spinlock.h>
  18. #ifndef BCD_TO_BIN
  19. #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
  20. #endif
  21. #ifndef BIN_TO_BCD
  22. #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
  23. #endif
  24. extern void (*rtc_get_time) (struct timespec *);
  25. extern int (*rtc_set_time) (const time_t);
  26. extern spinlock_t rtc_lock;
  27. extern void
  28. rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon,
  29. unsigned int BCD_day, unsigned int BCD_hr,
  30. unsigned int BCD_min, unsigned int BCD_sec);
  31. extern unsigned long
  32. rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon,
  33. unsigned int *BCD_day, unsigned int *BCD_hr,
  34. unsigned int *BCD_min, unsigned int *BCD_sec);
  35. void landisk_rtc_gettimeofday(struct timespec *tv)
  36. {
  37. unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
  38. unsigned long flags;
  39. spin_lock_irqsave(&rtc_lock, flags);
  40. tv->tv_sec = rs5c313_get_cmos_time
  41. (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
  42. tv->tv_nsec = 0;
  43. spin_unlock_irqrestore(&rtc_lock, flags);
  44. }
  45. int landisk_rtc_settimeofday(const time_t secs)
  46. {
  47. int retval = 0;
  48. int real_seconds, real_minutes, cmos_minutes;
  49. unsigned long flags;
  50. unsigned long nowtime = secs;
  51. unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
  52. spin_lock_irqsave(&rtc_lock, flags);
  53. rs5c313_get_cmos_time
  54. (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
  55. cmos_minutes = BCD_min;
  56. BCD_TO_BIN(cmos_minutes);
  57. /*
  58. * since we're only adjusting minutes and seconds,
  59. * don't interfere with hour overflow. This avoids
  60. * messing with unknown time zones but requires your
  61. * RTC not to be off by more than 15 minutes
  62. */
  63. real_seconds = nowtime % 60;
  64. real_minutes = nowtime / 60;
  65. if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
  66. real_minutes += 30; /* correct for half hour time zone */
  67. real_minutes %= 60;
  68. if (abs(real_minutes - cmos_minutes) < 30) {
  69. BIN_TO_BCD(real_seconds);
  70. BIN_TO_BCD(real_minutes);
  71. rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr,
  72. real_minutes, real_seconds);
  73. } else {
  74. printk(KERN_WARNING
  75. "set_rtc_time: can't update from %d to %d\n",
  76. cmos_minutes, real_minutes);
  77. retval = -1;
  78. }
  79. spin_unlock_irqrestore(&rtc_lock, flags);
  80. return retval;
  81. }
  82. void landisk_time_init(void)
  83. {
  84. rtc_get_time = landisk_rtc_gettimeofday;
  85. rtc_set_time = landisk_rtc_settimeofday;
  86. }