ds1338.c 6.2 KB

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