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