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