nslm7x.c revision 1.32 1 /* $NetBSD: nslm7x.c,v 1.32 2007/03/11 22:25:48 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Bill Squier.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: nslm7x.c,v 1.32 2007/03/11 22:25:48 christos Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/device.h>
47 #include <sys/conf.h>
48 #include <sys/time.h>
49
50 #include <machine/bus.h>
51
52 #include <dev/isa/isareg.h>
53 #include <dev/isa/isavar.h>
54
55 #include <dev/sysmon/sysmonvar.h>
56
57 #include <dev/ic/nslm7xvar.h>
58
59 #include <machine/intr.h>
60
61 #if defined(LMDEBUG)
62 #define DPRINTF(x) do { printf x; } while (0)
63 #else
64 #define DPRINTF(x)
65 #endif
66
67 /*
68 * LM78-compatible chips can typically measure voltages up to 4.096 V.
69 * To measure higher voltages the input is attenuated with (external)
70 * resistors. Negative voltages are measured using inverting op amps
71 * and resistors. So we have to convert the sensor values back to
72 * real voltages by applying the appropriate resistor factor.
73 */
74 #define RFACT_NONE 10000
75 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
76 #define NRFACT(x, y) (-RFACT_NONE * (x) / (y))
77
78 const struct envsys_range lm_ranges[] = { /* sc->sensors sub-intervals */
79 /* for each unit type */
80 { 7, 7, ENVSYS_STEMP },
81 { 8, 10, ENVSYS_SFANRPM },
82 { 1, 0, ENVSYS_SVOLTS_AC }, /* None */
83 { 0, 6, ENVSYS_SVOLTS_DC },
84 { 1, 0, ENVSYS_SOHMS }, /* None */
85 { 1, 0, ENVSYS_SWATTS }, /* None */
86 { 1, 0, ENVSYS_SAMPS } /* None */
87 };
88
89 static int lm_match(struct lm_softc *);
90 static int wb_match(struct lm_softc *);
91 static int def_match(struct lm_softc *);
92
93 static void lm_generic_banksel(struct lm_softc *, int);
94 static void lm_setup_sensors(struct lm_softc *, struct lm_sensor *);
95
96 static void lm_refresh_sensor_data(struct lm_softc *);
97 static void lm_refresh_volt(struct lm_softc *, int);
98 static void lm_refresh_temp(struct lm_softc *, int);
99 static void lm_refresh_fanrpm(struct lm_softc *, int);
100
101 static void wb_refresh_sensor_data(struct lm_softc *);
102 static void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
103 static void wb_refresh_nvolt(struct lm_softc *, int);
104 static void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
105 static void wb_refresh_temp(struct lm_softc *, int);
106 static void wb_refresh_fanrpm(struct lm_softc *, int);
107 static void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
108
109 static void as_refresh_temp(struct lm_softc *, int);
110
111 static int lm_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
112 static int generic_streinfo_fan(struct lm_softc *, struct envsys_basic_info *,
113 int, struct envsys_basic_info *);
114 static int lm_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
115 static int wb781_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
116 static int wb782_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
117
118 struct lm_chip {
119 int (*chip_match)(struct lm_softc *);
120 };
121
122 static struct lm_chip lm_chips[] = {
123 { wb_match },
124 { lm_match },
125 { def_match } /* Must be last */
126 };
127
128 static struct lm_sensor lm78_sensors[] = {
129 /* Voltage */
130 { "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
131 { "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
132 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
133 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) },
134 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) },
135 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) },
136 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) },
137
138 /* Temperature */
139 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
140
141 /* Fans */
142 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, lm_refresh_fanrpm, 0 },
143 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, lm_refresh_fanrpm, 0 },
144 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, lm_refresh_fanrpm, 0 },
145
146 { .desc = NULL }
147 };
148
149 static struct lm_sensor w83627hf_sensors[] = {
150 /* Voltage */
151 { "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
152 { "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
153 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
154 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
155 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
156 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
157 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
158 { "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
159 { "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
160
161 /* Temperature */
162 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
163 { "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
164 { "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
165
166 /* Fans */
167 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
168 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
169 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
170
171 { .desc = NULL }
172 };
173
174 /*
175 * The W83627EHF can measure voltages up to 2.048 V instead of the
176 * traditional 4.096 V. For measuring positive voltages, this can be
177 * accounted for by halving the resistor factor. Negative voltages
178 * need special treatment, also because the reference voltage is 2.048 V
179 * instead of the traditional 3.6 V.
180 */
181 static struct lm_sensor w83627ehf_sensors[] = {
182 /* Voltage */
183 { "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
184 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 },
185 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 },
186 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 24) / 2 },
187 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt, 0 },
188 { "Unknown", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
189 { "Unknown", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
190 { "3.3VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 },
191 { "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
192 { "Unknown", ENVSYS_SVOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
193
194 /* Temperature */
195 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
196 { "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
197 { "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
198
199 /* Fans */
200 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
201 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
202 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
203
204 { .desc = NULL }
205 };
206
207 static struct lm_sensor w83627dhg_sensors[] = {
208 /* Voltage */
209 { "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE/2 },
210 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56,10)/2 },
211 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
212 { "AVCC", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT_NONE },
213 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT(32, 56) },
214 /*
215 * I'm not sure about which one is -12V or -5V.
216 */
217 #if 0
218 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 60) },
219 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_w83627ehf_refresh_nvolt },
220 #endif
221 { "+3.3VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT_NONE },
222 { "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
223
224 /* Temperature */
225 { "System Temp", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
226 { "CPU Temp", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
227 { "Aux Temp", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
228
229 /* Fans */
230 { "System Fan", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
231 { "CPU Fan", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
232 { "Aux Fan", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
233
234 { .desc = NULL }
235 };
236
237 static struct lm_sensor w83637hf_sensors[] = {
238 /* Voltage */
239 { "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore, 0 },
240 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
241 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
242 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
243 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
244 { "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
245 { "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
246
247 /* Temperature */
248 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
249 { "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
250 { "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
251
252 /* Fans */
253 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
254 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
255 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
256
257 { .desc = NULL }
258 };
259
260 static struct lm_sensor w83697hf_sensors[] = {
261 /* Voltage */
262 { "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
263 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
264 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
265 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
266 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
267 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
268 { "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
269 { "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
270
271 /* Temperature */
272 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
273 { "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
274
275 /* Fans */
276 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
277 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
278
279 { .desc = NULL }
280 };
281
282 /*
283 * The datasheet doesn't mention the (internal) resistors used for the
284 * +5V, but using the values from the W83782D datasheets seems to
285 * provide sensible results.
286 */
287 static struct lm_sensor w83781d_sensors[] = {
288 /* Voltage */
289 { "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
290 { "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
291 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
292 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
293 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
294 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) },
295 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) },
296
297 /* Temperature */
298 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
299 { "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
300 { "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
301
302 /* Fans */
303 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, lm_refresh_fanrpm, 0 },
304 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, lm_refresh_fanrpm, 0 },
305 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, lm_refresh_fanrpm, 0 },
306
307 { .desc = NULL }
308 };
309
310 static struct lm_sensor w83782d_sensors[] = {
311 /* Voltage */
312 { "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
313 { "VINR0", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
314 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
315 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
316 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
317 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
318 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
319 { "5VSB", ENVSYS_SVOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) },
320 { "VBAT", ENVSYS_SVOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
321
322 /* Temperature */
323 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
324 { "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
325 { "Temp2", ENVSYS_STEMP, 2, 0x50, wb_refresh_temp, 0 },
326
327 /* Fans */
328 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
329 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
330 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
331
332 { .desc = NULL }
333 };
334
335 static struct lm_sensor w83783s_sensors[] = {
336 /* Voltage */
337 { "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
338 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
339 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
340 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
341 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
342 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
343
344 /* Temperature */
345 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
346 { "Temp1", ENVSYS_STEMP, 1, 0x50, wb_refresh_temp, 0 },
347
348 /* Fans */
349 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
350 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
351 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
352
353 { .desc = NULL }
354 };
355
356 static struct lm_sensor w83791d_sensors[] = {
357 /* Voltage */
358 { "VCore", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, 10000 },
359 { "VINR0", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, 10000 },
360 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, 10000 },
361 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
362 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
363 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
364 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
365 { "5VSB", ENVSYS_SVOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
366 { "VBAT", ENVSYS_SVOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
367 { "VINR1", ENVSYS_SVOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE },
368
369 /* Temperature */
370 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
371 { "Temp1", ENVSYS_STEMP, 0, 0xc0, wb_refresh_temp, 0 },
372 { "Temp2", ENVSYS_STEMP, 0, 0xc8, wb_refresh_temp, 0 },
373
374 /* Fans */
375 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_refresh_fanrpm, 0 },
376 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_refresh_fanrpm, 0 },
377 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_refresh_fanrpm, 0 },
378 { "Fan3", ENVSYS_SFANRPM, 0, 0xba, wb_refresh_fanrpm, 0 },
379 { "Fan4", ENVSYS_SFANRPM, 0, 0xbb, wb_refresh_fanrpm, 0 },
380
381 { .desc = NULL }
382 };
383
384 static struct lm_sensor w83792d_sensors[] = {
385 /* Voltage */
386 { "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
387 { "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
388 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
389 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) },
390 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
391 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
392 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) },
393 { "5VSB", ENVSYS_SVOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) },
394 { "VBAT", ENVSYS_SVOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE },
395
396 /* Temperature */
397 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
398 { "Temp1", ENVSYS_STEMP, 0, 0xc0, wb_refresh_temp, 0 },
399 { "Temp2", ENVSYS_STEMP, 0, 0xc8, wb_refresh_temp, 0 },
400
401 /* Fans */
402 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm, 0 },
403 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm, 0 },
404 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm, 0 },
405 { "Fan3", ENVSYS_SFANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm, 0 },
406 { "Fan4", ENVSYS_SFANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm, 0 },
407 { "Fan5", ENVSYS_SFANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm, 0 },
408 { "Fan6", ENVSYS_SFANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm, 0 },
409
410 { .desc = NULL }
411 };
412
413 static struct lm_sensor as99127f_sensors[] = {
414 /* Voltage */
415 { "VCore A", ENVSYS_SVOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
416 { "VCore B", ENVSYS_SVOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
417 { "+3.3V", ENVSYS_SVOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
418 { "+5V", ENVSYS_SVOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
419 { "+12V", ENVSYS_SVOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
420 { "-12V", ENVSYS_SVOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
421 { "-5V", ENVSYS_SVOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
422
423 /* Temperature */
424 { "Temp0", ENVSYS_STEMP, 0, 0x27, lm_refresh_temp, 0 },
425 { "Temp1", ENVSYS_STEMP, 1, 0x50, as_refresh_temp, 0 },
426 { "Temp2", ENVSYS_STEMP, 2, 0x50, as_refresh_temp, 0 },
427
428 /* Fans */
429 { "Fan0", ENVSYS_SFANRPM, 0, 0x28, lm_refresh_fanrpm, 0 },
430 { "Fan1", ENVSYS_SFANRPM, 0, 0x29, lm_refresh_fanrpm, 0 },
431 { "Fan2", ENVSYS_SFANRPM, 0, 0x2a, lm_refresh_fanrpm, 0 },
432
433 { .desc = NULL }
434 };
435
436 static void
437 lm_generic_banksel(struct lm_softc *lmsc, int bank)
438 {
439 (*lmsc->lm_writereg)(lmsc, WB_BANKSEL, bank);
440 }
441
442 /*
443 * bus independent probe
444 */
445 int
446 lm_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
447 {
448 uint8_t cr;
449 int rv;
450
451 /* Check for some power-on defaults */
452 bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
453
454 /* Perform LM78 reset */
455 bus_space_write_1(iot, ioh, LMC_DATA, 0x80);
456
457 /* XXX - Why do I have to reselect the register? */
458 bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
459 cr = bus_space_read_1(iot, ioh, LMC_DATA);
460
461 /* XXX - spec says *only* 0x08! */
462 if ((cr == 0x08) || (cr == 0x01) || (cr == 0x03))
463 rv = 1;
464 else
465 rv = 0;
466
467 DPRINTF(("lm: rv = %d, cr = %x\n", rv, cr));
468
469 return rv;
470 }
471
472
473 /*
474 * pre: lmsc contains valid busspace tag and handle
475 */
476 void
477 lm_attach(struct lm_softc *lmsc)
478 {
479 uint32_t i;
480
481 for (i = 0; i < __arraycount(lm_chips); i++)
482 if (lm_chips[i].chip_match(lmsc))
483 break;
484
485 /* Start the monitoring loop */
486 (*lmsc->lm_writereg)(lmsc, LMD_CONFIG, 0x01);
487
488 /* Indicate we have never read the registers */
489 timerclear(&lmsc->lastread);
490
491 /* Initialize sensors */
492 for (i = 0; i < lmsc->numsensors; ++i) {
493 lmsc->sensors[i].sensor = lmsc->info[i].sensor = i;
494 lmsc->sensors[i].validflags = (ENVSYS_FVALID|ENVSYS_FCURVALID);
495 lmsc->info[i].validflags = ENVSYS_FVALID;
496 lmsc->sensors[i].warnflags = ENVSYS_WARN_OK;
497 }
498 /*
499 * Hook into the System Monitor.
500 */
501 lmsc->sc_sysmon.sme_ranges = lm_ranges;
502 lmsc->sc_sysmon.sme_sensor_info = lmsc->info;
503 lmsc->sc_sysmon.sme_sensor_data = lmsc->sensors;
504 lmsc->sc_sysmon.sme_cookie = lmsc;
505
506 lmsc->sc_sysmon.sme_gtredata = lm_gtredata;
507 /* sme_streinfo set in chip-specific attach */
508
509 lmsc->sc_sysmon.sme_nsensors = lmsc->numsensors;
510 lmsc->sc_sysmon.sme_envsys_version = 1000;
511
512 if (sysmon_envsys_register(&lmsc->sc_sysmon))
513 aprint_error("%s: unable to register with sysmon\n",
514 lmsc->sc_dev.dv_xname);
515 }
516
517 static int
518 lm_match(struct lm_softc *sc)
519 {
520 const char *model = NULL;
521 int chipid;
522
523 /* See if we have an LM78/LM78J/LM79 or LM81 */
524 chipid = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
525 switch(chipid) {
526 case LM_ID_LM78:
527 model = "LM78";
528 break;
529 case LM_ID_LM78J:
530 model = "LM78J";
531 break;
532 case LM_ID_LM79:
533 model = "LM79";
534 break;
535 case LM_ID_LM81:
536 model = "LM81";
537 break;
538 default:
539 return 0;
540 }
541
542 aprint_normal(": National Semiconductor %s Hardware monitor\n", model);
543
544 lm_setup_sensors(sc, lm78_sensors);
545 sc->sc_sysmon.sme_streinfo = lm_streinfo;
546 sc->refresh_sensor_data = lm_refresh_sensor_data;
547 return 1;
548 }
549
550 static int
551 def_match(struct lm_softc *sc)
552 {
553 int chipid;
554
555 chipid = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
556 aprint_error(": Unknown chip (ID %d)\n", chipid);
557
558 lm_setup_sensors(sc, lm78_sensors);
559 sc->sc_sysmon.sme_streinfo = lm_streinfo;
560 sc->refresh_sensor_data = lm_refresh_sensor_data;
561 return 1;
562 }
563
564 static int
565 wb_match(struct lm_softc *sc)
566 {
567 const char *model;
568 int banksel, vendid, devid;
569
570 model = NULL;
571
572 /* Read vendor ID */
573 banksel = (*sc->lm_readreg)(sc, WB_BANKSEL);
574 lm_generic_banksel(sc, WB_BANKSEL_HBAC);
575
576 vendid = (*sc->lm_readreg)(sc, WB_VENDID) << 8;
577 lm_generic_banksel(sc, 0);
578 vendid |= (*sc->lm_readreg)(sc, WB_VENDID);
579 DPRINTF(("winbond vend id 0x%x\n", vendid));
580 if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS)
581 return 0;
582
583 /* Read device/chip ID */
584 lm_generic_banksel(sc, WB_BANKSEL_B0);
585 devid = (*sc->lm_readreg)(sc, LMD_CHIPID);
586 sc->chipid = (*sc->lm_readreg)(sc, WB_BANK0_CHIPID);
587 lm_generic_banksel(sc, banksel);
588 DPRINTF(("winbond chip id 0x%x\n", sc->chipid));
589
590 switch(sc->chipid) {
591 case WB_CHIPID_W83627HF:
592 model = "W83627HF";
593 lm_setup_sensors(sc, w83627hf_sensors);
594 break;
595 case WB_CHIPID_W83627THF:
596 model = "W83627THF";
597 lm_setup_sensors(sc, w83637hf_sensors);
598 break;
599 case WB_CHIPID_W83627EHF:
600 model = "W83627EHF";
601 lm_setup_sensors(sc, w83627ehf_sensors);
602 break;
603 case WB_CHIPID_W83627DHG:
604 model = "W83627DHG";
605 lm_setup_sensors(sc, w83627dhg_sensors);
606 break;
607 case WB_CHIPID_W83637HF:
608 model = "W83637HF";
609 lm_generic_banksel(sc, WB_BANKSEL_B0);
610 if ((*sc->lm_readreg)(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
611 sc->vrm9 = 1;
612 lm_generic_banksel(sc, banksel);
613 lm_setup_sensors(sc, w83637hf_sensors);
614 break;
615 case WB_CHIPID_W83697HF:
616 model = "W83697HF";
617 lm_setup_sensors(sc, w83697hf_sensors);
618 break;
619 case WB_CHIPID_W83781D:
620 case WB_CHIPID_W83781D_2:
621 model = "W83781D";
622 lm_setup_sensors(sc, w83781d_sensors);
623 sc->sc_sysmon.sme_streinfo = wb781_streinfo;
624 break;
625 case WB_CHIPID_W83782D:
626 model = "W83782D";
627 lm_setup_sensors(sc, w83782d_sensors);
628 sc->sc_sysmon.sme_streinfo = wb782_streinfo;
629 break;
630 case WB_CHIPID_W83783S:
631 model = "W83783S";
632 lm_setup_sensors(sc, w83783s_sensors);
633 break;
634 case WB_CHIPID_W83791D:
635 model = "W83791D";
636 lm_setup_sensors(sc, w83791d_sensors);
637 break;
638 case WB_CHIPID_W83791SD:
639 model = "W83791SD";
640 break;
641 case WB_CHIPID_W83792D:
642 model = "W83792D";
643 lm_setup_sensors(sc, w83792d_sensors);
644 break;
645 case WB_CHIPID_AS99127F:
646 if (vendid == WB_VENDID_ASUS) {
647 model = "AS99127F";
648 lm_setup_sensors(sc, w83781d_sensors);
649 } else {
650 model = "AS99127F rev 2";
651 lm_setup_sensors(sc, as99127f_sensors);
652 }
653 break;
654 default:
655 aprint_normal(": unknown Winbond chip (ID 0x%x)\n",
656 sc->chipid);
657 /* Handle as a standard LM78. */
658 lm_setup_sensors(sc, lm78_sensors);
659 sc->refresh_sensor_data = lm_refresh_sensor_data;
660 return 1;
661 }
662
663 aprint_normal(": Winbond %s Hardware monitor\n", model);
664
665 sc->sc_sysmon.sme_streinfo = lm_streinfo;
666 sc->refresh_sensor_data = wb_refresh_sensor_data;
667 return 1;
668 }
669
670 static void
671 lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors)
672 {
673 int i;
674
675 for (i = 0; sensors[i].desc; i++) {
676 sc->sensors[i].units = sc->info[i].units = sensors[i].type;
677 strlcpy(sc->info[i].desc, sensors[i].desc,
678 sizeof(sc->info[i].desc));
679 sc->numsensors++;
680 }
681 sc->lm_sensors = sensors;
682 }
683
684 static void
685 lm_refresh_sensor_data(struct lm_softc *sc)
686 {
687 int i;
688
689 /* Refresh our stored data for every sensor */
690 for (i = 0; i < sc->numsensors; i++)
691 sc->lm_sensors[i].refresh(sc, i);
692 }
693
694 static void
695 lm_refresh_volt(struct lm_softc *sc, int n)
696 {
697 int data;
698
699 data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
700 DPRINTF(("%s: volt[%d] 0x%x\n", __func__, n, data));
701 sc->sensors[n].cur.data_s = (data << 4);
702 sc->sensors[n].cur.data_s *= sc->lm_sensors[n].rfact;
703 sc->sensors[n].cur.data_s /= 10;
704 sc->info[n].rfact = sc->lm_sensors[n].rfact;
705 }
706
707 #define INVALIDATE_SENSOR(x) \
708 do { \
709 sc->sensors[(x)].validflags &= ~ENVSYS_FCURVALID; \
710 sc->sensors[(x)].cur.data_us = 0; \
711 } while (/* CONSTCOND */ 0)
712
713 static void
714 lm_refresh_temp(struct lm_softc *sc, int n)
715 {
716 int sdata;
717
718 /*
719 * The data sheet suggests that the range of the temperature
720 * sensor is between -55 degC and +125 degC.
721 */
722 sdata = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
723 if (sdata > 0x7d && sdata < 0xc9) {
724 INVALIDATE_SENSOR(n);
725 } else {
726 if (sdata & 0x80)
727 sdata -= 0x100;
728 sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
729 sc->sensors[n].cur.data_us = sdata * 1000000 + 273150000;
730 }
731 }
732
733 static void
734 lm_refresh_fanrpm(struct lm_softc *sc, int n)
735 {
736 int data, divisor = 1;
737
738 /*
739 * We might get more accurate fan readings by adjusting the
740 * divisor, but that might interfere with APM or other SMM
741 * BIOS code reading the fan speeds.
742 */
743
744 /* FAN3 has a fixed fan divisor. */
745 if (sc->lm_sensors[n].reg == LMD_FAN1 ||
746 sc->lm_sensors[n].reg == LMD_FAN2) {
747 data = (*sc->lm_readreg)(sc, LMD_VIDFAN);
748 if (sc->lm_sensors[n].reg == LMD_FAN1)
749 divisor = (data >> 4) & 0x03;
750 else
751 divisor = (data >> 6) & 0x03;
752 }
753
754 data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
755 if (data == 0xff || data == 0x00) {
756 INVALIDATE_SENSOR(n);
757 } else {
758 sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
759 sc->sensors[n].cur.data_us = 1350000 / (data << divisor);
760 }
761 }
762
763 static void
764 wb_refresh_sensor_data(struct lm_softc *sc)
765 {
766 int banksel, bank, i;
767
768 /*
769 * Properly save and restore bank selection register.
770 */
771
772 banksel = bank = sc->lm_readreg(sc, WB_BANKSEL);
773 for (i = 0; i < sc->numsensors; i++) {
774 if (bank != sc->lm_sensors[i].bank) {
775 bank = sc->lm_sensors[i].bank;
776 lm_generic_banksel(sc, bank);
777 }
778 sc->lm_sensors[i].refresh(sc, i);
779 }
780 lm_generic_banksel(sc, banksel);
781 }
782
783 static void
784 wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
785 {
786 int data;
787
788 data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
789
790 /*
791 * Depending on the voltage detection method,
792 * one of the following formulas is used:
793 * VRM8 method: value = raw * 0.016V
794 * VRM9 method: value = raw * 0.00488V + 0.70V
795 */
796 if (sc->vrm9)
797 sc->sensors[n].cur.data_s = (data * 4880) + 700000;
798 else
799 sc->sensors[n].cur.data_s = (data * 16000);
800 }
801
802 static void
803 wb_refresh_nvolt(struct lm_softc *sc, int n)
804 {
805 int data;
806
807 data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
808 sc->sensors[n].cur.data_s = ((data << 4) - WB_VREF);
809 sc->sensors[n].cur.data_s *= sc->lm_sensors[n].rfact;
810 sc->sensors[n].cur.data_s /= 10;
811 sc->sensors[n].cur.data_s += WB_VREF * 1000;
812 }
813
814 static void
815 wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n)
816 {
817 int data;
818
819 data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
820 sc->sensors[n].cur.data_s = ((data << 3) - WB_W83627EHF_VREF);
821 sc->sensors[n].cur.data_s *= RFACT(232, 10);
822 sc->sensors[n].cur.data_s /= 10;
823 sc->sensors[n].cur.data_s += WB_W83627EHF_VREF * 1000;
824 }
825
826 static void
827 wb_refresh_temp(struct lm_softc *sc, int n)
828 {
829 int sdata;
830
831 /*
832 * The data sheet suggests that the range of the temperature
833 * sensor is between -55 degC and +125 degC. However, values
834 * around -48 degC seem to be a very common bogus values.
835 * Since such values are unreasonably low, we use -45 degC for
836 * the lower limit instead.
837 */
838 sdata = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg) << 1;
839 sdata += (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg + 1) >> 7;
840 if (sdata > 0x0fa && sdata < 0x1a6) {
841 INVALIDATE_SENSOR(n);
842 } else {
843 if (sdata & 0x100)
844 sdata -= 0x200;
845 sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
846 sc->sensors[n].cur.data_us = sdata * 500000 + 273150000;
847 }
848 }
849
850 static void
851 wb_refresh_fanrpm(struct lm_softc *sc, int n)
852 {
853 int fan, data, divisor = 0;
854
855 /*
856 * This is madness; the fan divisor bits are scattered all
857 * over the place.
858 */
859
860 if (sc->lm_sensors[n].reg == LMD_FAN1 ||
861 sc->lm_sensors[n].reg == LMD_FAN2 ||
862 sc->lm_sensors[n].reg == LMD_FAN3) {
863 data = (*sc->lm_readreg)(sc, WB_BANK0_VBAT);
864 fan = (sc->lm_sensors[n].reg - LMD_FAN1);
865 if ((data >> 5) & (1 << fan))
866 divisor |= 0x04;
867 }
868
869 if (sc->lm_sensors[n].reg == LMD_FAN1 ||
870 sc->lm_sensors[n].reg == LMD_FAN2) {
871 data = (*sc->lm_readreg)(sc, LMD_VIDFAN);
872 if (sc->lm_sensors[n].reg == LMD_FAN1)
873 divisor |= (data >> 4) & 0x03;
874 else
875 divisor |= (data >> 6) & 0x03;
876 } else if (sc->lm_sensors[n].reg == LMD_FAN3) {
877 data = (*sc->lm_readreg)(sc, WB_PIN);
878 divisor |= (data >> 6) & 0x03;
879 } else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 ||
880 sc->lm_sensors[n].reg == WB_BANK0_FAN5) {
881 data = (*sc->lm_readreg)(sc, WB_BANK0_FAN45);
882 if (sc->lm_sensors[n].reg == WB_BANK0_FAN4)
883 divisor |= (data >> 0) & 0x07;
884 else
885 divisor |= (data >> 4) & 0x07;
886 }
887
888 data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
889 if (data == 0xff || data == 0x00) {
890 INVALIDATE_SENSOR(n);
891 } else {
892 sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
893 sc->sensors[n].cur.data_us = 1350000 / (data << divisor);
894 }
895 }
896
897 static void
898 wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n)
899 {
900 int reg, shift, data, divisor = 1;
901
902 shift = 0;
903
904 switch (sc->lm_sensors[n].reg) {
905 case 0x28:
906 reg = 0x47; shift = 0;
907 break;
908 case 0x29:
909 reg = 0x47; shift = 4;
910 break;
911 case 0x2a:
912 reg = 0x5b; shift = 0;
913 break;
914 case 0xb8:
915 reg = 0x5b; shift = 4;
916 break;
917 case 0xb9:
918 reg = 0x5c; shift = 0;
919 break;
920 case 0xba:
921 reg = 0x5c; shift = 4;
922 break;
923 case 0xbe:
924 reg = 0x9e; shift = 0;
925 break;
926 default:
927 reg = 0;
928 break;
929 }
930
931 data = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg);
932 if (data == 0xff || data == 0x00) {
933 INVALIDATE_SENSOR(n);
934 } else {
935 if (reg != 0)
936 divisor = ((*sc->lm_readreg)(sc, reg) >> shift) & 0x7;
937 sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
938 sc->sensors[n].cur.data_us = 1350000 / (data << divisor);
939 }
940 }
941
942 static void
943 as_refresh_temp(struct lm_softc *sc, int n)
944 {
945 int sdata;
946
947 /*
948 * It seems a shorted temperature diode produces an all-ones
949 * bit pattern.
950 */
951 sdata = (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg) << 1;
952 sdata += (*sc->lm_readreg)(sc, sc->lm_sensors[n].reg + 1) >> 7;
953 if (sdata == 0x1ff) {
954 INVALIDATE_SENSOR(n);
955 } else {
956 if (sdata & 0x100)
957 sdata -= 0x200;
958 sc->sensors[n].validflags |= (ENVSYS_FVALID|ENVSYS_FCURVALID);
959 sc->sensors[n].cur.data_us = sdata * 500000 + 273150000;
960 }
961 }
962
963 #undef INVALIDATE_SENSOR
964
965 static int
966 lm_gtredata(struct sysmon_envsys *sme, envsys_tre_data_t *tred)
967 {
968 static const struct timeval onepointfive = { 1, 500000 };
969 struct timeval t, utv;
970 struct lm_softc *sc = sme->sme_cookie;
971
972 /* read new values at most once every 1.5 seconds */
973 getmicrouptime(&utv);
974 timeradd(&sc->lastread, &onepointfive, &t);
975 if (timercmp(&utv, &t, >)) {
976 sc->lastread = utv;
977 sc->refresh_sensor_data(sc);
978 }
979
980 *tred = sc->sensors[tred->sensor];
981
982 return 0;
983 }
984
985 static int
986 generic_streinfo_fan(struct lm_softc *sc, envsys_basic_info_t *info, int n,
987 envsys_basic_info_t *binfo)
988 {
989 uint8_t sdata;
990 int divisor;
991
992 /* FAN1 and FAN2 can have divisors set, but not FAN3 */
993 if ((sc->info[binfo->sensor].units == ENVSYS_SFANRPM)
994 && (n < 2)) {
995 if (binfo->rpms == 0) {
996 binfo->validflags = 0;
997 return 0;
998 }
999
1000 /* write back the nominal FAN speed */
1001 info->rpms = binfo->rpms;
1002
1003 /* 153 is the nominal FAN speed value */
1004 divisor = 1350000 / (binfo->rpms * 153);
1005
1006 /* ...but we need lg(divisor) */
1007 if (divisor <= 1)
1008 divisor = 0;
1009 else if (divisor <= 2)
1010 divisor = 1;
1011 else if (divisor <= 4)
1012 divisor = 2;
1013 else
1014 divisor = 3;
1015
1016 /*
1017 * FAN1 div is in bits <5:4>, FAN2 div is
1018 * in <7:6>
1019 */
1020 sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
1021 if ( n == 0 ) { /* FAN1 */
1022 divisor <<= 4;
1023 sdata = (sdata & 0xCF) | divisor;
1024 } else { /* FAN2 */
1025 divisor <<= 6;
1026 sdata = (sdata & 0x3F) | divisor;
1027 }
1028
1029 (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
1030 }
1031 return 0;
1032
1033 }
1034
1035 static int
1036 lm_streinfo(struct sysmon_envsys *sme, envsys_basic_info_t *binfo)
1037 {
1038 struct lm_softc *sc = sme->sme_cookie;
1039
1040 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
1041 sc->info[binfo->sensor].rfact = binfo->rfact;
1042 else {
1043 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
1044 generic_streinfo_fan(sc, &sc->info[binfo->sensor],
1045 binfo->sensor - 8, binfo);
1046 }
1047 strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
1048 sizeof(sc->info[binfo->sensor].desc));
1049 binfo->validflags = ENVSYS_FVALID;
1050 }
1051 return 0;
1052 }
1053
1054 static int
1055 wb781_streinfo(struct sysmon_envsys *sme, envsys_basic_info_t *binfo)
1056 {
1057 struct lm_softc *sc = sme->sme_cookie;
1058 int divisor;
1059 uint8_t sdata;
1060 int i;
1061
1062 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
1063 sc->info[binfo->sensor].rfact = binfo->rfact;
1064 else {
1065 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
1066 if (binfo->rpms == 0) {
1067 binfo->validflags = 0;
1068 return 0;
1069 }
1070
1071 /* write back the nominal FAN speed */
1072 sc->info[binfo->sensor].rpms = binfo->rpms;
1073
1074 /* 153 is the nominal FAN speed value */
1075 divisor = 1350000 / (binfo->rpms * 153);
1076
1077 /* ...but we need lg(divisor) */
1078 for (i = 0; i < 7; i++) {
1079 if (divisor <= (1 << i))
1080 break;
1081 }
1082 divisor = i;
1083
1084 if (binfo->sensor == 10 || binfo->sensor == 11) {
1085 /*
1086 * FAN1 div is in bits <5:4>, FAN2 div
1087 * is in <7:6>
1088 */
1089 sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
1090 if ( binfo->sensor == 10 ) { /* FAN1 */
1091 sdata = (sdata & 0xCF) |
1092 ((divisor & 0x3) << 4);
1093 } else { /* FAN2 */
1094 sdata = (sdata & 0x3F) |
1095 ((divisor & 0x3) << 6);
1096 }
1097 (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
1098 } else {
1099 /* FAN3 is in WB_PIN <7:6> */
1100 sdata = (*sc->lm_readreg)(sc, WB_PIN);
1101 sdata = (sdata & 0x3F) |
1102 ((divisor & 0x3) << 6);
1103 (*sc->lm_writereg)(sc, WB_PIN, sdata);
1104 }
1105 }
1106 strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
1107 sizeof(sc->info[binfo->sensor].desc));
1108 binfo->validflags = ENVSYS_FVALID;
1109 }
1110 return 0;
1111 }
1112
1113 static int
1114 wb782_streinfo(struct sysmon_envsys *sme, envsys_basic_info_t *binfo)
1115 {
1116 struct lm_softc *sc = sme->sme_cookie;
1117 int divisor;
1118 uint8_t sdata;
1119 int i;
1120
1121 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
1122 sc->info[binfo->sensor].rfact = binfo->rfact;
1123 else {
1124 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
1125 if (binfo->rpms == 0) {
1126 binfo->validflags = 0;
1127 return 0;
1128 }
1129
1130 /* write back the nominal FAN speed */
1131 sc->info[binfo->sensor].rpms = binfo->rpms;
1132
1133 /* 153 is the nominal FAN speed value */
1134 divisor = 1350000 / (binfo->rpms * 153);
1135
1136 /* ...but we need lg(divisor) */
1137 for (i = 0; i < 7; i++) {
1138 if (divisor <= (1 << i))
1139 break;
1140 }
1141 divisor = i;
1142
1143 if (binfo->sensor == 12 || binfo->sensor == 13) {
1144 /*
1145 * FAN1 div is in bits <5:4>, FAN2 div
1146 * is in <7:6>
1147 */
1148 sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
1149 if ( binfo->sensor == 12 ) { /* FAN1 */
1150 sdata = (sdata & 0xCF) |
1151 ((divisor & 0x3) << 4);
1152 } else { /* FAN2 */
1153 sdata = (sdata & 0x3F) |
1154 ((divisor & 0x3) << 6);
1155 }
1156 (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
1157 } else {
1158 /* FAN3 is in WB_PIN <7:6> */
1159 sdata = (*sc->lm_readreg)(sc, WB_PIN);
1160 sdata = (sdata & 0x3F) |
1161 ((divisor & 0x3) << 6);
1162 (*sc->lm_writereg)(sc, WB_PIN, sdata);
1163 }
1164 /* Bit 2 of divisor is in WB_BANK0_VBAT */
1165 lm_generic_banksel(sc, WB_BANKSEL_B0);
1166 sdata = (*sc->lm_readreg)(sc, WB_BANK0_VBAT);
1167 sdata &= ~(0x20 << (binfo->sensor - 12));
1168 sdata |= (divisor & 0x4) << (binfo->sensor - 9);
1169 (*sc->lm_writereg)(sc, WB_BANK0_VBAT, sdata);
1170 }
1171
1172 strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
1173 sizeof(sc->info[binfo->sensor].desc));
1174 binfo->validflags = ENVSYS_FVALID;
1175 }
1176 return 0;
1177 }
1178