xref: /openbsd-src/sys/dev/ic/lm78.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: lm78.c,v 1.20 2007/06/25 22:50:18 cnst Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006 Mark Kettenis
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/kernel.h>
23 #include <sys/queue.h>
24 #include <sys/sensors.h>
25 #include <machine/bus.h>
26 
27 #include <dev/ic/lm78var.h>
28 
29 #if defined(LMDEBUG)
30 #define DPRINTF(x)		do { printf x; } while (0)
31 #else
32 #define DPRINTF(x)
33 #endif
34 
35 /*
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.
41  */
42 #define RFACT_NONE	10000
43 #define RFACT(x, y)	(RFACT_NONE * ((x) + (y)) / (y))
44 #define NRFACT(x, y)	(-RFACT_NONE * (x) / (y))
45 
46 struct cfdriver lm_cd = {
47 	NULL, "lm", DV_DULL
48 };
49 
50 int  lm_match(struct lm_softc *);
51 int  wb_match(struct lm_softc *);
52 int  def_match(struct lm_softc *);
53 
54 void lm_setup_sensors(struct lm_softc *, struct lm_sensor *);
55 void lm_refresh(void *);
56 
57 void lm_refresh_sensor_data(struct lm_softc *);
58 void lm_refresh_volt(struct lm_softc *, int);
59 void lm_refresh_temp(struct lm_softc *, int);
60 void lm_refresh_fanrpm(struct lm_softc *, int);
61 
62 void wb_refresh_sensor_data(struct lm_softc *);
63 void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
64 void wb_refresh_nvolt(struct lm_softc *, int);
65 void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
66 void wb_refresh_temp(struct lm_softc *, int);
67 void wb_refresh_fanrpm(struct lm_softc *, int);
68 void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
69 
70 void as_refresh_temp(struct lm_softc *, int);
71 
72 struct lm_chip {
73 	int (*chip_match)(struct lm_softc *);
74 };
75 
76 struct lm_chip lm_chips[] = {
77 	{ wb_match },
78 	{ lm_match },
79 	{ def_match } /* Must be last */
80 };
81 
82 struct lm_sensor lm78_sensors[] = {
83 	/* Voltage */
84 	{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
85 	{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
86 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
87 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) },
88 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) },
89 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) },
90 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) },
91 
92 	/* Temperature */
93 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
94 
95 	/* Fans */
96 	{ "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
97 	{ "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
98 	{ "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
99 
100 	{ NULL }
101 };
102 
103 struct lm_sensor w83627hf_sensors[] = {
104 	/* Voltage */
105 	{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
106 	{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
107 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
108 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
109 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
110 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
111 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
112 	{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
113 	{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
114 
115 	/* Temperature */
116 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
117 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
118 	{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
119 
120 	/* Fans */
121 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
122 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
123 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
124 
125 	{ NULL }
126 };
127 
128 /*
129  * The W83627EHF can measure voltages up to 2.048 V instead of the
130  * traditional 4.096 V.  For measuring positive voltages, this can be
131  * accounted for by halving the resistor factor.  Negative voltages
132  * need special treatment, also because the reference voltage is 2.048 V
133  * instead of the traditional 3.6 V.
134  */
135 struct lm_sensor w83627ehf_sensors[] = {
136 	/* Voltage */
137 	{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
138 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
139 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
140 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
141 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
142 	{ "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
143 	{ "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
144 	{ "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
145 	{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
146 	{ "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
147 
148 	/* Temperature */
149 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
150 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
151 	{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
152 
153 	/* Fans */
154 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
155 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
156 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
157 
158 	{ NULL }
159 };
160 
161 /*
162  * w83627dhg is almost identical to w83627ehf, except that
163  * it has 9 instead of 10 voltage sensors
164  */
165 struct lm_sensor w83627dhg_sensors[] = {
166 	/* Voltage */
167 	{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
168 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
169 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
170 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 },
171 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
172 	{ "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
173 	{ "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
174 	{ "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
175 	{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
176 
177 	/* Temperature */
178 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
179 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
180 	{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
181 
182 	/* Fans */
183 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
184 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
185 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
186 
187 	{ NULL }
188 };
189 
190 struct lm_sensor w83637hf_sensors[] = {
191 	/* Voltage */
192 	{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore },
193 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
194 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
195 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
196 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
197 	{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
198 	{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
199 
200 	/* Temperature */
201 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
202 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
203 	{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
204 
205 	/* Fans */
206 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
207 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
208 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
209 
210 	{ NULL }
211 };
212 
213 struct lm_sensor w83697hf_sensors[] = {
214 	/* Voltage */
215 	{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
216 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
217 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
218 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
219 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
220 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
221 	{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
222 	{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
223 
224 	/* Temperature */
225 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
226 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
227 
228 	/* Fans */
229 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
230 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
231 
232 	{ NULL }
233 };
234 
235 /*
236  * The datasheet doesn't mention the (internal) resistors used for the
237  * +5V, but using the values from the W83782D datasheets seems to
238  * provide sensible results.
239  */
240 struct lm_sensor w83781d_sensors[] = {
241 	/* Voltage */
242 	{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
243 	{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
244 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
245 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
246 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
247 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) },
248 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) },
249 
250 	/* Temperature */
251 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
252 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
253 	{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
254 
255 	/* Fans */
256 	{ "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
257 	{ "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
258 	{ "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
259 
260 	{ NULL }
261 };
262 
263 struct lm_sensor w83782d_sensors[] = {
264 	/* Voltage */
265 	{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
266 	{ "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
267 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
268 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
269 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
270 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
271 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
272 	{ "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
273 	{ "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
274 
275 	/* Temperature */
276 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
277 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
278 	{ "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
279 
280 	/* Fans */
281 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
282 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
283 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
284 
285 	{ NULL }
286 };
287 
288 struct lm_sensor w83783s_sensors[] = {
289 	/* Voltage */
290 	{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
291 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
292 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
293 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
294 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
295 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
296 
297 	/* Temperature */
298 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
299 	{ "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
300 
301 	/* Fans */
302 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
303 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
304 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
305 
306 	{ NULL }
307 };
308 
309 struct lm_sensor w83791d_sensors[] = {
310 	/* Voltage */
311 	{ "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, 10000 },
312 	{ "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, 10000 },
313 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, 10000 },
314 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
315 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
316 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
317 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
318 	{ "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
319 	{ "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
320 	{ "VINR1", SENSOR_VOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE },
321 
322 	/* Temperature */
323 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
324 	{ "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
325 	{ "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
326 
327 	/* Fans */
328 	{ "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
329 	{ "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
330 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
331 	{ "", SENSOR_FANRPM, 0, 0xba, wb_refresh_fanrpm },
332 	{ "", SENSOR_FANRPM, 0, 0xbb, wb_refresh_fanrpm },
333 
334 	{ NULL }
335 };
336 
337 struct lm_sensor w83792d_sensors[] = {
338 	/* Voltage */
339 	{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
340 	{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
341 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
342 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) },
343 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
344 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
345 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) },
346 	{ "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
347 	{ "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
348 
349 	/* Temperature */
350 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
351 	{ "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp },
352 	{ "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp },
353 
354 	/* Fans */
355 	{ "", SENSOR_FANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm },
356 	{ "", SENSOR_FANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm },
357 	{ "", SENSOR_FANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm },
358 	{ "", SENSOR_FANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm },
359 	{ "", SENSOR_FANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm },
360 	{ "", SENSOR_FANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm },
361 	{ "", SENSOR_FANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm },
362 
363 	{ NULL }
364 };
365 
366 struct lm_sensor as99127f_sensors[] = {
367 	/* Voltage */
368 	{ "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
369 	{ "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
370 	{ "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
371 	{ "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
372 	{ "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
373 	{ "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
374 	{ "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
375 
376 	/* Temperature */
377 	{ "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
378 	{ "", SENSOR_TEMP, 1, 0x50, as_refresh_temp },
379 	{ "", SENSOR_TEMP, 2, 0x50, as_refresh_temp },
380 
381 	/* Fans */
382 	{ "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
383 	{ "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
384 	{ "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
385 
386 	{ NULL }
387 };
388 
389 void
390 lm_attach(struct lm_softc *sc)
391 {
392 	u_int i, config;
393 
394 	for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
395 		if (lm_chips[i].chip_match(sc))
396 			break;
397 
398 	/* No point in doing anything if we don't have any sensors. */
399 	if (sc->numsensors == 0)
400 		return;
401 
402 	sc->sensortask = sensor_task_register(sc, lm_refresh, 5);
403 	if (sc->sensortask == NULL) {
404 		printf("%s: unable to register update task\n",
405 		    sc->sc_dev.dv_xname);
406 		return;
407 	}
408 
409 	/* Start the monitoring loop */
410 	config = sc->lm_readreg(sc, LM_CONFIG);
411 	sc->lm_writereg(sc, LM_CONFIG, config | 0x01);
412 
413 	/* Add sensors */
414 	for (i = 0; i < sc->numsensors; ++i)
415 		sensor_attach(&sc->sensordev, &sc->sensors[i]);
416 	sensordev_install(&sc->sensordev);
417 }
418 
419 int
420 lm_detach(struct lm_softc *sc)
421 {
422 	int i;
423 
424 	/* Remove sensors */
425 	sensordev_deinstall(&sc->sensordev);
426 	for (i = 0; i < sc->numsensors; i++)
427 		sensor_detach(&sc->sensordev, &sc->sensors[i]);
428 
429 	if (sc->sensortask != NULL)
430 		sensor_task_unregister(sc->sensortask);
431 
432 	return 0;
433 }
434 
435 int
436 lm_match(struct lm_softc *sc)
437 {
438 	int chipid;
439 
440 	/* See if we have an LM78 or LM79. */
441 	chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
442 	switch(chipid) {
443 	case LM_CHIPID_LM78:
444 		printf(": LM78\n");
445 		break;
446 	case LM_CHIPID_LM78J:
447 		printf(": LM78J\n");
448 		break;
449 	case LM_CHIPID_LM79:
450 		printf(": LM79\n");
451 		break;
452 	case LM_CHIPID_LM81:
453 		printf(": LM81\n");
454 		break;
455 	default:
456 		return 0;
457 	}
458 
459 	lm_setup_sensors(sc, lm78_sensors);
460 	sc->refresh_sensor_data = lm_refresh_sensor_data;
461 	return 1;
462 }
463 
464 int
465 def_match(struct lm_softc *sc)
466 {
467 	int chipid;
468 
469 	chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK;
470 	printf(": unknown chip (ID %d)\n", chipid);
471 
472 	lm_setup_sensors(sc, lm78_sensors);
473 	sc->refresh_sensor_data = lm_refresh_sensor_data;
474 	return 1;
475 }
476 
477 int
478 wb_match(struct lm_softc *sc)
479 {
480 	int banksel, vendid, devid;
481 
482 	/* Read vendor ID */
483 	banksel = sc->lm_readreg(sc, WB_BANKSEL);
484 	sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC);
485 	vendid = sc->lm_readreg(sc, WB_VENDID) << 8;
486 	sc->lm_writereg(sc, WB_BANKSEL, 0);
487 	vendid |= sc->lm_readreg(sc, WB_VENDID);
488 	sc->lm_writereg(sc, WB_BANKSEL, banksel);
489 	DPRINTF((" winbond vend id 0x%x\n", vendid));
490 	if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS)
491 		return 0;
492 
493 	/* Read device/chip ID */
494 	sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
495 	devid = sc->lm_readreg(sc, LM_CHIPID);
496 	sc->chipid = sc->lm_readreg(sc, WB_BANK0_CHIPID);
497 	sc->lm_writereg(sc, WB_BANKSEL, banksel);
498 	DPRINTF((" winbond chip id 0x%x\n", sc->chipid));
499 	switch(sc->chipid) {
500 	case WB_CHIPID_W83627HF:
501 		printf(": W83627HF\n");
502 		lm_setup_sensors(sc, w83627hf_sensors);
503 		break;
504 	case WB_CHIPID_W83627THF:
505 		printf(": W83627THF\n");
506 		lm_setup_sensors(sc, w83637hf_sensors);
507 		break;
508 	case WB_CHIPID_W83627EHF_A:
509 		printf(": W83627EHF-A\n");
510 		lm_setup_sensors(sc, w83627ehf_sensors);
511 		break;
512 	case WB_CHIPID_W83627EHF:
513 		printf(": W83627EHF\n");
514 		lm_setup_sensors(sc, w83627ehf_sensors);
515 		break;
516 	case WB_CHIPID_W83627DHG:
517 		printf(": W83627DHG\n");
518 		lm_setup_sensors(sc, w83627dhg_sensors);
519 		break;
520 	case WB_CHIPID_W83637HF:
521 		printf(": W83637HF\n");
522 		sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
523 		if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
524 			sc->vrm9 = 1;
525 		sc->lm_writereg(sc, WB_BANKSEL, banksel);
526 		lm_setup_sensors(sc, w83637hf_sensors);
527 		break;
528 	case WB_CHIPID_W83697HF:
529 		printf(": W83697HF\n");
530 		lm_setup_sensors(sc, w83697hf_sensors);
531 		break;
532 	case WB_CHIPID_W83781D:
533 	case WB_CHIPID_W83781D_2:
534 		printf(": W83781D\n");
535 		lm_setup_sensors(sc, w83781d_sensors);
536 		break;
537 	case WB_CHIPID_W83782D:
538 		printf(": W83782D\n");
539 		lm_setup_sensors(sc, w83782d_sensors);
540 		break;
541 	case WB_CHIPID_W83783S:
542 		printf(": W83783S\n");
543 		lm_setup_sensors(sc, w83783s_sensors);
544 		break;
545 	case WB_CHIPID_W83791D:
546 		printf(": W83791D\n");
547 		lm_setup_sensors(sc, w83791d_sensors);
548 		break;
549 	case WB_CHIPID_W83791SD:
550 		printf(": W83791SD\n");
551 		break;
552 	case WB_CHIPID_W83792D:
553 		if (devid >= 0x10 && devid <= 0x29)
554 			printf(": W83792D rev %c\n", 'A' + devid - 0x10);
555 		else
556 			printf(": W83792D rev 0x%x\n", devid);
557 		lm_setup_sensors(sc, w83792d_sensors);
558 		break;
559 	case WB_CHIPID_AS99127F:
560 		if (vendid == WB_VENDID_ASUS) {
561 			printf(": AS99127F\n");
562 			lm_setup_sensors(sc, w83781d_sensors);
563 		} else {
564 			printf(": AS99127F rev 2\n");
565 			lm_setup_sensors(sc, as99127f_sensors);
566 		}
567 		break;
568 	default:
569 		printf(": unknown Winbond chip (ID 0x%x)\n", sc->chipid);
570 		/* Handle as a standard LM78. */
571 		lm_setup_sensors(sc, lm78_sensors);
572 		sc->refresh_sensor_data = lm_refresh_sensor_data;
573 		return 1;
574 	}
575 
576 	sc->refresh_sensor_data = wb_refresh_sensor_data;
577 	return 1;
578 }
579 
580 void
581 lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors)
582 {
583 	int i;
584 
585 	strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
586 	    sizeof(sc->sensordev.xname));
587 
588 	for (i = 0; sensors[i].desc; i++) {
589 		sc->sensors[i].type = sensors[i].type;
590 		strlcpy(sc->sensors[i].desc, sensors[i].desc,
591 		    sizeof(sc->sensors[i].desc));
592 		sc->numsensors++;
593 	}
594 	sc->lm_sensors = sensors;
595 }
596 
597 void
598 lm_refresh(void *arg)
599 {
600 	struct lm_softc *sc = arg;
601 
602 	sc->refresh_sensor_data(sc);
603 }
604 
605 void
606 lm_refresh_sensor_data(struct lm_softc *sc)
607 {
608 	int i;
609 
610 	for (i = 0; i < sc->numsensors; i++)
611 		sc->lm_sensors[i].refresh(sc, i);
612 }
613 
614 void
615 lm_refresh_volt(struct lm_softc *sc, int n)
616 {
617 	struct ksensor *sensor = &sc->sensors[n];
618 	int data;
619 
620 	data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
621 	sensor->value = (data << 4);
622 	sensor->value *= sc->lm_sensors[n].rfact;
623 	sensor->value /= 10;
624 }
625 
626 void
627 lm_refresh_temp(struct lm_softc *sc, int n)
628 {
629 	struct ksensor *sensor = &sc->sensors[n];
630 	int sdata;
631 
632 	/*
633 	 * The data sheet suggests that the range of the temperature
634 	 * sensor is between -55 degC and +125 degC.
635 	 */
636 	sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
637 	if (sdata > 0x7d && sdata < 0xc9) {
638 		sensor->flags |= SENSOR_FINVALID;
639 		sensor->value = 0;
640 	} else {
641 		if (sdata & 0x80)
642 			sdata -= 0x100;
643 		sensor->flags &= ~SENSOR_FINVALID;
644 		sensor->value = sdata * 1000000 + 273150000;
645 	}
646 }
647 
648 void
649 lm_refresh_fanrpm(struct lm_softc *sc, int n)
650 {
651 	struct ksensor *sensor = &sc->sensors[n];
652 	int data, divisor = 1;
653 
654 	/*
655 	 * We might get more accurate fan readings by adjusting the
656 	 * divisor, but that might interfere with APM or other SMM
657 	 * BIOS code reading the fan speeds.
658 	 */
659 
660 	/* FAN3 has a fixed fan divisor. */
661 	if (sc->lm_sensors[n].reg == LM_FAN1 ||
662 	    sc->lm_sensors[n].reg == LM_FAN2) {
663 		data = sc->lm_readreg(sc, LM_VIDFAN);
664 		if (sc->lm_sensors[n].reg == LM_FAN1)
665 			divisor = (data >> 4) & 0x03;
666 		else
667 			divisor = (data >> 6) & 0x03;
668 	}
669 
670 	data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
671 	if (data == 0xff || data == 0x00) {
672 		sensor->flags |= SENSOR_FINVALID;
673 		sensor->value = 0;
674 	} else {
675 		sensor->flags &= ~SENSOR_FINVALID;
676 		sensor->value = 1350000 / (data << divisor);
677 	}
678 }
679 
680 void
681 wb_refresh_sensor_data(struct lm_softc *sc)
682 {
683 	int banksel, bank, i;
684 
685 	/*
686 	 * Properly save and restore bank selection register.
687 	 */
688 
689 	banksel = bank = sc->lm_readreg(sc, WB_BANKSEL);
690 	for (i = 0; i < sc->numsensors; i++) {
691 		if (bank != sc->lm_sensors[i].bank) {
692 			bank = sc->lm_sensors[i].bank;
693 			sc->lm_writereg(sc, WB_BANKSEL, bank);
694 		}
695 		sc->lm_sensors[i].refresh(sc, i);
696 	}
697 	sc->lm_writereg(sc, WB_BANKSEL, banksel);
698 }
699 
700 void
701 wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
702 {
703 	struct ksensor *sensor = &sc->sensors[n];
704 	int data;
705 
706 	data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
707 
708 	/*
709 	 * Depending on the voltage detection method,
710 	 * one of the following formulas is used:
711 	 *	VRM8 method: value = raw * 0.016V
712 	 *	VRM9 method: value = raw * 0.00488V + 0.70V
713 	 */
714 	if (sc->vrm9)
715 		sensor->value = (data * 4880) + 700000;
716 	else
717 		sensor->value = (data * 16000);
718 }
719 
720 void
721 wb_refresh_nvolt(struct lm_softc *sc, int n)
722 {
723 	struct ksensor *sensor = &sc->sensors[n];
724 	int data;
725 
726 	data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
727 	sensor->value = ((data << 4) - WB_VREF);
728 	sensor->value *= sc->lm_sensors[n].rfact;
729 	sensor->value /= 10;
730 	sensor->value += WB_VREF * 1000;
731 }
732 
733 void
734 wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n)
735 {
736 	struct ksensor *sensor = &sc->sensors[n];
737 	int data;
738 
739 	data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
740 	sensor->value = ((data << 3) - WB_W83627EHF_VREF);
741 	sensor->value *= RFACT(232, 10);
742 	sensor->value /= 10;
743 	sensor->value += WB_W83627EHF_VREF * 1000;
744 }
745 
746 void
747 wb_refresh_temp(struct lm_softc *sc, int n)
748 {
749 	struct ksensor *sensor = &sc->sensors[n];
750 	int sdata;
751 
752 	/*
753 	 * The data sheet suggests that the range of the temperature
754 	 * sensor is between -55 degC and +125 degC.  However, values
755 	 * around -48 degC seem to be a very common bogus values.
756 	 * Since such values are unreasonably low, we use -45 degC for
757 	 * the lower limit instead.
758 	 */
759 	sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
760 	sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
761 	if (sdata > 0x0fa && sdata < 0x1a6) {
762 		sensor->flags |= SENSOR_FINVALID;
763 		sensor->value = 0;
764 	} else {
765 		if (sdata & 0x100)
766 			sdata -= 0x200;
767 		sensor->flags &= ~SENSOR_FINVALID;
768 		sensor->value = sdata * 500000 + 273150000;
769 	}
770 }
771 
772 void
773 wb_refresh_fanrpm(struct lm_softc *sc, int n)
774 {
775 	struct ksensor *sensor = &sc->sensors[n];
776 	int fan, data, divisor = 0;
777 
778 	/*
779 	 * This is madness; the fan divisor bits are scattered all
780 	 * over the place.
781 	 */
782 
783 	if (sc->lm_sensors[n].reg == LM_FAN1 ||
784 	    sc->lm_sensors[n].reg == LM_FAN2 ||
785 	    sc->lm_sensors[n].reg == LM_FAN3) {
786 		data = sc->lm_readreg(sc, WB_BANK0_VBAT);
787 		fan = (sc->lm_sensors[n].reg - LM_FAN1);
788 		if ((data >> 5) & (1 << fan))
789 			divisor |= 0x04;
790 	}
791 
792 	if (sc->lm_sensors[n].reg == LM_FAN1 ||
793 	    sc->lm_sensors[n].reg == LM_FAN2) {
794 		data = sc->lm_readreg(sc, LM_VIDFAN);
795 		if (sc->lm_sensors[n].reg == LM_FAN1)
796 			divisor |= (data >> 4) & 0x03;
797 		else
798 			divisor |= (data >> 6) & 0x03;
799 	} else if (sc->lm_sensors[n].reg == LM_FAN3) {
800 		data = sc->lm_readreg(sc, WB_PIN);
801 		divisor |= (data >> 6) & 0x03;
802 	} else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 ||
803 		   sc->lm_sensors[n].reg == WB_BANK0_FAN5) {
804 		data = sc->lm_readreg(sc, WB_BANK0_FAN45);
805 		if (sc->lm_sensors[n].reg == WB_BANK0_FAN4)
806 			divisor |= (data >> 0) & 0x07;
807 		else
808 			divisor |= (data >> 4) & 0x07;
809 	}
810 
811 	data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
812 	if (data == 0xff || data == 0x00) {
813 		sensor->flags |= SENSOR_FINVALID;
814 		sensor->value = 0;
815 	} else {
816 		sensor->flags &= ~SENSOR_FINVALID;
817 		sensor->value = 1350000 / (data << divisor);
818 	}
819 }
820 
821 void
822 wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n)
823 {
824 	struct ksensor *sensor = &sc->sensors[n];
825 	int reg, shift, data, divisor = 1;
826 
827 	switch (sc->lm_sensors[n].reg) {
828 	case 0x28:
829 		reg = 0x47; shift = 0;
830 		break;
831 	case 0x29:
832 		reg = 0x47; shift = 4;
833 		break;
834 	case 0x2a:
835 		reg = 0x5b; shift = 0;
836 		break;
837 	case 0xb8:
838 		reg = 0x5b; shift = 4;
839 		break;
840 	case 0xb9:
841 		reg = 0x5c; shift = 0;
842 		break;
843 	case 0xba:
844 		reg = 0x5c; shift = 4;
845 		break;
846 	case 0xbe:
847 		reg = 0x9e; shift = 0;
848 		break;
849 	default:
850 		reg = 0;
851 		break;
852 	}
853 
854 	data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
855 	if (data == 0xff || data == 0x00) {
856 		sensor->flags |= SENSOR_FINVALID;
857 		sensor->value = 0;
858 	} else {
859 		if (reg != 0)
860 			divisor = (sc->lm_readreg(sc, reg) >> shift) & 0x7;
861 		sensor->flags &= ~SENSOR_FINVALID;
862 		sensor->value = 1350000 / (data << divisor);
863 	}
864 }
865 
866 void
867 as_refresh_temp(struct lm_softc *sc, int n)
868 {
869 	struct ksensor *sensor = &sc->sensors[n];
870 	int sdata;
871 
872 	/*
873 	 * It seems a shorted temperature diode produces an all-ones
874 	 * bit pattern.
875 	 */
876 	sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1;
877 	sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7;
878 	if (sdata == 0x1ff) {
879 		sensor->flags |= SENSOR_FINVALID;
880 		sensor->value = 0;
881 	} else {
882 		if (sdata & 0x100)
883 			sdata -= 0x200;
884 		sensor->flags &= ~SENSOR_FINVALID;
885 		sensor->value = sdata * 500000 + 273150000;
886 	}
887 }
888