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