tmp105.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. */
  21. #include "hw.h"
  22. #include "i2c.h"
  23. struct tmp105_s {
  24. i2c_slave i2c;
  25. int len;
  26. uint8_t buf[2];
  27. qemu_irq pin;
  28. uint8_t pointer;
  29. uint8_t config;
  30. int16_t temperature;
  31. int16_t limit[2];
  32. int faults;
  33. int alarm;
  34. };
  35. static void tmp105_interrupt_update(struct tmp105_s *s)
  36. {
  37. qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */
  38. }
  39. static void tmp105_alarm_update(struct tmp105_s *s)
  40. {
  41. if ((s->config >> 0) & 1) { /* SD */
  42. if ((s->config >> 7) & 1) /* OS */
  43. s->config &= ~(1 << 7); /* OS */
  44. else
  45. return;
  46. }
  47. if ((s->config >> 1) & 1) { /* TM */
  48. if (s->temperature >= s->limit[1])
  49. s->alarm = 1;
  50. else if (s->temperature < s->limit[0])
  51. s->alarm = 1;
  52. } else {
  53. if (s->temperature >= s->limit[1])
  54. s->alarm = 1;
  55. else if (s->temperature < s->limit[0])
  56. s->alarm = 0;
  57. }
  58. tmp105_interrupt_update(s);
  59. }
  60. /* Units are 0.001 centigrades relative to 0 C. */
  61. void tmp105_set(i2c_slave *i2c, int temp)
  62. {
  63. struct tmp105_s *s = (struct tmp105_s *) i2c;
  64. if (temp >= 128000 || temp < -128000) {
  65. fprintf(stderr, "%s: values is out of range (%i.%03i C)\n",
  66. __FUNCTION__, temp / 1000, temp % 1000);
  67. exit(-1);
  68. }
  69. s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
  70. tmp105_alarm_update(s);
  71. }
  72. static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
  73. static void tmp105_read(struct tmp105_s *s)
  74. {
  75. s->len = 0;
  76. if ((s->config >> 1) & 1) { /* TM */
  77. s->alarm = 0;
  78. tmp105_interrupt_update(s);
  79. }
  80. switch (s->pointer & 3) {
  81. case 0: /* Temperature */
  82. s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
  83. s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
  84. (0xf0 << ((~s->config >> 5) & 3)); /* R */
  85. break;
  86. case 1: /* Configuration */
  87. s->buf[s->len ++] = s->config;
  88. break;
  89. case 2: /* T_LOW */
  90. s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
  91. s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
  92. break;
  93. case 3: /* T_HIGH */
  94. s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
  95. s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
  96. break;
  97. }
  98. }
  99. static void tmp105_write(struct tmp105_s *s)
  100. {
  101. switch (s->pointer & 3) {
  102. case 0: /* Temperature */
  103. break;
  104. case 1: /* Configuration */
  105. if (s->buf[0] & ~s->config & (1 << 0)) /* SD */
  106. printf("%s: TMP105 shutdown\n", __FUNCTION__);
  107. s->config = s->buf[0];
  108. s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
  109. tmp105_alarm_update(s);
  110. break;
  111. case 2: /* T_LOW */
  112. case 3: /* T_HIGH */
  113. if (s->len >= 3)
  114. s->limit[s->pointer & 1] = (int16_t)
  115. ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
  116. tmp105_alarm_update(s);
  117. break;
  118. }
  119. }
  120. static int tmp105_rx(i2c_slave *i2c)
  121. {
  122. struct tmp105_s *s = (struct tmp105_s *) i2c;
  123. if (s->len < 2)
  124. return s->buf[s->len ++];
  125. else
  126. return 0xff;
  127. }
  128. static int tmp105_tx(i2c_slave *i2c, uint8_t data)
  129. {
  130. struct tmp105_s *s = (struct tmp105_s *) i2c;
  131. if (!s->len ++)
  132. s->pointer = data;
  133. else {
  134. if (s->len <= 2)
  135. s->buf[s->len - 1] = data;
  136. tmp105_write(s);
  137. }
  138. return 0;
  139. }
  140. static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
  141. {
  142. struct tmp105_s *s = (struct tmp105_s *) i2c;
  143. if (event == I2C_START_RECV)
  144. tmp105_read(s);
  145. s->len = 0;
  146. }
  147. static void tmp105_save(QEMUFile *f, void *opaque)
  148. {
  149. struct tmp105_s *s = (struct tmp105_s *) opaque;
  150. qemu_put_byte(f, s->len);
  151. qemu_put_8s(f, &s->buf[0]);
  152. qemu_put_8s(f, &s->buf[1]);
  153. qemu_put_8s(f, &s->pointer);
  154. qemu_put_8s(f, &s->config);
  155. qemu_put_sbe16s(f, &s->temperature);
  156. qemu_put_sbe16s(f, &s->limit[0]);
  157. qemu_put_sbe16s(f, &s->limit[1]);
  158. qemu_put_byte(f, s->alarm);
  159. s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
  160. i2c_slave_save(f, &s->i2c);
  161. }
  162. static int tmp105_load(QEMUFile *f, void *opaque, int version_id)
  163. {
  164. struct tmp105_s *s = (struct tmp105_s *) opaque;
  165. s->len = qemu_get_byte(f);
  166. qemu_get_8s(f, &s->buf[0]);
  167. qemu_get_8s(f, &s->buf[1]);
  168. qemu_get_8s(f, &s->pointer);
  169. qemu_get_8s(f, &s->config);
  170. qemu_get_sbe16s(f, &s->temperature);
  171. qemu_get_sbe16s(f, &s->limit[0]);
  172. qemu_get_sbe16s(f, &s->limit[1]);
  173. s->alarm = qemu_get_byte(f);
  174. tmp105_interrupt_update(s);
  175. i2c_slave_load(f, &s->i2c);
  176. return 0;
  177. }
  178. void tmp105_reset(i2c_slave *i2c)
  179. {
  180. struct tmp105_s *s = (struct tmp105_s *) i2c;
  181. s->temperature = 0;
  182. s->pointer = 0;
  183. s->config = 0;
  184. s->faults = tmp105_faultq[(s->config >> 3) & 3];
  185. s->alarm = 0;
  186. tmp105_interrupt_update(s);
  187. }
  188. struct i2c_slave *tmp105_init(i2c_bus *bus, qemu_irq alarm)
  189. {
  190. struct tmp105_s *s = (struct tmp105_s *)
  191. i2c_slave_init(bus, 0, sizeof(struct tmp105_s));
  192. s->i2c.event = tmp105_event;
  193. s->i2c.recv = tmp105_rx;
  194. s->i2c.send = tmp105_tx;
  195. s->pin = alarm;
  196. tmp105_reset(&s->i2c);
  197. register_savevm("TMP105", -1, 0, tmp105_save, tmp105_load, s);
  198. return &s->i2c;
  199. }