1 /* $NetBSD: dbcool.c,v 1.13 2009/11/02 21:37:44 christos Exp $ */
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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);
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
));
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
{
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
137 * If you rearrange the order of these items, be sure to
138 * update the sysctl_index in the XXX_sensor_table[] for
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
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,
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
,
192 DBCOOL_VCCP_LOWLIM
}, 3, 0, 1 },
193 { DBC_VOLT
, { DBCOOL_VCC
,
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
,
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
,
207 DBCOOL_VTT_LOWLIM
}, 14, 0, 5 },
208 { DBC_VOLT
, { DBCOOL_IMON
,
210 DBCOOL_IMON_LOWLIM
}, 15, 0, 5 },
211 { DBC_FAN
, { DBCOOL_FAN1_TACH_LSB
,
213 DBCOOL_TACH1_MIN_LSB
}, 5, 0, 0 },
214 { DBC_FAN
, { DBCOOL_FAN2_TACH_LSB
,
216 DBCOOL_TACH2_MIN_LSB
}, 6, 0, 0 },
217 { DBC_FAN
, { DBCOOL_FAN3_TACH_LSB
,
219 DBCOOL_TACH3_MIN_LSB
}, 7, 0, 0 },
220 { DBC_FAN
, { DBCOOL_FAN4_TACH_LSB
,
222 DBCOOL_TACH4_MIN_LSB
}, 8, 0, 0 },
223 { DBC_CTL
, { DBCOOL_LOCAL_TMIN
,
225 DBCOOL_NO_REG
}, 0, 5, 0 },
226 { DBC_CTL
, { DBCOOL_LOCAL_TTHRESH
,
228 DBCOOL_NO_REG
}, 0, 6, 0 },
229 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
| 0x80,
231 DBCOOL_NO_REG
}, 0, 7, 0 },
232 { DBC_CTL
, { DBCOOL_REMOTE1_TMIN
,
234 DBCOOL_NO_REG
}, 1, 5, 0 },
235 { DBC_CTL
, { DBCOOL_REMOTE1_TTHRESH
,
237 DBCOOL_NO_REG
}, 1, 6, 0 },
238 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
,
240 DBCOOL_NO_REG
}, 1, 7, 0 },
241 { DBC_CTL
, { DBCOOL_REMOTE2_TMIN
,
243 DBCOOL_NO_REG
}, 2, 5, 0 },
244 { DBC_CTL
, { DBCOOL_REMOTE2_TTHRESH
,
246 DBCOOL_NO_REG
}, 2, 6, 0 },
247 { DBC_CTL
, { DBCOOL_R2_TMIN_HYST
,
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
,
265 DBCOOL_VCCP_LOWLIM
}, 3, 0, 1 },
266 { DBC_VOLT
, { DBCOOL_VCC
,
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
,
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
,
280 DBCOOL_TACH1_MIN_LSB
}, 5, 0, 0 },
281 { DBC_FAN
, { DBCOOL_FAN2_TACH_LSB
,
283 DBCOOL_TACH2_MIN_LSB
}, 6, 0, 0 },
284 { DBC_FAN
, { DBCOOL_FAN3_TACH_LSB
,
286 DBCOOL_TACH3_MIN_LSB
}, 7, 0, 0 },
287 { DBC_FAN
, { DBCOOL_FAN4_TACH_LSB
,
289 DBCOOL_TACH4_MIN_LSB
}, 8, 0, 0 },
290 { DBC_CTL
, { DBCOOL_LOCAL_TMIN
,
292 DBCOOL_NO_REG
}, 0, 5, 0 },
293 { DBC_CTL
, { DBCOOL_LOCAL_TTHRESH
,
295 DBCOOL_NO_REG
}, 0, 6, 0 },
296 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
| 0x80,
298 DBCOOL_NO_REG
}, 0, 7, 0 },
299 { DBC_CTL
, { DBCOOL_REMOTE1_TMIN
,
301 DBCOOL_NO_REG
}, 1, 5, 0 },
302 { DBC_CTL
, { DBCOOL_REMOTE1_TTHRESH
,
304 DBCOOL_NO_REG
}, 1, 6, 0 },
305 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
,
307 DBCOOL_NO_REG
}, 1, 7, 0 },
308 { DBC_CTL
, { DBCOOL_REMOTE2_TMIN
,
310 DBCOOL_NO_REG
}, 2, 5, 0 },
311 { DBC_CTL
, { DBCOOL_REMOTE2_TTHRESH
,
313 DBCOOL_NO_REG
}, 2, 6, 0 },
314 { DBC_CTL
, { DBCOOL_R2_TMIN_HYST
,
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
,
332 DBCOOL_VCCP_LOWLIM
}, 3, 0, 1 },
333 { DBC_VOLT
, { DBCOOL_VCC
,
335 DBCOOL_VCC_LOWLIM
}, 4, 0, 0 },
336 { DBC_FAN
, { DBCOOL_FAN1_TACH_LSB
,
338 DBCOOL_TACH1_MIN_LSB
}, 5, 0, 0 },
339 { DBC_FAN
, { DBCOOL_FAN2_TACH_LSB
,
341 DBCOOL_TACH2_MIN_LSB
}, 6, 0, 0 },
342 { DBC_FAN
, { DBCOOL_FAN3_TACH_LSB
,
344 DBCOOL_TACH3_MIN_LSB
}, 7, 0, 0 },
345 { DBC_FAN
, { DBCOOL_FAN4_TACH_LSB
,
347 DBCOOL_TACH4_MIN_LSB
}, 8, 0, 0 },
348 { DBC_CTL
, { DBCOOL_LOCAL_TMIN
,
350 DBCOOL_NO_REG
}, 0, 5, 0 },
351 { DBC_CTL
, { DBCOOL_LOCAL_TTHRESH
,
353 DBCOOL_NO_REG
}, 0, 6, 0 },
354 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
| 0x80,
356 DBCOOL_NO_REG
}, 0, 7, 0 },
357 { DBC_CTL
, { DBCOOL_REMOTE1_TMIN
,
359 DBCOOL_NO_REG
}, 1, 5, 0 },
360 { DBC_CTL
, { DBCOOL_REMOTE1_TTHRESH
,
362 DBCOOL_NO_REG
}, 1, 6, 0 },
363 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
,
365 DBCOOL_NO_REG
}, 1, 7, 0 },
366 { DBC_CTL
, { DBCOOL_REMOTE2_TMIN
,
368 DBCOOL_NO_REG
}, 2, 5, 0 },
369 { DBC_CTL
, { DBCOOL_REMOTE2_TTHRESH
,
371 DBCOOL_NO_REG
}, 2, 6, 0 },
372 { DBC_CTL
, { DBCOOL_R2_TMIN_HYST
,
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
},
386 { { DBCOOL_PWM2_CTL
, DBCOOL_PWM2_MINDUTY
,
387 DBCOOL_PWM2_MAXDUTY
, DBCOOL_PWM2_CURDUTY
},
389 { { DBCOOL_PWM3_CTL
, DBCOOL_PWM3_MINDUTY
,
390 DBCOOL_PWM3_MAXDUTY
, DBCOOL_PWM3_CURDUTY
},
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
,
413 DBCOOL_ADT7466_FANA_LOLIM_LSB
}, 5, 0, 0 },
414 { DBC_FAN
, { DBCOOL_ADT7466_FANB_LSB
,
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
,
432 DBCOOL_VCCP_LOWLIM
}, 3, 0, 1 },
433 { DBC_VOLT
, { DBCOOL_VCC
,
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
,
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
,
447 DBCOOL_TACH1_MIN_LSB
}, 5, 0, 0 },
448 { DBC_FAN
, { DBCOOL_FAN2_TACH_LSB
,
450 DBCOOL_TACH2_MIN_LSB
}, 6, 0, 0 },
451 { DBC_FAN
, { DBCOOL_FAN3_TACH_LSB
,
453 DBCOOL_TACH3_MIN_LSB
}, 7, 0, 0 },
454 { DBC_FAN
, { DBCOOL_FAN4_TACH_LSB
,
456 DBCOOL_TACH4_MIN_LSB
}, 8, 0, 0 },
457 { DBC_CTL
, { DBCOOL_LOCAL_TMIN
,
459 DBCOOL_NO_REG
}, 0, 5, 0 },
460 { DBC_CTL
, { DBCOOL_LOCAL_TTHRESH
,
462 DBCOOL_NO_REG
}, 0, 6, 0 },
463 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
| 0x80,
465 DBCOOL_NO_REG
}, 0, 7, 0 },
466 { DBC_CTL
, { DBCOOL_REMOTE1_TMIN
,
468 DBCOOL_NO_REG
}, 1, 5, 0 },
469 { DBC_CTL
, { DBCOOL_REMOTE1_TTHRESH
,
471 DBCOOL_NO_REG
}, 1, 6, 0 },
472 { DBC_CTL
, { DBCOOL_R1_LCL_TMIN_HYST
,
474 DBCOOL_NO_REG
}, 1, 7, 0 },
475 { DBC_CTL
, { DBCOOL_REMOTE2_TMIN
,
477 DBCOOL_NO_REG
}, 2, 5, 0 },
478 { DBC_CTL
, { DBCOOL_REMOTE2_TTHRESH
,
480 DBCOOL_NO_REG
}, 2, 6, 0 },
481 { DBC_CTL
, { DBCOOL_R2_TMIN_HYST
,
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
,
496 DBCOOL_ADM1030_FAN_LO_LIM
}, 5, 0, 0 },
497 { DBC_CTL
, { DBCOOL_ADM1030_L_TMIN
,
499 DBCOOL_NO_REG
}, 0, 8, 0 },
500 { DBC_CTL
, { DBCOOL_ADM1030_L_TTHRESH
,
502 DBCOOL_NO_REG
}, 0, 9, 0 },
503 { DBC_CTL
, { DBCOOL_ADM1030_L_TTHRESH
,
505 DBCOOL_NO_REG
}, 0, 6, 0 },
506 { DBC_CTL
, { DBCOOL_ADM1030_R_TMIN
,
508 DBCOOL_NO_REG
}, 1, 8, 0 },
509 { DBC_CTL
, { DBCOOL_ADM1030_L_TTHRESH
,
511 DBCOOL_NO_REG
}, 1, 9, 0 },
512 { DBC_CTL
, { DBCOOL_ADM1030_R_TTHRESH
,
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
},
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
|
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
,
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
;
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
)
601 if (dbcool_chip_ident(&dc
) >= 0)
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
;
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
);
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);
631 aprint_normal_dev(self
, "%s dBCool(tm) Controller "
632 "(rev 0x%04x)\n", sc
->sc_dc
.dc_chip
->name
, ver
);
636 if (!pmf_device_register(self
, dbcool_pmf_suspend
, dbcool_pmf_resume
))
637 aprint_error_dev(self
, "couldn't establish power handler\n");
641 dbcool_detach(device_t self
, int flags
)
643 struct dbcool_softc
*sc
= device_private(self
);
645 sysmon_envsys_unregister(sc
->sc_sme
);
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)
659 if (sc
->sc_dc
.dc_chip
->flags
&& DBCFLAG_ADT7466
) {
660 reg
= DBCOOL_ADT7466_CONFIG2
;
661 bit
= DBCOOL_ADT7466_CFG2_SHDN
;
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
;
669 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, reg
, cfg
);
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)
683 if (sc
->sc_dc
.dc_chip
->flags
&& DBCFLAG_ADT7466
) {
684 reg
= DBCOOL_ADT7466_CONFIG2
;
685 bit
= DBCOOL_ADT7466_CFG2_SHDN
;
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
);
699 dbcool_readreg(struct dbcool_chipset
*dc
, uint8_t reg
)
703 if (iic_acquire_bus(dc
->dc_tag
, 0) != 0)
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)
710 (void)iic_smbus_receive_byte(dc
->dc_tag
, dc
->dc_addr
, &data
, 0);
712 (void)iic_smbus_read_byte(dc
->dc_tag
, dc
->dc_addr
, reg
, &data
,
716 iic_release_bus(dc
->dc_tag
, 0);
721 dbcool_writereg(struct dbcool_chipset
*dc
, uint8_t reg
, uint8_t val
)
723 if (iic_acquire_bus(dc
->dc_tag
, 0) != 0)
726 (void)iic_smbus_write_byte(dc
->dc_tag
, dc
->dc_addr
, reg
, val
, 0);
728 iic_release_bus(dc
->dc_tag
, 0);
732 dbcool_islocked(struct dbcool_softc
*sc
)
736 if (sc
->sc_dc
.dc_chip
->flags
& DBCFLAG_ADM1030
)
739 if (sc
->sc_dc
.dc_chip
->flags
& DBCFLAG_ADT7466
)
740 cfg_reg
= DBCOOL_ADT7466_CONFIG1
;
742 cfg_reg
= DBCOOL_CONFIG1_REG
;
744 if (sc
->sc_dc
.dc_readreg(&sc
->sc_dc
, cfg_reg
) & DBCOOL_CFG1_LOCK
)
751 dbcool_read_temp(struct dbcool_softc
*sc
, uint8_t reg
, bool extres
)
753 uint8_t t1
, t2
, t3
, val
, ext
= 0;
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
);
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
769 ext
= sc
->sc_dc
.dc_readreg(&sc
->sc_dc
, DBCOOL_ADM1030_TEMP_EXTRES
);
770 if (reg
== DBCOOL_ADM1030_L_TEMP
)
776 val
= sc
->sc_dc
.dc_readreg(&sc
->sc_dc
, reg
);
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
);
786 case DBCOOL_REMOTE1_TEMP
:
790 case DBCOOL_LOCAL_TEMP
:
794 case DBCOOL_REMOTE2_TEMP
:
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))
812 /* If using offset mode, adjust, else treat as signed */
813 if (sc
->sc_temp_offset
) {
815 temp
-= sc
->sc_temp_offset
;
819 /* Convert degC to uK and include extended precision bits */
821 temp
+= 250000 * (int)ext
;
828 dbcool_read_rpm(struct dbcool_softc
*sc
, uint8_t reg
)
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;
837 rpm_hi
= sc
->sc_dc
.dc_readreg(&sc
->sc_dc
, reg
+ 1);
839 rpm
= (rpm_hi
<< 8) | rpm_lo
;
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 */
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
)
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
)
866 * Nominal voltages are calculated in microvolts
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
;
875 nom
= nominal_voltages
[nom_idx
];
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
);
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.
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
) {
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
);
935 * Scale the nominal value by the 10-bit fraction
937 * Returned value is in microvolts.
942 ret
= (ret
* nom
) / 0x300;
947 SYSCTL_SETUP(sysctl_dbcoolsetup
, "sysctl dBCool subtree setup")
949 sysctl_createv(NULL
, 0, NULL
, NULL
,
951 CTLTYPE_NODE
, "hw", NULL
,
957 sysctl_dbcool_temp(SYSCTLFN_ARGS
)
959 struct sysctlnode node
;
960 struct dbcool_softc
*sc
;
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
;
973 reg
= (int8_t)sc
->sc_dc
.dc_readreg(&sc
->sc_dc
, chipreg
);
975 node
.sysctl_data
= ®
;
976 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
978 if (error
|| newp
== NULL
)
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
)
986 newreg
= *(int *)node
.sysctl_data
;
987 newreg
+= sc
->sc_temp_offset
;
988 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newreg
);
993 sysctl_adm1030_temp(SYSCTLFN_ARGS
)
995 struct sysctlnode node
;
996 struct dbcool_softc
*sc
;
998 uint8_t chipreg
, oldreg
, newreg
;
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
= ®
;
1008 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1010 if (error
|| newp
== NULL
)
1013 /* We were asked to update the value - sanity check before writing */
1014 if (*(int *)node
.sysctl_data
< 0 || *(int *)node
.sysctl_data
> 127)
1017 newreg
= *(int *)node
.sysctl_data
;
1020 newreg
|= (oldreg
& 0x07);
1021 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newreg
);
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
;
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
= ®
;
1041 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1043 if (error
|| newp
== NULL
)
1046 /* We were asked to update the value - sanity check before writing */
1047 newval
= *(int *)node
.sysctl_data
;
1051 else if (newval
== 10)
1053 else if (newval
== 20)
1055 else if (newval
== 40)
1057 else if (newval
== 80)
1062 newreg
|= (oldreg
& ~0x07);
1063 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newreg
);
1068 sysctl_dbcool_duty(SYSCTLFN_ARGS
)
1070 struct sysctlnode node
;
1071 struct dbcool_softc
*sc
;
1073 uint8_t chipreg
, oldreg
, newreg
;
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;
1084 reg
= (reg
* 100) / 255;
1085 node
.sysctl_data
= ®
;
1086 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1088 if (error
|| newp
== NULL
)
1091 /* We were asked to update the value - sanity check before writing */
1092 if (*(int *)node
.sysctl_data
< 0 || *(int *)node
.sysctl_data
> 100)
1095 if (sc
->sc_dc
.dc_chip
->flags
& DBCFLAG_ADM1030
) {
1096 newreg
= *(uint8_t *)(node
.sysctl_data
) * 15 / 100;
1097 newreg
|= oldreg
& 0xf0;
1099 newreg
= *(uint8_t *)(node
.sysctl_data
) * 255 / 100;
1100 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newreg
);
1105 sysctl_dbcool_behavior(SYSCTLFN_ARGS
)
1107 struct sysctlnode node
;
1108 struct dbcool_softc
*sc
;
1110 uint8_t chipreg
, oldreg
, newreg
;
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)
1121 else if ((oldreg
& 0x80) == 0)
1123 else if ((oldreg
& 0x60) == 0)
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
)
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)
1142 if (i
>= __arraycount(behavior
))
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.
1152 oldreg
= sc
->sc_dc
.dc_readreg(&sc
->sc_dc
, DBCOOL_ADM1030_CFG2
);
1154 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, DBCOOL_ADM1030_CFG2
, oldreg
);
1158 else if (newreg
== 6)
1160 else if (newreg
== 7)
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
);
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
);
1178 sysctl_dbcool_slope(SYSCTLFN_ARGS
)
1180 struct sysctlnode node
;
1181 struct dbcool_softc
*sc
;
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
= ®
;
1192 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1194 if (error
|| newp
== NULL
)
1197 /* We were asked to update the value - sanity check before writing */
1198 if (*(int *)node
.sysctl_data
< 0 || *(int *)node
.sysctl_data
> 0x0f)
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
);
1208 sysctl_dbcool_volt_limit(SYSCTLFN_ARGS
)
1210 struct sysctlnode node
;
1211 struct dbcool_softc
*sc
;
1213 int nom
, sensor_index
;
1214 int64_t val
, newval
;
1215 uint8_t chipreg
, newreg
;
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
];
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
);
1234 val
/= 0xc0; /* values are scaled so 0xc0 == nominal voltage */
1236 node
.sysctl_data
= ®
;
1237 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1239 if (error
|| newp
== NULL
)
1243 * We were asked to update the value, so scale it and sanity
1244 * check before writing
1248 newval
= *(int *)node
.sysctl_data
;
1251 if (newval
< 0 || newval
> 0xff)
1255 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newreg
);
1260 sysctl_dbcool_temp_limit(SYSCTLFN_ARGS
)
1262 struct sysctlnode node
;
1263 struct dbcool_softc
*sc
;
1264 int reg
, error
, newtemp
;
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
;
1276 reg
= (int8_t)sc
->sc_dc
.dc_readreg(&sc
->sc_dc
, chipreg
);
1278 node
.sysctl_data
= ®
;
1279 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1281 if (error
|| newp
== NULL
)
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)
1289 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newtemp
);
1294 sysctl_dbcool_fan_limit(SYSCTLFN_ARGS
)
1296 struct sysctlnode node
;
1297 struct dbcool_softc
*sc
;
1298 int reg
, error
, newrpm
, dividend
;
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
= ®
;
1310 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1312 if (error
|| newp
== NULL
)
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)
1325 if (sc
->sc_dc
.dc_chip
->flags
& DBCFLAG_ADM1030
)
1326 dividend
= 11250 * 60;
1328 dividend
= 90000 * 60;
1329 newrpm
= dividend
/ newrpm
;
1330 if (newrpm
& ~0xffff)
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
);
1343 sysctl_dbcool_vid(SYSCTLFN_ARGS
)
1345 struct sysctlnode node
;
1346 struct dbcool_softc
*sc
;
1348 uint8_t chipreg
, newreg
;
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
) &&
1358 reg
= newreg
& 0x3f;
1360 reg
= newreg
& 0x1f;
1362 node
.sysctl_data
= ®
;
1363 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1365 if (error
== 0 && newp
!= NULL
)
1372 sysctl_dbcool_thyst(SYSCTLFN_ARGS
)
1374 struct sysctlnode node
;
1375 struct dbcool_softc
*sc
;
1378 uint8_t newreg
, newhyst
;
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)
1392 node
.sysctl_data
= ®
;
1393 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1395 if (error
|| newp
== NULL
)
1398 /* We were asked to update the value - sanity check before writing */
1399 newhyst
= *(int *)node
.sysctl_data
;
1403 /* Insert new value into field and update register */
1404 if ((node
.sysctl_num
& 0x80) == 0) {
1406 newreg
|= (newhyst
<< 4);
1411 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newreg
);
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!
1428 sysctl_dbcool_reg_select(SYSCTLFN_ARGS
)
1430 struct sysctlnode node
;
1431 struct dbcool_softc
*sc
;
1435 sc
= (struct dbcool_softc
*)node
.sysctl_data
;
1437 reg
= sc
->sc_user_reg
;
1438 node
.sysctl_data
= ®
;
1439 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1441 if (error
|| newp
== NULL
)
1444 sc
->sc_user_reg
= *(int *)node
.sysctl_data
;
1449 sysctl_dbcool_reg_access(SYSCTLFN_ARGS
)
1451 struct sysctlnode node
;
1452 struct dbcool_softc
*sc
;
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
= ®
;
1463 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
1465 if (error
|| newp
== NULL
)
1468 newreg
= *(int *)node
.sysctl_data
;
1469 sc
->sc_dc
.dc_writereg(&sc
->sc_dc
, chipreg
, newreg
);
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)
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;
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;
1504 sc
->sc_temp_offset
= 64;
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
,
1518 CTLTYPE_NODE
, device_xname(self
), NULL
,
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
,
1527 CTL_HW
, me
->sysctl_num
, DBCOOL_VID_REG
, CTL_EOL
);
1529 node
->sysctl_data
= sc
;
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
,
1538 CTL_HW
, me
->sysctl_num
, CTL_CREATE
, CTL_EOL
);
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
,
1547 CTL_HW
, me
->sysctl_num
, CTL_CREATE
, CTL_EOL
);
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
))
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
;
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
);
1590 sysmon_envsys_destroy(sc
->sc_sme
);
1594 dbcool_setup_sensors(struct dbcool_softc
*sc
, const struct sysctlnode
*me
,
1595 int rw_flag
, int ro_flag
)
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");
1610 switch (sc
->sc_dc
.dc_chip
->table
[i
].type
) {
1612 sc
->sc_sensor
[i
].units
= ENVSYS_STEMP
;
1613 error
= dbcool_attach_sensor(sc
, me
, i
,
1614 sysctl_dbcool_temp_limit
);
1617 sc
->sc_sensor
[i
].units
= ENVSYS_SVOLTS_DC
;
1618 error
= dbcool_attach_sensor(sc
, me
, i
,
1619 sysctl_dbcool_volt_limit
);
1622 sc
->sc_sensor
[i
].units
= ENVSYS_SFANRPM
;
1623 error
= dbcool_attach_sensor(sc
, me
, i
,
1624 sysctl_dbcool_fan_limit
);
1628 * Search for the corresponding temp sensor
1629 * (temp sensors need to be created first!)
1632 for (j
= 0; j
< i
; j
++) {
1633 if (j
> DBCOOL_MAXSENSORS
||
1634 sc
->sc_dc
.dc_chip
->table
[j
].type
!= DBC_TEMP
)
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
];
1642 if (sysctl_num
== -1)
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
,
1648 ret
= sysctl_createv(NULL
, 0, NULL
,
1649 (const struct sysctlnode
**)&node
,
1650 dbc_sysctl_table
[sysctl_index
].lockable
?
1653 dbc_sysctl_table
[sysctl_index
].desc
,
1654 dbc_sysctl_table
[sysctl_index
].helper
,
1656 CTL_HW
, me
->sysctl_num
, sysctl_num
,
1657 DBC_PWM_SYSCTL(i
, sysctl_reg
), CTL_EOL
);
1659 node
->sysctl_data
= sc
;
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
);
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
;
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
]);
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
,
1703 CTL_HW
, me
->sysctl_num
, CTL_CREATE
, CTL_EOL
);
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
,
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
);
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
)
1724 sysctl_reg
= sc
->sc_regs
[idx
]->hi_lim_reg
;
1725 ret
= sysctl_createv(NULL
, 0, NULL
,
1726 (const struct sysctlnode
**)&node
,
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
);
1732 node
->sysctl_data
= sc
;
1738 dbcool_setup_controllers(struct dbcool_softc
*sc
, const struct sysctlnode
*me
,
1739 int rw_flag
, int ro_flag
)
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
,
1751 CTLTYPE_NODE
, name
, NULL
,
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)
1759 sysctl_reg
= sc
->sc_dc
.dc_chip
->power
[i
].power_regs
[j
];
1760 if (sysctl_reg
== DBCOOL_NO_REG
)
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
,
1769 dbc_sysctl_table
[j
].desc
,
1770 dbc_sysctl_table
[j
].helper
,
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
);
1777 node
->sysctl_data
= sc
;
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
;
1788 struct reg_list
*reg
;
1791 reg
= sc
->sc_regs
[i
];
1792 switch (edata
->units
)
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);
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
,
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);
1808 case ENVSYS_SFANRPM
:
1809 cur
= dbcool_read_rpm(sc
, reg
->val_reg
);
1810 low
= dbcool_read_rpm(sc
, reg
->lo_lim_reg
);
1814 edata
->state
= ENVSYS_SINVALID
;
1818 if (cur
== 0 && edata
->units
!= ENVSYS_SFANRPM
)
1819 edata
->state
= ENVSYS_SINVALID
;
1821 /* Make sure limits are sensible */
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
1837 edata
->state
= ENVSYS_SCRITUNDER
;
1839 edata
->state
= ENVSYS_SCRITOVER
;
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
;
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
];
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
,