No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / i2c / dbcool.c
blob386d6859874357314fd4d43c413ddea709829c94
1 /* $NetBSD: dbcool.c,v 1.13 2009/11/02 21:37:44 christos Exp $ */
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Goyette
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 /*
33 * a driver for the dbCool(tm) family of environmental controllers
35 * Data sheets for the various supported chips are available at
37 * http://www.onsemi.com/pub/Collateral/ADM1027-D.PDF
38 * http://www.onsemi.com/pub/Collateral/ADM1030-D.PDF
39 * http://www.onsemi.com/pub/Collateral/ADT7463-D.PDF
40 * http://www.onsemi.com/pub/Collateral/ADT7466.PDF
41 * http://www.onsemi.com/pub/Collateral/ADT7467-D.PDF
42 * http://www.onsemi.com/pub/Collateral/ADT7468-D.PDF
43 * http://www.onsemi.com/pub/Collateral/ADT7473-D.PDF
44 * http://www.onsemi.com/pub/Collateral/ADT7475-D.PDF
45 * http://www.onsemi.com/pub/Collateral/ADT7476-D.PDF
46 * http://www.onsemi.com/pub/Collateral/ADT7490-D.PDF
48 * (URLs are correct as of October 5, 2008)
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: dbcool.c,v 1.13 2009/11/02 21:37:44 christos Exp $");
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/kernel.h>
57 #include <sys/device.h>
58 #include <sys/malloc.h>
59 #include <sys/sysctl.h>
61 #include <uvm/uvm_extern.h>
63 #include <dev/i2c/dbcool_var.h>
64 #include <dev/i2c/dbcool_reg.h>
66 /* Config interface */
67 static int dbcool_match(device_t, cfdata_t, void *);
68 static void dbcool_attach(device_t, device_t, void *);
69 static int dbcool_detach(device_t, int);
71 /* Device attributes */
72 static int dbcool_supply_voltage(struct dbcool_softc *);
73 static bool dbcool_islocked(struct dbcool_softc *);
75 /* Sensor read functions */
76 static void dbcool_refresh(struct sysmon_envsys *, envsys_data_t *);
77 static int dbcool_read_rpm(struct dbcool_softc *, uint8_t);
78 static int dbcool_read_temp(struct dbcool_softc *, uint8_t, bool);
79 static int dbcool_read_volt(struct dbcool_softc *, uint8_t, int, bool);
81 /* SYSCTL Helpers */
82 static int sysctl_dbcool_temp(SYSCTLFN_PROTO);
83 static int sysctl_adm1030_temp(SYSCTLFN_PROTO);
84 static int sysctl_adm1030_trange(SYSCTLFN_PROTO);
85 static int sysctl_dbcool_duty(SYSCTLFN_PROTO);
86 static int sysctl_dbcool_behavior(SYSCTLFN_PROTO);
87 static int sysctl_dbcool_slope(SYSCTLFN_PROTO);
88 static int sysctl_dbcool_volt_limit(SYSCTLFN_PROTO);
89 static int sysctl_dbcool_temp_limit(SYSCTLFN_PROTO);
90 static int sysctl_dbcool_fan_limit(SYSCTLFN_PROTO);
91 static int sysctl_dbcool_thyst(SYSCTLFN_PROTO);
92 static int sysctl_dbcool_vid(SYSCTLFN_PROTO);
94 /* Set-up subroutines */
95 static void dbcool_setup_controllers(struct dbcool_softc *,
96 const struct sysctlnode *, int, int);
97 static int dbcool_setup_sensors(struct dbcool_softc *,
98 const struct sysctlnode *, int, int);
99 static int dbcool_attach_sensor(struct dbcool_softc *,
100 const struct sysctlnode *, int, int (*)(SYSCTLFN_PROTO));
102 #ifdef DBCOOL_DEBUG
103 static int sysctl_dbcool_reg_select(SYSCTLFN_PROTO);
104 static int sysctl_dbcool_reg_access(SYSCTLFN_PROTO);
105 #endif /* DBCOOL_DEBUG */
108 * Descriptions for SYSCTL entries
110 struct dbc_sysctl_info {
111 const char *name;
112 const char *desc;
113 bool lockable;
114 int (*helper)(SYSCTLFN_PROTO);
117 static struct dbc_sysctl_info dbc_sysctl_table[] = {
119 * The first several entries must remain in the same order as the
120 * corresponding entries in enum dbc_pwm_params
122 { "behavior", "operating behavior and temp selector",
123 true, sysctl_dbcool_behavior },
124 { "min_duty", "minimum fan controller PWM duty cycle",
125 true, sysctl_dbcool_duty },
126 { "max_duty", "maximum fan controller PWM duty cycle",
127 true, sysctl_dbcool_duty },
128 { "cur_duty", "current fan controller PWM duty cycle",
129 false, sysctl_dbcool_duty },
132 * The rest of these should be in the order in which they
133 * are to be stored in the sysctl tree; the table index is
134 * used as the high-order bits of the sysctl_num to maintain
135 * the sequence.
137 * If you rearrange the order of these items, be sure to
138 * update the sysctl_index in the XXX_sensor_table[] for
139 * the various chips!
141 { "Trange", "temp slope/range to reach 100% duty cycle",
142 true, sysctl_dbcool_slope },
143 { "Tmin", "temp at which to start fan controller",
144 true, sysctl_dbcool_temp },
145 { "Ttherm", "temp at which THERM is asserted",
146 true, sysctl_dbcool_temp },
147 { "Thyst", "temp hysteresis for stopping fan controller",
148 true, sysctl_dbcool_thyst },
149 { "Tmin", "temp at which to start fan controller",
150 true, sysctl_adm1030_temp },
151 { "Trange", "temp slope/range to reach 100% duty cycle",
152 true, sysctl_adm1030_trange },
155 static const char *dbc_sensor_names[] = {
156 "l_temp", "r1_temp", "r2_temp", "Vccp", "Vcc", "fan1",
157 "fan2", "fan3", "fan4", "AIN1", "AIN2", "V2dot5",
158 "V5", "V12", "Vtt", "Imon"
162 * Following table derived from product data-sheets
164 static int64_t nominal_voltages[] = {
165 -1, /* Vcc can be either 3.3 or 5.0V
166 at 3/4 scale */
167 2249939, /* Vccp 2.25V 3/4 scale */
168 2497436, /* 2.5VIN 2.5V 3/4 scale */
169 5002466, /* 5VIN 5V 3/4 scale */
170 12000000, /* 12VIN 12V 3/4 scale */
171 1690809, /* Vtt, Imon 2.25V full scale */
172 1689600, /* AIN1, AIN2 2.25V full scale */
177 * Sensor-type, { val-reg, hilim-reg, lolim-reg}, name-idx, sysctl-table-idx,
178 * nom-voltage-index
180 struct dbcool_sensor ADT7490_sensor_table[] = {
181 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
182 DBCOOL_LOCAL_HIGHLIM,
183 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
184 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
185 DBCOOL_REMOTE1_HIGHLIM,
186 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
187 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
188 DBCOOL_REMOTE2_HIGHLIM,
189 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
190 { DBC_VOLT, { DBCOOL_VCCP,
191 DBCOOL_VCCP_HIGHLIM,
192 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
193 { DBC_VOLT, { DBCOOL_VCC,
194 DBCOOL_VCC_HIGHLIM,
195 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
196 { DBC_VOLT, { DBCOOL_25VIN,
197 DBCOOL_25VIN_HIGHLIM,
198 DBCOOL_25VIN_LOWLIM }, 11, 0, 2 },
199 { DBC_VOLT, { DBCOOL_5VIN,
200 DBCOOL_5VIN_HIGHLIM,
201 DBCOOL_5VIN_LOWLIM }, 12, 0, 3 },
202 { DBC_VOLT, { DBCOOL_12VIN,
203 DBCOOL_12VIN_HIGHLIM,
204 DBCOOL_12VIN_LOWLIM }, 13, 0, 4 },
205 { DBC_VOLT, { DBCOOL_VTT,
206 DBCOOL_VTT_HIGHLIM,
207 DBCOOL_VTT_LOWLIM }, 14, 0, 5 },
208 { DBC_VOLT, { DBCOOL_IMON,
209 DBCOOL_IMON_HIGHLIM,
210 DBCOOL_IMON_LOWLIM }, 15, 0, 5 },
211 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
212 DBCOOL_NO_REG,
213 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
214 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
215 DBCOOL_NO_REG,
216 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
217 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
218 DBCOOL_NO_REG,
219 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
220 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
221 DBCOOL_NO_REG,
222 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
223 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
224 DBCOOL_NO_REG,
225 DBCOOL_NO_REG }, 0, 5, 0 },
226 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
227 DBCOOL_NO_REG,
228 DBCOOL_NO_REG }, 0, 6, 0 },
229 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
230 DBCOOL_NO_REG,
231 DBCOOL_NO_REG }, 0, 7, 0 },
232 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
233 DBCOOL_NO_REG,
234 DBCOOL_NO_REG }, 1, 5, 0 },
235 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
236 DBCOOL_NO_REG,
237 DBCOOL_NO_REG }, 1, 6, 0 },
238 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
239 DBCOOL_NO_REG,
240 DBCOOL_NO_REG }, 1, 7, 0 },
241 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
242 DBCOOL_NO_REG,
243 DBCOOL_NO_REG }, 2, 5, 0 },
244 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
245 DBCOOL_NO_REG,
246 DBCOOL_NO_REG }, 2, 6, 0 },
247 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
248 DBCOOL_NO_REG,
249 DBCOOL_NO_REG }, 2, 7, 0 },
250 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
253 struct dbcool_sensor ADT7476_sensor_table[] = {
254 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
255 DBCOOL_LOCAL_HIGHLIM,
256 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
257 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
258 DBCOOL_REMOTE1_HIGHLIM,
259 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
260 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
261 DBCOOL_REMOTE2_HIGHLIM,
262 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
263 { DBC_VOLT, { DBCOOL_VCCP,
264 DBCOOL_VCCP_HIGHLIM,
265 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
266 { DBC_VOLT, { DBCOOL_VCC,
267 DBCOOL_VCC_HIGHLIM,
268 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
269 { DBC_VOLT, { DBCOOL_25VIN,
270 DBCOOL_25VIN_HIGHLIM,
271 DBCOOL_25VIN_LOWLIM }, 11, 0, 2 },
272 { DBC_VOLT, { DBCOOL_5VIN,
273 DBCOOL_5VIN_HIGHLIM,
274 DBCOOL_5VIN_LOWLIM }, 12, 0, 3 },
275 { DBC_VOLT, { DBCOOL_12VIN,
276 DBCOOL_12VIN_HIGHLIM,
277 DBCOOL_12VIN_LOWLIM }, 13, 0, 4 },
278 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
279 DBCOOL_NO_REG,
280 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
281 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
282 DBCOOL_NO_REG,
283 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
284 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
285 DBCOOL_NO_REG,
286 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
287 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
288 DBCOOL_NO_REG,
289 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
290 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
291 DBCOOL_NO_REG,
292 DBCOOL_NO_REG }, 0, 5, 0 },
293 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
294 DBCOOL_NO_REG,
295 DBCOOL_NO_REG }, 0, 6, 0 },
296 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
297 DBCOOL_NO_REG,
298 DBCOOL_NO_REG }, 0, 7, 0 },
299 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
300 DBCOOL_NO_REG,
301 DBCOOL_NO_REG }, 1, 5, 0 },
302 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
303 DBCOOL_NO_REG,
304 DBCOOL_NO_REG }, 1, 6, 0 },
305 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
306 DBCOOL_NO_REG,
307 DBCOOL_NO_REG }, 1, 7, 0 },
308 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
309 DBCOOL_NO_REG,
310 DBCOOL_NO_REG }, 2, 5, 0 },
311 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
312 DBCOOL_NO_REG,
313 DBCOOL_NO_REG }, 2, 6, 0 },
314 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
315 DBCOOL_NO_REG,
316 DBCOOL_NO_REG }, 2, 7, 0 },
317 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
320 struct dbcool_sensor ADT7475_sensor_table[] = {
321 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
322 DBCOOL_LOCAL_HIGHLIM,
323 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
324 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
325 DBCOOL_REMOTE1_HIGHLIM,
326 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
327 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
328 DBCOOL_REMOTE2_HIGHLIM,
329 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
330 { DBC_VOLT, { DBCOOL_VCCP,
331 DBCOOL_VCCP_HIGHLIM,
332 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
333 { DBC_VOLT, { DBCOOL_VCC,
334 DBCOOL_VCC_HIGHLIM,
335 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
336 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
337 DBCOOL_NO_REG,
338 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
339 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
340 DBCOOL_NO_REG,
341 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
342 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
343 DBCOOL_NO_REG,
344 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
345 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
346 DBCOOL_NO_REG,
347 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
348 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
349 DBCOOL_NO_REG,
350 DBCOOL_NO_REG }, 0, 5, 0 },
351 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
352 DBCOOL_NO_REG,
353 DBCOOL_NO_REG }, 0, 6, 0 },
354 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
355 DBCOOL_NO_REG,
356 DBCOOL_NO_REG }, 0, 7, 0 },
357 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
358 DBCOOL_NO_REG,
359 DBCOOL_NO_REG }, 1, 5, 0 },
360 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
361 DBCOOL_NO_REG,
362 DBCOOL_NO_REG }, 1, 6, 0 },
363 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
364 DBCOOL_NO_REG,
365 DBCOOL_NO_REG }, 1, 7, 0 },
366 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
367 DBCOOL_NO_REG,
368 DBCOOL_NO_REG }, 2, 5, 0 },
369 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
370 DBCOOL_NO_REG,
371 DBCOOL_NO_REG }, 2, 6, 0 },
372 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
373 DBCOOL_NO_REG,
374 DBCOOL_NO_REG }, 2, 7, 0 },
375 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
379 * The registers of dbcool_power_control must be in the same order as
380 * in enum dbc_pwm_params
382 struct dbcool_power_control ADT7475_power_table[] = {
383 { { DBCOOL_PWM1_CTL, DBCOOL_PWM1_MINDUTY,
384 DBCOOL_PWM1_MAXDUTY, DBCOOL_PWM1_CURDUTY },
385 "fan_control_1" },
386 { { DBCOOL_PWM2_CTL, DBCOOL_PWM2_MINDUTY,
387 DBCOOL_PWM2_MAXDUTY, DBCOOL_PWM2_CURDUTY },
388 "fan_control_2" },
389 { { DBCOOL_PWM3_CTL, DBCOOL_PWM3_MINDUTY,
390 DBCOOL_PWM3_MAXDUTY, DBCOOL_PWM3_CURDUTY },
391 "fan_control_3" },
392 { { 0, 0, 0, 0 }, NULL }
395 struct dbcool_sensor ADT7466_sensor_table[] = {
396 { DBC_TEMP, { DBCOOL_ADT7466_LCL_TEMP_MSB,
397 DBCOOL_ADT7466_LCL_TEMP_HILIM,
398 DBCOOL_ADT7466_LCL_TEMP_LOLIM }, 0, 0, 0 },
399 { DBC_TEMP, { DBCOOL_ADT7466_REM_TEMP_MSB,
400 DBCOOL_ADT7466_REM_TEMP_HILIM,
401 DBCOOL_ADT7466_REM_TEMP_LOLIM }, 1, 0, 0 },
402 { DBC_VOLT, { DBCOOL_ADT7466_VCC,
403 DBCOOL_ADT7466_VCC_HILIM,
404 DBCOOL_ADT7466_VCC_LOLIM }, 4, 0, 0 },
405 { DBC_VOLT, { DBCOOL_ADT7466_AIN1,
406 DBCOOL_ADT7466_AIN1_HILIM,
407 DBCOOL_ADT7466_AIN1_LOLIM }, 9, 0, 6 },
408 { DBC_VOLT, { DBCOOL_ADT7466_AIN2,
409 DBCOOL_ADT7466_AIN2_HILIM,
410 DBCOOL_ADT7466_AIN2_LOLIM }, 10, 0, 6 },
411 { DBC_FAN, { DBCOOL_ADT7466_FANA_LSB,
412 DBCOOL_NO_REG,
413 DBCOOL_ADT7466_FANA_LOLIM_LSB }, 5, 0, 0 },
414 { DBC_FAN, { DBCOOL_ADT7466_FANB_LSB,
415 DBCOOL_NO_REG,
416 DBCOOL_ADT7466_FANB_LOLIM_LSB }, 6, 0, 0 },
417 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
420 struct dbcool_sensor ADM1027_sensor_table[] = {
421 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
422 DBCOOL_LOCAL_HIGHLIM,
423 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
424 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
425 DBCOOL_REMOTE1_HIGHLIM,
426 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
427 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
428 DBCOOL_REMOTE2_HIGHLIM,
429 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
430 { DBC_VOLT, { DBCOOL_VCCP,
431 DBCOOL_VCCP_HIGHLIM,
432 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
433 { DBC_VOLT, { DBCOOL_VCC,
434 DBCOOL_VCC_HIGHLIM,
435 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
436 { DBC_VOLT, { DBCOOL_25VIN,
437 DBCOOL_25VIN_HIGHLIM,
438 DBCOOL_25VIN_LOWLIM }, 11, 0, 2 },
439 { DBC_VOLT, { DBCOOL_5VIN,
440 DBCOOL_5VIN_HIGHLIM,
441 DBCOOL_5VIN_LOWLIM }, 12, 0, 3 },
442 { DBC_VOLT, { DBCOOL_12VIN,
443 DBCOOL_12VIN_HIGHLIM,
444 DBCOOL_12VIN_LOWLIM }, 13, 0, 4 },
445 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
446 DBCOOL_NO_REG,
447 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
448 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
449 DBCOOL_NO_REG,
450 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
451 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
452 DBCOOL_NO_REG,
453 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
454 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
455 DBCOOL_NO_REG,
456 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
457 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
458 DBCOOL_NO_REG,
459 DBCOOL_NO_REG }, 0, 5, 0 },
460 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
461 DBCOOL_NO_REG,
462 DBCOOL_NO_REG }, 0, 6, 0 },
463 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
464 DBCOOL_NO_REG,
465 DBCOOL_NO_REG }, 0, 7, 0 },
466 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
467 DBCOOL_NO_REG,
468 DBCOOL_NO_REG }, 1, 5, 0 },
469 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
470 DBCOOL_NO_REG,
471 DBCOOL_NO_REG }, 1, 6, 0 },
472 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
473 DBCOOL_NO_REG,
474 DBCOOL_NO_REG }, 1, 7, 0 },
475 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
476 DBCOOL_NO_REG,
477 DBCOOL_NO_REG }, 2, 5, 0 },
478 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
479 DBCOOL_NO_REG,
480 DBCOOL_NO_REG }, 2, 6, 0 },
481 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
482 DBCOOL_NO_REG,
483 DBCOOL_NO_REG }, 2, 7, 0 },
484 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
487 struct dbcool_sensor ADM1030_sensor_table[] = {
488 { DBC_TEMP, { DBCOOL_ADM1030_L_TEMP,
489 DBCOOL_ADM1030_L_HI_LIM,
490 DBCOOL_ADM1030_L_LO_LIM }, 0, 0, 0 },
491 { DBC_TEMP, { DBCOOL_ADM1030_R_TEMP,
492 DBCOOL_ADM1030_R_HI_LIM,
493 DBCOOL_ADM1030_R_LO_LIM }, 1, 0, 0 },
494 { DBC_FAN, { DBCOOL_ADM1030_FAN_TACH,
495 DBCOOL_NO_REG,
496 DBCOOL_ADM1030_FAN_LO_LIM }, 5, 0, 0 },
497 { DBC_CTL, { DBCOOL_ADM1030_L_TMIN,
498 DBCOOL_NO_REG,
499 DBCOOL_NO_REG }, 0, 8, 0 },
500 { DBC_CTL, { DBCOOL_ADM1030_L_TTHRESH,
501 DBCOOL_NO_REG,
502 DBCOOL_NO_REG }, 0, 9, 0 },
503 { DBC_CTL, { DBCOOL_ADM1030_L_TTHRESH,
504 DBCOOL_NO_REG,
505 DBCOOL_NO_REG }, 0, 6, 0 },
506 { DBC_CTL, { DBCOOL_ADM1030_R_TMIN,
507 DBCOOL_NO_REG,
508 DBCOOL_NO_REG }, 1, 8, 0 },
509 { DBC_CTL, { DBCOOL_ADM1030_L_TTHRESH,
510 DBCOOL_NO_REG,
511 DBCOOL_NO_REG }, 1, 9, 0 },
512 { DBC_CTL, { DBCOOL_ADM1030_R_TTHRESH,
513 DBCOOL_NO_REG,
514 DBCOOL_NO_REG }, 1, 6, 0 },
515 { DBC_EOF, {0, 0, 0 }, 0, 0, 0 }
518 struct dbcool_power_control ADM1030_power_table[] = {
519 { { DBCOOL_ADM1030_CFG1, DBCOOL_NO_REG, DBCOOL_NO_REG,
520 DBCOOL_ADM1030_FAN_SPEED_CFG },
521 "fan_control_1" },
522 { { 0, 0, 0, 0 }, NULL }
525 struct chip_id chip_table[] = {
526 { DBCOOL_COMPANYID, ADT7490_DEVICEID, ADT7490_REV_ID,
527 ADT7475_sensor_table, ADT7475_power_table,
528 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_VID |
529 DBCFLAG_HAS_PECI,
530 90000 * 60, "ADT7490" },
531 { DBCOOL_COMPANYID, ADT7476_DEVICEID, 0xff,
532 ADT7476_sensor_table, ADT7475_power_table,
533 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_VID,
534 90000 * 60, "ADT7476" },
535 { DBCOOL_COMPANYID, ADT7475_DEVICEID, 0xff,
536 ADT7475_sensor_table, ADT7475_power_table,
537 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
538 90000 * 60, "ADT7475" },
539 { DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID1,
540 ADT7475_sensor_table, ADT7475_power_table,
541 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
542 90000 * 60, "ADT7460/ADT7463" },
543 { DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID2,
544 ADT7475_sensor_table, ADT7475_power_table,
545 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
546 90000 * 60, "ADT7463-1" },
547 { DBCOOL_COMPANYID, ADT7468_DEVICEID, 0xff,
548 ADT7476_sensor_table, ADT7475_power_table,
549 DBCFLAG_TEMPOFFSET | DBCFLAG_MULTI_VCC | DBCFLAG_HAS_MAXDUTY |
550 DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN | DBCFLAG_HAS_VID,
551 90000 * 60, "ADT7467/ADT7468" },
552 { DBCOOL_COMPANYID, ADT7466_DEVICEID, 0xff,
553 ADT7466_sensor_table, NULL,
554 DBCFLAG_ADT7466 | DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_SHDN,
555 82000 * 60, "ADT7466" },
556 { DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID1,
557 ADM1027_sensor_table, ADT7475_power_table,
558 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN |
559 DBCFLAG_ADM1027 | DBCFLAG_HAS_VID,
560 90000 * 60, "ADT7463" },
561 { DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID2,
562 ADM1027_sensor_table, ADT7475_power_table,
563 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN |
564 DBCFLAG_HAS_VID | DBCFLAG_HAS_VID_SEL,
565 90000 * 60, "ADT7463" },
566 { DBCOOL_COMPANYID, ADM1027_DEVICEID, ADM1027_REV_ID,
567 ADM1027_sensor_table, ADT7475_power_table,
568 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_VID,
569 90000 * 60, "ADM1027" },
570 { DBCOOL_COMPANYID, ADM1030_DEVICEID, 0xff,
571 ADM1030_sensor_table, ADM1030_power_table,
572 DBCFLAG_ADM1030,
573 11250 * 60, "ADM1030" },
574 { 0, 0, 0, NULL, NULL, 0, 0, NULL }
577 static const char *behavior[] = {
578 "remote1", "local", "remote2", "full-speed",
579 "disabled", "local+remote2","all-temps", "manual"
582 static char dbcool_cur_behav[16];
584 CFATTACH_DECL_NEW(dbcool, sizeof(struct dbcool_softc),
585 dbcool_match, dbcool_attach, dbcool_detach, NULL);
588 dbcool_match(device_t parent, cfdata_t cf, void *aux)
590 struct i2c_attach_args *ia = aux;
591 struct dbcool_chipset dc;
592 dc.dc_tag = ia->ia_tag;
593 dc.dc_addr = ia->ia_addr;
594 dc.dc_chip = NULL;
595 dc.dc_readreg = dbcool_readreg;
596 dc.dc_writereg = dbcool_writereg;
598 /* no probing if we attach to iic, but verify chip id and address */
599 if ((ia->ia_addr & DBCOOL_ADDRMASK) != DBCOOL_ADDR)
600 return 0;
601 if (dbcool_chip_ident(&dc) >= 0)
602 return 1;
604 return 0;
607 void
608 dbcool_attach(device_t parent, device_t self, void *aux)
610 struct dbcool_softc *sc = device_private(self);
611 struct i2c_attach_args *args = aux;
612 uint8_t ver;
614 sc->sc_dc.dc_addr = args->ia_addr;
615 sc->sc_dc.dc_tag = args->ia_tag;
616 sc->sc_dc.dc_chip = NULL;
617 sc->sc_dc.dc_readreg = dbcool_readreg;
618 sc->sc_dc.dc_writereg = dbcool_writereg;
619 (void)dbcool_chip_ident(&sc->sc_dc);
620 sc->sc_dev = self;
622 aprint_naive("\n");
623 aprint_normal("\n");
625 ver = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REVISION_REG);
626 if (sc->sc_dc.dc_chip->flags & DBCFLAG_4BIT_VER)
627 aprint_normal_dev(self, "%s dBCool(tm) Controller "
628 "(rev 0x%02x, stepping 0x%02x)\n", sc->sc_dc.dc_chip->name,
629 ver >> 4, ver & 0x0f);
630 else
631 aprint_normal_dev(self, "%s dBCool(tm) Controller "
632 "(rev 0x%04x)\n", sc->sc_dc.dc_chip->name, ver);
634 dbcool_setup(self);
636 if (!pmf_device_register(self, dbcool_pmf_suspend, dbcool_pmf_resume))
637 aprint_error_dev(self, "couldn't establish power handler\n");
640 static int
641 dbcool_detach(device_t self, int flags)
643 struct dbcool_softc *sc = device_private(self);
645 sysmon_envsys_unregister(sc->sc_sme);
646 sc->sc_sme = NULL;
647 return 0;
650 /* On suspend, we save the state of the SHDN bit, then set it */
651 bool dbcool_pmf_suspend(device_t dev, pmf_qual_t qual)
653 struct dbcool_softc *sc = device_private(dev);
654 uint8_t reg, bit, cfg;
656 if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0)
657 return true;
659 if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) {
660 reg = DBCOOL_ADT7466_CONFIG2;
661 bit = DBCOOL_ADT7466_CFG2_SHDN;
662 } else {
663 reg = DBCOOL_CONFIG2_REG;
664 bit = DBCOOL_CFG2_SHDN;
666 cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
667 sc->sc_suspend = cfg & bit;
668 cfg |= bit;
669 sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg);
671 return true;
674 /* On resume, we restore the previous state of the SHDN bit */
675 bool dbcool_pmf_resume(device_t dev, pmf_qual_t qual)
677 struct dbcool_softc *sc = device_private(dev);
678 uint8_t reg, bit, cfg;
680 if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0)
681 return true;
683 if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) {
684 reg = DBCOOL_ADT7466_CONFIG2;
685 bit = DBCOOL_ADT7466_CFG2_SHDN;
686 } else {
687 reg = DBCOOL_CONFIG2_REG;
688 bit = DBCOOL_CFG2_SHDN;
690 cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
691 cfg &= ~sc->sc_suspend;
692 sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg);
694 return true;
698 uint8_t
699 dbcool_readreg(struct dbcool_chipset *dc, uint8_t reg)
701 uint8_t data = 0;
703 if (iic_acquire_bus(dc->dc_tag, 0) != 0)
704 return data;
706 if (dc->dc_chip == NULL || dc->dc_chip->flags & DBCFLAG_ADM1027) {
707 /* ADM1027 doesn't support i2c read_byte protocol */
708 if (iic_smbus_send_byte(dc->dc_tag, dc->dc_addr, reg, 0) != 0)
709 goto bad;
710 (void)iic_smbus_receive_byte(dc->dc_tag, dc->dc_addr, &data, 0);
711 } else
712 (void)iic_smbus_read_byte(dc->dc_tag, dc->dc_addr, reg, &data,
715 bad:
716 iic_release_bus(dc->dc_tag, 0);
717 return data;
720 void
721 dbcool_writereg(struct dbcool_chipset *dc, uint8_t reg, uint8_t val)
723 if (iic_acquire_bus(dc->dc_tag, 0) != 0)
724 return;
726 (void)iic_smbus_write_byte(dc->dc_tag, dc->dc_addr, reg, val, 0);
728 iic_release_bus(dc->dc_tag, 0);
731 static bool
732 dbcool_islocked(struct dbcool_softc *sc)
734 uint8_t cfg_reg;
736 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
737 return 0;
739 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
740 cfg_reg = DBCOOL_ADT7466_CONFIG1;
741 else
742 cfg_reg = DBCOOL_CONFIG1_REG;
744 if (sc->sc_dc.dc_readreg(&sc->sc_dc, cfg_reg) & DBCOOL_CFG1_LOCK)
745 return 1;
746 else
747 return 0;
750 static int
751 dbcool_read_temp(struct dbcool_softc *sc, uint8_t reg, bool extres)
753 uint8_t t1, t2, t3, val, ext = 0;
754 int temp;
756 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
758 * ADT7466 temps are in strange location
760 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1);
761 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
762 if (extres)
763 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
764 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
766 * ADM1030 temps are in their own special place, too
768 if (extres) {
769 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_TEMP_EXTRES);
770 if (reg == DBCOOL_ADM1030_L_TEMP)
771 ext >>= 6;
772 else
773 ext >>= 1;
774 ext &= 0x03;
776 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
777 } else if (extres) {
778 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG);
780 /* Read all msb regs to unlatch them */
781 t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_12VIN);
782 t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE1_TEMP);
783 t2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE2_TEMP);
784 t3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_LOCAL_TEMP);
785 switch (reg) {
786 case DBCOOL_REMOTE1_TEMP:
787 val = t1;
788 ext >>= 2;
789 break;
790 case DBCOOL_LOCAL_TEMP:
791 val = t3;
792 ext >>= 4;
793 break;
794 case DBCOOL_REMOTE2_TEMP:
795 val = t2;
796 ext >>= 6;
797 break;
798 default:
799 val = 0;
800 break;
802 ext &= 0x03;
804 else
805 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
807 /* Check for invalid temp values */
808 if ((sc->sc_temp_offset == 0 && val == 0x80) ||
809 (sc->sc_temp_offset != 0 && val == 0))
810 return 0;
812 /* If using offset mode, adjust, else treat as signed */
813 if (sc->sc_temp_offset) {
814 temp = val;
815 temp -= sc->sc_temp_offset;
816 } else
817 temp = (int8_t)val;
819 /* Convert degC to uK and include extended precision bits */
820 temp *= 1000000;
821 temp += 250000 * (int)ext;
822 temp += 273150000U;
824 return temp;
827 static int
828 dbcool_read_rpm(struct dbcool_softc *sc, uint8_t reg)
830 int rpm;
831 uint8_t rpm_lo, rpm_hi;
833 rpm_lo = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
834 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
835 rpm_hi = (rpm_lo == 0xff)?0xff:0x0;
836 else
837 rpm_hi = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
839 rpm = (rpm_hi << 8) | rpm_lo;
840 if (rpm == 0xffff)
841 return 0; /* 0xffff indicates stalled/failed fan */
843 return (sc->sc_dc.dc_chip->rpm_dividend / rpm);
846 /* Provide chip's supply voltage, in microvolts */
847 static int
848 dbcool_supply_voltage(struct dbcool_softc *sc)
850 if (sc->sc_dc.dc_chip->flags & DBCFLAG_MULTI_VCC) {
851 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG) & DBCOOL_CFG1_Vcc)
852 return 5002500;
853 else
854 return 3300000;
855 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
856 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) &
857 DBCOOL_ADT7466_CFG1_Vcc)
858 return 5000000;
859 else
860 return 3300000;
861 } else
862 return 3300000;
866 * Nominal voltages are calculated in microvolts
868 static int
869 dbcool_read_volt(struct dbcool_softc *sc, uint8_t reg, int nom_idx, bool extres)
871 uint8_t ext = 0, v1, v2, v3, v4, val;
872 int64_t ret;
873 int64_t nom;
875 nom = nominal_voltages[nom_idx];
876 if (nom < 0)
877 nom = sc->sc_supply_voltage;
879 /* ADT7466 voltages are in strange locations with only 8-bits */
880 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
881 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
882 else
884 * It's a "normal" dbCool chip - check for regs that
885 * share extended resolution bits since we have to
886 * read all the MSB registers to unlatch them.
888 if (!extres)
889 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
890 else if (reg == DBCOOL_12VIN) {
891 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG) && 0x03;
892 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
893 (void)dbcool_read_temp(sc, DBCOOL_LOCAL_TEMP, true);
894 } else if (reg == DBCOOL_VTT || reg == DBCOOL_IMON) {
895 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES_VTT_IMON);
896 v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_IMON);
897 v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VTT);
898 if (reg == DBCOOL_IMON) {
899 val = v1;
900 ext >>= 6;
901 } else
902 val = v2;
903 ext >>= 4;
904 ext &= 0x0f;
905 } else {
906 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES1_REG);
907 v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_25VIN);
908 v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCCP);
909 v3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCC);
910 v4 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_5VIN);
912 switch (reg) {
913 case DBCOOL_25VIN:
914 val = v1;
915 break;
916 case DBCOOL_VCCP:
917 val = v2;
918 ext >>= 2;
919 break;
920 case DBCOOL_VCC:
921 val = v3;
922 ext >>= 4;
923 break;
924 case DBCOOL_5VIN:
925 val = v4;
926 ext >>= 6;
927 break;
928 default:
929 val = nom = 0;
931 ext &= 0x03;
935 * Scale the nominal value by the 10-bit fraction
937 * Returned value is in microvolts.
939 ret = val;
940 ret <<= 2;
941 ret |= ext;
942 ret = (ret * nom) / 0x300;
944 return ret;
947 SYSCTL_SETUP(sysctl_dbcoolsetup, "sysctl dBCool subtree setup")
949 sysctl_createv(NULL, 0, NULL, NULL,
950 CTLFLAG_PERMANENT,
951 CTLTYPE_NODE, "hw", NULL,
952 NULL, 0, NULL, 0,
953 CTL_HW, CTL_EOL);
956 static int
957 sysctl_dbcool_temp(SYSCTLFN_ARGS)
959 struct sysctlnode node;
960 struct dbcool_softc *sc;
961 int reg, error;
962 uint8_t chipreg;
963 uint8_t newreg;
965 node = *rnode;
966 sc = (struct dbcool_softc *)node.sysctl_data;
967 chipreg = node.sysctl_num & 0xff;
969 if (sc->sc_temp_offset) {
970 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
971 reg -= sc->sc_temp_offset;
972 } else
973 reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
975 node.sysctl_data = &reg;
976 error = sysctl_lookup(SYSCTLFN_CALL(&node));
978 if (error || newp == NULL)
979 return error;
981 /* We were asked to update the value - sanity check before writing */
982 if (*(int *)node.sysctl_data < -64 ||
983 *(int *)node.sysctl_data > 127 + sc->sc_temp_offset)
984 return EINVAL;
986 newreg = *(int *)node.sysctl_data;
987 newreg += sc->sc_temp_offset;
988 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
989 return 0;
992 static int
993 sysctl_adm1030_temp(SYSCTLFN_ARGS)
995 struct sysctlnode node;
996 struct dbcool_softc *sc;
997 int reg, error;
998 uint8_t chipreg, oldreg, newreg;
1000 node = *rnode;
1001 sc = (struct dbcool_softc *)node.sysctl_data;
1002 chipreg = node.sysctl_num & 0xff;
1004 oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1005 reg = (oldreg >> 1) & ~0x03;
1007 node.sysctl_data = &reg;
1008 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1010 if (error || newp == NULL)
1011 return error;
1013 /* We were asked to update the value - sanity check before writing */
1014 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 127)
1015 return EINVAL;
1017 newreg = *(int *)node.sysctl_data;
1018 newreg &= ~0x03;
1019 newreg <<= 1;
1020 newreg |= (oldreg & 0x07);
1021 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1022 return 0;
1025 static int
1026 sysctl_adm1030_trange(SYSCTLFN_ARGS)
1028 struct sysctlnode node;
1029 struct dbcool_softc *sc;
1030 int reg, error, newval;
1031 uint8_t chipreg, oldreg, newreg;
1033 node = *rnode;
1034 sc = (struct dbcool_softc *)node.sysctl_data;
1035 chipreg = node.sysctl_num & 0xff;
1037 oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1038 reg = oldreg & 0x07;
1040 node.sysctl_data = &reg;
1041 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1043 if (error || newp == NULL)
1044 return error;
1046 /* We were asked to update the value - sanity check before writing */
1047 newval = *(int *)node.sysctl_data;
1049 if (newval == 5)
1050 newreg = 0;
1051 else if (newval == 10)
1052 newreg = 1;
1053 else if (newval == 20)
1054 newreg = 2;
1055 else if (newval == 40)
1056 newreg = 3;
1057 else if (newval == 80)
1058 newreg = 4;
1059 else
1060 return EINVAL;
1062 newreg |= (oldreg & ~0x07);
1063 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1064 return 0;
1067 static int
1068 sysctl_dbcool_duty(SYSCTLFN_ARGS)
1070 struct sysctlnode node;
1071 struct dbcool_softc *sc;
1072 int reg, error;
1073 uint8_t chipreg, oldreg, newreg;
1075 node = *rnode;
1076 sc = (struct dbcool_softc *)node.sysctl_data;
1077 chipreg = node.sysctl_num & 0xff;
1079 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1080 reg = (uint32_t)oldreg;
1081 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
1082 reg = ((reg & 0x0f) * 100) / 15;
1083 else
1084 reg = (reg * 100) / 255;
1085 node.sysctl_data = &reg;
1086 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1088 if (error || newp == NULL)
1089 return error;
1091 /* We were asked to update the value - sanity check before writing */
1092 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 100)
1093 return EINVAL;
1095 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
1096 newreg = *(uint8_t *)(node.sysctl_data) * 15 / 100;
1097 newreg |= oldreg & 0xf0;
1098 } else
1099 newreg = *(uint8_t *)(node.sysctl_data) * 255 / 100;
1100 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1101 return 0;
1104 static int
1105 sysctl_dbcool_behavior(SYSCTLFN_ARGS)
1107 struct sysctlnode node;
1108 struct dbcool_softc *sc;
1109 int i, reg, error;
1110 uint8_t chipreg, oldreg, newreg;
1112 node = *rnode;
1113 sc = (struct dbcool_softc *)node.sysctl_data;
1114 chipreg = node.sysctl_num & 0xff;
1116 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1118 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
1119 if ((sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) & 1) == 0)
1120 reg = 4;
1121 else if ((oldreg & 0x80) == 0)
1122 reg = 7;
1123 else if ((oldreg & 0x60) == 0)
1124 reg = 4;
1125 else
1126 reg = 6;
1127 } else
1128 reg = (oldreg >> 5) & 0x07;
1130 strlcpy(dbcool_cur_behav, behavior[reg], sizeof(dbcool_cur_behav));
1131 node.sysctl_data = dbcool_cur_behav;
1132 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1134 if (error || newp == NULL)
1135 return error;
1137 /* We were asked to update the value - convert string to value */
1138 newreg = __arraycount(behavior);
1139 for (i = 0; i < __arraycount(behavior); i++)
1140 if (strcmp(node.sysctl_data, behavior[i]) == 0)
1141 break;
1142 if (i >= __arraycount(behavior))
1143 return EINVAL;
1145 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
1147 * ADM1030 splits fan controller behavior across two
1148 * registers. We also do not support Auto-Filter mode
1149 * nor do we support Manual-RPM-feedback.
1151 if (newreg == 4) {
1152 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2);
1153 oldreg &= ~0x01;
1154 sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
1155 } else {
1156 if (newreg == 0)
1157 newreg = 4;
1158 else if (newreg == 6)
1159 newreg = 7;
1160 else if (newreg == 7)
1161 newreg = 0;
1162 else
1163 return EINVAL;
1164 newreg <<= 5;
1165 newreg |= (oldreg & 0x1f);
1166 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1167 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) | 1;
1168 sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
1170 } else {
1171 newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x1f) | (i << 5);
1172 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1174 return 0;
1177 static int
1178 sysctl_dbcool_slope(SYSCTLFN_ARGS)
1180 struct sysctlnode node;
1181 struct dbcool_softc *sc;
1182 int reg, error;
1183 uint8_t chipreg;
1184 uint8_t newreg;
1186 node = *rnode;
1187 sc = (struct dbcool_softc *)node.sysctl_data;
1188 chipreg = node.sysctl_num & 0xff;
1190 reg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) >> 4) & 0x0f;
1191 node.sysctl_data = &reg;
1192 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1194 if (error || newp == NULL)
1195 return error;
1197 /* We were asked to update the value - sanity check before writing */
1198 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 0x0f)
1199 return EINVAL;
1201 newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x0f) |
1202 (*(int *)node.sysctl_data << 4);
1203 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1204 return 0;
1207 static int
1208 sysctl_dbcool_volt_limit(SYSCTLFN_ARGS)
1210 struct sysctlnode node;
1211 struct dbcool_softc *sc;
1212 int reg, error;
1213 int nom, sensor_index;
1214 int64_t val, newval;
1215 uint8_t chipreg, newreg;
1217 node = *rnode;
1218 sc = (struct dbcool_softc *)node.sysctl_data;
1219 chipreg = node.sysctl_num & 0xff;
1222 * Retrieve the nominal value for the voltage sensor
1224 sensor_index = (node.sysctl_num >> 8 ) & 0xff;
1225 nom = nominal_voltages[sc->sc_dc.dc_chip->table[sensor_index].nom_volt_index];
1226 if (nom < 0)
1227 nom = dbcool_supply_voltage(sc);
1230 * Use int64_t for calculation to avoid overflow
1232 val = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1233 val *= nom;
1234 val /= 0xc0; /* values are scaled so 0xc0 == nominal voltage */
1235 reg = val;
1236 node.sysctl_data = &reg;
1237 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1239 if (error || newp == NULL)
1240 return error;
1243 * We were asked to update the value, so scale it and sanity
1244 * check before writing
1246 if (nom == 0)
1247 return EINVAL;
1248 newval = *(int *)node.sysctl_data;
1249 newval *= 0xc0;
1250 newval /= nom;
1251 if (newval < 0 || newval > 0xff)
1252 return EINVAL;
1254 newreg = newval;
1255 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1256 return 0;
1259 static int
1260 sysctl_dbcool_temp_limit(SYSCTLFN_ARGS)
1262 struct sysctlnode node;
1263 struct dbcool_softc *sc;
1264 int reg, error, newtemp;
1265 uint8_t chipreg;
1267 node = *rnode;
1268 sc = (struct dbcool_softc *)node.sysctl_data;
1269 chipreg = node.sysctl_num & 0xff;
1271 /* If using offset mode, adjust, else treat as signed */
1272 if (sc->sc_temp_offset) {
1273 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1274 reg -= sc->sc_temp_offset;
1275 } else
1276 reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1278 node.sysctl_data = &reg;
1279 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1281 if (error || newp == NULL)
1282 return error;
1284 /* We were asked to update the value - sanity check before writing */
1285 newtemp = *(int *)node.sysctl_data + sc->sc_temp_offset;
1286 if (newtemp < 0 || newtemp > 0xff)
1287 return EINVAL;
1289 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newtemp);
1290 return 0;
1293 static int
1294 sysctl_dbcool_fan_limit(SYSCTLFN_ARGS)
1296 struct sysctlnode node;
1297 struct dbcool_softc *sc;
1298 int reg, error, newrpm, dividend;
1299 uint8_t chipreg;
1300 uint8_t newreg;
1302 node = *rnode;
1303 sc = (struct dbcool_softc *)node.sysctl_data;
1304 chipreg = node.sysctl_num & 0xff;
1306 /* retrieve two-byte limit */
1307 reg = dbcool_read_rpm(sc, chipreg);
1309 node.sysctl_data = &reg;
1310 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1312 if (error || newp == NULL)
1313 return error;
1316 * We were asked to update the value. Calculate the two-byte
1317 * limit and validate it. Due to the way fan RPM is calculated,
1318 * the new value must be at least 83 RPM (331 RPM for ADM1030)!
1319 * Allow a value of -1 or 0 to indicate no limit.
1321 newrpm = *(int *)node.sysctl_data;
1322 if (newrpm == 0 || newrpm == -1)
1323 newrpm = 0xffff;
1324 else {
1325 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
1326 dividend = 11250 * 60;
1327 else
1328 dividend = 90000 * 60;
1329 newrpm = dividend / newrpm;
1330 if (newrpm & ~0xffff)
1331 return EINVAL;
1334 /* Update the on-chip registers with new value */
1335 newreg = newrpm & 0xff;
1336 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1337 newreg = (newrpm >> 8) & 0xff;
1338 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg + 1, newreg);
1339 return 0;
1342 static int
1343 sysctl_dbcool_vid(SYSCTLFN_ARGS)
1345 struct sysctlnode node;
1346 struct dbcool_softc *sc;
1347 int reg, error;
1348 uint8_t chipreg, newreg;
1350 node = *rnode;
1351 sc = (struct dbcool_softc *)node.sysctl_data;
1352 chipreg = node.sysctl_num;
1354 /* retrieve 5- or 6-bit value */
1355 newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1356 if ((sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_VID_SEL) &&
1357 (reg & 0x80))
1358 reg = newreg & 0x3f;
1359 else
1360 reg = newreg & 0x1f;
1362 node.sysctl_data = &reg;
1363 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1365 if (error == 0 && newp != NULL)
1366 error = EINVAL;
1368 return error;
1371 static int
1372 sysctl_dbcool_thyst(SYSCTLFN_ARGS)
1374 struct sysctlnode node;
1375 struct dbcool_softc *sc;
1376 int reg, error;
1377 uint8_t chipreg;
1378 uint8_t newreg, newhyst;
1380 node = *rnode;
1381 sc = (struct dbcool_softc *)node.sysctl_data;
1382 chipreg = node.sysctl_num & 0x7f;
1384 /* retrieve 4-bit value */
1385 newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1386 if ((node.sysctl_num & 0x80) == 0)
1387 reg = newreg >> 4;
1388 else
1389 reg = newreg;
1390 reg = reg & 0x0f;
1392 node.sysctl_data = &reg;
1393 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1395 if (error || newp == NULL)
1396 return error;
1398 /* We were asked to update the value - sanity check before writing */
1399 newhyst = *(int *)node.sysctl_data;
1400 if (newhyst > 0x0f)
1401 return EINVAL;
1403 /* Insert new value into field and update register */
1404 if ((node.sysctl_num & 0x80) == 0) {
1405 newreg &= 0x0f;
1406 newreg |= (newhyst << 4);
1407 } else {
1408 newreg &= 0xf0;
1409 newreg |= newhyst;
1411 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1412 return 0;
1415 #ifdef DBCOOL_DEBUG
1418 * These routines can be used for debugging. reg_select is used to
1419 * select any arbitrary register in the device. reg_access is used
1420 * to read (and optionally update) the selected register.
1422 * No attempt is made to validate the data passed. If you use these
1423 * routines, you are assumed to know what you're doing!
1425 * Caveat user
1427 static int
1428 sysctl_dbcool_reg_select(SYSCTLFN_ARGS)
1430 struct sysctlnode node;
1431 struct dbcool_softc *sc;
1432 int reg, error;
1434 node = *rnode;
1435 sc = (struct dbcool_softc *)node.sysctl_data;
1437 reg = sc->sc_user_reg;
1438 node.sysctl_data = &reg;
1439 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1441 if (error || newp == NULL)
1442 return error;
1444 sc->sc_user_reg = *(int *)node.sysctl_data;
1445 return 0;
1448 static int
1449 sysctl_dbcool_reg_access(SYSCTLFN_ARGS)
1451 struct sysctlnode node;
1452 struct dbcool_softc *sc;
1453 int reg, error;
1454 uint8_t chipreg;
1455 uint8_t newreg;
1457 node = *rnode;
1458 sc = (struct dbcool_softc *)node.sysctl_data;
1459 chipreg = sc->sc_user_reg;
1461 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1462 node.sysctl_data = &reg;
1463 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1465 if (error || newp == NULL)
1466 return error;
1468 newreg = *(int *)node.sysctl_data;
1469 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1470 return 0;
1472 #endif /* DBCOOL_DEBUG */
1475 * Encode an index number and register number for use as a sysctl_num
1476 * so we can select the correct device register later.
1478 #define DBC_PWM_SYSCTL(seq, reg) ((seq << 8) | reg)
1480 void
1481 dbcool_setup(device_t self)
1483 struct dbcool_softc *sc = device_private(self);
1484 const struct sysctlnode *me = NULL;
1485 struct sysctlnode *node = NULL;
1486 uint8_t cfg_val, cfg_reg;
1487 int ro_flag, rw_flag, ret, error;
1490 * Some chips are capable of reporting an extended temperature range
1491 * by default. On these models, config register 5 bit 0 can be set
1492 * to 1 for compatability with other chips that report 2s complement.
1494 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
1495 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) & 0x80)
1496 sc->sc_temp_offset = 64;
1497 else
1498 sc->sc_temp_offset = 0;
1499 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_TEMPOFFSET) {
1500 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG5_REG) &
1501 DBCOOL_CFG5_TWOSCOMP)
1502 sc->sc_temp_offset = 0;
1503 else
1504 sc->sc_temp_offset = 64;
1505 } else
1506 sc->sc_temp_offset = 0;
1508 /* Determine Vcc for this chip */
1509 sc->sc_supply_voltage = dbcool_supply_voltage(sc);
1511 sc->sc_sme = sysmon_envsys_create();
1513 ro_flag = dbcool_islocked(sc)?CTLFLAG_READONLY:CTLFLAG_READWRITE;
1514 ro_flag |= CTLFLAG_OWNDESC;
1515 rw_flag = CTLFLAG_READWRITE | CTLFLAG_OWNDESC;
1516 ret = sysctl_createv(NULL, 0, NULL, &me,
1517 CTLFLAG_READWRITE,
1518 CTLTYPE_NODE, device_xname(self), NULL,
1519 NULL, 0, NULL, 0,
1520 CTL_HW, CTL_CREATE, CTL_EOL);
1521 if (sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_VID) {
1522 ret = sysctl_createv(NULL, 0, NULL,
1523 (const struct sysctlnode **)&node,
1524 CTLFLAG_READONLY, CTLTYPE_INT, "CPU_VID_bits", NULL,
1525 sysctl_dbcool_vid,
1526 0, sc, sizeof(int),
1527 CTL_HW, me->sysctl_num, DBCOOL_VID_REG, CTL_EOL);
1528 if (node != NULL)
1529 node->sysctl_data = sc;
1532 #ifdef DBCOOL_DEBUG
1533 ret = sysctl_createv(NULL, 0, NULL,
1534 (const struct sysctlnode **)&node,
1535 CTLFLAG_READWRITE, CTLTYPE_INT, "reg_select", NULL,
1536 sysctl_dbcool_reg_select,
1537 0, sc, sizeof(int),
1538 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
1539 if (node != NULL)
1540 node->sysctl_data = sc;
1542 ret = sysctl_createv(NULL, 0, NULL,
1543 (const struct sysctlnode **)&node,
1544 CTLFLAG_READWRITE, CTLTYPE_INT, "reg_access", NULL,
1545 sysctl_dbcool_reg_access,
1546 0, sc, sizeof(int),
1547 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
1548 if (node != NULL)
1549 node->sysctl_data = sc;
1550 #endif /* DBCOOL_DEBUG */
1552 /* Create the sensors for this device */
1553 if (dbcool_setup_sensors(sc, me, rw_flag, ro_flag))
1554 goto out;
1556 /* If supported, create sysctl tree for fan PWM controllers */
1557 if (sc->sc_dc.dc_chip->power != NULL)
1558 dbcool_setup_controllers(sc, me, rw_flag, ro_flag);
1561 * Read and rewrite config register to activate device
1563 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
1564 cfg_reg = DBCOOL_ADM1030_CFG1;
1565 else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
1566 cfg_reg = DBCOOL_ADT7466_CONFIG1;
1567 else
1568 cfg_reg = DBCOOL_CONFIG1_REG;
1569 cfg_val = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG);
1570 if ((cfg_val & DBCOOL_CFG1_START) == 0) {
1571 cfg_val |= DBCOOL_CFG1_START;
1572 sc->sc_dc.dc_writereg(&sc->sc_dc, cfg_reg, cfg_val);
1574 if (dbcool_islocked(sc))
1575 aprint_normal_dev(self, "configuration locked\n");
1577 sc->sc_sme->sme_name = device_xname(self);
1578 sc->sc_sme->sme_cookie = sc;
1579 sc->sc_sme->sme_refresh = dbcool_refresh;
1581 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
1582 aprint_error_dev(self,
1583 "unable to register with sysmon (%d)\n", error);
1584 goto out;
1587 return;
1589 out:
1590 sysmon_envsys_destroy(sc->sc_sme);
1593 static int
1594 dbcool_setup_sensors(struct dbcool_softc *sc, const struct sysctlnode *me,
1595 int rw_flag, int ro_flag)
1597 int i, j, ret;
1598 int error = 0;
1599 uint8_t sysctl_reg;
1600 struct sysctlnode *node = NULL;
1601 int sysctl_index, sysctl_num;
1602 char name[SYSCTL_NAMELEN];
1604 for (i=0; sc->sc_dc.dc_chip->table[i].type != DBC_EOF; i++) {
1605 if (i >= DBCOOL_MAXSENSORS &&
1606 sc->sc_dc.dc_chip->table[i].type != DBC_CTL) {
1607 aprint_normal_dev(sc->sc_dev, "chip table too big!\n");
1608 break;
1610 switch (sc->sc_dc.dc_chip->table[i].type) {
1611 case DBC_TEMP:
1612 sc->sc_sensor[i].units = ENVSYS_STEMP;
1613 error = dbcool_attach_sensor(sc, me, i,
1614 sysctl_dbcool_temp_limit);
1615 break;
1616 case DBC_VOLT:
1617 sc->sc_sensor[i].units = ENVSYS_SVOLTS_DC;
1618 error = dbcool_attach_sensor(sc, me, i,
1619 sysctl_dbcool_volt_limit);
1620 break;
1621 case DBC_FAN:
1622 sc->sc_sensor[i].units = ENVSYS_SFANRPM;
1623 error = dbcool_attach_sensor(sc, me, i,
1624 sysctl_dbcool_fan_limit);
1625 break;
1626 case DBC_CTL:
1628 * Search for the corresponding temp sensor
1629 * (temp sensors need to be created first!)
1631 sysctl_num = -1;
1632 for (j = 0; j < i; j++) {
1633 if (j > DBCOOL_MAXSENSORS ||
1634 sc->sc_dc.dc_chip->table[j].type != DBC_TEMP)
1635 continue;
1636 if (sc->sc_dc.dc_chip->table[j].name_index ==
1637 sc->sc_dc.dc_chip->table[i].name_index) {
1638 sysctl_num = sc->sc_sysctl_num[j];
1639 break;
1642 if (sysctl_num == -1)
1643 break;
1644 sysctl_index = sc->sc_dc.dc_chip->table[i].sysctl_index;
1645 sysctl_reg = sc->sc_dc.dc_chip->table[i].reg.val_reg;
1646 strlcpy(name, dbc_sysctl_table[sysctl_index].name,
1647 sizeof(name));
1648 ret = sysctl_createv(NULL, 0, NULL,
1649 (const struct sysctlnode **)&node,
1650 dbc_sysctl_table[sysctl_index].lockable?
1651 ro_flag:rw_flag,
1652 CTLTYPE_INT, name,
1653 dbc_sysctl_table[sysctl_index].desc,
1654 dbc_sysctl_table[sysctl_index].helper,
1655 0, sc, sizeof(int),
1656 CTL_HW, me->sysctl_num, sysctl_num,
1657 DBC_PWM_SYSCTL(i, sysctl_reg), CTL_EOL);
1658 if (node != NULL)
1659 node->sysctl_data = sc;
1660 break;
1661 default:
1662 aprint_error_dev(sc->sc_dev,
1663 "sensor_table index %d has bad type %d\n",
1664 i, sc->sc_dc.dc_chip->table[i].type);
1665 break;
1667 if (error)
1668 break;
1670 return error;
1673 static int
1674 dbcool_attach_sensor(struct dbcool_softc *sc, const struct sysctlnode *me,
1675 int idx, int (*helper)(SYSCTLFN_PROTO))
1677 struct sysctlnode *node = NULL;
1678 const struct sysctlnode *me2 = NULL;
1679 uint8_t sysctl_reg;
1680 int name_index;
1681 int ret;
1682 int error = 0;
1684 name_index = sc->sc_dc.dc_chip->table[idx].name_index;
1685 strlcpy(sc->sc_sensor[idx].desc, dbc_sensor_names[name_index],
1686 sizeof(sc->sc_sensor[idx].desc));
1687 sc->sc_regs[idx] = &sc->sc_dc.dc_chip->table[idx].reg;
1688 sc->sc_nom_volt[idx] = sc->sc_dc.dc_chip->table[idx].nom_volt_index;
1690 sc->sc_sensor[idx].flags |= ENVSYS_FMONLIMITS;
1692 error = sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[idx]);
1693 if (error)
1694 return error;
1697 * create sysctl node for the sensor, and the nodes for
1698 * the sensor's high and low limit values
1700 ret = sysctl_createv(NULL, 0, NULL, &me2, CTLFLAG_READWRITE,
1701 CTLTYPE_NODE, sc->sc_sensor[idx].desc, NULL,
1702 NULL, 0, NULL, 0,
1703 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
1704 if (me2 == NULL)
1705 return 0;
1707 sc->sc_sysctl_num[idx] = me2->sysctl_num;
1709 /* create sysctl node for the low limit */
1710 sysctl_reg = sc->sc_regs[idx]->lo_lim_reg;
1711 ret = sysctl_createv(NULL, 0, NULL,
1712 (const struct sysctlnode **)&node,
1713 CTLFLAG_READWRITE,
1714 CTLTYPE_INT, "low_lim", NULL, helper, 0, sc, 0,
1715 CTL_HW, me->sysctl_num, me2->sysctl_num,
1716 DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL);
1717 if (node != NULL)
1718 node->sysctl_data = sc;
1720 /* Fans do not have a high limit */
1721 if (sc->sc_dc.dc_chip->table[idx].type == DBC_FAN)
1722 return 0;
1724 sysctl_reg = sc->sc_regs[idx]->hi_lim_reg;
1725 ret = sysctl_createv(NULL, 0, NULL,
1726 (const struct sysctlnode **)&node,
1727 CTLFLAG_READWRITE,
1728 CTLTYPE_INT, "hi_lim", NULL, helper, 0, sc, 0,
1729 CTL_HW, me->sysctl_num, me2->sysctl_num,
1730 DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL);
1731 if (node != NULL)
1732 node->sysctl_data = sc;
1734 return 0;
1737 static void
1738 dbcool_setup_controllers(struct dbcool_softc *sc, const struct sysctlnode *me,
1739 int rw_flag, int ro_flag)
1741 int i, j, ret;
1742 uint8_t sysctl_reg;
1743 const struct sysctlnode *me2 = NULL;
1744 struct sysctlnode *node = NULL;
1745 char name[SYSCTL_NAMELEN];
1747 for (i = 0; sc->sc_dc.dc_chip->power[i].desc != NULL; i++) {
1748 snprintf(name, sizeof(name), "fan_ctl_%d", i);
1749 ret = sysctl_createv(NULL, 0, NULL, &me2,
1750 rw_flag,
1751 CTLTYPE_NODE, name, NULL,
1752 NULL, 0, NULL, 0,
1753 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
1755 for (j = DBC_PWM_BEHAVIOR; j < DBC_PWM_LAST_PARAM; j++) {
1756 if (j == DBC_PWM_MAX_DUTY &&
1757 (sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_MAXDUTY) == 0)
1758 continue;
1759 sysctl_reg = sc->sc_dc.dc_chip->power[i].power_regs[j];
1760 if (sysctl_reg == DBCOOL_NO_REG)
1761 continue;
1762 strlcpy(name, dbc_sysctl_table[j].name, sizeof(name));
1763 ret = sysctl_createv(NULL, 0, NULL,
1764 (const struct sysctlnode **)&node,
1765 (dbc_sysctl_table[j].lockable)?ro_flag:rw_flag,
1766 (j == DBC_PWM_BEHAVIOR)?
1767 CTLTYPE_STRING:CTLTYPE_INT,
1768 name,
1769 dbc_sysctl_table[j].desc,
1770 dbc_sysctl_table[j].helper,
1771 0, sc,
1772 ( j == DBC_PWM_BEHAVIOR)?
1773 sizeof(dbcool_cur_behav): sizeof(int),
1774 CTL_HW, me->sysctl_num, me2->sysctl_num,
1775 DBC_PWM_SYSCTL(j, sysctl_reg), CTL_EOL);
1776 if (node != NULL)
1777 node->sysctl_data = sc;
1782 static void
1783 dbcool_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1785 struct dbcool_softc *sc=sme->sme_cookie;
1786 int i, nom_volt_idx;
1787 int cur, hi, low;
1788 struct reg_list *reg;
1790 i = edata->sensor;
1791 reg = sc->sc_regs[i];
1792 switch (edata->units)
1794 case ENVSYS_STEMP:
1795 cur = dbcool_read_temp(sc, reg->val_reg, true);
1796 low = dbcool_read_temp(sc, reg->lo_lim_reg, false);
1797 hi = dbcool_read_temp(sc, reg->hi_lim_reg, false);
1798 break;
1799 case ENVSYS_SVOLTS_DC:
1800 nom_volt_idx = sc->sc_nom_volt[i];
1801 cur = dbcool_read_volt(sc, reg->val_reg, nom_volt_idx,
1802 true);
1803 low = dbcool_read_volt(sc, reg->lo_lim_reg,
1804 nom_volt_idx, false);
1805 hi = dbcool_read_volt(sc, reg->hi_lim_reg,
1806 nom_volt_idx, false);
1807 break;
1808 case ENVSYS_SFANRPM:
1809 cur = dbcool_read_rpm(sc, reg->val_reg);
1810 low = dbcool_read_rpm(sc, reg->lo_lim_reg);
1811 hi = 1 << 16;
1812 break;
1813 default:
1814 edata->state = ENVSYS_SINVALID;
1815 return;
1818 if (cur == 0 && edata->units != ENVSYS_SFANRPM)
1819 edata->state = ENVSYS_SINVALID;
1821 /* Make sure limits are sensible */
1822 else if (hi <= low)
1823 edata->state = ENVSYS_SVALID;
1826 * If fan is "stalled" but has no low limit, treat
1827 * it as though the fan is not installed.
1829 else if (edata->units == ENVSYS_SFANRPM && cur == 0 &&
1830 (low == 0 || low == -1))
1831 edata->state = ENVSYS_SINVALID;
1834 * Compare current value against the limits
1836 else if (cur < low)
1837 edata->state = ENVSYS_SCRITUNDER;
1838 else if (cur > hi)
1839 edata->state = ENVSYS_SCRITOVER;
1840 else
1841 edata->state = ENVSYS_SVALID;
1843 edata->value_cur = cur;
1847 dbcool_chip_ident(struct dbcool_chipset *dc)
1849 /* verify this is a supported dbCool chip */
1850 uint8_t c_id, d_id, r_id;
1851 int i;
1853 c_id = dc->dc_readreg(dc, DBCOOL_COMPANYID_REG);
1854 d_id = dc->dc_readreg(dc, DBCOOL_DEVICEID_REG);
1855 r_id = dc->dc_readreg(dc, DBCOOL_REVISION_REG);
1857 for (i = 0; chip_table[i].company != 0; i++)
1858 if ((c_id == chip_table[i].company) &&
1859 (d_id == chip_table[i].device ||
1860 chip_table[i].device == 0xff) &&
1861 (r_id == chip_table[i].rev ||
1862 chip_table[i].rev == 0xff)) {
1863 dc->dc_chip = &chip_table[i];
1864 return i;
1867 aprint_verbose("dbcool_chip_ident: addr 0x%02x c_id 0x%02x d_id 0x%02x"
1868 " r_id 0x%02x: No match.\n", dc->dc_addr, c_id, d_id,
1869 r_id);
1871 return -1;