dbcool.c revision 1.28 1 /* $NetBSD: dbcool.c,v 1.28 2011/03/11 19:12:46 pgoyette Exp $ */
2
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Goyette
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
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.
30 */
31
32 /*
33 * a driver for the dbCool(tm) family of environmental controllers
34 *
35 * Data sheets for the various supported chips are available at
36 *
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
47 * http://www.smsc.com/media/Downloads_Public/Data_Sheets/6d103s.pdf
48 *
49 * (URLs are correct as of October 5, 2008)
50 */
51
52 #include <sys/cdefs.h>
53 __KERNEL_RCSID(0, "$NetBSD: dbcool.c,v 1.28 2011/03/11 19:12:46 pgoyette Exp $");
54
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/kernel.h>
58 #include <sys/device.h>
59 #include <sys/malloc.h>
60 #include <sys/sysctl.h>
61
62 #include <dev/i2c/dbcool_var.h>
63 #include <dev/i2c/dbcool_reg.h>
64
65 /* Config interface */
66 static int dbcool_match(device_t, cfdata_t, void *);
67 static void dbcool_attach(device_t, device_t, void *);
68 static int dbcool_detach(device_t, int);
69
70 /* Device attributes */
71 static int dbcool_supply_voltage(struct dbcool_softc *);
72 static bool dbcool_islocked(struct dbcool_softc *);
73
74 /* Sensor read functions */
75 static void dbcool_refresh(struct sysmon_envsys *, envsys_data_t *);
76 static int dbcool_read_rpm(struct dbcool_softc *, uint8_t);
77 static int dbcool_read_temp(struct dbcool_softc *, uint8_t, bool);
78 static int dbcool_read_volt(struct dbcool_softc *, uint8_t, int, bool);
79
80 /* Sensor get/set limit functions */
81 static void dbcool_get_limits(struct sysmon_envsys *, envsys_data_t *,
82 sysmon_envsys_lim_t *, uint32_t *);
83 static void dbcool_get_temp_limits(struct dbcool_softc *, int,
84 sysmon_envsys_lim_t *, uint32_t *);
85 static void dbcool_get_volt_limits(struct dbcool_softc *, int,
86 sysmon_envsys_lim_t *, uint32_t *);
87 static void dbcool_get_fan_limits(struct dbcool_softc *, int,
88 sysmon_envsys_lim_t *, uint32_t *);
89
90 static void dbcool_set_limits(struct sysmon_envsys *, envsys_data_t *,
91 sysmon_envsys_lim_t *, uint32_t *);
92 static void dbcool_set_temp_limits(struct dbcool_softc *, int,
93 sysmon_envsys_lim_t *, uint32_t *);
94 static void dbcool_set_volt_limits(struct dbcool_softc *, int,
95 sysmon_envsys_lim_t *, uint32_t *);
96 static void dbcool_set_fan_limits(struct dbcool_softc *, int,
97 sysmon_envsys_lim_t *, uint32_t *);
98
99 /* SYSCTL Helpers */
100 static int sysctl_dbcool_temp(SYSCTLFN_PROTO);
101 static int sysctl_adm1030_temp(SYSCTLFN_PROTO);
102 static int sysctl_adm1030_trange(SYSCTLFN_PROTO);
103 static int sysctl_dbcool_duty(SYSCTLFN_PROTO);
104 static int sysctl_dbcool_behavior(SYSCTLFN_PROTO);
105 static int sysctl_dbcool_slope(SYSCTLFN_PROTO);
106 static int sysctl_dbcool_thyst(SYSCTLFN_PROTO);
107
108 /* Set-up subroutines */
109 static void dbcool_setup_controllers(struct dbcool_softc *);
110 static int dbcool_setup_sensors(struct dbcool_softc *);
111 static int dbcool_attach_sensor(struct dbcool_softc *, int);
112 static int dbcool_attach_temp_control(struct dbcool_softc *, int,
113 struct chip_id *);
114
115 #ifdef DBCOOL_DEBUG
116 static int sysctl_dbcool_reg_select(SYSCTLFN_PROTO);
117 static int sysctl_dbcool_reg_access(SYSCTLFN_PROTO);
118 #endif /* DBCOOL_DEBUG */
119
120 /*
121 * Descriptions for SYSCTL entries
122 */
123 struct dbc_sysctl_info {
124 const char *name;
125 const char *desc;
126 bool lockable;
127 int (*helper)(SYSCTLFN_PROTO);
128 };
129
130 static struct dbc_sysctl_info dbc_sysctl_table[] = {
131 /*
132 * The first several entries must remain in the same order as the
133 * corresponding entries in enum dbc_pwm_params
134 */
135 { "behavior", "operating behavior and temp selector",
136 true, sysctl_dbcool_behavior },
137 { "min_duty", "minimum fan controller PWM duty cycle",
138 true, sysctl_dbcool_duty },
139 { "max_duty", "maximum fan controller PWM duty cycle",
140 true, sysctl_dbcool_duty },
141 { "cur_duty", "current fan controller PWM duty cycle",
142 false, sysctl_dbcool_duty },
143
144 /*
145 * The rest of these should be in the order in which they
146 * are to be stored in the sysctl tree; the table index is
147 * used as the high-order bits of the sysctl_num to maintain
148 * the sequence.
149 *
150 * If you rearrange the order of these items, be sure to
151 * update the sysctl_index in the XXX_sensor_table[] for
152 * the various chips!
153 */
154 { "Trange", "temp slope/range to reach 100% duty cycle",
155 true, sysctl_dbcool_slope },
156 { "Tmin", "temp at which to start fan controller",
157 true, sysctl_dbcool_temp },
158 { "Ttherm", "temp at which THERM is asserted",
159 true, sysctl_dbcool_temp },
160 { "Thyst", "temp hysteresis for stopping fan controller",
161 true, sysctl_dbcool_thyst },
162 { "Tmin", "temp at which to start fan controller",
163 true, sysctl_adm1030_temp },
164 { "Trange", "temp slope/range to reach 100% duty cycle",
165 true, sysctl_adm1030_trange },
166 };
167
168 static const char *dbc_sensor_names[] = {
169 "l_temp", "r1_temp", "r2_temp", "Vccp", "Vcc", "fan1",
170 "fan2", "fan3", "fan4", "AIN1", "AIN2", "V2dot5",
171 "V5", "V12", "Vtt", "Imon", "VID"
172 };
173
174 /*
175 * Following table derived from product data-sheets
176 */
177 static int64_t nominal_voltages[] = {
178 -1, /* Vcc can be either 3.3 or 5.0V
179 at 3/4 scale */
180 2249939, /* Vccp 2.25V 3/4 scale */
181 2497436, /* 2.5VIN 2.5V 3/4 scale */
182 5002466, /* 5VIN 5V 3/4 scale */
183 12000000, /* 12VIN 12V 3/4 scale */
184 1690809, /* Vtt, Imon 2.25V full scale */
185 1689600, /* AIN1, AIN2 2.25V full scale */
186 0
187 };
188
189 /*
190 * Sensor-type, { val-reg, hilim-reg, lolim-reg}, name-idx, sysctl-table-idx,
191 * nom-voltage-index
192 */
193 struct dbcool_sensor ADT7490_sensor_table[] = {
194 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
195 DBCOOL_LOCAL_HIGHLIM,
196 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
197 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
198 DBCOOL_REMOTE1_HIGHLIM,
199 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
200 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
201 DBCOOL_REMOTE2_HIGHLIM,
202 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
203 { DBC_VOLT, { DBCOOL_VCCP,
204 DBCOOL_VCCP_HIGHLIM,
205 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
206 { DBC_VOLT, { DBCOOL_VCC,
207 DBCOOL_VCC_HIGHLIM,
208 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
209 { DBC_VOLT, { DBCOOL_25VIN,
210 DBCOOL_25VIN_HIGHLIM,
211 DBCOOL_25VIN_LOWLIM }, 11, 0, 2 },
212 { DBC_VOLT, { DBCOOL_5VIN,
213 DBCOOL_5VIN_HIGHLIM,
214 DBCOOL_5VIN_LOWLIM }, 12, 0, 3 },
215 { DBC_VOLT, { DBCOOL_12VIN,
216 DBCOOL_12VIN_HIGHLIM,
217 DBCOOL_12VIN_LOWLIM }, 13, 0, 4 },
218 { DBC_VOLT, { DBCOOL_VTT,
219 DBCOOL_VTT_HIGHLIM,
220 DBCOOL_VTT_LOWLIM }, 14, 0, 5 },
221 { DBC_VOLT, { DBCOOL_IMON,
222 DBCOOL_IMON_HIGHLIM,
223 DBCOOL_IMON_LOWLIM }, 15, 0, 5 },
224 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
225 DBCOOL_NO_REG,
226 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
227 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
228 DBCOOL_NO_REG,
229 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
230 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
231 DBCOOL_NO_REG,
232 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
233 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
234 DBCOOL_NO_REG,
235 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
236 { DBC_VID, { DBCOOL_VID_REG,
237 DBCOOL_NO_REG,
238 DBCOOL_NO_REG }, 16, 0, 0 },
239 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
240 DBCOOL_NO_REG,
241 DBCOOL_NO_REG }, 0, 5, 0 },
242 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
243 DBCOOL_NO_REG,
244 DBCOOL_NO_REG }, 0, 6, 0 },
245 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
246 DBCOOL_NO_REG,
247 DBCOOL_NO_REG }, 0, 7, 0 },
248 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
249 DBCOOL_NO_REG,
250 DBCOOL_NO_REG }, 1, 5, 0 },
251 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
252 DBCOOL_NO_REG,
253 DBCOOL_NO_REG }, 1, 6, 0 },
254 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
255 DBCOOL_NO_REG,
256 DBCOOL_NO_REG }, 1, 7, 0 },
257 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
258 DBCOOL_NO_REG,
259 DBCOOL_NO_REG }, 2, 5, 0 },
260 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
261 DBCOOL_NO_REG,
262 DBCOOL_NO_REG }, 2, 6, 0 },
263 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
264 DBCOOL_NO_REG,
265 DBCOOL_NO_REG }, 2, 7, 0 },
266 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
267 };
268
269 struct dbcool_sensor ADT7476_sensor_table[] = {
270 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
271 DBCOOL_LOCAL_HIGHLIM,
272 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
273 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
274 DBCOOL_REMOTE1_HIGHLIM,
275 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
276 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
277 DBCOOL_REMOTE2_HIGHLIM,
278 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
279 { DBC_VOLT, { DBCOOL_VCCP,
280 DBCOOL_VCCP_HIGHLIM,
281 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
282 { DBC_VOLT, { DBCOOL_VCC,
283 DBCOOL_VCC_HIGHLIM,
284 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
285 { DBC_VOLT, { DBCOOL_25VIN,
286 DBCOOL_25VIN_HIGHLIM,
287 DBCOOL_25VIN_LOWLIM }, 11, 0, 2 },
288 { DBC_VOLT, { DBCOOL_5VIN,
289 DBCOOL_5VIN_HIGHLIM,
290 DBCOOL_5VIN_LOWLIM }, 12, 0, 3 },
291 { DBC_VOLT, { DBCOOL_12VIN,
292 DBCOOL_12VIN_HIGHLIM,
293 DBCOOL_12VIN_LOWLIM }, 13, 0, 4 },
294 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
295 DBCOOL_NO_REG,
296 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
297 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
298 DBCOOL_NO_REG,
299 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
300 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
301 DBCOOL_NO_REG,
302 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
303 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
304 DBCOOL_NO_REG,
305 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
306 { DBC_VID, { DBCOOL_VID_REG,
307 DBCOOL_NO_REG,
308 DBCOOL_NO_REG }, 16, 0, 0 },
309 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
310 DBCOOL_NO_REG,
311 DBCOOL_NO_REG }, 0, 5, 0 },
312 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
313 DBCOOL_NO_REG,
314 DBCOOL_NO_REG }, 0, 6, 0 },
315 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
316 DBCOOL_NO_REG,
317 DBCOOL_NO_REG }, 0, 7, 0 },
318 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
319 DBCOOL_NO_REG,
320 DBCOOL_NO_REG }, 1, 5, 0 },
321 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
322 DBCOOL_NO_REG,
323 DBCOOL_NO_REG }, 1, 6, 0 },
324 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
325 DBCOOL_NO_REG,
326 DBCOOL_NO_REG }, 1, 7, 0 },
327 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
328 DBCOOL_NO_REG,
329 DBCOOL_NO_REG }, 2, 5, 0 },
330 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
331 DBCOOL_NO_REG,
332 DBCOOL_NO_REG }, 2, 6, 0 },
333 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
334 DBCOOL_NO_REG,
335 DBCOOL_NO_REG }, 2, 7, 0 },
336 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
337 };
338
339 struct dbcool_sensor ADT7475_sensor_table[] = {
340 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
341 DBCOOL_LOCAL_HIGHLIM,
342 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
343 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
344 DBCOOL_REMOTE1_HIGHLIM,
345 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
346 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
347 DBCOOL_REMOTE2_HIGHLIM,
348 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
349 { DBC_VOLT, { DBCOOL_VCCP,
350 DBCOOL_VCCP_HIGHLIM,
351 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
352 { DBC_VOLT, { DBCOOL_VCC,
353 DBCOOL_VCC_HIGHLIM,
354 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
355 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
356 DBCOOL_NO_REG,
357 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
358 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
359 DBCOOL_NO_REG,
360 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
361 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
362 DBCOOL_NO_REG,
363 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
364 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
365 DBCOOL_NO_REG,
366 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
367 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
368 DBCOOL_NO_REG,
369 DBCOOL_NO_REG }, 0, 5, 0 },
370 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
371 DBCOOL_NO_REG,
372 DBCOOL_NO_REG }, 0, 6, 0 },
373 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
374 DBCOOL_NO_REG,
375 DBCOOL_NO_REG }, 0, 7, 0 },
376 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
377 DBCOOL_NO_REG,
378 DBCOOL_NO_REG }, 1, 5, 0 },
379 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
380 DBCOOL_NO_REG,
381 DBCOOL_NO_REG }, 1, 6, 0 },
382 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
383 DBCOOL_NO_REG,
384 DBCOOL_NO_REG }, 1, 7, 0 },
385 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
386 DBCOOL_NO_REG,
387 DBCOOL_NO_REG }, 2, 5, 0 },
388 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
389 DBCOOL_NO_REG,
390 DBCOOL_NO_REG }, 2, 6, 0 },
391 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
392 DBCOOL_NO_REG,
393 DBCOOL_NO_REG }, 2, 7, 0 },
394 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
395 };
396
397 /*
398 * The registers of dbcool_power_control must be in the same order as
399 * in enum dbc_pwm_params
400 */
401 struct dbcool_power_control ADT7475_power_table[] = {
402 { { DBCOOL_PWM1_CTL, DBCOOL_PWM1_MINDUTY,
403 DBCOOL_PWM1_MAXDUTY, DBCOOL_PWM1_CURDUTY },
404 "fan_control_1" },
405 { { DBCOOL_PWM2_CTL, DBCOOL_PWM2_MINDUTY,
406 DBCOOL_PWM2_MAXDUTY, DBCOOL_PWM2_CURDUTY },
407 "fan_control_2" },
408 { { DBCOOL_PWM3_CTL, DBCOOL_PWM3_MINDUTY,
409 DBCOOL_PWM3_MAXDUTY, DBCOOL_PWM3_CURDUTY },
410 "fan_control_3" },
411 { { 0, 0, 0, 0 }, NULL }
412 };
413
414 struct dbcool_sensor ADT7466_sensor_table[] = {
415 { DBC_TEMP, { DBCOOL_ADT7466_LCL_TEMP_MSB,
416 DBCOOL_ADT7466_LCL_TEMP_HILIM,
417 DBCOOL_ADT7466_LCL_TEMP_LOLIM }, 0, 0, 0 },
418 { DBC_TEMP, { DBCOOL_ADT7466_REM_TEMP_MSB,
419 DBCOOL_ADT7466_REM_TEMP_HILIM,
420 DBCOOL_ADT7466_REM_TEMP_LOLIM }, 1, 0, 0 },
421 { DBC_VOLT, { DBCOOL_ADT7466_VCC,
422 DBCOOL_ADT7466_VCC_HILIM,
423 DBCOOL_ADT7466_VCC_LOLIM }, 4, 0, 0 },
424 { DBC_VOLT, { DBCOOL_ADT7466_AIN1,
425 DBCOOL_ADT7466_AIN1_HILIM,
426 DBCOOL_ADT7466_AIN1_LOLIM }, 9, 0, 6 },
427 { DBC_VOLT, { DBCOOL_ADT7466_AIN2,
428 DBCOOL_ADT7466_AIN2_HILIM,
429 DBCOOL_ADT7466_AIN2_LOLIM }, 10, 0, 6 },
430 { DBC_FAN, { DBCOOL_ADT7466_FANA_LSB,
431 DBCOOL_NO_REG,
432 DBCOOL_ADT7466_FANA_LOLIM_LSB }, 5, 0, 0 },
433 { DBC_FAN, { DBCOOL_ADT7466_FANB_LSB,
434 DBCOOL_NO_REG,
435 DBCOOL_ADT7466_FANB_LOLIM_LSB }, 6, 0, 0 },
436 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
437 };
438
439 struct dbcool_sensor ADM1027_sensor_table[] = {
440 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
441 DBCOOL_LOCAL_HIGHLIM,
442 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
443 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
444 DBCOOL_REMOTE1_HIGHLIM,
445 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
446 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
447 DBCOOL_REMOTE2_HIGHLIM,
448 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
449 { DBC_VOLT, { DBCOOL_VCCP,
450 DBCOOL_VCCP_HIGHLIM,
451 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
452 { DBC_VOLT, { DBCOOL_VCC,
453 DBCOOL_VCC_HIGHLIM,
454 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
455 { DBC_VOLT, { DBCOOL_25VIN,
456 DBCOOL_25VIN_HIGHLIM,
457 DBCOOL_25VIN_LOWLIM }, 11, 0, 2 },
458 { DBC_VOLT, { DBCOOL_5VIN,
459 DBCOOL_5VIN_HIGHLIM,
460 DBCOOL_5VIN_LOWLIM }, 12, 0, 3 },
461 { DBC_VOLT, { DBCOOL_12VIN,
462 DBCOOL_12VIN_HIGHLIM,
463 DBCOOL_12VIN_LOWLIM }, 13, 0, 4 },
464 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
465 DBCOOL_NO_REG,
466 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
467 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
468 DBCOOL_NO_REG,
469 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
470 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
471 DBCOOL_NO_REG,
472 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
473 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
474 DBCOOL_NO_REG,
475 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
476 { DBC_VID, { DBCOOL_VID_REG,
477 DBCOOL_NO_REG,
478 DBCOOL_NO_REG }, 16, 0, 0 },
479 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
480 DBCOOL_NO_REG,
481 DBCOOL_NO_REG }, 0, 5, 0 },
482 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
483 DBCOOL_NO_REG,
484 DBCOOL_NO_REG }, 0, 6, 0 },
485 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST | 0x80,
486 DBCOOL_NO_REG,
487 DBCOOL_NO_REG }, 0, 7, 0 },
488 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
489 DBCOOL_NO_REG,
490 DBCOOL_NO_REG }, 1, 5, 0 },
491 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
492 DBCOOL_NO_REG,
493 DBCOOL_NO_REG }, 1, 6, 0 },
494 { DBC_CTL, { DBCOOL_R1_LCL_TMIN_HYST,
495 DBCOOL_NO_REG,
496 DBCOOL_NO_REG }, 1, 7, 0 },
497 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
498 DBCOOL_NO_REG,
499 DBCOOL_NO_REG }, 2, 5, 0 },
500 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
501 DBCOOL_NO_REG,
502 DBCOOL_NO_REG }, 2, 6, 0 },
503 { DBC_CTL, { DBCOOL_R2_TMIN_HYST,
504 DBCOOL_NO_REG,
505 DBCOOL_NO_REG }, 2, 7, 0 },
506 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
507 };
508
509 struct dbcool_sensor ADM1030_sensor_table[] = {
510 { DBC_TEMP, { DBCOOL_ADM1030_L_TEMP,
511 DBCOOL_ADM1030_L_HI_LIM,
512 DBCOOL_ADM1030_L_LO_LIM }, 0, 0, 0 },
513 { DBC_TEMP, { DBCOOL_ADM1030_R_TEMP,
514 DBCOOL_ADM1030_R_HI_LIM,
515 DBCOOL_ADM1030_R_LO_LIM }, 1, 0, 0 },
516 { DBC_FAN, { DBCOOL_ADM1030_FAN_TACH,
517 DBCOOL_NO_REG,
518 DBCOOL_ADM1030_FAN_LO_LIM }, 5, 0, 0 },
519 { DBC_CTL, { DBCOOL_ADM1030_L_TMIN,
520 DBCOOL_NO_REG,
521 DBCOOL_NO_REG }, 0, 8, 0 },
522 { DBC_CTL, { DBCOOL_ADM1030_L_TTHRESH,
523 DBCOOL_NO_REG,
524 DBCOOL_NO_REG }, 0, 9, 0 },
525 { DBC_CTL, { DBCOOL_ADM1030_L_TTHRESH,
526 DBCOOL_NO_REG,
527 DBCOOL_NO_REG }, 0, 6, 0 },
528 { DBC_CTL, { DBCOOL_ADM1030_R_TMIN,
529 DBCOOL_NO_REG,
530 DBCOOL_NO_REG }, 1, 8, 0 },
531 { DBC_CTL, { DBCOOL_ADM1030_R_TTHRESH,
532 DBCOOL_NO_REG,
533 DBCOOL_NO_REG }, 1, 9, 0 },
534 { DBC_CTL, { DBCOOL_ADM1030_R_TTHRESH,
535 DBCOOL_NO_REG,
536 DBCOOL_NO_REG }, 1, 6, 0 },
537 { DBC_EOF, {0, 0, 0 }, 0, 0, 0 }
538 };
539
540 struct dbcool_power_control ADM1030_power_table[] = {
541 { { DBCOOL_ADM1030_CFG1, DBCOOL_NO_REG, DBCOOL_NO_REG,
542 DBCOOL_ADM1030_FAN_SPEED_CFG },
543 "fan_control_1" },
544 { { 0, 0, 0, 0 }, NULL }
545 };
546
547 struct dbcool_sensor ADM1031_sensor_table[] = {
548 { DBC_TEMP, { DBCOOL_ADM1030_L_TEMP,
549 DBCOOL_ADM1030_L_HI_LIM,
550 DBCOOL_ADM1030_L_LO_LIM }, 0, 0, 0 },
551 { DBC_TEMP, { DBCOOL_ADM1030_R_TEMP,
552 DBCOOL_ADM1030_R_HI_LIM,
553 DBCOOL_ADM1030_R_LO_LIM }, 1, 0, 0 },
554 { DBC_TEMP, { DBCOOL_ADM1031_R2_TEMP,
555 DBCOOL_ADM1031_R2_HI_LIM,
556 DBCOOL_ADM1031_R2_LO_LIM }, 2, 0, 0 },
557 { DBC_FAN, { DBCOOL_ADM1030_FAN_TACH,
558 DBCOOL_NO_REG,
559 DBCOOL_ADM1030_FAN_LO_LIM }, 5, 0, 0 },
560 { DBC_FAN, { DBCOOL_ADM1031_FAN2_TACH,
561 DBCOOL_NO_REG,
562 DBCOOL_ADM1031_FAN2_LO_LIM }, 6, 0, 0 },
563 { DBC_CTL, { DBCOOL_ADM1030_L_TMIN,
564 DBCOOL_NO_REG,
565 DBCOOL_NO_REG }, 0, 8, 0 },
566 { DBC_CTL, { DBCOOL_ADM1030_L_TTHRESH,
567 DBCOOL_NO_REG,
568 DBCOOL_NO_REG }, 0, 9, 0 },
569 { DBC_CTL, { DBCOOL_ADM1030_L_TTHRESH,
570 DBCOOL_NO_REG,
571 DBCOOL_NO_REG }, 0, 6, 0 },
572 { DBC_CTL, { DBCOOL_ADM1030_R_TMIN,
573 DBCOOL_NO_REG,
574 DBCOOL_NO_REG }, 1, 8, 0 },
575 { DBC_CTL, { DBCOOL_ADM1030_R_TTHRESH,
576 DBCOOL_NO_REG,
577 DBCOOL_NO_REG }, 1, 9, 0 },
578 { DBC_CTL, { DBCOOL_ADM1030_R_TTHRESH,
579 DBCOOL_NO_REG,
580 DBCOOL_NO_REG }, 1, 6, 0 },
581 { DBC_CTL, { DBCOOL_ADM1031_R2_TMIN,
582 DBCOOL_NO_REG,
583 DBCOOL_NO_REG }, 2, 8, 0 },
584 { DBC_CTL, { DBCOOL_ADM1031_R2_TTHRESH,
585 DBCOOL_NO_REG,
586 DBCOOL_NO_REG }, 2, 9, 0 },
587 { DBC_CTL, { DBCOOL_ADM1031_R2_TTHRESH,
588 DBCOOL_NO_REG,
589 DBCOOL_NO_REG }, 2, 6, 0 },
590 { DBC_EOF, {0, 0, 0 }, 0, 0, 0 }
591 };
592
593 struct dbcool_power_control ADM1031_power_table[] = {
594 { { DBCOOL_ADM1030_CFG1, DBCOOL_NO_REG, DBCOOL_NO_REG,
595 DBCOOL_ADM1030_FAN_SPEED_CFG },
596 "fan_control_1" },
597 { { DBCOOL_ADM1030_CFG1, DBCOOL_NO_REG, DBCOOL_NO_REG,
598 DBCOOL_ADM1030_FAN_SPEED_CFG },
599 "fan_control_2" },
600 { { 0, 0, 0, 0 }, NULL }
601 };
602
603 struct dbcool_sensor EMC6D103S_sensor_table[] = {
604 { DBC_TEMP, { DBCOOL_LOCAL_TEMP,
605 DBCOOL_LOCAL_HIGHLIM,
606 DBCOOL_LOCAL_LOWLIM }, 0, 0, 0 },
607 { DBC_TEMP, { DBCOOL_REMOTE1_TEMP,
608 DBCOOL_REMOTE1_HIGHLIM,
609 DBCOOL_REMOTE1_LOWLIM }, 1, 0, 0 },
610 { DBC_TEMP, { DBCOOL_REMOTE2_TEMP,
611 DBCOOL_REMOTE2_HIGHLIM,
612 DBCOOL_REMOTE2_LOWLIM }, 2, 0, 0 },
613 { DBC_VOLT, { DBCOOL_VCCP,
614 DBCOOL_VCCP_HIGHLIM,
615 DBCOOL_VCCP_LOWLIM }, 3, 0, 1 },
616 { DBC_VOLT, { DBCOOL_VCC,
617 DBCOOL_VCC_HIGHLIM,
618 DBCOOL_VCC_LOWLIM }, 4, 0, 0 },
619 { DBC_VOLT, { DBCOOL_25VIN,
620 DBCOOL_25VIN_HIGHLIM,
621 DBCOOL_25VIN_LOWLIM }, 11, 0, 2 },
622 { DBC_VOLT, { DBCOOL_5VIN,
623 DBCOOL_5VIN_HIGHLIM,
624 DBCOOL_5VIN_LOWLIM }, 12, 0, 3 },
625 { DBC_VOLT, { DBCOOL_12VIN,
626 DBCOOL_12VIN_HIGHLIM,
627 DBCOOL_12VIN_LOWLIM }, 13, 0, 4 },
628 { DBC_FAN, { DBCOOL_FAN1_TACH_LSB,
629 DBCOOL_NO_REG,
630 DBCOOL_TACH1_MIN_LSB }, 5, 0, 0 },
631 { DBC_FAN, { DBCOOL_FAN2_TACH_LSB,
632 DBCOOL_NO_REG,
633 DBCOOL_TACH2_MIN_LSB }, 6, 0, 0 },
634 { DBC_FAN, { DBCOOL_FAN3_TACH_LSB,
635 DBCOOL_NO_REG,
636 DBCOOL_TACH3_MIN_LSB }, 7, 0, 0 },
637 { DBC_FAN, { DBCOOL_FAN4_TACH_LSB,
638 DBCOOL_NO_REG,
639 DBCOOL_TACH4_MIN_LSB }, 8, 0, 0 },
640 { DBC_VID, { DBCOOL_VID_REG,
641 DBCOOL_NO_REG,
642 DBCOOL_NO_REG }, 16, 0, 0 },
643 { DBC_CTL, { DBCOOL_LOCAL_TMIN,
644 DBCOOL_NO_REG,
645 DBCOOL_NO_REG }, 0, 5, 0 },
646 { DBC_CTL, { DBCOOL_LOCAL_TTHRESH,
647 DBCOOL_NO_REG,
648 DBCOOL_NO_REG }, 0, 6, 0 },
649 { DBC_CTL, { DBCOOL_REMOTE1_TMIN,
650 DBCOOL_NO_REG,
651 DBCOOL_NO_REG }, 1, 5, 0 },
652 { DBC_CTL, { DBCOOL_REMOTE1_TTHRESH,
653 DBCOOL_NO_REG,
654 DBCOOL_NO_REG }, 1, 6, 0 },
655 { DBC_CTL, { DBCOOL_REMOTE2_TMIN,
656 DBCOOL_NO_REG,
657 DBCOOL_NO_REG }, 2, 5, 0 },
658 { DBC_CTL, { DBCOOL_REMOTE2_TTHRESH,
659 DBCOOL_NO_REG,
660 DBCOOL_NO_REG }, 2, 6, 0 },
661 { DBC_EOF, { 0, 0, 0 }, 0, 0, 0 }
662 };
663
664 struct chip_id chip_table[] = {
665 { DBCOOL_COMPANYID, ADT7490_DEVICEID, ADT7490_REV_ID,
666 ADT7490_sensor_table, ADT7475_power_table,
667 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_PECI,
668 90000 * 60, "ADT7490" },
669 { DBCOOL_COMPANYID, ADT7476_DEVICEID, 0xff,
670 ADT7476_sensor_table, ADT7475_power_table,
671 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY,
672 90000 * 60, "ADT7476" },
673 { DBCOOL_COMPANYID, ADT7475_DEVICEID, 0xff,
674 ADT7475_sensor_table, ADT7475_power_table,
675 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
676 90000 * 60, "ADT7475" },
677 { DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID1,
678 ADT7475_sensor_table, ADT7475_power_table,
679 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
680 90000 * 60, "ADT7460/ADT7463" },
681 { DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID2,
682 ADT7475_sensor_table, ADT7475_power_table,
683 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
684 90000 * 60, "ADT7463-1" },
685 { DBCOOL_COMPANYID, ADT7468_DEVICEID, 0xff,
686 ADT7476_sensor_table, ADT7475_power_table,
687 DBCFLAG_TEMPOFFSET | DBCFLAG_MULTI_VCC | DBCFLAG_HAS_MAXDUTY |
688 DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN,
689 90000 * 60, "ADT7467/ADT7468" },
690 { DBCOOL_COMPANYID, ADT7466_DEVICEID, 0xff,
691 ADT7466_sensor_table, NULL,
692 DBCFLAG_ADT7466 | DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_SHDN,
693 82000 * 60, "ADT7466" },
694 { DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID1,
695 ADM1027_sensor_table, ADT7475_power_table,
696 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN,
697 90000 * 60, "ADT7463" },
698 { DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID2,
699 ADM1027_sensor_table, ADT7475_power_table,
700 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN |
701 DBCFLAG_HAS_VID_SEL,
702 90000 * 60, "ADT7463" },
703 { DBCOOL_COMPANYID, ADM1027_DEVICEID, ADM1027_REV_ID,
704 ADM1027_sensor_table, ADT7475_power_table,
705 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER,
706 90000 * 60, "ADM1027" },
707 { DBCOOL_COMPANYID, ADM1030_DEVICEID, 0xff,
708 ADM1030_sensor_table, ADM1030_power_table,
709 DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE,
710 11250 * 60, "ADM1030" },
711 { DBCOOL_COMPANYID, ADM1031_DEVICEID, 0xff,
712 ADM1031_sensor_table, ADM1030_power_table,
713 DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE,
714 11250 * 60, "ADM1031" },
715 { SMSC_COMPANYID, EMC6D103S_DEVICEID, EMC6D103S_REV_ID,
716 EMC6D103S_sensor_table, ADT7475_power_table,
717 DBCFLAG_4BIT_VER,
718 90000 * 60, "EMC6D103S" },
719 { 0, 0, 0, NULL, NULL, 0, 0, NULL }
720 };
721
722 static const char *behavior[] = {
723 "remote1", "local", "remote2", "full-speed",
724 "disabled", "local+remote2","all-temps", "manual"
725 };
726
727 static char dbcool_cur_behav[16];
728
729 CFATTACH_DECL_NEW(dbcool, sizeof(struct dbcool_softc),
730 dbcool_match, dbcool_attach, dbcool_detach, NULL);
731
732 int
733 dbcool_match(device_t parent, cfdata_t cf, void *aux)
734 {
735 struct i2c_attach_args *ia = aux;
736 struct dbcool_chipset dc;
737 dc.dc_tag = ia->ia_tag;
738 dc.dc_addr = ia->ia_addr;
739 dc.dc_chip = NULL;
740 dc.dc_readreg = dbcool_readreg;
741 dc.dc_writereg = dbcool_writereg;
742
743 /* no probing if we attach to iic, but verify chip id and address */
744 if ((ia->ia_addr & DBCOOL_ADDRMASK) != DBCOOL_ADDR)
745 return 0;
746 if (dbcool_chip_ident(&dc) >= 0)
747 return 1;
748
749 return 0;
750 }
751
752 void
753 dbcool_attach(device_t parent, device_t self, void *aux)
754 {
755 struct dbcool_softc *sc = device_private(self);
756 struct i2c_attach_args *args = aux;
757 uint8_t ver;
758
759 sc->sc_dc.dc_addr = args->ia_addr;
760 sc->sc_dc.dc_tag = args->ia_tag;
761 sc->sc_dc.dc_chip = NULL;
762 sc->sc_dc.dc_readreg = dbcool_readreg;
763 sc->sc_dc.dc_writereg = dbcool_writereg;
764 (void)dbcool_chip_ident(&sc->sc_dc);
765 sc->sc_dev = self;
766
767 aprint_naive("\n");
768 aprint_normal("\n");
769
770 ver = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REVISION_REG);
771 if (sc->sc_dc.dc_chip->flags & DBCFLAG_4BIT_VER)
772 if (sc->sc_dc.dc_chip->company == SMSC_COMPANYID)
773 {
774 aprint_normal_dev(self, "SMSC %s Controller "
775 "(rev 0x%02x, stepping 0x%02x)\n", sc->sc_dc.dc_chip->name,
776 ver >> 4, ver & 0x0f);
777 } else {
778 aprint_normal_dev(self, "%s dBCool(tm) Controller "
779 "(rev 0x%02x, stepping 0x%02x)\n", sc->sc_dc.dc_chip->name,
780 ver >> 4, ver & 0x0f);
781 }
782 else
783 aprint_normal_dev(self, "%s dBCool(tm) Controller "
784 "(rev 0x%04x)\n", sc->sc_dc.dc_chip->name, ver);
785
786 dbcool_setup(self);
787
788 if (!pmf_device_register(self, dbcool_pmf_suspend, dbcool_pmf_resume))
789 aprint_error_dev(self, "couldn't establish power handler\n");
790 }
791
792 static int
793 dbcool_detach(device_t self, int flags)
794 {
795 struct dbcool_softc *sc = device_private(self);
796
797 sysmon_envsys_unregister(sc->sc_sme);
798 sc->sc_sme = NULL;
799 return 0;
800 }
801
802 /* On suspend, we save the state of the SHDN bit, then set it */
803 bool dbcool_pmf_suspend(device_t dev, const pmf_qual_t *qual)
804 {
805 struct dbcool_softc *sc = device_private(dev);
806 uint8_t reg, bit, cfg;
807
808 if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0)
809 return true;
810
811 if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) {
812 reg = DBCOOL_ADT7466_CONFIG2;
813 bit = DBCOOL_ADT7466_CFG2_SHDN;
814 } else {
815 reg = DBCOOL_CONFIG2_REG;
816 bit = DBCOOL_CFG2_SHDN;
817 }
818 cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
819 sc->sc_suspend = cfg & bit;
820 cfg |= bit;
821 sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg);
822
823 return true;
824 }
825
826 /* On resume, we restore the previous state of the SHDN bit */
827 bool dbcool_pmf_resume(device_t dev, const pmf_qual_t *qual)
828 {
829 struct dbcool_softc *sc = device_private(dev);
830 uint8_t reg, bit, cfg;
831
832 if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0)
833 return true;
834
835 if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) {
836 reg = DBCOOL_ADT7466_CONFIG2;
837 bit = DBCOOL_ADT7466_CFG2_SHDN;
838 } else {
839 reg = DBCOOL_CONFIG2_REG;
840 bit = DBCOOL_CFG2_SHDN;
841 }
842 cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
843 cfg &= ~sc->sc_suspend;
844 sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg);
845
846 return true;
847
848 }
849
850 uint8_t
851 dbcool_readreg(struct dbcool_chipset *dc, uint8_t reg)
852 {
853 uint8_t data = 0;
854
855 if (iic_acquire_bus(dc->dc_tag, 0) != 0)
856 return data;
857
858 if (dc->dc_chip == NULL || dc->dc_chip->flags & DBCFLAG_NO_READBYTE) {
859 /* ADM1027 doesn't support i2c read_byte protocol */
860 if (iic_smbus_send_byte(dc->dc_tag, dc->dc_addr, reg, 0) != 0)
861 goto bad;
862 (void)iic_smbus_receive_byte(dc->dc_tag, dc->dc_addr, &data, 0);
863 } else
864 (void)iic_smbus_read_byte(dc->dc_tag, dc->dc_addr, reg, &data,
865 0);
866
867 bad:
868 iic_release_bus(dc->dc_tag, 0);
869 return data;
870 }
871
872 void
873 dbcool_writereg(struct dbcool_chipset *dc, uint8_t reg, uint8_t val)
874 {
875 if (iic_acquire_bus(dc->dc_tag, 0) != 0)
876 return;
877
878 (void)iic_smbus_write_byte(dc->dc_tag, dc->dc_addr, reg, val, 0);
879
880 iic_release_bus(dc->dc_tag, 0);
881 }
882
883 static bool
884 dbcool_islocked(struct dbcool_softc *sc)
885 {
886 uint8_t cfg_reg;
887
888 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
889 return 0;
890
891 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
892 cfg_reg = DBCOOL_ADT7466_CONFIG1;
893 else
894 cfg_reg = DBCOOL_CONFIG1_REG;
895
896 if (sc->sc_dc.dc_readreg(&sc->sc_dc, cfg_reg) & DBCOOL_CFG1_LOCK)
897 return 1;
898 else
899 return 0;
900 }
901
902 static int
903 dbcool_read_temp(struct dbcool_softc *sc, uint8_t reg, bool extres)
904 {
905 uint8_t t1, t2, t3, val, ext = 0;
906 int temp;
907
908 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
909 /*
910 * ADT7466 temps are in strange location
911 */
912 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1);
913 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
914 if (extres)
915 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
916 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
917 /*
918 * ADM1030 temps are in their own special place, too
919 */
920 if (extres) {
921 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_TEMP_EXTRES);
922 if (reg == DBCOOL_ADM1030_L_TEMP)
923 ext >>= 6;
924 else if (reg == DBCOOL_ADM1031_R2_TEMP)
925 ext >>= 4;
926 else
927 ext >>= 1;
928 ext &= 0x03;
929 }
930 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
931 } else if (extres) {
932 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG);
933
934 /* Read all msb regs to unlatch them */
935 t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_12VIN);
936 t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE1_TEMP);
937 t2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE2_TEMP);
938 t3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_LOCAL_TEMP);
939 switch (reg) {
940 case DBCOOL_REMOTE1_TEMP:
941 val = t1;
942 ext >>= 2;
943 break;
944 case DBCOOL_LOCAL_TEMP:
945 val = t3;
946 ext >>= 4;
947 break;
948 case DBCOOL_REMOTE2_TEMP:
949 val = t2;
950 ext >>= 6;
951 break;
952 default:
953 val = 0;
954 break;
955 }
956 ext &= 0x03;
957 }
958 else
959 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
960
961 /* Check for invalid temp values */
962 if ((sc->sc_temp_offset == 0 && val == 0x80) ||
963 (sc->sc_temp_offset != 0 && val == 0))
964 return 0;
965
966 /* If using offset mode, adjust, else treat as signed */
967 if (sc->sc_temp_offset) {
968 temp = val;
969 temp -= sc->sc_temp_offset;
970 } else
971 temp = (int8_t)val;
972
973 /* Convert degC to uK and include extended precision bits */
974 temp *= 1000000;
975 temp += 250000 * (int)ext;
976 temp += 273150000U;
977
978 return temp;
979 }
980
981 static int
982 dbcool_read_rpm(struct dbcool_softc *sc, uint8_t reg)
983 {
984 int rpm;
985 uint8_t rpm_lo, rpm_hi;
986
987 rpm_lo = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
988 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
989 rpm_hi = (rpm_lo == 0xff)?0xff:0x0;
990 else
991 rpm_hi = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
992
993 rpm = (rpm_hi << 8) | rpm_lo;
994 if (rpm == 0xffff)
995 return 0; /* 0xffff indicates stalled/failed fan */
996
997 /* don't divide by zero */
998 return (rpm == 0)? 0 : (sc->sc_dc.dc_chip->rpm_dividend / rpm);
999 }
1000
1001 /* Provide chip's supply voltage, in microvolts */
1002 static int
1003 dbcool_supply_voltage(struct dbcool_softc *sc)
1004 {
1005 if (sc->sc_dc.dc_chip->flags & DBCFLAG_MULTI_VCC) {
1006 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG) & DBCOOL_CFG1_Vcc)
1007 return 5002500;
1008 else
1009 return 3300000;
1010 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
1011 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) &
1012 DBCOOL_ADT7466_CFG1_Vcc)
1013 return 5000000;
1014 else
1015 return 3300000;
1016 } else
1017 return 3300000;
1018 }
1019
1020 /*
1021 * Nominal voltages are calculated in microvolts
1022 */
1023 static int
1024 dbcool_read_volt(struct dbcool_softc *sc, uint8_t reg, int nom_idx, bool extres)
1025 {
1026 uint8_t ext = 0, v1, v2, v3, v4, val;
1027 int64_t ret;
1028 int64_t nom;
1029
1030 nom = nominal_voltages[nom_idx];
1031 if (nom < 0)
1032 nom = sc->sc_supply_voltage;
1033
1034 /* ADT7466 voltages are in strange locations with only 8-bits */
1035 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
1036 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
1037 else
1038 /*
1039 * It's a "normal" dbCool chip - check for regs that
1040 * share extended resolution bits since we have to
1041 * read all the MSB registers to unlatch them.
1042 */
1043 if (!extres)
1044 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
1045 else if (reg == DBCOOL_12VIN) {
1046 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG) && 0x03;
1047 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
1048 (void)dbcool_read_temp(sc, DBCOOL_LOCAL_TEMP, true);
1049 } else if (reg == DBCOOL_VTT || reg == DBCOOL_IMON) {
1050 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES_VTT_IMON);
1051 v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_IMON);
1052 v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VTT);
1053 if (reg == DBCOOL_IMON) {
1054 val = v1;
1055 ext >>= 6;
1056 } else
1057 val = v2;
1058 ext >>= 4;
1059 ext &= 0x0f;
1060 } else {
1061 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES1_REG);
1062 v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_25VIN);
1063 v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCCP);
1064 v3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCC);
1065 v4 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_5VIN);
1066
1067 switch (reg) {
1068 case DBCOOL_25VIN:
1069 val = v1;
1070 break;
1071 case DBCOOL_VCCP:
1072 val = v2;
1073 ext >>= 2;
1074 break;
1075 case DBCOOL_VCC:
1076 val = v3;
1077 ext >>= 4;
1078 break;
1079 case DBCOOL_5VIN:
1080 val = v4;
1081 ext >>= 6;
1082 break;
1083 default:
1084 val = nom = 0;
1085 }
1086 ext &= 0x03;
1087 }
1088
1089 /*
1090 * Scale the nominal value by the 10-bit fraction
1091 *
1092 * Returned value is in microvolts.
1093 */
1094 ret = val;
1095 ret <<= 2;
1096 ret |= ext;
1097 ret = (ret * nom) / 0x300;
1098
1099 return ret;
1100 }
1101
1102 SYSCTL_SETUP(sysctl_dbcoolsetup, "sysctl dBCool subtree setup")
1103 {
1104 sysctl_createv(NULL, 0, NULL, NULL,
1105 CTLFLAG_PERMANENT,
1106 CTLTYPE_NODE, "hw", NULL,
1107 NULL, 0, NULL, 0,
1108 CTL_HW, CTL_EOL);
1109 }
1110
1111 static int
1112 sysctl_dbcool_temp(SYSCTLFN_ARGS)
1113 {
1114 struct sysctlnode node;
1115 struct dbcool_softc *sc;
1116 int reg, error;
1117 uint8_t chipreg;
1118 uint8_t newreg;
1119
1120 node = *rnode;
1121 sc = (struct dbcool_softc *)node.sysctl_data;
1122 chipreg = node.sysctl_num & 0xff;
1123
1124 if (sc->sc_temp_offset) {
1125 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1126 reg -= sc->sc_temp_offset;
1127 } else
1128 reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1129
1130 node.sysctl_data = ®
1131 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1132
1133 if (error || newp == NULL)
1134 return error;
1135
1136 /* We were asked to update the value - sanity check before writing */
1137 if (*(int *)node.sysctl_data < -64 ||
1138 *(int *)node.sysctl_data > 127 + sc->sc_temp_offset)
1139 return EINVAL;
1140
1141 newreg = *(int *)node.sysctl_data;
1142 newreg += sc->sc_temp_offset;
1143 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1144 return 0;
1145 }
1146
1147 static int
1148 sysctl_adm1030_temp(SYSCTLFN_ARGS)
1149 {
1150 struct sysctlnode node;
1151 struct dbcool_softc *sc;
1152 int reg, error;
1153 uint8_t chipreg, oldreg, newreg;
1154
1155 node = *rnode;
1156 sc = (struct dbcool_softc *)node.sysctl_data;
1157 chipreg = node.sysctl_num & 0xff;
1158
1159 oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1160 reg = (oldreg >> 1) & ~0x03;
1161
1162 node.sysctl_data = ®
1163 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1164
1165 if (error || newp == NULL)
1166 return error;
1167
1168 /* We were asked to update the value - sanity check before writing */
1169 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 127)
1170 return EINVAL;
1171
1172 newreg = *(int *)node.sysctl_data;
1173 newreg &= ~0x03;
1174 newreg <<= 1;
1175 newreg |= (oldreg & 0x07);
1176 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1177 return 0;
1178 }
1179
1180 static int
1181 sysctl_adm1030_trange(SYSCTLFN_ARGS)
1182 {
1183 struct sysctlnode node;
1184 struct dbcool_softc *sc;
1185 int reg, error, newval;
1186 uint8_t chipreg, oldreg, newreg;
1187
1188 node = *rnode;
1189 sc = (struct dbcool_softc *)node.sysctl_data;
1190 chipreg = node.sysctl_num & 0xff;
1191
1192 oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1193 reg = oldreg & 0x07;
1194
1195 node.sysctl_data = ®
1196 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1197
1198 if (error || newp == NULL)
1199 return error;
1200
1201 /* We were asked to update the value - sanity check before writing */
1202 newval = *(int *)node.sysctl_data;
1203
1204 if (newval == 5)
1205 newreg = 0;
1206 else if (newval == 10)
1207 newreg = 1;
1208 else if (newval == 20)
1209 newreg = 2;
1210 else if (newval == 40)
1211 newreg = 3;
1212 else if (newval == 80)
1213 newreg = 4;
1214 else
1215 return EINVAL;
1216
1217 newreg |= (oldreg & ~0x07);
1218 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1219 return 0;
1220 }
1221
1222 static int
1223 sysctl_dbcool_duty(SYSCTLFN_ARGS)
1224 {
1225 struct sysctlnode node;
1226 struct dbcool_softc *sc;
1227 int reg, error;
1228 uint8_t chipreg, oldreg, newreg;
1229
1230 node = *rnode;
1231 sc = (struct dbcool_softc *)node.sysctl_data;
1232 chipreg = node.sysctl_num & 0xff;
1233
1234 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1235 reg = (uint32_t)oldreg;
1236 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
1237 reg = ((reg & 0x0f) * 100) / 15;
1238 else
1239 reg = (reg * 100) / 255;
1240 node.sysctl_data = ®
1241 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1242
1243 if (error || newp == NULL)
1244 return error;
1245
1246 /* We were asked to update the value - sanity check before writing */
1247 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 100)
1248 return EINVAL;
1249
1250 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
1251 newreg = *(uint8_t *)(node.sysctl_data) * 15 / 100;
1252 newreg |= oldreg & 0xf0;
1253 } else
1254 newreg = *(uint8_t *)(node.sysctl_data) * 255 / 100;
1255 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1256 return 0;
1257 }
1258
1259 static int
1260 sysctl_dbcool_behavior(SYSCTLFN_ARGS)
1261 {
1262 struct sysctlnode node;
1263 struct dbcool_softc *sc;
1264 int i, reg, error;
1265 uint8_t chipreg, oldreg, newreg;
1266
1267 node = *rnode;
1268 sc = (struct dbcool_softc *)node.sysctl_data;
1269 chipreg = node.sysctl_num & 0xff;
1270
1271 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1272
1273 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
1274 if ((sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) & 1) == 0)
1275 reg = 4;
1276 else if ((oldreg & 0x80) == 0)
1277 reg = 7;
1278 else if ((oldreg & 0x60) == 0)
1279 reg = 4;
1280 else
1281 reg = 6;
1282 } else
1283 reg = (oldreg >> 5) & 0x07;
1284
1285 strlcpy(dbcool_cur_behav, behavior[reg], sizeof(dbcool_cur_behav));
1286 node.sysctl_data = dbcool_cur_behav;
1287 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1288
1289 if (error || newp == NULL)
1290 return error;
1291
1292 /* We were asked to update the value - convert string to value */
1293 newreg = __arraycount(behavior);
1294 for (i = 0; i < __arraycount(behavior); i++)
1295 if (strcmp(node.sysctl_data, behavior[i]) == 0)
1296 break;
1297 if (i >= __arraycount(behavior))
1298 return EINVAL;
1299
1300 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
1301 /*
1302 * ADM1030 splits fan controller behavior across two
1303 * registers. We also do not support Auto-Filter mode
1304 * nor do we support Manual-RPM-feedback.
1305 */
1306 if (newreg == 4) {
1307 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2);
1308 oldreg &= ~0x01;
1309 sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
1310 } else {
1311 if (newreg == 0)
1312 newreg = 4;
1313 else if (newreg == 6)
1314 newreg = 7;
1315 else if (newreg == 7)
1316 newreg = 0;
1317 else
1318 return EINVAL;
1319 newreg <<= 5;
1320 newreg |= (oldreg & 0x1f);
1321 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1322 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) | 1;
1323 sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
1324 }
1325 } else {
1326 newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x1f) | (i << 5);
1327 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1328 }
1329 return 0;
1330 }
1331
1332 static int
1333 sysctl_dbcool_slope(SYSCTLFN_ARGS)
1334 {
1335 struct sysctlnode node;
1336 struct dbcool_softc *sc;
1337 int reg, error;
1338 uint8_t chipreg;
1339 uint8_t newreg;
1340
1341 node = *rnode;
1342 sc = (struct dbcool_softc *)node.sysctl_data;
1343 chipreg = node.sysctl_num & 0xff;
1344
1345 reg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) >> 4) & 0x0f;
1346 node.sysctl_data = ®
1347 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1348
1349 if (error || newp == NULL)
1350 return error;
1351
1352 /* We were asked to update the value - sanity check before writing */
1353 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 0x0f)
1354 return EINVAL;
1355
1356 newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x0f) |
1357 (*(int *)node.sysctl_data << 4);
1358 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1359 return 0;
1360 }
1361
1362 static int
1363 sysctl_dbcool_thyst(SYSCTLFN_ARGS)
1364 {
1365 struct sysctlnode node;
1366 struct dbcool_softc *sc;
1367 int reg, error;
1368 uint8_t chipreg;
1369 uint8_t newreg, newhyst;
1370
1371 node = *rnode;
1372 sc = (struct dbcool_softc *)node.sysctl_data;
1373 chipreg = node.sysctl_num & 0x7f;
1374
1375 /* retrieve 4-bit value */
1376 newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1377 if ((node.sysctl_num & 0x80) == 0)
1378 reg = newreg >> 4;
1379 else
1380 reg = newreg;
1381 reg = reg & 0x0f;
1382
1383 node.sysctl_data = ®
1384 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1385
1386 if (error || newp == NULL)
1387 return error;
1388
1389 /* We were asked to update the value - sanity check before writing */
1390 newhyst = *(int *)node.sysctl_data;
1391 if (newhyst > 0x0f)
1392 return EINVAL;
1393
1394 /* Insert new value into field and update register */
1395 if ((node.sysctl_num & 0x80) == 0) {
1396 newreg &= 0x0f;
1397 newreg |= (newhyst << 4);
1398 } else {
1399 newreg &= 0xf0;
1400 newreg |= newhyst;
1401 }
1402 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1403 return 0;
1404 }
1405
1406 #ifdef DBCOOL_DEBUG
1407
1408 /*
1409 * These routines can be used for debugging. reg_select is used to
1410 * select any arbitrary register in the device. reg_access is used
1411 * to read (and optionally update) the selected register.
1412 *
1413 * No attempt is made to validate the data passed. If you use these
1414 * routines, you are assumed to know what you're doing!
1415 *
1416 * Caveat user
1417 */
1418 static int
1419 sysctl_dbcool_reg_select(SYSCTLFN_ARGS)
1420 {
1421 struct sysctlnode node;
1422 struct dbcool_softc *sc;
1423 int reg, error;
1424
1425 node = *rnode;
1426 sc = (struct dbcool_softc *)node.sysctl_data;
1427
1428 reg = sc->sc_user_reg;
1429 node.sysctl_data = ®
1430 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1431
1432 if (error || newp == NULL)
1433 return error;
1434
1435 sc->sc_user_reg = *(int *)node.sysctl_data;
1436 return 0;
1437 }
1438
1439 static int
1440 sysctl_dbcool_reg_access(SYSCTLFN_ARGS)
1441 {
1442 struct sysctlnode node;
1443 struct dbcool_softc *sc;
1444 int reg, error;
1445 uint8_t chipreg;
1446 uint8_t newreg;
1447
1448 node = *rnode;
1449 sc = (struct dbcool_softc *)node.sysctl_data;
1450 chipreg = sc->sc_user_reg;
1451
1452 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
1453 node.sysctl_data = ®
1454 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1455
1456 if (error || newp == NULL)
1457 return error;
1458
1459 newreg = *(int *)node.sysctl_data;
1460 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
1461 return 0;
1462 }
1463 #endif /* DBCOOL_DEBUG */
1464
1465 /*
1466 * Encode an index number and register number for use as a sysctl_num
1467 * so we can select the correct device register later.
1468 */
1469 #define DBC_PWM_SYSCTL(seq, reg) ((seq << 8) | reg)
1470
1471 void
1472 dbcool_setup(device_t self)
1473 {
1474 struct dbcool_softc *sc = device_private(self);
1475 const struct sysctlnode *me = NULL;
1476 #ifdef DBCOOL_DEBUG
1477 struct sysctlnode *node = NULL;
1478 #endif
1479 uint8_t cfg_val, cfg_reg;
1480 int ret, error;
1481
1482 /*
1483 * Some chips are capable of reporting an extended temperature range
1484 * by default. On these models, config register 5 bit 0 can be set
1485 * to 1 for compatability with other chips that report 2s complement.
1486 */
1487 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
1488 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) & 0x80)
1489 sc->sc_temp_offset = 64;
1490 else
1491 sc->sc_temp_offset = 0;
1492 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_TEMPOFFSET) {
1493 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG5_REG) &
1494 DBCOOL_CFG5_TWOSCOMP)
1495 sc->sc_temp_offset = 0;
1496 else
1497 sc->sc_temp_offset = 64;
1498 } else
1499 sc->sc_temp_offset = 0;
1500
1501 /* Determine Vcc for this chip */
1502 sc->sc_supply_voltage = dbcool_supply_voltage(sc);
1503
1504 ret = sysctl_createv(NULL, 0, NULL, &me,
1505 CTLFLAG_READWRITE,
1506 CTLTYPE_NODE, device_xname(self), NULL,
1507 NULL, 0, NULL, 0,
1508 CTL_HW, CTL_CREATE, CTL_EOL);
1509 if (ret == 0)
1510 sc->sc_root_sysctl_num = me->sysctl_num;
1511 else
1512 sc->sc_root_sysctl_num = 0;
1513
1514 aprint_debug_dev(self,
1515 "Supply voltage %"PRId64".%06"PRId64"V, %s temp range\n",
1516 sc->sc_supply_voltage / 1000000,
1517 sc->sc_supply_voltage % 1000000,
1518 sc->sc_temp_offset ? "extended" : "normal");
1519
1520 /* Create the sensors for this device */
1521 sc->sc_sme = sysmon_envsys_create();
1522 if (dbcool_setup_sensors(sc))
1523 goto out;
1524
1525 if (sc->sc_root_sysctl_num != 0) {
1526 /* If supported, create sysctl tree for fan PWM controllers */
1527 if (sc->sc_dc.dc_chip->power != NULL)
1528 dbcool_setup_controllers(sc);
1529
1530 #ifdef DBCOOL_DEBUG
1531 ret = sysctl_createv(NULL, 0, NULL,
1532 (const struct sysctlnode **)&node,
1533 CTLFLAG_READWRITE, CTLTYPE_INT, "reg_select", NULL,
1534 sysctl_dbcool_reg_select,
1535 0, sc, sizeof(int),
1536 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
1537 if (node != NULL)
1538 node->sysctl_data = sc;
1539
1540 ret = sysctl_createv(NULL, 0, NULL,
1541 (const struct sysctlnode **)&node,
1542 CTLFLAG_READWRITE, CTLTYPE_INT, "reg_access", NULL,
1543 sysctl_dbcool_reg_access,
1544 0, sc, sizeof(int),
1545 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
1546 if (node != NULL)
1547 node->sysctl_data = sc;
1548 #endif /* DBCOOL_DEBUG */
1549 }
1550
1551 /*
1552 * Read and rewrite config register to activate device
1553 */
1554 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
1555 cfg_reg = DBCOOL_ADM1030_CFG1;
1556 else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
1557 cfg_reg = DBCOOL_ADT7466_CONFIG1;
1558 else
1559 cfg_reg = DBCOOL_CONFIG1_REG;
1560 cfg_val = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG);
1561 if ((cfg_val & DBCOOL_CFG1_START) == 0) {
1562 cfg_val |= DBCOOL_CFG1_START;
1563 sc->sc_dc.dc_writereg(&sc->sc_dc, cfg_reg, cfg_val);
1564 }
1565 if (dbcool_islocked(sc))
1566 aprint_normal_dev(self, "configuration locked\n");
1567
1568 sc->sc_sme->sme_name = device_xname(self);
1569 sc->sc_sme->sme_cookie = sc;
1570 sc->sc_sme->sme_refresh = dbcool_refresh;
1571 sc->sc_sme->sme_set_limits = dbcool_set_limits;
1572 sc->sc_sme->sme_get_limits = dbcool_get_limits;
1573
1574 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
1575 aprint_error_dev(self,
1576 "unable to register with sysmon (%d)\n", error);
1577 goto out;
1578 }
1579
1580 return;
1581
1582 out:
1583 sysmon_envsys_destroy(sc->sc_sme);
1584 }
1585
1586 static int
1587 dbcool_setup_sensors(struct dbcool_softc *sc)
1588 {
1589 int i;
1590 int error = 0;
1591 uint8_t vid_reg, vid_val;
1592 struct chip_id *chip = sc->sc_dc.dc_chip;
1593
1594 for (i=0; chip->table[i].type != DBC_EOF; i++) {
1595 if (i < DBCOOL_MAXSENSORS)
1596 sc->sc_sysctl_num[i] = -1;
1597 else if (chip->table[i].type != DBC_CTL) {
1598 aprint_normal_dev(sc->sc_dev, "chip table too big!\n");
1599 break;
1600 }
1601 switch (chip->table[i].type) {
1602 case DBC_TEMP:
1603 sc->sc_sensor[i].units = ENVSYS_STEMP;
1604 sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
1605 error = dbcool_attach_sensor(sc, i);
1606 break;
1607 case DBC_VOLT:
1608 /*
1609 * If 12V-In pin has been reconfigured as 6th bit
1610 * of VID code, don't create a 12V-In sensor
1611 */
1612 if ((chip->flags & DBCFLAG_HAS_VID_SEL) &&
1613 (chip->table[i].reg.val_reg == DBCOOL_12VIN) &&
1614 (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VID_REG) &
1615 0x80))
1616 break;
1617
1618 sc->sc_sensor[i].units = ENVSYS_SVOLTS_DC;
1619 sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
1620 error = dbcool_attach_sensor(sc, i);
1621 break;
1622 case DBC_FAN:
1623 sc->sc_sensor[i].units = ENVSYS_SFANRPM;
1624 sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
1625 error = dbcool_attach_sensor(sc, i);
1626 break;
1627 case DBC_VID:
1628 sc->sc_sensor[i].units = ENVSYS_INTEGER;
1629 sc->sc_sensor[i].flags |= ENVSYS_FMONNOTSUPP;
1630
1631 /* retrieve 5- or 6-bit value */
1632 vid_reg = chip->table[i].reg.val_reg;
1633 vid_val = sc->sc_dc.dc_readreg(&sc->sc_dc, vid_reg);
1634 if (chip->flags & DBCFLAG_HAS_VID_SEL)
1635 vid_val &= 0x3f;
1636 else
1637 vid_val &= 0x1f;
1638 sc->sc_sensor[i].value_cur = vid_val;
1639
1640 error = dbcool_attach_sensor(sc, i);
1641 break;
1642 case DBC_CTL:
1643 error = dbcool_attach_temp_control(sc, i, chip);
1644 if (error) {
1645 aprint_error_dev(sc->sc_dev,
1646 "attach index %d failed %d\n",
1647 i, error);
1648 error = 0;
1649 }
1650 break;
1651 default:
1652 aprint_error_dev(sc->sc_dev,
1653 "sensor_table index %d has bad type %d\n",
1654 i, chip->table[i].type);
1655 break;
1656 }
1657 if (error)
1658 break;
1659 }
1660 return error;
1661 }
1662
1663 static int
1664 dbcool_attach_sensor(struct dbcool_softc *sc, int idx)
1665 {
1666 int name_index;
1667 int error = 0;
1668
1669 name_index = sc->sc_dc.dc_chip->table[idx].name_index;
1670 strlcpy(sc->sc_sensor[idx].desc, dbc_sensor_names[name_index],
1671 sizeof(sc->sc_sensor[idx].desc));
1672 sc->sc_regs[idx] = &sc->sc_dc.dc_chip->table[idx].reg;
1673 sc->sc_nom_volt[idx] = sc->sc_dc.dc_chip->table[idx].nom_volt_index;
1674
1675 error = sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[idx]);
1676 return error;
1677 }
1678
1679 static int
1680 dbcool_attach_temp_control(struct dbcool_softc *sc, int idx,
1681 struct chip_id *chip)
1682 {
1683 const struct sysctlnode *me2 = NULL;
1684 struct sysctlnode *node = NULL;
1685 int j, ret, sysctl_index, rw_flag;
1686 uint8_t sysctl_reg;
1687 char name[SYSCTL_NAMELEN];
1688
1689 /* Search for the corresponding temp sensor */
1690 for (j = 0; j < idx; j++) {
1691 if (j >= DBCOOL_MAXSENSORS || chip->table[j].type != DBC_TEMP)
1692 continue;
1693 if (chip->table[j].name_index == chip->table[idx].name_index)
1694 break;
1695 }
1696 if (j >= idx) /* Temp sensor not found */
1697 return ENOENT;
1698
1699 /* create sysctl node for the sensor if not one already there */
1700 if (sc->sc_sysctl_num[j] == -1) {
1701 ret = sysctl_createv(NULL, 0, NULL, &me2, CTLFLAG_READWRITE,
1702 CTLTYPE_NODE, sc->sc_sensor[j].desc, NULL,
1703 NULL, 0, NULL, 0,
1704 CTL_HW, sc->sc_root_sysctl_num, CTL_CREATE,
1705 CTL_EOL);
1706 if (me2 != NULL)
1707 sc->sc_sysctl_num[j] = me2->sysctl_num;
1708 else
1709 return ret;
1710 }
1711 /* add sysctl leaf node for this control variable */
1712 sysctl_index = chip->table[idx].sysctl_index;
1713 sysctl_reg = chip->table[idx].reg.val_reg;
1714 strlcpy(name, dbc_sysctl_table[sysctl_index].name, sizeof(name));
1715 if (dbc_sysctl_table[sysctl_index].lockable && dbcool_islocked(sc))
1716 rw_flag = CTLFLAG_READONLY | CTLFLAG_OWNDESC;
1717 else
1718 rw_flag = CTLFLAG_READWRITE | CTLFLAG_OWNDESC;
1719 ret = sysctl_createv(NULL, 0, NULL,
1720 (const struct sysctlnode **)&node, rw_flag,
1721 CTLTYPE_INT, name,
1722 SYSCTL_DESCR(dbc_sysctl_table[sysctl_index].desc),
1723 dbc_sysctl_table[sysctl_index].helper,
1724 0, sc, sizeof(int),
1725 CTL_HW, sc->sc_root_sysctl_num,
1726 sc->sc_sysctl_num[j],
1727 DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL);
1728 if (node != NULL)
1729 node->sysctl_data = sc;
1730
1731 return ret;
1732 }
1733
1734 static void
1735 dbcool_setup_controllers(struct dbcool_softc *sc)
1736 {
1737 int i, j, ret, rw_flag;
1738 uint8_t sysctl_reg;
1739 struct chip_id *chip = sc->sc_dc.dc_chip;
1740 const struct sysctlnode *me2 = NULL;
1741 struct sysctlnode *node = NULL;
1742 char name[SYSCTL_NAMELEN];
1743
1744 for (i = 0; chip->power[i].desc != NULL; i++) {
1745 snprintf(name, sizeof(name), "fan_ctl_%d", i);
1746 ret = sysctl_createv(NULL, 0, NULL, &me2,
1747 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
1748 CTLTYPE_NODE, name, NULL,
1749 NULL, 0, NULL, 0,
1750 CTL_HW, sc->sc_root_sysctl_num, CTL_CREATE, CTL_EOL);
1751
1752 for (j = DBC_PWM_BEHAVIOR; j < DBC_PWM_LAST_PARAM; j++) {
1753 if (j == DBC_PWM_MAX_DUTY &&
1754 (chip->flags & DBCFLAG_HAS_MAXDUTY) == 0)
1755 continue;
1756 sysctl_reg = chip->power[i].power_regs[j];
1757 if (sysctl_reg == DBCOOL_NO_REG)
1758 continue;
1759 strlcpy(name, dbc_sysctl_table[j].name, sizeof(name));
1760 if (dbc_sysctl_table[j].lockable && dbcool_islocked(sc))
1761 rw_flag = CTLFLAG_READONLY | CTLFLAG_OWNDESC;
1762 else
1763 rw_flag = CTLFLAG_READWRITE | CTLFLAG_OWNDESC;
1764 ret = sysctl_createv(NULL, 0, NULL,
1765 (const struct sysctlnode **)&node, rw_flag,
1766 (j == DBC_PWM_BEHAVIOR)?
1767 CTLTYPE_STRING:CTLTYPE_INT,
1768 name,
1769 SYSCTL_DESCR(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, sc->sc_root_sysctl_num, me2->sysctl_num,
1775 DBC_PWM_SYSCTL(j, sysctl_reg), CTL_EOL);
1776 if (node != NULL)
1777 node->sysctl_data = sc;
1778 }
1779 }
1780 }
1781
1782 static void
1783 dbcool_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1784 {
1785 struct dbcool_softc *sc=sme->sme_cookie;
1786 int i, nom_volt_idx, cur;
1787 struct reg_list *reg;
1788
1789 i = edata->sensor;
1790 reg = sc->sc_regs[i];
1791
1792 edata->state = ENVSYS_SVALID;
1793 switch (edata->units)
1794 {
1795 case ENVSYS_STEMP:
1796 cur = dbcool_read_temp(sc, reg->val_reg, true);
1797 break;
1798 case ENVSYS_SVOLTS_DC:
1799 nom_volt_idx = sc->sc_nom_volt[i];
1800 cur = dbcool_read_volt(sc, reg->val_reg, nom_volt_idx,
1801 true);
1802 break;
1803 case ENVSYS_SFANRPM:
1804 cur = dbcool_read_rpm(sc, reg->val_reg);
1805 break;
1806 case ENVSYS_INTEGER:
1807 return;
1808 default:
1809 edata->state = ENVSYS_SINVALID;
1810 return;
1811 }
1812
1813 if (cur == 0 && (edata->units != ENVSYS_SFANRPM))
1814 edata->state = ENVSYS_SINVALID;
1815
1816 /*
1817 * If fan is "stalled" but has no low limit, treat
1818 * it as though the fan is not installed.
1819 */
1820 else if (edata->units == ENVSYS_SFANRPM && cur == 0 &&
1821 !(edata->upropset & (PROP_CRITMIN | PROP_WARNMIN)))
1822 edata->state = ENVSYS_SINVALID;
1823
1824 edata->value_cur = cur;
1825 }
1826
1827 int
1828 dbcool_chip_ident(struct dbcool_chipset *dc)
1829 {
1830 /* verify this is a supported dbCool chip */
1831 uint8_t c_id, d_id, r_id;
1832 int i;
1833
1834 c_id = dc->dc_readreg(dc, DBCOOL_COMPANYID_REG);
1835 d_id = dc->dc_readreg(dc, DBCOOL_DEVICEID_REG);
1836 r_id = dc->dc_readreg(dc, DBCOOL_REVISION_REG);
1837
1838 /* The EMC6D103S only supports read_byte and since dc->dc_chip is
1839 * NULL when we call dc->dc_readreg above we use
1840 * send_byte/receive_byte which doesn't work.
1841 *
1842 * So if we only get 0's back then try again with dc->dc_chip
1843 * set to the EMC6D103S_DEVICEID and which dosn't have
1844 * DBCFLAG_NO_READBYTE set so read_byte will be used
1845 */
1846 if ((c_id == 0) && (d_id == 0) && (r_id == 0)) {
1847 for (i = 0; chip_table[i].company != 0; i++)
1848 if ((SMSC_COMPANYID == chip_table[i].company) &&
1849 (EMC6D103S_DEVICEID == chip_table[i].device)) {
1850 dc->dc_chip = &chip_table[i];
1851 break;
1852 }
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);
1856 }
1857
1858 for (i = 0; chip_table[i].company != 0; i++)
1859 if ((c_id == chip_table[i].company) &&
1860 (d_id == chip_table[i].device ||
1861 chip_table[i].device == 0xff) &&
1862 (r_id == chip_table[i].rev ||
1863 chip_table[i].rev == 0xff)) {
1864 dc->dc_chip = &chip_table[i];
1865 return i;
1866 }
1867
1868 aprint_verbose("dbcool_chip_ident: addr 0x%02x c_id 0x%02x d_id 0x%02x"
1869 " r_id 0x%02x: No match.\n", dc->dc_addr, c_id, d_id,
1870 r_id);
1871
1872 return -1;
1873 }
1874
1875 /*
1876 * Retrieve sensor limits from the chip registers
1877 */
1878 static void
1879 dbcool_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
1880 sysmon_envsys_lim_t *limits, uint32_t *props)
1881 {
1882 int index = edata->sensor;
1883 struct dbcool_softc *sc = sme->sme_cookie;
1884
1885 *props &= ~(PROP_CRITMIN | PROP_CRITMAX);
1886 switch (edata->units) {
1887 case ENVSYS_STEMP:
1888 dbcool_get_temp_limits(sc, index, limits, props);
1889 break;
1890 case ENVSYS_SVOLTS_DC:
1891 dbcool_get_volt_limits(sc, index, limits, props);
1892 break;
1893 case ENVSYS_SFANRPM:
1894 dbcool_get_fan_limits(sc, index, limits, props);
1895
1896 /* FALLTHROUGH */
1897 default:
1898 break;
1899 }
1900 *props &= ~PROP_DRIVER_LIMITS;
1901
1902 /* If both limits provided, make sure they're sane */
1903 if ((*props & PROP_CRITMIN) &&
1904 (*props & PROP_CRITMAX) &&
1905 (limits->sel_critmin >= limits->sel_critmax))
1906 *props &= ~(PROP_CRITMIN | PROP_CRITMAX);
1907
1908 /*
1909 * If this is the first time through, save these values
1910 * in case user overrides them and then requests a reset.
1911 */
1912 if (sc->sc_defprops[index] == 0) {
1913 sc->sc_defprops[index] = *props | PROP_DRIVER_LIMITS;
1914 sc->sc_deflims[index] = *limits;
1915 }
1916 }
1917
1918 static void
1919 dbcool_get_temp_limits(struct dbcool_softc *sc, int idx,
1920 sysmon_envsys_lim_t *lims, uint32_t *props)
1921 {
1922 struct reg_list *reg = sc->sc_regs[idx];
1923 uint8_t lo_lim, hi_lim;
1924
1925 lo_lim = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->lo_lim_reg);
1926 hi_lim = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->hi_lim_reg);
1927
1928 if (sc->sc_temp_offset) {
1929 if (lo_lim > 0x01) {
1930 lims->sel_critmin = lo_lim - sc->sc_temp_offset;
1931 *props |= PROP_CRITMIN;
1932 }
1933 if (hi_lim != 0xff) {
1934 lims->sel_critmax = hi_lim - sc->sc_temp_offset;
1935 *props |= PROP_CRITMAX;
1936 }
1937 } else {
1938 if (lo_lim != 0x80 && lo_lim != 0x81) {
1939 lims->sel_critmin = (int8_t)lo_lim;
1940 *props |= PROP_CRITMIN;
1941 }
1942
1943 if (hi_lim != 0x7f) {
1944 lims->sel_critmax = (int8_t)hi_lim;
1945 *props |= PROP_CRITMAX;
1946 }
1947 }
1948
1949 /* Convert temp limits to microKelvin */
1950 lims->sel_critmin *= 1000000;
1951 lims->sel_critmin += 273150000;
1952 lims->sel_critmax *= 1000000;
1953 lims->sel_critmax += 273150000;
1954 }
1955
1956 static void
1957 dbcool_get_volt_limits(struct dbcool_softc *sc, int idx,
1958 sysmon_envsys_lim_t *lims, uint32_t *props)
1959 {
1960 struct reg_list *reg = sc->sc_regs[idx];
1961 int64_t limit;
1962 int nom;
1963
1964 nom = nominal_voltages[sc->sc_dc.dc_chip->table[idx].nom_volt_index];
1965 if (nom < 0)
1966 nom = dbcool_supply_voltage(sc);
1967 nom *= 1000000; /* scale for microvolts */
1968
1969 limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->lo_lim_reg);
1970 if (limit != 0x00 && limit != 0xff) {
1971 limit *= nom;
1972 limit /= 0xc0;
1973 lims->sel_critmin = limit;
1974 *props |= PROP_CRITMIN;
1975 }
1976 limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->hi_lim_reg);
1977 if (limit != 0x00 && limit != 0xff) {
1978 limit *= nom;
1979 limit /= 0xc0;
1980 lims->sel_critmax = limit;
1981 *props |= PROP_CRITMAX;
1982 }
1983 }
1984
1985 static void
1986 dbcool_get_fan_limits(struct dbcool_softc *sc, int idx,
1987 sysmon_envsys_lim_t *lims, uint32_t *props)
1988 {
1989 struct reg_list *reg = sc->sc_regs[idx];
1990 int32_t limit;
1991
1992 limit = dbcool_read_rpm(sc, reg->lo_lim_reg);
1993 if (limit) {
1994 lims->sel_critmin = limit;
1995 *props |= PROP_CRITMIN;
1996 }
1997 }
1998
1999 /*
2000 * Update sensor limits in the chip registers
2001 */
2002 static void
2003 dbcool_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
2004 sysmon_envsys_lim_t *limits, uint32_t *props)
2005 {
2006 int index = edata->sensor;
2007 struct dbcool_softc *sc = sme->sme_cookie;
2008
2009 if (limits == NULL) {
2010 limits = &sc->sc_deflims[index];
2011 props = &sc->sc_defprops[index];
2012 }
2013 switch (edata->units) {
2014 case ENVSYS_STEMP:
2015 dbcool_set_temp_limits(sc, index, limits, props);
2016 break;
2017 case ENVSYS_SVOLTS_DC:
2018 dbcool_set_volt_limits(sc, index, limits, props);
2019 break;
2020 case ENVSYS_SFANRPM:
2021 dbcool_set_fan_limits(sc, index, limits, props);
2022
2023 /* FALLTHROUGH */
2024 default:
2025 break;
2026 }
2027 *props &= ~PROP_DRIVER_LIMITS;
2028 }
2029
2030 static void
2031 dbcool_set_temp_limits(struct dbcool_softc *sc, int idx,
2032 sysmon_envsys_lim_t *lims, uint32_t *props)
2033 {
2034 struct reg_list *reg = sc->sc_regs[idx];
2035 int32_t limit;
2036
2037 if (*props & PROP_CRITMIN) {
2038 limit = lims->sel_critmin - 273150000;
2039 limit /= 1000000;
2040 if (sc->sc_temp_offset) {
2041 limit += sc->sc_temp_offset;
2042 if (limit < 0)
2043 limit = 0;
2044 else if (limit > 255)
2045 limit = 255;
2046 } else {
2047 if (limit < -127)
2048 limit = -127;
2049 else if (limit > 127)
2050 limit = 127;
2051 }
2052 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg,
2053 (uint8_t)limit);
2054 } else if (*props & PROP_DRIVER_LIMITS) {
2055 if (sc->sc_temp_offset)
2056 limit = 0x00;
2057 else
2058 limit = 0x80;
2059 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg,
2060 (uint8_t)limit);
2061 }
2062
2063 if (*props & PROP_CRITMAX) {
2064 limit = lims->sel_critmax - 273150000;
2065 limit /= 1000000;
2066 if (sc->sc_temp_offset) {
2067 limit += sc->sc_temp_offset;
2068 if (limit < 0)
2069 limit = 0;
2070 else if (limit > 255)
2071 limit = 255;
2072 } else {
2073 if (limit < -127)
2074 limit = -127;
2075 else if (limit > 127)
2076 limit = 127;
2077 }
2078 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg,
2079 (uint8_t)limit);
2080 } else if (*props & PROP_DRIVER_LIMITS) {
2081 if (sc->sc_temp_offset)
2082 limit = 0xff;
2083 else
2084 limit = 0x7f;
2085 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg,
2086 (uint8_t)limit);
2087 }
2088 }
2089
2090 static void
2091 dbcool_set_volt_limits(struct dbcool_softc *sc, int idx,
2092 sysmon_envsys_lim_t *lims, uint32_t *props)
2093 {
2094 struct reg_list *reg = sc->sc_regs[idx];
2095 int64_t limit;
2096 int nom;
2097
2098 nom = nominal_voltages[sc->sc_dc.dc_chip->table[idx].nom_volt_index];
2099 if (nom < 0)
2100 nom = dbcool_supply_voltage(sc);
2101 nom *= 1000000; /* scale for microvolts */
2102
2103 if (*props & PROP_CRITMIN) {
2104 limit = lims->sel_critmin;
2105 limit *= 0xc0;
2106 limit /= nom;
2107 if (limit > 0xff)
2108 limit = 0xff;
2109 else if (limit < 0)
2110 limit = 0;
2111 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg, limit);
2112 } else if (*props & PROP_DRIVER_LIMITS)
2113 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg, 0);
2114
2115 if (*props & PROP_CRITMAX) {
2116 limit = lims->sel_critmax;
2117 limit *= 0xc0;
2118 limit /= nom;
2119 if (limit > 0xff)
2120 limit = 0xff;
2121 else if (limit < 0)
2122 limit = 0;
2123 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg, limit);
2124 } else if (*props & PROP_DRIVER_LIMITS)
2125 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg, 0xff);
2126 }
2127
2128 static void
2129 dbcool_set_fan_limits(struct dbcool_softc *sc, int idx,
2130 sysmon_envsys_lim_t *lims, uint32_t *props)
2131 {
2132 struct reg_list *reg = sc->sc_regs[idx];
2133 int32_t limit, dividend;
2134
2135 if (*props & PROP_CRITMIN) {
2136 limit = lims->sel_critmin;
2137 if (limit == 0)
2138 limit = 0xffff;
2139 else {
2140 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
2141 dividend = 11250 * 60;
2142 else
2143 dividend = 90000 * 60;
2144 limit = limit / dividend;
2145 if (limit > 0xffff)
2146 limit = 0xffff;
2147 }
2148 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg,
2149 limit & 0xff);
2150 limit >>= 8;
2151 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg + 1,
2152 limit & 0xff);
2153 } else if (*props & PROP_DRIVER_LIMITS) {
2154 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg, 0xff);
2155 sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg + 1, 0xff);
2156 }
2157 }
2158