dps310.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright 2017-2021 Joel Stanley <joel@jms.id.au>, IBM Corporation
  4. *
  5. * Infineon DPS310 temperature and humidity sensor
  6. *
  7. * https://www.infineon.com/cms/en/product/sensor/pressure-sensors/pressure-sensors-for-iot/dps310/
  8. */
  9. #include "qemu/osdep.h"
  10. #include "qemu/log.h"
  11. #include "hw/i2c/i2c.h"
  12. #include "qapi/error.h"
  13. #include "qapi/visitor.h"
  14. #include "migration/vmstate.h"
  15. #define NUM_REGISTERS 0x33
  16. typedef struct DPS310State {
  17. /*< private >*/
  18. I2CSlave i2c;
  19. /*< public >*/
  20. uint8_t regs[NUM_REGISTERS];
  21. uint8_t len;
  22. uint8_t pointer;
  23. } DPS310State;
  24. #define TYPE_DPS310 "dps310"
  25. #define DPS310(obj) OBJECT_CHECK(DPS310State, (obj), TYPE_DPS310)
  26. #define DPS310_PRS_B2 0x00
  27. #define DPS310_PRS_B1 0x01
  28. #define DPS310_PRS_B0 0x02
  29. #define DPS310_TMP_B2 0x03
  30. #define DPS310_TMP_B1 0x04
  31. #define DPS310_TMP_B0 0x05
  32. #define DPS310_PRS_CFG 0x06
  33. #define DPS310_TMP_CFG 0x07
  34. #define DPS310_TMP_RATE_BITS (0x70)
  35. #define DPS310_MEAS_CFG 0x08
  36. #define DPS310_MEAS_CTRL_BITS (0x07)
  37. #define DPS310_PRESSURE_EN BIT(0)
  38. #define DPS310_TEMP_EN BIT(1)
  39. #define DPS310_BACKGROUND BIT(2)
  40. #define DPS310_PRS_RDY BIT(4)
  41. #define DPS310_TMP_RDY BIT(5)
  42. #define DPS310_SENSOR_RDY BIT(6)
  43. #define DPS310_COEF_RDY BIT(7)
  44. #define DPS310_CFG_REG 0x09
  45. #define DPS310_RESET 0x0c
  46. #define DPS310_RESET_MAGIC (BIT(0) | BIT(3))
  47. #define DPS310_COEF_BASE 0x10
  48. #define DPS310_COEF_LAST 0x21
  49. #define DPS310_COEF_SRC 0x28
  50. static void dps310_reset(DeviceState *dev)
  51. {
  52. DPS310State *s = DPS310(dev);
  53. static const uint8_t regs_reset_state[sizeof(s->regs)] = {
  54. 0xfe, 0x2f, 0xee, 0x02, 0x69, 0xa6, 0x00, 0x80, 0xc7, 0x00, 0x00, 0x00,
  55. 0x00, 0x10, 0x00, 0x00, 0x0e, 0x1e, 0xdd, 0x13, 0xca, 0x5f, 0x21, 0x52,
  56. 0xf9, 0xc6, 0x04, 0xd1, 0xdb, 0x47, 0x00, 0x5b, 0xfb, 0x3a, 0x00, 0x00,
  57. 0x20, 0x49, 0x4e, 0xa5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  58. 0x60, 0x15, 0x02
  59. };
  60. memcpy(s->regs, regs_reset_state, sizeof(s->regs));
  61. s->pointer = 0;
  62. /* TODO: assert these after some timeout ? */
  63. s->regs[DPS310_MEAS_CFG] = DPS310_COEF_RDY | DPS310_SENSOR_RDY
  64. | DPS310_TMP_RDY | DPS310_PRS_RDY;
  65. }
  66. static uint8_t dps310_read(DPS310State *s, uint8_t reg)
  67. {
  68. if (reg >= sizeof(s->regs)) {
  69. qemu_log_mask(LOG_GUEST_ERROR, "%s: register 0x%02x out of bounds\n",
  70. __func__, s->pointer);
  71. return 0xFF;
  72. }
  73. switch (reg) {
  74. case DPS310_PRS_B2:
  75. case DPS310_PRS_B1:
  76. case DPS310_PRS_B0:
  77. case DPS310_TMP_B2:
  78. case DPS310_TMP_B1:
  79. case DPS310_TMP_B0:
  80. case DPS310_PRS_CFG:
  81. case DPS310_TMP_CFG:
  82. case DPS310_MEAS_CFG:
  83. case DPS310_CFG_REG:
  84. case DPS310_COEF_BASE...DPS310_COEF_LAST:
  85. case DPS310_COEF_SRC:
  86. case 0x32: /* Undocumented register to indicate workaround not required */
  87. return s->regs[reg];
  88. default:
  89. qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n",
  90. __func__, reg);
  91. return 0xFF;
  92. }
  93. }
  94. static void dps310_write(DPS310State *s, uint8_t reg, uint8_t data)
  95. {
  96. if (reg >= sizeof(s->regs)) {
  97. qemu_log_mask(LOG_GUEST_ERROR, "%s: register %d out of bounds\n",
  98. __func__, s->pointer);
  99. return;
  100. }
  101. switch (reg) {
  102. case DPS310_RESET:
  103. if (data == DPS310_RESET_MAGIC) {
  104. device_cold_reset(DEVICE(s));
  105. }
  106. break;
  107. case DPS310_PRS_CFG:
  108. case DPS310_TMP_CFG:
  109. case DPS310_MEAS_CFG:
  110. case DPS310_CFG_REG:
  111. s->regs[reg] = data;
  112. break;
  113. default:
  114. qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n",
  115. __func__, reg);
  116. return;
  117. }
  118. }
  119. static uint8_t dps310_rx(I2CSlave *i2c)
  120. {
  121. DPS310State *s = DPS310(i2c);
  122. if (s->len == 1) {
  123. return dps310_read(s, s->pointer++);
  124. } else {
  125. return 0xFF;
  126. }
  127. }
  128. static int dps310_tx(I2CSlave *i2c, uint8_t data)
  129. {
  130. DPS310State *s = DPS310(i2c);
  131. if (s->len == 0) {
  132. /*
  133. * first byte is the register pointer for a read or write
  134. * operation
  135. */
  136. s->pointer = data;
  137. s->len++;
  138. } else if (s->len == 1) {
  139. dps310_write(s, s->pointer++, data);
  140. }
  141. return 0;
  142. }
  143. static int dps310_event(I2CSlave *i2c, enum i2c_event event)
  144. {
  145. DPS310State *s = DPS310(i2c);
  146. switch (event) {
  147. case I2C_START_SEND:
  148. s->pointer = 0xFF;
  149. s->len = 0;
  150. break;
  151. case I2C_START_RECV:
  152. if (s->len != 1) {
  153. qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid recv sequence\n",
  154. __func__);
  155. }
  156. break;
  157. default:
  158. break;
  159. }
  160. return 0;
  161. }
  162. static const VMStateDescription vmstate_dps310 = {
  163. .name = "DPS310",
  164. .version_id = 0,
  165. .minimum_version_id = 0,
  166. .fields = (VMStateField[]) {
  167. VMSTATE_UINT8(len, DPS310State),
  168. VMSTATE_UINT8_ARRAY(regs, DPS310State, NUM_REGISTERS),
  169. VMSTATE_UINT8(pointer, DPS310State),
  170. VMSTATE_I2C_SLAVE(i2c, DPS310State),
  171. VMSTATE_END_OF_LIST()
  172. }
  173. };
  174. static void dps310_class_init(ObjectClass *klass, void *data)
  175. {
  176. DeviceClass *dc = DEVICE_CLASS(klass);
  177. I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
  178. k->event = dps310_event;
  179. k->recv = dps310_rx;
  180. k->send = dps310_tx;
  181. dc->reset = dps310_reset;
  182. dc->vmsd = &vmstate_dps310;
  183. }
  184. static const TypeInfo dps310_info = {
  185. .name = TYPE_DPS310,
  186. .parent = TYPE_I2C_SLAVE,
  187. .instance_size = sizeof(DPS310State),
  188. .class_init = dps310_class_init,
  189. };
  190. static void dps310_register_types(void)
  191. {
  192. type_register_static(&dps310_info);
  193. }
  194. type_init(dps310_register_types)