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