ds1338.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * MAXIM DS1338 I2C RTC+NVRAM
  3. *
  4. * Copyright (c) 2009 CodeSourcery.
  5. * Written by Paul Brook
  6. *
  7. * This code is licensed under the GNU GPL v2.
  8. */
  9. #include "i2c.h"
  10. typedef struct {
  11. i2c_slave i2c;
  12. time_t offset;
  13. struct tm now;
  14. uint8_t nvram[56];
  15. int ptr;
  16. int addr_byte;
  17. } DS1338State;
  18. static void ds1338_event(i2c_slave *i2c, enum i2c_event event)
  19. {
  20. DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
  21. switch (event) {
  22. case I2C_START_RECV:
  23. qemu_get_timedate(&s->now, s->offset);
  24. s->nvram[0] = to_bcd(s->now.tm_sec);
  25. s->nvram[1] = to_bcd(s->now.tm_min);
  26. if (s->nvram[2] & 0x40) {
  27. s->nvram[2] = (to_bcd((s->now.tm_hour % 12)) + 1) | 0x40;
  28. if (s->now.tm_hour >= 12) {
  29. s->nvram[2] |= 0x20;
  30. }
  31. } else {
  32. s->nvram[2] = to_bcd(s->now.tm_hour);
  33. }
  34. s->nvram[3] = to_bcd(s->now.tm_wday) + 1;
  35. s->nvram[4] = to_bcd(s->now.tm_mday);
  36. s->nvram[5] = to_bcd(s->now.tm_mon) + 1;
  37. s->nvram[6] = to_bcd(s->now.tm_year - 100);
  38. break;
  39. case I2C_START_SEND:
  40. s->addr_byte = 1;
  41. break;
  42. default:
  43. break;
  44. }
  45. }
  46. static int ds1338_recv(i2c_slave *i2c)
  47. {
  48. DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
  49. uint8_t res;
  50. res = s->nvram[s->ptr];
  51. s->ptr = (s->ptr + 1) & 0xff;
  52. return res;
  53. }
  54. static int ds1338_send(i2c_slave *i2c, uint8_t data)
  55. {
  56. DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
  57. if (s->addr_byte) {
  58. s->ptr = data;
  59. s->addr_byte = 0;
  60. return 0;
  61. }
  62. s->nvram[s->ptr - 8] = data;
  63. if (data < 8) {
  64. qemu_get_timedate(&s->now, s->offset);
  65. switch(data) {
  66. case 0:
  67. /* TODO: Implement CH (stop) bit. */
  68. s->now.tm_sec = from_bcd(data & 0x7f);
  69. break;
  70. case 1:
  71. s->now.tm_min = from_bcd(data & 0x7f);
  72. break;
  73. case 2:
  74. if (data & 0x40) {
  75. if (data & 0x20) {
  76. data = from_bcd(data & 0x4f) + 11;
  77. } else {
  78. data = from_bcd(data & 0x1f) - 1;
  79. }
  80. } else {
  81. data = from_bcd(data);
  82. }
  83. s->now.tm_hour = data;
  84. break;
  85. case 3:
  86. s->now.tm_wday = from_bcd(data & 7) - 1;
  87. break;
  88. case 4:
  89. s->now.tm_mday = from_bcd(data & 0x3f);
  90. break;
  91. case 5:
  92. s->now.tm_mon = from_bcd(data & 0x1f) - 1;
  93. case 6:
  94. s->now.tm_year = from_bcd(data) + 100;
  95. break;
  96. case 7:
  97. /* Control register. Currently ignored. */
  98. break;
  99. }
  100. s->offset = qemu_timedate_diff(&s->now);
  101. }
  102. s->ptr = (s->ptr + 1) & 0xff;
  103. return 0;
  104. }
  105. static int ds1338_init(i2c_slave *i2c)
  106. {
  107. return 0;
  108. }
  109. static I2CSlaveInfo ds1338_info = {
  110. .qdev.name = "ds1338",
  111. .qdev.size = sizeof(DS1338State),
  112. .init = ds1338_init,
  113. .event = ds1338_event,
  114. .recv = ds1338_recv,
  115. .send = ds1338_send,
  116. };
  117. static void ds1338_register_devices(void)
  118. {
  119. i2c_register_slave(&ds1338_info);
  120. }
  121. device_init(ds1338_register_devices)