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