lm93.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /* $OpenBSD: lm93.c,v 1.8 2007/10/31 20:46:17 cnst Exp $ */
  2. /*
  3. * Copyright (c) 2007 Theo de Raadt
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/systm.h>
  19. #include <sys/device.h>
  20. #include <sys/sensors.h>
  21. #include <dev/i2c/i2cvar.h>
  22. /* LM93 registers */
  23. #define LM93_CPU1_TEMP 0x50
  24. #define LM93_CPU2_TEMP 0x51
  25. #define LM93_INT_TEMP 0x52
  26. #define LM93_EXT_TEMP 0x53
  27. #define LM93_IN1_V 0x56
  28. #define LM93_IN2_V 0x57
  29. #define LM93_IN3_V 0x58
  30. #define LM93_IN4_V 0x59
  31. #define LM93_IN5_V 0x5a
  32. #define LM93_IN6_V 0x5b
  33. #define LM93_IN7_V 0x5c
  34. #define LM93_IN8_V 0x5d
  35. #define LM93_IN9_V 0x5e
  36. #define LM93_IN10_V 0x5f
  37. #define LM93_IN11_V 0x60
  38. #define LM93_IN12_V 0x61
  39. #define LM93_IN13_V 0x62
  40. #define LM93_IN14_V 0x63
  41. #define LM93_IN15_V 0x64
  42. #define LM93_IN16_V 0x65
  43. #define LM93_TACH1L 0x6e
  44. #define LM93_TACH1H 0x6f
  45. #define LM93_TACH2L 0x70
  46. #define LM93_TACH2H 0x71
  47. #define LM93_TACH3L 0x72
  48. #define LM93_TACH3H 0x73
  49. #define LM93_TACH4L 0x74
  50. #define LM93_TACH4H 0x75
  51. #define LM93_REVISION 0x3f
  52. /* Sensors */
  53. #define LMN_CPU1_TEMP 0
  54. #define LMN_CPU2_TEMP 1
  55. #define LMN_INT_TEMP 2
  56. #define LMN_EXT_TEMP 3
  57. #define LMN_IN1_V 4
  58. #define LMN_IN2_V 5
  59. #define LMN_IN3_V 6
  60. #define LMN_IN4_V 7
  61. #define LMN_IN5_V 8
  62. #define LMN_IN6_V 9
  63. #define LMN_IN7_V 10
  64. #define LMN_IN8_V 11
  65. #define LMN_IN9_V 12
  66. #define LMN_IN10_V 13
  67. #define LMN_IN11_V 14
  68. #define LMN_IN12_V 15
  69. #define LMN_IN13_V 16
  70. #define LMN_IN14_V 17
  71. #define LMN_IN15_V 18
  72. #define LMN_IN16_V 19
  73. #define LMN_TACH1 20
  74. #define LMN_TACH2 21
  75. #define LMN_TACH3 22
  76. #define LMN_TACH4 23
  77. #define LMN_NUM_SENSORS 24
  78. struct {
  79. char sensor;
  80. u_int8_t cmd;
  81. char *name;
  82. u_short mVscale;
  83. u_short tempscale; /* else a fan */
  84. } lmn_worklist[] = {
  85. { LMN_CPU1_TEMP, LM93_CPU1_TEMP, "CPU", 0, 1 },
  86. { LMN_CPU2_TEMP, LM93_CPU2_TEMP, "CPU", 0, 1 },
  87. { LMN_INT_TEMP, LM93_INT_TEMP, "Internal", 0, 1 },
  88. { LMN_EXT_TEMP, LM93_EXT_TEMP, "External", 0, 1 },
  89. { LMN_IN1_V, LM93_IN1_V, "+12V", 1236*10, 0 },
  90. { LMN_IN2_V, LM93_IN2_V, "+12V", 1236*10, 0 },
  91. { LMN_IN3_V, LM93_IN3_V, "+12V", 1236*10, 0 },
  92. { LMN_IN4_V, LM93_IN4_V, "FSB_Vtt 1.6V", 1600, 0 },
  93. { LMN_IN5_V, LM93_IN5_V, "3GIO 2V ", 2000, 0 },
  94. { LMN_IN6_V, LM93_IN6_V, "ICH_Core 2V", 2000, 0 },
  95. { LMN_IN7_V, LM93_IN7_V, "Vccp 1.6V", 1600, 0 },
  96. { LMN_IN8_V, LM93_IN8_V, "Vccp 1.6V", 1600, 0 },
  97. { LMN_IN9_V, LM93_IN9_V, "+3.3V", 4400, 0 },
  98. { LMN_IN10_V, LM93_IN10_V, "+5V", 6667, 0 },
  99. { LMN_IN11_V, LM93_IN11_V, "SCSI_Core 3.3V", 3333, 0 },
  100. { LMN_IN12_V, LM93_IN12_V, "Mem_Core 2.6V", 2625, 0 },
  101. { LMN_IN13_V, LM93_IN13_V, "Mem_Vtt 1.3V", 1312, 0 },
  102. { LMN_IN14_V, LM93_IN14_V, "Gbit_Core 1.3V", 1312, 0 },
  103. { LMN_IN15_V, LM93_IN15_V, "-12V", -1236*10, 0 },
  104. { LMN_IN16_V, LM93_IN16_V, "+3.3V S/B", 3600, 0 },
  105. { LMN_TACH1, LM93_TACH1L, "", 0, 0 },
  106. { LMN_TACH2, LM93_TACH2L, "", 0, 0 },
  107. { LMN_TACH3, LM93_TACH3L, "", 0, 0 },
  108. { LMN_TACH4, LM93_TACH4L, "", 0, 0 }
  109. };
  110. struct lmn_softc {
  111. struct device sc_dev;
  112. i2c_tag_t sc_tag;
  113. i2c_addr_t sc_addr;
  114. u_int8_t sc_conf;
  115. struct ksensor sc_sensor[LMN_NUM_SENSORS];
  116. struct ksensordev sc_sensordev;
  117. };
  118. int lmn_match(struct device *, void *, void *);
  119. void lmn_attach(struct device *, struct device *, void *);
  120. void lmn_refresh(void *);
  121. struct cfattach lmn_ca = {
  122. sizeof(struct lmn_softc), lmn_match, lmn_attach
  123. };
  124. struct cfdriver lmn_cd = {
  125. NULL, "lmn", DV_DULL
  126. };
  127. int
  128. lmn_match(struct device *parent, void *match, void *aux)
  129. {
  130. struct i2c_attach_args *ia = aux;
  131. if (strcmp(ia->ia_name, "lm93") == 0)
  132. return (1);
  133. return (0);
  134. }
  135. void
  136. lmn_attach(struct device *parent, struct device *self, void *aux)
  137. {
  138. struct lmn_softc *sc = (struct lmn_softc *)self;
  139. struct i2c_attach_args *ia = aux;
  140. int i;
  141. sc->sc_tag = ia->ia_tag;
  142. sc->sc_addr = ia->ia_addr;
  143. printf(": %s", ia->ia_name);
  144. /* Initialize sensor data. */
  145. strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  146. sizeof(sc->sc_sensordev.xname));
  147. if (sensor_task_register(sc, lmn_refresh, 5) == NULL) {
  148. printf(", unable to register update task\n");
  149. return;
  150. }
  151. for (i = 0; i < LMN_NUM_SENSORS; i++) {
  152. if (lmn_worklist[i].tempscale)
  153. sc->sc_sensor[i].type = SENSOR_TEMP;
  154. else if (lmn_worklist[i].mVscale)
  155. sc->sc_sensor[i].type = SENSOR_VOLTS_DC;
  156. else
  157. sc->sc_sensor[i].type = SENSOR_FANRPM;
  158. strlcpy(sc->sc_sensor[i].desc, lmn_worklist[i].name,
  159. sizeof(sc->sc_sensor[i].desc));
  160. sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
  161. }
  162. sensordev_install(&sc->sc_sensordev);
  163. printf("\n");
  164. }
  165. void
  166. lmn_refresh(void *arg)
  167. {
  168. struct lmn_softc *sc = arg;
  169. u_int8_t cmd, data, data2;
  170. u_int16_t fan;
  171. int i;
  172. iic_acquire_bus(sc->sc_tag, 0);
  173. for (i = 0; i < sizeof lmn_worklist / sizeof(lmn_worklist[0]); i++) {
  174. cmd = lmn_worklist[i].cmd;
  175. if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  176. sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  177. sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  178. continue;
  179. }
  180. sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
  181. if (lmn_worklist[i].tempscale) {
  182. if (data == 0x80)
  183. sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  184. else
  185. sc->sc_sensor[i].value =
  186. (int8_t)data * 1000000 + 273150000;
  187. } else if (lmn_worklist[i].mVscale) {
  188. sc->sc_sensor[i].value = lmn_worklist[i].mVscale *
  189. 1000 * (u_int)data / 192;
  190. } else {
  191. cmd = lmn_worklist[i].cmd + 1; /* TACHnH follows TACHnL */
  192. if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  193. sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
  194. sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  195. continue;
  196. }
  197. fan = data + (data2 << 8);
  198. if (fan == 0 || fan == 0xffff)
  199. sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  200. else
  201. sc->sc_sensor[i].value = (90000 * 60) / fan;
  202. }
  203. }
  204. iic_release_bus(sc->sc_tag, 0);
  205. }