2
0

ds1338.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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 "qemu/module.h"
  17. #include "qom/object.h"
  18. #include "sysemu/rtc.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 = (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. inc_regptr(s);
  116. return res;
  117. }
  118. static int ds1338_send(I2CSlave *i2c, uint8_t data)
  119. {
  120. DS1338State *s = DS1338(i2c);
  121. if (s->addr_byte) {
  122. s->ptr = data & (NVRAM_SIZE - 1);
  123. s->addr_byte = false;
  124. return 0;
  125. }
  126. if (s->ptr < 7) {
  127. /* Time register. */
  128. struct tm now;
  129. qemu_get_timedate(&now, s->offset);
  130. switch(s->ptr) {
  131. case 0:
  132. /* TODO: Implement CH (stop) bit. */
  133. now.tm_sec = from_bcd(data & 0x7f);
  134. break;
  135. case 1:
  136. now.tm_min = from_bcd(data & 0x7f);
  137. break;
  138. case 2:
  139. if (data & HOURS_12) {
  140. int tmp = from_bcd(data & (HOURS_PM - 1));
  141. if (data & HOURS_PM) {
  142. tmp += 12;
  143. }
  144. if (tmp % 12 == 0) {
  145. tmp -= 12;
  146. }
  147. now.tm_hour = tmp;
  148. } else {
  149. now.tm_hour = from_bcd(data & (HOURS_12 - 1));
  150. }
  151. break;
  152. case 3:
  153. {
  154. /* The day field is supposed to contain a value in
  155. the range 1-7. Otherwise behavior is undefined.
  156. */
  157. int user_wday = (data & 7) - 1;
  158. s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
  159. }
  160. break;
  161. case 4:
  162. now.tm_mday = from_bcd(data & 0x3f);
  163. break;
  164. case 5:
  165. now.tm_mon = from_bcd(data & 0x1f) - 1;
  166. break;
  167. case 6:
  168. now.tm_year = from_bcd(data) + 100;
  169. break;
  170. }
  171. s->offset = qemu_timedate_diff(&now);
  172. } else if (s->ptr == 7) {
  173. /* Control register. */
  174. /* Ensure bits 2, 3 and 6 will read back as zero. */
  175. data &= 0xB3;
  176. /* Attempting to write the OSF flag to logic 1 leaves the
  177. value unchanged. */
  178. data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
  179. s->nvram[s->ptr] = data;
  180. } else {
  181. s->nvram[s->ptr] = data;
  182. }
  183. inc_regptr(s);
  184. return 0;
  185. }
  186. static void ds1338_reset(DeviceState *dev)
  187. {
  188. DS1338State *s = DS1338(dev);
  189. /* The clock is running and synchronized with the host */
  190. s->offset = 0;
  191. s->wday_offset = 0;
  192. memset(s->nvram, 0, NVRAM_SIZE);
  193. s->ptr = 0;
  194. s->addr_byte = false;
  195. }
  196. static void ds1338_class_init(ObjectClass *klass, void *data)
  197. {
  198. DeviceClass *dc = DEVICE_CLASS(klass);
  199. I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
  200. k->event = ds1338_event;
  201. k->recv = ds1338_recv;
  202. k->send = ds1338_send;
  203. dc->reset = ds1338_reset;
  204. dc->vmsd = &vmstate_ds1338;
  205. }
  206. static const TypeInfo ds1338_info = {
  207. .name = TYPE_DS1338,
  208. .parent = TYPE_I2C_SLAVE,
  209. .instance_size = sizeof(DS1338State),
  210. .class_init = ds1338_class_init,
  211. };
  212. static void ds1338_register_types(void)
  213. {
  214. type_register_static(&ds1338_info);
  215. }
  216. type_init(ds1338_register_types)