ds1338.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. * Contributions after 2012-01-13 are licensed under the terms of the
  10. * GNU GPL, version 2 or (at your option) any later version.
  11. */
  12. #include "i2c.h"
  13. /* Size of NVRAM including both the user-accessible area and the
  14. * secondary register area.
  15. */
  16. #define NVRAM_SIZE 64
  17. /* Flags definitions */
  18. #define SECONDS_CH 0x80
  19. #define HOURS_12 0x40
  20. #define HOURS_PM 0x20
  21. #define CTRL_OSF 0x20
  22. typedef struct {
  23. I2CSlave i2c;
  24. int64_t offset;
  25. uint8_t wday_offset;
  26. uint8_t nvram[NVRAM_SIZE];
  27. int32_t ptr;
  28. bool addr_byte;
  29. } DS1338State;
  30. static const VMStateDescription vmstate_ds1338 = {
  31. .name = "ds1338",
  32. .version_id = 2,
  33. .minimum_version_id = 1,
  34. .minimum_version_id_old = 1,
  35. .fields = (VMStateField[]) {
  36. VMSTATE_I2C_SLAVE(i2c, DS1338State),
  37. VMSTATE_INT64(offset, DS1338State),
  38. VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
  39. VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
  40. VMSTATE_INT32(ptr, DS1338State),
  41. VMSTATE_BOOL(addr_byte, DS1338State),
  42. VMSTATE_END_OF_LIST()
  43. }
  44. };
  45. static void capture_current_time(DS1338State *s)
  46. {
  47. /* Capture the current time into the secondary registers
  48. * which will be actually read by the data transfer operation.
  49. */
  50. struct tm now;
  51. qemu_get_timedate(&now, s->offset);
  52. s->nvram[0] = to_bcd(now.tm_sec);
  53. s->nvram[1] = to_bcd(now.tm_min);
  54. if (s->nvram[2] & HOURS_12) {
  55. int tmp = now.tm_hour;
  56. if (tmp == 0) {
  57. tmp = 24;
  58. }
  59. if (tmp <= 12) {
  60. s->nvram[2] = HOURS_12 | to_bcd(tmp);
  61. } else {
  62. s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
  63. }
  64. } else {
  65. s->nvram[2] = to_bcd(now.tm_hour);
  66. }
  67. s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
  68. s->nvram[4] = to_bcd(now.tm_mday);
  69. s->nvram[5] = to_bcd(now.tm_mon + 1);
  70. s->nvram[6] = to_bcd(now.tm_year - 100);
  71. }
  72. static void inc_regptr(DS1338State *s)
  73. {
  74. /* The register pointer wraps around after 0x3F; wraparound
  75. * causes the current time/date to be retransferred into
  76. * the secondary registers.
  77. */
  78. s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
  79. if (!s->ptr) {
  80. capture_current_time(s);
  81. }
  82. }
  83. static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
  84. {
  85. DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
  86. switch (event) {
  87. case I2C_START_RECV:
  88. /* In h/w, capture happens on any START condition, not just a
  89. * START_RECV, but there is no need to actually capture on
  90. * START_SEND, because the guest can't get at that data
  91. * without going through a START_RECV which would overwrite it.
  92. */
  93. capture_current_time(s);
  94. break;
  95. case I2C_START_SEND:
  96. s->addr_byte = true;
  97. break;
  98. default:
  99. break;
  100. }
  101. }
  102. static int ds1338_recv(I2CSlave *i2c)
  103. {
  104. DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
  105. uint8_t res;
  106. res = s->nvram[s->ptr];
  107. inc_regptr(s);
  108. return res;
  109. }
  110. static int ds1338_send(I2CSlave *i2c, uint8_t data)
  111. {
  112. DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
  113. if (s->addr_byte) {
  114. s->ptr = data & (NVRAM_SIZE - 1);
  115. s->addr_byte = false;
  116. return 0;
  117. }
  118. if (s->ptr < 7) {
  119. /* Time register. */
  120. struct tm now;
  121. qemu_get_timedate(&now, s->offset);
  122. switch(s->ptr) {
  123. case 0:
  124. /* TODO: Implement CH (stop) bit. */
  125. now.tm_sec = from_bcd(data & 0x7f);
  126. break;
  127. case 1:
  128. now.tm_min = from_bcd(data & 0x7f);
  129. break;
  130. case 2:
  131. if (data & HOURS_12) {
  132. int tmp = from_bcd(data & (HOURS_PM - 1));
  133. if (data & HOURS_PM) {
  134. tmp += 12;
  135. }
  136. if (tmp == 24) {
  137. tmp = 0;
  138. }
  139. now.tm_hour = tmp;
  140. } else {
  141. now.tm_hour = from_bcd(data & (HOURS_12 - 1));
  142. }
  143. break;
  144. case 3:
  145. {
  146. /* The day field is supposed to contain a value in
  147. the range 1-7. Otherwise behavior is undefined.
  148. */
  149. int user_wday = (data & 7) - 1;
  150. s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
  151. }
  152. break;
  153. case 4:
  154. now.tm_mday = from_bcd(data & 0x3f);
  155. break;
  156. case 5:
  157. now.tm_mon = from_bcd(data & 0x1f) - 1;
  158. break;
  159. case 6:
  160. now.tm_year = from_bcd(data) + 100;
  161. break;
  162. }
  163. s->offset = qemu_timedate_diff(&now);
  164. } else if (s->ptr == 7) {
  165. /* Control register. */
  166. /* Ensure bits 2, 3 and 6 will read back as zero. */
  167. data &= 0xB3;
  168. /* Attempting to write the OSF flag to logic 1 leaves the
  169. value unchanged. */
  170. data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
  171. s->nvram[s->ptr] = data;
  172. } else {
  173. s->nvram[s->ptr] = data;
  174. }
  175. inc_regptr(s);
  176. return 0;
  177. }
  178. static int ds1338_init(I2CSlave *i2c)
  179. {
  180. return 0;
  181. }
  182. static void ds1338_reset(DeviceState *dev)
  183. {
  184. DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE(dev));
  185. /* The clock is running and synchronized with the host */
  186. s->offset = 0;
  187. s->wday_offset = 0;
  188. memset(s->nvram, 0, NVRAM_SIZE);
  189. s->ptr = 0;
  190. s->addr_byte = false;
  191. }
  192. static void ds1338_class_init(ObjectClass *klass, void *data)
  193. {
  194. DeviceClass *dc = DEVICE_CLASS(klass);
  195. I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
  196. k->init = ds1338_init;
  197. k->event = ds1338_event;
  198. k->recv = ds1338_recv;
  199. k->send = ds1338_send;
  200. dc->reset = ds1338_reset;
  201. dc->vmsd = &vmstate_ds1338;
  202. }
  203. static const TypeInfo ds1338_info = {
  204. .name = "ds1338",
  205. .parent = TYPE_I2C_SLAVE,
  206. .instance_size = sizeof(DS1338State),
  207. .class_init = ds1338_class_init,
  208. };
  209. static void ds1338_register_types(void)
  210. {
  211. type_register_static(&ds1338_info);
  212. }
  213. type_init(ds1338_register_types)