eeprom_at24c.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * *AT24C* series I2C EEPROM
  3. *
  4. * Copyright (c) 2015 Michael Davidsaver
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2. See
  7. * the LICENSE file in the top-level directory.
  8. */
  9. #include "qemu/osdep.h"
  10. #include "qapi/error.h"
  11. #include "qemu/module.h"
  12. #include "hw/i2c/i2c.h"
  13. #include "hw/qdev-properties.h"
  14. #include "sysemu/block-backend.h"
  15. /* #define DEBUG_AT24C */
  16. #ifdef DEBUG_AT24C
  17. #define DPRINTK(FMT, ...) printf(TYPE_AT24C_EE " : " FMT, ## __VA_ARGS__)
  18. #else
  19. #define DPRINTK(FMT, ...) do {} while (0)
  20. #endif
  21. #define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \
  22. ## __VA_ARGS__)
  23. #define TYPE_AT24C_EE "at24c-eeprom"
  24. #define AT24C_EE(obj) OBJECT_CHECK(EEPROMState, (obj), TYPE_AT24C_EE)
  25. typedef struct EEPROMState {
  26. I2CSlave parent_obj;
  27. /* address counter */
  28. uint16_t cur;
  29. /* total size in bytes */
  30. uint32_t rsize;
  31. bool writable;
  32. /* cells changed since last START? */
  33. bool changed;
  34. /* during WRITE, # of address bytes transfered */
  35. uint8_t haveaddr;
  36. uint8_t *mem;
  37. BlockBackend *blk;
  38. } EEPROMState;
  39. static
  40. int at24c_eeprom_event(I2CSlave *s, enum i2c_event event)
  41. {
  42. EEPROMState *ee = container_of(s, EEPROMState, parent_obj);
  43. switch (event) {
  44. case I2C_START_SEND:
  45. case I2C_START_RECV:
  46. case I2C_FINISH:
  47. ee->haveaddr = 0;
  48. DPRINTK("clear\n");
  49. if (ee->blk && ee->changed) {
  50. int len = blk_pwrite(ee->blk, 0, ee->mem, ee->rsize, 0);
  51. if (len != ee->rsize) {
  52. ERR(TYPE_AT24C_EE
  53. " : failed to write backing file\n");
  54. }
  55. DPRINTK("Wrote to backing file\n");
  56. }
  57. ee->changed = false;
  58. break;
  59. case I2C_NACK:
  60. break;
  61. }
  62. return 0;
  63. }
  64. static
  65. uint8_t at24c_eeprom_recv(I2CSlave *s)
  66. {
  67. EEPROMState *ee = AT24C_EE(s);
  68. uint8_t ret;
  69. ret = ee->mem[ee->cur];
  70. ee->cur = (ee->cur + 1u) % ee->rsize;
  71. DPRINTK("Recv %02x %c\n", ret, ret);
  72. return ret;
  73. }
  74. static
  75. int at24c_eeprom_send(I2CSlave *s, uint8_t data)
  76. {
  77. EEPROMState *ee = AT24C_EE(s);
  78. if (ee->haveaddr < 2) {
  79. ee->cur <<= 8;
  80. ee->cur |= data;
  81. ee->haveaddr++;
  82. if (ee->haveaddr == 2) {
  83. ee->cur %= ee->rsize;
  84. DPRINTK("Set pointer %04x\n", ee->cur);
  85. }
  86. } else {
  87. if (ee->writable) {
  88. DPRINTK("Send %02x\n", data);
  89. ee->mem[ee->cur] = data;
  90. ee->changed = true;
  91. } else {
  92. DPRINTK("Send error %02x read-only\n", data);
  93. }
  94. ee->cur = (ee->cur + 1u) % ee->rsize;
  95. }
  96. return 0;
  97. }
  98. static void at24c_eeprom_realize(DeviceState *dev, Error **errp)
  99. {
  100. EEPROMState *ee = AT24C_EE(dev);
  101. if (ee->blk) {
  102. int64_t len = blk_getlength(ee->blk);
  103. if (len != ee->rsize) {
  104. error_setg(errp, "%s: Backing file size %" PRId64 " != %u",
  105. TYPE_AT24C_EE, len, ee->rsize);
  106. return;
  107. }
  108. if (blk_set_perm(ee->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
  109. BLK_PERM_ALL, &error_fatal) < 0)
  110. {
  111. error_setg(errp, "%s: Backing file incorrect permission",
  112. TYPE_AT24C_EE);
  113. return;
  114. }
  115. }
  116. ee->mem = g_malloc0(ee->rsize);
  117. }
  118. static
  119. void at24c_eeprom_reset(DeviceState *state)
  120. {
  121. EEPROMState *ee = AT24C_EE(state);
  122. ee->changed = false;
  123. ee->cur = 0;
  124. ee->haveaddr = 0;
  125. memset(ee->mem, 0, ee->rsize);
  126. if (ee->blk) {
  127. int len = blk_pread(ee->blk, 0, ee->mem, ee->rsize);
  128. if (len != ee->rsize) {
  129. ERR(TYPE_AT24C_EE
  130. " : Failed initial sync with backing file\n");
  131. }
  132. DPRINTK("Reset read backing file\n");
  133. }
  134. }
  135. static Property at24c_eeprom_props[] = {
  136. DEFINE_PROP_UINT32("rom-size", EEPROMState, rsize, 0),
  137. DEFINE_PROP_BOOL("writable", EEPROMState, writable, true),
  138. DEFINE_PROP_DRIVE("drive", EEPROMState, blk),
  139. DEFINE_PROP_END_OF_LIST()
  140. };
  141. static
  142. void at24c_eeprom_class_init(ObjectClass *klass, void *data)
  143. {
  144. DeviceClass *dc = DEVICE_CLASS(klass);
  145. I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
  146. dc->realize = &at24c_eeprom_realize;
  147. k->event = &at24c_eeprom_event;
  148. k->recv = &at24c_eeprom_recv;
  149. k->send = &at24c_eeprom_send;
  150. dc->props = at24c_eeprom_props;
  151. dc->reset = at24c_eeprom_reset;
  152. }
  153. static
  154. const TypeInfo at24c_eeprom_type = {
  155. .name = TYPE_AT24C_EE,
  156. .parent = TYPE_I2C_SLAVE,
  157. .instance_size = sizeof(EEPROMState),
  158. .class_size = sizeof(I2CSlaveClass),
  159. .class_init = at24c_eeprom_class_init,
  160. };
  161. static void at24c_eeprom_register(void)
  162. {
  163. type_register_static(&at24c_eeprom_type);
  164. }
  165. type_init(at24c_eeprom_register)