lm75.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* $OpenBSD: lm75.c,v 1.20 2015/05/30 08:39:05 kettenis Exp $ */
  2. /* $NetBSD: lm75.c,v 1.1 2003/09/30 00:35:31 thorpej Exp $ */
  3. /*
  4. * Copyright (c) 2006 Theo de Raadt <deraadt@openbsd.org>
  5. * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
  6. *
  7. * Permission to use, copy, modify, and distribute this software for any
  8. * purpose with or without fee is hereby granted, provided that the above
  9. * copyright notice and this permission notice appear in all copies.
  10. *
  11. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  14. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. /*
  20. * National Semiconductor LM75/LM76/LM77 temperature sensor.
  21. */
  22. #include <sys/param.h>
  23. #include <sys/systm.h>
  24. #include <sys/device.h>
  25. #include <sys/sensors.h>
  26. #include <dev/i2c/i2cvar.h>
  27. #define LM_MODEL_LM75 1
  28. #define LM_MODEL_LM77 2
  29. #define LM_MODEL_DS1775 3
  30. #define LM_MODEL_LM75A 4
  31. #define LM_MODEL_LM76 5
  32. #define LM_POLLTIME 3 /* 3s */
  33. #define LM75_REG_TEMP 0x00
  34. #define LM75_REG_CONFIG 0x01
  35. #define LM75_CONFIG_SHUTDOWN 0x01
  36. #define LM75_CONFIG_CMPINT 0x02
  37. #define LM75_CONFIG_OSPOLARITY 0x04
  38. #define LM75_CONFIG_FAULT_QUEUE_MASK 0x18
  39. #define LM75_CONFIG_FAULT_QUEUE_1 (0 << 3)
  40. #define LM75_CONFIG_FAULT_QUEUE_2 (1 << 3)
  41. #define LM75_CONFIG_FAULT_QUEUE_4 (2 << 3)
  42. #define LM75_CONFIG_FAULT_QUEUE_6 (3 << 3)
  43. #define LM77_CONFIG_INTPOLARITY 0x08
  44. #define LM77_CONFIG_FAULT_QUEUE_4 0x10
  45. #define DS1755_CONFIG_RESOLUTION(i) (9 + (((i) >> 5) & 3))
  46. #define LM75_REG_THYST_SET_POINT 0x02
  47. #define LM75_REG_TOS_SET_POINT 0x03
  48. #define LM77_REG_TLOW 0x04
  49. #define LM77_REG_THIGH 0x05
  50. struct lmtemp_softc {
  51. struct device sc_dev;
  52. i2c_tag_t sc_tag;
  53. int sc_addr;
  54. int sc_model;
  55. int sc_bits;
  56. int sc_ratio;
  57. struct ksensor sc_sensor;
  58. struct ksensordev sc_sensordev;
  59. };
  60. int lmtemp_match(struct device *, void *, void *);
  61. void lmtemp_attach(struct device *, struct device *, void *);
  62. struct cfattach lmtemp_ca = {
  63. sizeof(struct lmtemp_softc),
  64. lmtemp_match,
  65. lmtemp_attach
  66. };
  67. struct cfdriver lmtemp_cd = {
  68. NULL, "lmtemp", DV_DULL
  69. };
  70. /*
  71. * Temperature on the LM75 is represented by a 9-bit two's complement
  72. * integer in steps of 0.5C. The following examples are taken from
  73. * the LM75 data sheet:
  74. *
  75. * +125C 0 1111 1010 0x0fa
  76. * +25C 0 0011 0010 0x032
  77. * +0.5C 0 0000 0001 0x001
  78. * 0C 0 0000 0000 0x000
  79. * -0.5C 1 1111 1111 0x1ff
  80. * -25C 1 1100 1110 0x1ce
  81. * -55C 1 1001 0010 0x192
  82. *
  83. * Temperature on the LM75A is represented by an 11-bit two's complement
  84. * integer in steps of 0.125C. The LM75A can be treated like an LM75 if
  85. * the extra precision is not required. The following examples are
  86. * taken from the LM75A data sheet:
  87. *
  88. * +127.000C 011 1111 1000 0x3f8
  89. * +126.875C 011 1111 0111 0x3f7
  90. * +126.125C 011 1111 0001 0x3f1
  91. * +125.000C 011 1110 1000 0x3e8
  92. * +25.000C 000 1100 1000 0x0c8
  93. * +0.125C 000 0000 0001 0x001
  94. * 0C 000 0000 0000 0x000
  95. * -0.125C 111 1111 1111 0x7ff
  96. * -25.000C 111 0011 1000 0x738
  97. * -54.875C 110 0100 1001 0x649
  98. * -55.000C 110 0100 1000 0x648
  99. *
  100. * Temperature on the LM77 is represented by a 13-bit two's complement
  101. * integer in steps of 0.5C. The LM76 is similar, but the integer is
  102. * in steps of 0.065C
  103. *
  104. * LM75 temperature word:
  105. *
  106. * MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X X X
  107. * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  108. *
  109. *
  110. * LM75A temperature word:
  111. *
  112. * MSB Bit9 Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X
  113. * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  114. *
  115. *
  116. * LM77 temperature word:
  117. *
  118. * Sign Sign Sign Sign MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 Status bits
  119. * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  120. */
  121. int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, int *);
  122. void lmtemp_refresh_sensor_data(void *);
  123. int
  124. lmtemp_match(struct device *parent, void *match, void *aux)
  125. {
  126. struct i2c_attach_args *ia = aux;
  127. if (strcmp(ia->ia_name, "lm75") == 0 ||
  128. strcmp(ia->ia_name, "lm76") == 0 ||
  129. strcmp(ia->ia_name, "lm77") == 0 ||
  130. strcmp(ia->ia_name, "ds1775") == 0 ||
  131. strcmp(ia->ia_name, "lm75a") == 0)
  132. return (1);
  133. return (0);
  134. }
  135. void
  136. lmtemp_attach(struct device *parent, struct device *self, void *aux)
  137. {
  138. struct lmtemp_softc *sc = (struct lmtemp_softc *)self;
  139. struct i2c_attach_args *ia = aux;
  140. u_int8_t cmd, data;
  141. sc->sc_tag = ia->ia_tag;
  142. sc->sc_addr = ia->ia_addr;
  143. printf(": %s", ia->ia_name);
  144. /* If in SHUTDOWN mode, wake it up */
  145. iic_acquire_bus(sc->sc_tag, 0);
  146. cmd = LM75_REG_CONFIG;
  147. if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  148. sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  149. iic_release_bus(sc->sc_tag, 0);
  150. printf(", fails to respond\n");
  151. return;
  152. }
  153. if (data & LM75_CONFIG_SHUTDOWN) {
  154. data &= ~LM75_CONFIG_SHUTDOWN;
  155. if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
  156. sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  157. printf(", cannot wake up\n");
  158. iic_release_bus(sc->sc_tag, 0);
  159. return;
  160. }
  161. printf(", woken up");
  162. }
  163. iic_release_bus(sc->sc_tag, 0);
  164. sc->sc_model = LM_MODEL_LM75;
  165. sc->sc_bits = 9;
  166. sc->sc_ratio = 500000; /* 0.5 degC for LSB */
  167. if (strcmp(ia->ia_name, "lm77") == 0) {
  168. sc->sc_model = LM_MODEL_LM77;
  169. sc->sc_bits = 13;
  170. } else if (strcmp(ia->ia_name, "lm76") == 0) {
  171. sc->sc_model = LM_MODEL_LM76;
  172. sc->sc_bits = 13;
  173. sc->sc_ratio = 62500; /* 0.0625 degC for LSB */
  174. } else if (strcmp(ia->ia_name, "ds1775") == 0) {
  175. sc->sc_model = LM_MODEL_DS1775;
  176. //sc->sc_bits = DS1755_CONFIG_RESOLUTION(data);
  177. } else if (strcmp(ia->ia_name, "lm75a") == 0) {
  178. /* For simplicity's sake, treat the LM75A as an LM75 */
  179. sc->sc_model = LM_MODEL_LM75A;
  180. }
  181. printf("\n");
  182. /* Initialize sensor data */
  183. strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  184. sizeof(sc->sc_sensordev.xname));
  185. sc->sc_sensor.type = SENSOR_TEMP;
  186. /* Hook into the hw.sensors sysctl */
  187. sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
  188. sensordev_install(&sc->sc_sensordev);
  189. sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME);
  190. }
  191. int
  192. lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp)
  193. {
  194. u_int8_t cmd = which;
  195. u_int16_t data = 0x0000;
  196. int error;
  197. iic_acquire_bus(sc->sc_tag, 0);
  198. error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  199. sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
  200. iic_release_bus(sc->sc_tag, 0);
  201. if (error)
  202. return (error);
  203. /* Some chips return transient 0's.. we try next time */
  204. if (data == 0x0000)
  205. return (1);
  206. /* convert to half-degrees C */
  207. *valp = betoh16(data) / (1 << (16 - sc->sc_bits));
  208. return (0);
  209. }
  210. void
  211. lmtemp_refresh_sensor_data(void *aux)
  212. {
  213. struct lmtemp_softc *sc = aux;
  214. int val;
  215. int error;
  216. error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val);
  217. if (error) {
  218. #if 0
  219. printf("%s: unable to read temperature, error = %d\n",
  220. sc->sc_dev.dv_xname, error);
  221. #endif
  222. sc->sc_sensor.flags |= SENSOR_FINVALID;
  223. return;
  224. }
  225. sc->sc_sensor.value = val * sc->sc_ratio + 273150000;
  226. sc->sc_sensor.flags &= ~SENSOR_FINVALID;
  227. }