rtc.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Read/write DS3231M RTC
  3. */
  4. #include <string.h>
  5. #include "fw.h"
  6. #include "console.h"
  7. #include "io.h"
  8. #include "systime.h"
  9. static inline uint32_t i2c_wait(void)
  10. {
  11. waitfor(I2C_IRQ);
  12. }
  13. static void i2c_send(uint8_t byte, uint8_t ctl)
  14. {
  15. i2c_wait();
  16. I2C_WDATA = (byte << 8) | I2C_NAK | ctl;
  17. }
  18. static bool i2c_acked(void)
  19. {
  20. i2c_wait();
  21. return !(I2C_RDATA & I2C_NAK);
  22. }
  23. static uint8_t i2c_recv(uint8_t ctl)
  24. {
  25. uint32_t rdata;
  26. i2c_wait();
  27. I2C_WDATA = (~0xff) | ctl;
  28. i2c_wait();
  29. return I2C_RDATA_DATA;
  30. }
  31. #define RTC_REGS 19
  32. #define RTC_ADDR 0x68
  33. #define RTC_WCMD ((RTC_ADDR << 1)+0)
  34. #define RTC_RCMD ((RTC_ADDR << 1)+1)
  35. static unsigned int unbcd(uint8_t v)
  36. {
  37. return (v & 0x0f) + (v >> 4) * 10;
  38. }
  39. void read_rtc(void)
  40. {
  41. uint8_t rtc_regs[RTC_REGS];
  42. int i;
  43. struct tms tms;
  44. int sda_retry_count = 16;
  45. i2c_set_speed(400);
  46. /* SDA held low? */
  47. while (!(I2C_RDATA & I2C_SDA)) {
  48. i2c_send(0xff, I2C_DUMMY);
  49. if (!sda_retry_count--) {
  50. con_printf("RTC: I2C SDA stuck low\n");
  51. return;
  52. }
  53. }
  54. i2c_send(RTC_WCMD, 0);
  55. if (!i2c_acked()) {
  56. con_printf("No RTC detected at I2C address 0x%02x\n", RTC_ADDR);
  57. i2c_send(0xff, I2C_P);
  58. return;
  59. }
  60. i2c_send(0, I2C_SR);
  61. i2c_send(RTC_RCMD, 0);
  62. for (i = 0; i < RTC_REGS-1; i++)
  63. rtc_regs[i] = i2c_recv(0);
  64. rtc_regs[i] = i2c_recv(I2C_NAK | I2C_P);
  65. /* Convert to struct tms and set systime */
  66. memset(&tms, 0, sizeof tms);
  67. unsigned int sec = unbcd(rtc_regs[0]);
  68. tms.tm_2sec = sec >> 1;
  69. tms.hold.tm_1sec = sec & 1;
  70. tms.hold.tm_tick = 0x4000; /* Without more info, assume mid-second */
  71. tms.tm_min = unbcd(rtc_regs[1]);
  72. unsigned int hour;
  73. if (rtc_regs[2] & 0x40) {
  74. /* AM/PM mode - this shouldn't happen */
  75. hour = unbcd(rtc_regs[2] & 0x1f);
  76. if (hour > 11)
  77. hour -= 12;
  78. if (rtc_regs[2] & 0x20)
  79. hour += 12;
  80. } else {
  81. /* 24-hour mode */
  82. hour = unbcd(rtc_regs[2]);
  83. }
  84. tms.tm_hour = hour;
  85. tms.tm_mday = unbcd(rtc_regs[4]);
  86. tms.tm_mon = unbcd(rtc_regs[5] & 0x1f);
  87. tms.tm_year = unbcd(rtc_regs[6]) + (rtc_regs[5] & 0x80 ? 100 : 0) + 20;
  88. set_systime(tms);
  89. con_printf("RTC register content:\n");
  90. for (i = 0; i < RTC_REGS; i++)
  91. con_printf(" %02x", rtc_regs[i]);
  92. con_printf("\nRTC time: %04u-%02u-%02u %02u:%02u:%02u\n",
  93. tms.tm_year + 1980, tms.tm_mon, tms.tm_mday,
  94. tms.tm_hour, tms.tm_min, tms_sec(tms));
  95. }