tmp105.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Texas Instruments TMP105 temperature sensor.
  3. *
  4. * Copyright (C) 2008 Nokia Corporation
  5. * Written by Andrzej Zaborowski <andrew@openedhand.com>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 or
  10. * (at your option) version 3 of the License.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "qemu/osdep.h"
  21. #include "hw/i2c/i2c.h"
  22. #include "hw/irq.h"
  23. #include "migration/vmstate.h"
  24. #include "hw/sensor/tmp105.h"
  25. #include "qapi/error.h"
  26. #include "qapi/visitor.h"
  27. #include "qemu/module.h"
  28. static void tmp105_interrupt_update(TMP105State *s)
  29. {
  30. qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */
  31. }
  32. static void tmp105_alarm_update(TMP105State *s)
  33. {
  34. if ((s->config >> 0) & 1) { /* SD */
  35. if ((s->config >> 7) & 1) /* OS */
  36. s->config &= ~(1 << 7); /* OS */
  37. else
  38. return;
  39. }
  40. if (s->config >> 1 & 1) {
  41. /*
  42. * TM == 1 : Interrupt mode. We signal Alert when the
  43. * temperature rises above T_high, and expect the guest to clear
  44. * it (eg by reading a device register).
  45. */
  46. if (s->detect_falling) {
  47. if (s->temperature < s->limit[0]) {
  48. s->alarm = 1;
  49. s->detect_falling = false;
  50. }
  51. } else {
  52. if (s->temperature >= s->limit[1]) {
  53. s->alarm = 1;
  54. s->detect_falling = true;
  55. }
  56. }
  57. } else {
  58. /*
  59. * TM == 0 : Comparator mode. We signal Alert when the temperature
  60. * rises above T_high, and stop signalling it when the temperature
  61. * falls below T_low.
  62. */
  63. if (s->detect_falling) {
  64. if (s->temperature < s->limit[0]) {
  65. s->alarm = 0;
  66. s->detect_falling = false;
  67. }
  68. } else {
  69. if (s->temperature >= s->limit[1]) {
  70. s->alarm = 1;
  71. s->detect_falling = true;
  72. }
  73. }
  74. }
  75. tmp105_interrupt_update(s);
  76. }
  77. static void tmp105_get_temperature(Object *obj, Visitor *v, const char *name,
  78. void *opaque, Error **errp)
  79. {
  80. TMP105State *s = TMP105(obj);
  81. int64_t value = s->temperature * 1000 / 256;
  82. visit_type_int(v, name, &value, errp);
  83. }
  84. /* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
  85. * fixed point, so units are 1/256 centigrades. A simple ratio will do.
  86. */
  87. static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
  88. void *opaque, Error **errp)
  89. {
  90. TMP105State *s = TMP105(obj);
  91. int64_t temp;
  92. if (!visit_type_int(v, name, &temp, errp)) {
  93. return;
  94. }
  95. if (temp >= 128000 || temp < -128000) {
  96. error_setg(errp, "value %" PRId64 ".%03" PRIu64 " C is out of range",
  97. temp / 1000, temp % 1000);
  98. return;
  99. }
  100. s->temperature = (int16_t) (temp * 256 / 1000);
  101. tmp105_alarm_update(s);
  102. }
  103. static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
  104. static void tmp105_read(TMP105State *s)
  105. {
  106. s->len = 0;
  107. if ((s->config >> 1) & 1) { /* TM */
  108. s->alarm = 0;
  109. tmp105_interrupt_update(s);
  110. }
  111. switch (s->pointer & 3) {
  112. case TMP105_REG_TEMPERATURE:
  113. s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
  114. s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
  115. (0xf0 << ((~s->config >> 5) & 3)); /* R */
  116. break;
  117. case TMP105_REG_CONFIG:
  118. s->buf[s->len ++] = s->config;
  119. break;
  120. case TMP105_REG_T_LOW:
  121. s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
  122. s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
  123. break;
  124. case TMP105_REG_T_HIGH:
  125. s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
  126. s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
  127. break;
  128. }
  129. }
  130. static void tmp105_write(TMP105State *s)
  131. {
  132. switch (s->pointer & 3) {
  133. case TMP105_REG_TEMPERATURE:
  134. break;
  135. case TMP105_REG_CONFIG:
  136. if (s->buf[0] & ~s->config & (1 << 0)) /* SD */
  137. printf("%s: TMP105 shutdown\n", __func__);
  138. s->config = s->buf[0];
  139. s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
  140. tmp105_alarm_update(s);
  141. break;
  142. case TMP105_REG_T_LOW:
  143. case TMP105_REG_T_HIGH:
  144. if (s->len >= 3)
  145. s->limit[s->pointer & 1] = (int16_t)
  146. ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
  147. tmp105_alarm_update(s);
  148. break;
  149. }
  150. }
  151. static uint8_t tmp105_rx(I2CSlave *i2c)
  152. {
  153. TMP105State *s = TMP105(i2c);
  154. if (s->len < 2) {
  155. return s->buf[s->len ++];
  156. } else {
  157. return 0xff;
  158. }
  159. }
  160. static int tmp105_tx(I2CSlave *i2c, uint8_t data)
  161. {
  162. TMP105State *s = TMP105(i2c);
  163. if (s->len == 0) {
  164. s->pointer = data;
  165. s->len++;
  166. } else {
  167. if (s->len <= 2) {
  168. s->buf[s->len - 1] = data;
  169. }
  170. s->len++;
  171. tmp105_write(s);
  172. }
  173. return 0;
  174. }
  175. static int tmp105_event(I2CSlave *i2c, enum i2c_event event)
  176. {
  177. TMP105State *s = TMP105(i2c);
  178. if (event == I2C_START_RECV) {
  179. tmp105_read(s);
  180. }
  181. s->len = 0;
  182. return 0;
  183. }
  184. static int tmp105_post_load(void *opaque, int version_id)
  185. {
  186. TMP105State *s = opaque;
  187. s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
  188. tmp105_interrupt_update(s);
  189. return 0;
  190. }
  191. static bool detect_falling_needed(void *opaque)
  192. {
  193. TMP105State *s = opaque;
  194. /*
  195. * We only need to migrate the detect_falling bool if it's set;
  196. * for migration from older machines we assume that it is false
  197. * (ie temperature is not out of range).
  198. */
  199. return s->detect_falling;
  200. }
  201. static const VMStateDescription vmstate_tmp105_detect_falling = {
  202. .name = "TMP105/detect-falling",
  203. .version_id = 1,
  204. .minimum_version_id = 1,
  205. .needed = detect_falling_needed,
  206. .fields = (VMStateField[]) {
  207. VMSTATE_BOOL(detect_falling, TMP105State),
  208. VMSTATE_END_OF_LIST()
  209. }
  210. };
  211. static const VMStateDescription vmstate_tmp105 = {
  212. .name = "TMP105",
  213. .version_id = 0,
  214. .minimum_version_id = 0,
  215. .post_load = tmp105_post_load,
  216. .fields = (VMStateField[]) {
  217. VMSTATE_UINT8(len, TMP105State),
  218. VMSTATE_UINT8_ARRAY(buf, TMP105State, 2),
  219. VMSTATE_UINT8(pointer, TMP105State),
  220. VMSTATE_UINT8(config, TMP105State),
  221. VMSTATE_INT16(temperature, TMP105State),
  222. VMSTATE_INT16_ARRAY(limit, TMP105State, 2),
  223. VMSTATE_UINT8(alarm, TMP105State),
  224. VMSTATE_I2C_SLAVE(i2c, TMP105State),
  225. VMSTATE_END_OF_LIST()
  226. },
  227. .subsections = (const VMStateDescription*[]) {
  228. &vmstate_tmp105_detect_falling,
  229. NULL
  230. }
  231. };
  232. static void tmp105_reset(I2CSlave *i2c)
  233. {
  234. TMP105State *s = TMP105(i2c);
  235. s->temperature = 0;
  236. s->pointer = 0;
  237. s->config = 0;
  238. s->faults = tmp105_faultq[(s->config >> 3) & 3];
  239. s->alarm = 0;
  240. s->detect_falling = false;
  241. s->limit[0] = 0x4b00; /* T_LOW, 75 degrees C */
  242. s->limit[1] = 0x5000; /* T_HIGH, 80 degrees C */
  243. tmp105_interrupt_update(s);
  244. }
  245. static void tmp105_realize(DeviceState *dev, Error **errp)
  246. {
  247. I2CSlave *i2c = I2C_SLAVE(dev);
  248. TMP105State *s = TMP105(i2c);
  249. qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
  250. tmp105_reset(&s->i2c);
  251. }
  252. static void tmp105_initfn(Object *obj)
  253. {
  254. object_property_add(obj, "temperature", "int",
  255. tmp105_get_temperature,
  256. tmp105_set_temperature, NULL, NULL);
  257. }
  258. static void tmp105_class_init(ObjectClass *klass, void *data)
  259. {
  260. DeviceClass *dc = DEVICE_CLASS(klass);
  261. I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
  262. dc->realize = tmp105_realize;
  263. k->event = tmp105_event;
  264. k->recv = tmp105_rx;
  265. k->send = tmp105_tx;
  266. dc->vmsd = &vmstate_tmp105;
  267. }
  268. static const TypeInfo tmp105_info = {
  269. .name = TYPE_TMP105,
  270. .parent = TYPE_I2C_SLAVE,
  271. .instance_size = sizeof(TMP105State),
  272. .instance_init = tmp105_initfn,
  273. .class_init = tmp105_class_init,
  274. };
  275. static void tmp105_register_types(void)
  276. {
  277. type_register_static(&tmp105_info);
  278. }
  279. type_init(tmp105_register_types)