2 * Copyright (c) 2005, 2006 Mark Kettenis
3 * Copyright (c) 2006, 2007 Constantine A. Murenin
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.
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.
17 * $OpenBSD: lm78.c,v 1.18 2007/05/26 22:47:39 cnst Exp $
18 * $DragonFly: src/sys/dev/powermng/lm/lm78.c,v 1.1 2007/10/02 13:37:38 hasso Exp $
21 #include <sys/cdefs.h>
22 #include <sys/param.h>
23 #include <sys/systm.h>
25 #include <sys/sensors.h>
30 #define DPRINTF(x) do { printf x; } while (0)
36 * LM78-compatible chips can typically measure voltages up to 4.096 V.
37 * To measure higher voltages the input is attenuated with (external)
38 * resistors. Negative voltages are measured using inverting op amps
39 * and resistors. So we have to convert the sensor values back to
40 * real voltages by applying the appropriate resistor factor.
42 #define RFACT_NONE 10000
43 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
44 #define NRFACT(x, y) (-RFACT_NONE * (x) / (y))
46 int lm_match(struct lm_softc *);
47 int wb_match(struct lm_softc *);
48 int def_match(struct lm_softc *);
50 void lm_setup_sensors(struct lm_softc *, struct lm_sensor *);
51 void lm_refresh(void *);
53 void lm_refresh_sensor_data(struct lm_softc *);
54 void lm_refresh_volt(struct lm_softc *, int);
55 void lm_refresh_temp(struct lm_softc *, int);
56 void lm_refresh_fanrpm(struct lm_softc *, int);
58 void wb_refresh_sensor_data(struct lm_softc *);
59 void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
60 void wb_refresh_nvolt(struct lm_softc *, int);
61 void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
62 void wb_refresh_temp(struct lm_softc *, int);
63 void wb_refresh_fanrpm(struct lm_softc *, int);
64 void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
66 void as_refresh_temp(struct lm_softc *, int);
69 int (*chip_match)(struct lm_softc *);
72 struct lm_chip lm_chips[] = {
75 { def_match } /* Must be last */
78 struct lm_sensor lm78_sensors[] = {
80 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
81 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
82 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
83 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) },
84 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) },
85 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) },
86 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) },
89 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
92 { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
93 { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
94 { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
99 struct lm_sensor w83627hf_sensors[] = {
101 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
102 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
103 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
104 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
105 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
106 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
107 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
108 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
109 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
112 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
113 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
114 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
117 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
118 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
119 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
125 * The W83627EHF can measure voltages up to 2.048 V instead of the
126 * traditional 4.096 V. For measuring positive voltages, this can be
127 * accounted for by halving the resistor factor. Negative voltages
128 * need special treatment, also because the reference voltage is 2.048 V
129 * instead of the traditional 3.6 V.
131 struct lm_sensor w83627ehf_sensors[] = {
133 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
134 { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
135 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
136 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
137 { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
138 { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
139 { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
140 { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
141 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
142 { "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
145 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
146 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
147 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
150 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
151 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
152 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
158 * w83627dhg is almost identical to w83627ehf, except that
159 * it has 9 instead of 10 voltage sensors
161 struct lm_sensor w83627dhg_sensors[] = {
163 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
164 { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
165 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
166 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
167 { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
168 { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
169 { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
170 { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
171 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
174 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
175 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
176 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
179 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
180 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
181 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
186 struct lm_sensor w83637hf_sensors[] = {
188 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore },
189 { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
190 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
191 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
192 { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
193 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
194 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
197 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
198 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
199 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
202 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
203 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
204 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
209 struct lm_sensor w83697hf_sensors[] = {
211 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
212 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
213 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
214 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
215 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
216 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
217 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
218 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
221 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
222 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
225 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
226 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
232 * The datasheet doesn't mention the (internal) resistors used for the
233 * +5V, but using the values from the W83782D datasheets seems to
234 * provide sensible results.
236 struct lm_sensor w83781d_sensors[] = {
238 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
239 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
240 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
241 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
242 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
243 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) },
244 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) },
247 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
248 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
249 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
252 { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
253 { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
254 { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
259 struct lm_sensor w83782d_sensors[] = {
261 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
262 { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
263 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
264 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
265 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
266 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
267 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
268 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
269 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
272 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
273 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
274 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
277 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
278 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
279 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
284 struct lm_sensor w83783s_sensors[] = {
286 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
287 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
288 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
289 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
290 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
291 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
294 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
295 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
298 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
299 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
300 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
305 struct lm_sensor w83791d_sensors[] = {
307 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
308 { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
309 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
310 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
311 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
312 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
313 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
314 { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
315 { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
316 { "VINR1", SENSOR_VOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE },
319 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
320 { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
321 { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
324 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
325 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
326 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
327 { "", SENSOR_FANRPM, 0, 0xba, wb_refresh_fanrpm },
328 { "", SENSOR_FANRPM, 0, 0xbb, wb_refresh_fanrpm },
333 struct lm_sensor w83792d_sensors[] = {
335 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
336 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
337 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
338 { "-5V", SENSOR_VOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) },
339 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
340 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
341 { "+5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) },
342 { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
343 { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
346 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
347 { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
348 { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
351 { "", SENSOR_FANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm },
352 { "", SENSOR_FANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm },
353 { "", SENSOR_FANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm },
354 { "", SENSOR_FANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm },
355 { "", SENSOR_FANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm },
356 { "", SENSOR_FANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm },
357 { "", SENSOR_FANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm },
362 struct lm_sensor as99127f_sensors[] = {
364 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
365 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
366 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
367 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
368 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
369 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
370 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
373 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
374 { "", SENSOR_TEMP, 1, 0x50, as_refresh_temp },
375 { "", SENSOR_TEMP, 2, 0x50, as_refresh_temp },
378 { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
379 { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
380 { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
386 lm_probe(struct lm_softc *sc)
390 for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
391 if (lm_chips[i].chip_match(sc))
396 lm_attach(struct lm_softc *sc)
400 /* No point in doing anything if we don't have any sensors. */
401 if (sc->numsensors == 0)
404 if (sensor_task_register(sc, lm_refresh, 5)) {
405 device_printf(sc->sc_dev, "unable to register update task\n");
409 /* Start the monitoring loop */
410 config = sc->lm_readreg(sc, LM_CONFIG);
411 sc->lm_writereg(sc, LM_CONFIG, config | 0x01);
414 strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev),
415 sizeof(sc->sensordev.xname));
416 for (i = 0; i < sc->numsensors; ++i)
417 sensor_attach(&sc->sensordev, &sc->sensors[i]);
418 sensordev_install(&sc->sensordev);
422 lm_detach(struct lm_softc *sc)
427 sensordev_deinstall(&sc->sensordev);
428 for (i = 0; i < sc->numsensors; i++)
429 sensor_detach(&sc->sensordev, &sc->sensors[i]);
431 sensor_task_unregister(sc);
437 lm_match(struct lm_softc *sc)
443 /* See if we have an LM78 or LM79. */
444 chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
449 case LM_CHIPID_LM78J:
461 ksnprintf(fulldesc, sizeof(fulldesc),
462 "National Semiconductor %s Hardware Monitor", cdesc);
463 device_set_desc_copy(sc->sc_dev, fulldesc);
465 lm_setup_sensors(sc, lm78_sensors);
466 sc->refresh_sensor_data = lm_refresh_sensor_data;
471 def_match(struct lm_softc *sc)
476 chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
477 ksnprintf(fulldesc, sizeof(fulldesc),
478 "unknown Hardware Monitor (ID 0x%x)", chipid);
479 device_set_desc_copy(sc->sc_dev, fulldesc);
481 lm_setup_sensors(sc, lm78_sensors);
482 sc->refresh_sensor_data = lm_refresh_sensor_data;
487 wb_match(struct lm_softc *sc)
489 int banksel, vendid, devid;
495 banksel = sc->lm_readreg(sc, WB_BANKSEL);
496 sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC);
497 vendid = sc->lm_readreg(sc, WB_VENDID) << 8;
498 sc->lm_writereg(sc, WB_BANKSEL, 0);
499 vendid |= sc->lm_readreg(sc, WB_VENDID);
500 sc->lm_writereg(sc, WB_BANKSEL, banksel);
501 DPRINTF((" winbond vend id 0x%x\n", vendid));
502 if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS)
505 /* Read device/chip ID */
506 sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
507 devid = sc->lm_readreg(sc, LM_CHIPID);
508 sc->chipid = sc->lm_readreg(sc, WB_BANK0_CHIPID);
509 sc->lm_writereg(sc, WB_BANKSEL, banksel);
510 DPRINTF((" winbond chip id 0x%x\n", sc->chipid));
512 case WB_CHIPID_W83627HF:
514 lm_setup_sensors(sc, w83627hf_sensors);
516 case WB_CHIPID_W83627THF:
518 lm_setup_sensors(sc, w83637hf_sensors);
520 case WB_CHIPID_W83627EHF:
522 lm_setup_sensors(sc, w83627ehf_sensors);
524 case WB_CHIPID_W83627DHG:
526 lm_setup_sensors(sc, w83627dhg_sensors);
528 case WB_CHIPID_W83637HF:
530 sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
531 if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
533 sc->lm_writereg(sc, WB_BANKSEL, banksel);
534 lm_setup_sensors(sc, w83637hf_sensors);
536 case WB_CHIPID_W83697HF:
538 lm_setup_sensors(sc, w83697hf_sensors);
540 case WB_CHIPID_W83781D:
541 case WB_CHIPID_W83781D_2:
543 lm_setup_sensors(sc, w83781d_sensors);
545 case WB_CHIPID_W83782D:
547 lm_setup_sensors(sc, w83782d_sensors);
549 case WB_CHIPID_W83783S:
551 lm_setup_sensors(sc, w83783s_sensors);
553 case WB_CHIPID_W83791D:
555 lm_setup_sensors(sc, w83791d_sensors);
557 case WB_CHIPID_W83791SD:
560 case WB_CHIPID_W83792D:
561 if (devid >= 0x10 && devid <= 0x29)
562 ksnprintf(desc, sizeof(desc),
563 "W83792D rev %c", 'A' + devid - 0x10);
565 ksnprintf(desc, sizeof(desc),
566 "W83792D rev 0x%x", devid);
568 lm_setup_sensors(sc, w83792d_sensors);
570 case WB_CHIPID_AS99127F:
571 if (vendid == WB_VENDID_ASUS) {
573 lm_setup_sensors(sc, w83781d_sensors);
575 cdesc = "AS99127F rev 2";
576 lm_setup_sensors(sc, as99127f_sensors);
580 ksnprintf(fulldesc, sizeof(fulldesc),
581 "unknown Winbond Hardware Monitor (Chip ID 0x%x)",
583 device_set_desc_copy(sc->sc_dev, fulldesc);
584 /* Handle as a standard LM78. */
585 lm_setup_sensors(sc, lm78_sensors);
586 sc->refresh_sensor_data = lm_refresh_sensor_data;
591 ksnprintf(fulldesc, sizeof(fulldesc),
592 "Winbond %s Hardware Monitor", cdesc);
594 ksnprintf(fulldesc, sizeof(fulldesc),
595 "ASUS %s Hardware Monitor", cdesc);
596 device_set_desc_copy(sc->sc_dev, fulldesc);
598 sc->refresh_sensor_data = wb_refresh_sensor_data;
603 lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors)
607 for (i = 0; sensors[i].desc; i++) {
608 sc->sensors[i].type = sensors[i].type;
609 strlcpy(sc->sensors[i].desc, sensors[i].desc,
610 sizeof(sc->sensors[i].desc));
613 sc->lm_sensors = sensors;
617 lm_refresh(void *arg)
619 struct lm_softc *sc = arg;
621 sc->refresh_sensor_data(sc);
625 lm_refresh_sensor_data(struct lm_softc *sc)
629 for (i = 0; i < sc->numsensors; i++)
630 sc->lm_sensors[i].refresh(sc, i);
634 lm_refresh_volt(struct lm_softc *sc, int n)
636 struct ksensor *sensor = &sc->sensors[n];
639 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
640 sensor->value = (data << 4);
641 sensor->value *= sc->lm_sensors[n].rfact;
646 lm_refresh_temp(struct lm_softc *sc, int n)
648 struct ksensor *sensor = &sc->sensors[n];
652 * The data sheet suggests that the range of the temperature
653 * sensor is between -55 degC and +125 degC.
655 sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
656 if (sdata > 0x7d && sdata < 0xc9) {
657 sensor->flags |= SENSOR_FINVALID;
662 sensor->flags &= ~SENSOR_FINVALID;
663 sensor->value = sdata * 1000000 + 273150000;
668 lm_refresh_fanrpm(struct lm_softc *sc, int n)
670 struct ksensor *sensor = &sc->sensors[n];
671 int data, divisor = 1;
674 * We might get more accurate fan readings by adjusting the
675 * divisor, but that might interfere with APM or other SMM
676 * BIOS code reading the fan speeds.
679 /* FAN3 has a fixed fan divisor. */
680 if (sc->lm_sensors[n].reg == LM_FAN1 ||
681 sc->lm_sensors[n].reg == LM_FAN2) {
682 data = sc->lm_readreg(sc, LM_VIDFAN);
683 if (sc->lm_sensors[n].reg == LM_FAN1)
684 divisor = (data >> 4) & 0x03;
686 divisor = (data >> 6) & 0x03;
689 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
690 if (data == 0xff || data == 0x00) {
691 sensor->flags |= SENSOR_FINVALID;
694 sensor->flags &= ~SENSOR_FINVALID;
695 sensor->value = 1350000 / (data << divisor);
700 wb_refresh_sensor_data(struct lm_softc *sc)
702 int banksel, bank, i;
705 * Properly save and restore bank selection register.
708 banksel = bank = sc->lm_readreg(sc, WB_BANKSEL);
709 for (i = 0; i < sc->numsensors; i++) {
710 if (bank != sc->lm_sensors[i].bank) {
711 bank = sc->lm_sensors[i].bank;
712 sc->lm_writereg(sc, WB_BANKSEL, bank);
714 sc->lm_sensors[i].refresh(sc, i);
716 sc->lm_writereg(sc, WB_BANKSEL, banksel);
720 wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
722 struct ksensor *sensor = &sc->sensors[n];
725 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
728 * Depending on the voltage detection method,
729 * one of the following formulas is used:
730 * VRM8 method: value = raw * 0.016V
731 * VRM9 method: value = raw * 0.00488V + 0.70V
734 sensor->value = (data * 4880) + 700000;
736 sensor->value = (data * 16000);
740 wb_refresh_nvolt(struct lm_softc *sc, int n)
742 struct ksensor *sensor = &sc->sensors[n];
745 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
746 sensor->value = ((data << 4) - WB_VREF);
747 sensor->value *= sc->lm_sensors[n].rfact;
749 sensor->value += WB_VREF * 1000;
753 wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n)
755 struct ksensor *sensor = &sc->sensors[n];
758 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
759 sensor->value = ((data << 3) - WB_W83627EHF_VREF);
760 sensor->value *= RFACT(232, 10);
762 sensor->value += WB_W83627EHF_VREF * 1000;
766 wb_refresh_temp(struct lm_softc *sc, int n)
768 struct ksensor *sensor = &sc->sensors[n];
772 * The data sheet suggests that the range of the temperature
773 * sensor is between -55 degC and +125 degC. However, values
774 * around -48 degC seem to be a very common bogus values.
775 * Since such values are unreasonably low, we use -45 degC for
776 * the lower limit instead.
778 sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
779 sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
780 if (sdata > 0x0fa && sdata < 0x1a6) {
781 sensor->flags |= SENSOR_FINVALID;
786 sensor->flags &= ~SENSOR_FINVALID;
787 sensor->value = sdata * 500000 + 273150000;
792 wb_refresh_fanrpm(struct lm_softc *sc, int n)
794 struct ksensor *sensor = &sc->sensors[n];
795 int fan, data, divisor = 0;
798 * This is madness; the fan divisor bits are scattered all
802 if (sc->lm_sensors[n].reg == LM_FAN1 ||
803 sc->lm_sensors[n].reg == LM_FAN2 ||
804 sc->lm_sensors[n].reg == LM_FAN3) {
805 data = sc->lm_readreg(sc, WB_BANK0_VBAT);
806 fan = (sc->lm_sensors[n].reg - LM_FAN1);
807 if ((data >> 5) & (1 << fan))
811 if (sc->lm_sensors[n].reg == LM_FAN1 ||
812 sc->lm_sensors[n].reg == LM_FAN2) {
813 data = sc->lm_readreg(sc, LM_VIDFAN);
814 if (sc->lm_sensors[n].reg == LM_FAN1)
815 divisor |= (data >> 4) & 0x03;
817 divisor |= (data >> 6) & 0x03;
818 } else if (sc->lm_sensors[n].reg == LM_FAN3) {
819 data = sc->lm_readreg(sc, WB_PIN);
820 divisor |= (data >> 6) & 0x03;
821 } else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 ||
822 sc->lm_sensors[n].reg == WB_BANK0_FAN5) {
823 data = sc->lm_readreg(sc, WB_BANK0_FAN45);
824 if (sc->lm_sensors[n].reg == WB_BANK0_FAN4)
825 divisor |= (data >> 0) & 0x07;
827 divisor |= (data >> 4) & 0x07;
830 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
831 if (data == 0xff || data == 0x00) {
832 sensor->flags |= SENSOR_FINVALID;
835 sensor->flags &= ~SENSOR_FINVALID;
836 sensor->value = 1350000 / (data << divisor);
841 wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n)
843 struct ksensor *sensor = &sc->sensors[n];
844 int reg, shift, data, divisor = 1;
846 switch (sc->lm_sensors[n].reg) {
848 reg = 0x47; shift = 0;
851 reg = 0x47; shift = 4;
854 reg = 0x5b; shift = 0;
857 reg = 0x5b; shift = 4;
860 reg = 0x5c; shift = 0;
863 reg = 0x5c; shift = 4;
866 reg = 0x9e; shift = 0;
873 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
874 if (data == 0xff || data == 0x00) {
875 sensor->flags |= SENSOR_FINVALID;
879 divisor = (sc->lm_readreg(sc, reg) >> shift) & 0x7;
880 sensor->flags &= ~SENSOR_FINVALID;
881 sensor->value = 1350000 / (data << divisor);
886 as_refresh_temp(struct lm_softc *sc, int n)
888 struct ksensor *sensor = &sc->sensors[n];
892 * It seems a shorted temperature diode produces an all-ones
895 sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
896 sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
897 if (sdata == 0x1ff) {
898 sensor->flags |= SENSOR_FINVALID;
903 sensor->flags &= ~SENSOR_FINVALID;
904 sensor->value = sdata * 500000 + 273150000;