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