rtc.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support
  3. *
  4. * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
  5. * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
  6. */
  7. #include <linux/init.h>
  8. #include <linux/kernel.h>
  9. #include <linux/sched.h>
  10. #include <linux/time.h>
  11. #include <linux/bcd.h>
  12. #include <asm/io.h>
  13. #include <asm/rtc.h>
  14. void sh_rtc_gettimeofday(struct timespec *ts)
  15. {
  16. unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit;
  17. unsigned long flags;
  18. again:
  19. do {
  20. local_irq_save(flags);
  21. ctrl_outb(0, RCR1); /* Clear CF-bit */
  22. sec128 = ctrl_inb(R64CNT);
  23. sec = ctrl_inb(RSECCNT);
  24. min = ctrl_inb(RMINCNT);
  25. hr = ctrl_inb(RHRCNT);
  26. wk = ctrl_inb(RWKCNT);
  27. day = ctrl_inb(RDAYCNT);
  28. mon = ctrl_inb(RMONCNT);
  29. #if defined(CONFIG_CPU_SH4)
  30. yr = ctrl_inw(RYRCNT);
  31. yr100 = (yr >> 8);
  32. yr &= 0xff;
  33. #else
  34. yr = ctrl_inb(RYRCNT);
  35. yr100 = (yr == 0x99) ? 0x19 : 0x20;
  36. #endif
  37. sec2 = ctrl_inb(R64CNT);
  38. cf_bit = ctrl_inb(RCR1) & RCR1_CF;
  39. local_irq_restore(flags);
  40. } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
  41. BCD_TO_BIN(yr100);
  42. BCD_TO_BIN(yr);
  43. BCD_TO_BIN(mon);
  44. BCD_TO_BIN(day);
  45. BCD_TO_BIN(hr);
  46. BCD_TO_BIN(min);
  47. BCD_TO_BIN(sec);
  48. if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
  49. hr > 23 || min > 59 || sec > 59) {
  50. printk(KERN_ERR
  51. "SH RTC: invalid value, resetting to 1 Jan 2000\n");
  52. local_irq_save(flags);
  53. ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */
  54. ctrl_outb(0, RSECCNT);
  55. ctrl_outb(0, RMINCNT);
  56. ctrl_outb(0, RHRCNT);
  57. ctrl_outb(6, RWKCNT);
  58. ctrl_outb(1, RDAYCNT);
  59. ctrl_outb(1, RMONCNT);
  60. #if defined(CONFIG_CPU_SH4)
  61. ctrl_outw(0x2000, RYRCNT);
  62. #else
  63. ctrl_outb(0, RYRCNT);
  64. #endif
  65. ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */
  66. goto again;
  67. }
  68. #if RTC_BIT_INVERTED != 0
  69. if ((sec128 & RTC_BIT_INVERTED))
  70. sec--;
  71. #endif
  72. ts->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
  73. ts->tv_nsec = ((sec128 * 1000000) / 128) * 1000;
  74. }
  75. /*
  76. * Changed to only care about tv_sec, and not the full timespec struct
  77. * (i.e. tv_nsec). It can easily be switched to timespec for future cpus
  78. * that support setting usec or nsec RTC values.
  79. */
  80. int sh_rtc_settimeofday(const time_t secs)
  81. {
  82. int retval = 0;
  83. int real_seconds, real_minutes, cmos_minutes;
  84. unsigned long flags;
  85. local_irq_save(flags);
  86. ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */
  87. cmos_minutes = ctrl_inb(RMINCNT);
  88. BCD_TO_BIN(cmos_minutes);
  89. /*
  90. * since we're only adjusting minutes and seconds,
  91. * don't interfere with hour overflow. This avoids
  92. * messing with unknown time zones but requires your
  93. * RTC not to be off by more than 15 minutes
  94. */
  95. real_seconds = secs % 60;
  96. real_minutes = secs / 60;
  97. if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
  98. real_minutes += 30; /* correct for half hour time zone */
  99. real_minutes %= 60;
  100. if (abs(real_minutes - cmos_minutes) < 30) {
  101. BIN_TO_BCD(real_seconds);
  102. BIN_TO_BCD(real_minutes);
  103. ctrl_outb(real_seconds, RSECCNT);
  104. ctrl_outb(real_minutes, RMINCNT);
  105. } else {
  106. printk(KERN_WARNING
  107. "set_rtc_time: can't update from %d to %d\n",
  108. cmos_minutes, real_minutes);
  109. retval = -1;
  110. }
  111. ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */
  112. local_irq_restore(flags);
  113. return retval;
  114. }