1 /* $NetBSD: dbcool.c,v 1.14 2010/01/08 20:04:31 dyoung 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.14 2010/01/08 20:04:31 dyoung 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, "ADT7460/ADT7463" }, 543 { DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID2, 544 ADT7475_sensor_table, ADT7475_power_table, 545 DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN, 546 90000 * 60, "ADT7463-1" }, 547 { DBCOOL_COMPANYID, ADT7468_DEVICEID, 0xff, 548 ADT7476_sensor_table, ADT7475_power_table, 549 DBCFLAG_TEMPOFFSET | DBCFLAG_MULTI_VCC | DBCFLAG_HAS_MAXDUTY | 550 DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN | DBCFLAG_HAS_VID, 551 90000 * 60, "ADT7467/ADT7468" }, 552 { DBCOOL_COMPANYID, ADT7466_DEVICEID, 0xff, 553 ADT7466_sensor_table, NULL, 554 DBCFLAG_ADT7466 | DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_SHDN, 555 82000 * 60, "ADT7466" }, 556 { DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID1, 557 ADM1027_sensor_table, ADT7475_power_table, 558 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN | 559 DBCFLAG_ADM1027 | DBCFLAG_HAS_VID, 560 90000 * 60, "ADT7463" }, 561 { DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID2, 562 ADM1027_sensor_table, ADT7475_power_table, 563 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN | 564 DBCFLAG_HAS_VID | DBCFLAG_HAS_VID_SEL, 565 90000 * 60, "ADT7463" }, 566 { DBCOOL_COMPANYID, ADM1027_DEVICEID, ADM1027_REV_ID, 567 ADM1027_sensor_table, ADT7475_power_table, 568 DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_VID, 569 90000 * 60, "ADM1027" }, 570 { DBCOOL_COMPANYID, ADM1030_DEVICEID, 0xff, 571 ADM1030_sensor_table, ADM1030_power_table, 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_chipset dc; 592 dc.dc_tag = ia->ia_tag; 593 dc.dc_addr = ia->ia_addr; 594 dc.dc_chip = NULL; 595 dc.dc_readreg = dbcool_readreg; 596 dc.dc_writereg = dbcool_writereg; 597 598 /* no probing if we attach to iic, but verify chip id and address */ 599 if ((ia->ia_addr & DBCOOL_ADDRMASK) != DBCOOL_ADDR) 600 return 0; 601 if (dbcool_chip_ident(&dc) >= 0) 602 return 1; 603 604 return 0; 605 } 606 607 void 608 dbcool_attach(device_t parent, device_t self, void *aux) 609 { 610 struct dbcool_softc *sc = device_private(self); 611 struct i2c_attach_args *args = aux; 612 uint8_t ver; 613 614 sc->sc_dc.dc_addr = args->ia_addr; 615 sc->sc_dc.dc_tag = args->ia_tag; 616 sc->sc_dc.dc_chip = NULL; 617 sc->sc_dc.dc_readreg = dbcool_readreg; 618 sc->sc_dc.dc_writereg = dbcool_writereg; 619 (void)dbcool_chip_ident(&sc->sc_dc); 620 sc->sc_dev = self; 621 622 aprint_naive("\n"); 623 aprint_normal("\n"); 624 625 ver = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REVISION_REG); 626 if (sc->sc_dc.dc_chip->flags & DBCFLAG_4BIT_VER) 627 aprint_normal_dev(self, "%s dBCool(tm) Controller " 628 "(rev 0x%02x, stepping 0x%02x)\n", sc->sc_dc.dc_chip->name, 629 ver >> 4, ver & 0x0f); 630 else 631 aprint_normal_dev(self, "%s dBCool(tm) Controller " 632 "(rev 0x%04x)\n", sc->sc_dc.dc_chip->name, ver); 633 634 dbcool_setup(self); 635 636 if (!pmf_device_register(self, dbcool_pmf_suspend, dbcool_pmf_resume)) 637 aprint_error_dev(self, "couldn't establish power handler\n"); 638 } 639 640 static int 641 dbcool_detach(device_t self, int flags) 642 { 643 struct dbcool_softc *sc = device_private(self); 644 645 sysmon_envsys_unregister(sc->sc_sme); 646 sc->sc_sme = NULL; 647 return 0; 648 } 649 650 /* On suspend, we save the state of the SHDN bit, then set it */ 651 bool dbcool_pmf_suspend(device_t dev, pmf_qual_t qual) 652 { 653 struct dbcool_softc *sc = device_private(dev); 654 uint8_t reg, bit, cfg; 655 656 if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0) 657 return true; 658 659 if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) { 660 reg = DBCOOL_ADT7466_CONFIG2; 661 bit = DBCOOL_ADT7466_CFG2_SHDN; 662 } else { 663 reg = DBCOOL_CONFIG2_REG; 664 bit = DBCOOL_CFG2_SHDN; 665 } 666 cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 667 sc->sc_suspend = cfg & bit; 668 cfg |= bit; 669 sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg); 670 671 return true; 672 } 673 674 /* On resume, we restore the previous state of the SHDN bit */ 675 bool dbcool_pmf_resume(device_t dev, pmf_qual_t qual) 676 { 677 struct dbcool_softc *sc = device_private(dev); 678 uint8_t reg, bit, cfg; 679 680 if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0) 681 return true; 682 683 if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) { 684 reg = DBCOOL_ADT7466_CONFIG2; 685 bit = DBCOOL_ADT7466_CFG2_SHDN; 686 } else { 687 reg = DBCOOL_CONFIG2_REG; 688 bit = DBCOOL_CFG2_SHDN; 689 } 690 cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 691 cfg &= ~sc->sc_suspend; 692 sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg); 693 694 return true; 695 696 } 697 698 uint8_t 699 dbcool_readreg(struct dbcool_chipset *dc, uint8_t reg) 700 { 701 uint8_t data = 0; 702 703 if (iic_acquire_bus(dc->dc_tag, 0) != 0) 704 return data; 705 706 if (dc->dc_chip == NULL || dc->dc_chip->flags & DBCFLAG_ADM1027) { 707 /* ADM1027 doesn't support i2c read_byte protocol */ 708 if (iic_smbus_send_byte(dc->dc_tag, dc->dc_addr, reg, 0) != 0) 709 goto bad; 710 (void)iic_smbus_receive_byte(dc->dc_tag, dc->dc_addr, &data, 0); 711 } else 712 (void)iic_smbus_read_byte(dc->dc_tag, dc->dc_addr, reg, &data, 713 0); 714 715 bad: 716 iic_release_bus(dc->dc_tag, 0); 717 return data; 718 } 719 720 void 721 dbcool_writereg(struct dbcool_chipset *dc, uint8_t reg, uint8_t val) 722 { 723 if (iic_acquire_bus(dc->dc_tag, 0) != 0) 724 return; 725 726 (void)iic_smbus_write_byte(dc->dc_tag, dc->dc_addr, reg, val, 0); 727 728 iic_release_bus(dc->dc_tag, 0); 729 } 730 731 static bool 732 dbcool_islocked(struct dbcool_softc *sc) 733 { 734 uint8_t cfg_reg; 735 736 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) 737 return 0; 738 739 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) 740 cfg_reg = DBCOOL_ADT7466_CONFIG1; 741 else 742 cfg_reg = DBCOOL_CONFIG1_REG; 743 744 if (sc->sc_dc.dc_readreg(&sc->sc_dc, cfg_reg) & DBCOOL_CFG1_LOCK) 745 return 1; 746 else 747 return 0; 748 } 749 750 static int 751 dbcool_read_temp(struct dbcool_softc *sc, uint8_t reg, bool extres) 752 { 753 uint8_t t1, t2, t3, val, ext = 0; 754 int temp; 755 756 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) { 757 /* 758 * ADT7466 temps are in strange location 759 */ 760 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1); 761 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 762 if (extres) 763 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1); 764 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) { 765 /* 766 * ADM1030 temps are in their own special place, too 767 */ 768 if (extres) { 769 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_TEMP_EXTRES); 770 if (reg == DBCOOL_ADM1030_L_TEMP) 771 ext >>= 6; 772 else 773 ext >>= 1; 774 ext &= 0x03; 775 } 776 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 777 } else if (extres) { 778 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG); 779 780 /* Read all msb regs to unlatch them */ 781 t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_12VIN); 782 t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE1_TEMP); 783 t2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE2_TEMP); 784 t3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_LOCAL_TEMP); 785 switch (reg) { 786 case DBCOOL_REMOTE1_TEMP: 787 val = t1; 788 ext >>= 2; 789 break; 790 case DBCOOL_LOCAL_TEMP: 791 val = t3; 792 ext >>= 4; 793 break; 794 case DBCOOL_REMOTE2_TEMP: 795 val = t2; 796 ext >>= 6; 797 break; 798 default: 799 val = 0; 800 break; 801 } 802 ext &= 0x03; 803 } 804 else 805 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 806 807 /* Check for invalid temp values */ 808 if ((sc->sc_temp_offset == 0 && val == 0x80) || 809 (sc->sc_temp_offset != 0 && val == 0)) 810 return 0; 811 812 /* If using offset mode, adjust, else treat as signed */ 813 if (sc->sc_temp_offset) { 814 temp = val; 815 temp -= sc->sc_temp_offset; 816 } else 817 temp = (int8_t)val; 818 819 /* Convert degC to uK and include extended precision bits */ 820 temp *= 1000000; 821 temp += 250000 * (int)ext; 822 temp += 273150000U; 823 824 return temp; 825 } 826 827 static int 828 dbcool_read_rpm(struct dbcool_softc *sc, uint8_t reg) 829 { 830 int rpm; 831 uint8_t rpm_lo, rpm_hi; 832 833 rpm_lo = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 834 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) 835 rpm_hi = (rpm_lo == 0xff)?0xff:0x0; 836 else 837 rpm_hi = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1); 838 839 rpm = (rpm_hi << 8) | rpm_lo; 840 if (rpm == 0xffff) 841 return 0; /* 0xffff indicates stalled/failed fan */ 842 843 return (sc->sc_dc.dc_chip->rpm_dividend / rpm); 844 } 845 846 /* Provide chip's supply voltage, in microvolts */ 847 static int 848 dbcool_supply_voltage(struct dbcool_softc *sc) 849 { 850 if (sc->sc_dc.dc_chip->flags & DBCFLAG_MULTI_VCC) { 851 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG) & DBCOOL_CFG1_Vcc) 852 return 5002500; 853 else 854 return 3300000; 855 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) { 856 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) & 857 DBCOOL_ADT7466_CFG1_Vcc) 858 return 5000000; 859 else 860 return 3300000; 861 } else 862 return 3300000; 863 } 864 865 /* 866 * Nominal voltages are calculated in microvolts 867 */ 868 static int 869 dbcool_read_volt(struct dbcool_softc *sc, uint8_t reg, int nom_idx, bool extres) 870 { 871 uint8_t ext = 0, v1, v2, v3, v4, val; 872 int64_t ret; 873 int64_t nom; 874 875 nom = nominal_voltages[nom_idx]; 876 if (nom < 0) 877 nom = sc->sc_supply_voltage; 878 879 /* ADT7466 voltages are in strange locations with only 8-bits */ 880 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) 881 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 882 else 883 /* 884 * It's a "normal" dbCool chip - check for regs that 885 * share extended resolution bits since we have to 886 * read all the MSB registers to unlatch them. 887 */ 888 if (!extres) 889 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 890 else if (reg == DBCOOL_12VIN) { 891 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG) && 0x03; 892 val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg); 893 (void)dbcool_read_temp(sc, DBCOOL_LOCAL_TEMP, true); 894 } else if (reg == DBCOOL_VTT || reg == DBCOOL_IMON) { 895 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES_VTT_IMON); 896 v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_IMON); 897 v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VTT); 898 if (reg == DBCOOL_IMON) { 899 val = v1; 900 ext >>= 6; 901 } else 902 val = v2; 903 ext >>= 4; 904 ext &= 0x0f; 905 } else { 906 ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES1_REG); 907 v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_25VIN); 908 v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCCP); 909 v3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCC); 910 v4 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_5VIN); 911 912 switch (reg) { 913 case DBCOOL_25VIN: 914 val = v1; 915 break; 916 case DBCOOL_VCCP: 917 val = v2; 918 ext >>= 2; 919 break; 920 case DBCOOL_VCC: 921 val = v3; 922 ext >>= 4; 923 break; 924 case DBCOOL_5VIN: 925 val = v4; 926 ext >>= 6; 927 break; 928 default: 929 val = nom = 0; 930 } 931 ext &= 0x03; 932 } 933 934 /* 935 * Scale the nominal value by the 10-bit fraction 936 * 937 * Returned value is in microvolts. 938 */ 939 ret = val; 940 ret <<= 2; 941 ret |= ext; 942 ret = (ret * nom) / 0x300; 943 944 return ret; 945 } 946 947 SYSCTL_SETUP(sysctl_dbcoolsetup, "sysctl dBCool subtree setup") 948 { 949 sysctl_createv(NULL, 0, NULL, NULL, 950 CTLFLAG_PERMANENT, 951 CTLTYPE_NODE, "hw", NULL, 952 NULL, 0, NULL, 0, 953 CTL_HW, CTL_EOL); 954 } 955 956 static int 957 sysctl_dbcool_temp(SYSCTLFN_ARGS) 958 { 959 struct sysctlnode node; 960 struct dbcool_softc *sc; 961 int reg, error; 962 uint8_t chipreg; 963 uint8_t newreg; 964 965 node = *rnode; 966 sc = (struct dbcool_softc *)node.sysctl_data; 967 chipreg = node.sysctl_num & 0xff; 968 969 if (sc->sc_temp_offset) { 970 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 971 reg -= sc->sc_temp_offset; 972 } else 973 reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 974 975 node.sysctl_data = ® 976 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 977 978 if (error || newp == NULL) 979 return error; 980 981 /* We were asked to update the value - sanity check before writing */ 982 if (*(int *)node.sysctl_data < -64 || 983 *(int *)node.sysctl_data > 127 + sc->sc_temp_offset) 984 return EINVAL; 985 986 newreg = *(int *)node.sysctl_data; 987 newreg += sc->sc_temp_offset; 988 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 989 return 0; 990 } 991 992 static int 993 sysctl_adm1030_temp(SYSCTLFN_ARGS) 994 { 995 struct sysctlnode node; 996 struct dbcool_softc *sc; 997 int reg, error; 998 uint8_t chipreg, oldreg, newreg; 999 1000 node = *rnode; 1001 sc = (struct dbcool_softc *)node.sysctl_data; 1002 chipreg = node.sysctl_num & 0xff; 1003 1004 oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1005 reg = (oldreg >> 1) & ~0x03; 1006 1007 node.sysctl_data = ® 1008 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1009 1010 if (error || newp == NULL) 1011 return error; 1012 1013 /* We were asked to update the value - sanity check before writing */ 1014 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 127) 1015 return EINVAL; 1016 1017 newreg = *(int *)node.sysctl_data; 1018 newreg &= ~0x03; 1019 newreg <<= 1; 1020 newreg |= (oldreg & 0x07); 1021 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1022 return 0; 1023 } 1024 1025 static int 1026 sysctl_adm1030_trange(SYSCTLFN_ARGS) 1027 { 1028 struct sysctlnode node; 1029 struct dbcool_softc *sc; 1030 int reg, error, newval; 1031 uint8_t chipreg, oldreg, newreg; 1032 1033 node = *rnode; 1034 sc = (struct dbcool_softc *)node.sysctl_data; 1035 chipreg = node.sysctl_num & 0xff; 1036 1037 oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1038 reg = oldreg & 0x07; 1039 1040 node.sysctl_data = ® 1041 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1042 1043 if (error || newp == NULL) 1044 return error; 1045 1046 /* We were asked to update the value - sanity check before writing */ 1047 newval = *(int *)node.sysctl_data; 1048 1049 if (newval == 5) 1050 newreg = 0; 1051 else if (newval == 10) 1052 newreg = 1; 1053 else if (newval == 20) 1054 newreg = 2; 1055 else if (newval == 40) 1056 newreg = 3; 1057 else if (newval == 80) 1058 newreg = 4; 1059 else 1060 return EINVAL; 1061 1062 newreg |= (oldreg & ~0x07); 1063 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1064 return 0; 1065 } 1066 1067 static int 1068 sysctl_dbcool_duty(SYSCTLFN_ARGS) 1069 { 1070 struct sysctlnode node; 1071 struct dbcool_softc *sc; 1072 int reg, error; 1073 uint8_t chipreg, oldreg, newreg; 1074 1075 node = *rnode; 1076 sc = (struct dbcool_softc *)node.sysctl_data; 1077 chipreg = node.sysctl_num & 0xff; 1078 1079 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1080 reg = (uint32_t)oldreg; 1081 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) 1082 reg = ((reg & 0x0f) * 100) / 15; 1083 else 1084 reg = (reg * 100) / 255; 1085 node.sysctl_data = ® 1086 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1087 1088 if (error || newp == NULL) 1089 return error; 1090 1091 /* We were asked to update the value - sanity check before writing */ 1092 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 100) 1093 return EINVAL; 1094 1095 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) { 1096 newreg = *(uint8_t *)(node.sysctl_data) * 15 / 100; 1097 newreg |= oldreg & 0xf0; 1098 } else 1099 newreg = *(uint8_t *)(node.sysctl_data) * 255 / 100; 1100 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1101 return 0; 1102 } 1103 1104 static int 1105 sysctl_dbcool_behavior(SYSCTLFN_ARGS) 1106 { 1107 struct sysctlnode node; 1108 struct dbcool_softc *sc; 1109 int i, reg, error; 1110 uint8_t chipreg, oldreg, newreg; 1111 1112 node = *rnode; 1113 sc = (struct dbcool_softc *)node.sysctl_data; 1114 chipreg = node.sysctl_num & 0xff; 1115 1116 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1117 1118 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) { 1119 if ((sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) & 1) == 0) 1120 reg = 4; 1121 else if ((oldreg & 0x80) == 0) 1122 reg = 7; 1123 else if ((oldreg & 0x60) == 0) 1124 reg = 4; 1125 else 1126 reg = 6; 1127 } else 1128 reg = (oldreg >> 5) & 0x07; 1129 1130 strlcpy(dbcool_cur_behav, behavior[reg], sizeof(dbcool_cur_behav)); 1131 node.sysctl_data = dbcool_cur_behav; 1132 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1133 1134 if (error || newp == NULL) 1135 return error; 1136 1137 /* We were asked to update the value - convert string to value */ 1138 newreg = __arraycount(behavior); 1139 for (i = 0; i < __arraycount(behavior); i++) 1140 if (strcmp(node.sysctl_data, behavior[i]) == 0) 1141 break; 1142 if (i >= __arraycount(behavior)) 1143 return EINVAL; 1144 1145 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) { 1146 /* 1147 * ADM1030 splits fan controller behavior across two 1148 * registers. We also do not support Auto-Filter mode 1149 * nor do we support Manual-RPM-feedback. 1150 */ 1151 if (newreg == 4) { 1152 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2); 1153 oldreg &= ~0x01; 1154 sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg); 1155 } else { 1156 if (newreg == 0) 1157 newreg = 4; 1158 else if (newreg == 6) 1159 newreg = 7; 1160 else if (newreg == 7) 1161 newreg = 0; 1162 else 1163 return EINVAL; 1164 newreg <<= 5; 1165 newreg |= (oldreg & 0x1f); 1166 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1167 oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) | 1; 1168 sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg); 1169 } 1170 } else { 1171 newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x1f) | (i << 5); 1172 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1173 } 1174 return 0; 1175 } 1176 1177 static int 1178 sysctl_dbcool_slope(SYSCTLFN_ARGS) 1179 { 1180 struct sysctlnode node; 1181 struct dbcool_softc *sc; 1182 int reg, error; 1183 uint8_t chipreg; 1184 uint8_t newreg; 1185 1186 node = *rnode; 1187 sc = (struct dbcool_softc *)node.sysctl_data; 1188 chipreg = node.sysctl_num & 0xff; 1189 1190 reg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) >> 4) & 0x0f; 1191 node.sysctl_data = ® 1192 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1193 1194 if (error || newp == NULL) 1195 return error; 1196 1197 /* We were asked to update the value - sanity check before writing */ 1198 if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 0x0f) 1199 return EINVAL; 1200 1201 newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x0f) | 1202 (*(int *)node.sysctl_data << 4); 1203 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1204 return 0; 1205 } 1206 1207 static int 1208 sysctl_dbcool_volt_limit(SYSCTLFN_ARGS) 1209 { 1210 struct sysctlnode node; 1211 struct dbcool_softc *sc; 1212 int reg, error; 1213 int nom, sensor_index; 1214 int64_t val, newval; 1215 uint8_t chipreg, newreg; 1216 1217 node = *rnode; 1218 sc = (struct dbcool_softc *)node.sysctl_data; 1219 chipreg = node.sysctl_num & 0xff; 1220 1221 /* 1222 * Retrieve the nominal value for the voltage sensor 1223 */ 1224 sensor_index = (node.sysctl_num >> 8 ) & 0xff; 1225 nom = nominal_voltages[sc->sc_dc.dc_chip->table[sensor_index].nom_volt_index]; 1226 if (nom < 0) 1227 nom = dbcool_supply_voltage(sc); 1228 1229 /* 1230 * Use int64_t for calculation to avoid overflow 1231 */ 1232 val = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1233 val *= nom; 1234 val /= 0xc0; /* values are scaled so 0xc0 == nominal voltage */ 1235 reg = val; 1236 node.sysctl_data = ® 1237 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1238 1239 if (error || newp == NULL) 1240 return error; 1241 1242 /* 1243 * We were asked to update the value, so scale it and sanity 1244 * check before writing 1245 */ 1246 if (nom == 0) 1247 return EINVAL; 1248 newval = *(int *)node.sysctl_data; 1249 newval *= 0xc0; 1250 newval /= nom; 1251 if (newval < 0 || newval > 0xff) 1252 return EINVAL; 1253 1254 newreg = newval; 1255 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1256 return 0; 1257 } 1258 1259 static int 1260 sysctl_dbcool_temp_limit(SYSCTLFN_ARGS) 1261 { 1262 struct sysctlnode node; 1263 struct dbcool_softc *sc; 1264 int reg, error, newtemp; 1265 uint8_t chipreg; 1266 1267 node = *rnode; 1268 sc = (struct dbcool_softc *)node.sysctl_data; 1269 chipreg = node.sysctl_num & 0xff; 1270 1271 /* If using offset mode, adjust, else treat as signed */ 1272 if (sc->sc_temp_offset) { 1273 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1274 reg -= sc->sc_temp_offset; 1275 } else 1276 reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1277 1278 node.sysctl_data = ® 1279 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1280 1281 if (error || newp == NULL) 1282 return error; 1283 1284 /* We were asked to update the value - sanity check before writing */ 1285 newtemp = *(int *)node.sysctl_data + sc->sc_temp_offset; 1286 if (newtemp < 0 || newtemp > 0xff) 1287 return EINVAL; 1288 1289 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newtemp); 1290 return 0; 1291 } 1292 1293 static int 1294 sysctl_dbcool_fan_limit(SYSCTLFN_ARGS) 1295 { 1296 struct sysctlnode node; 1297 struct dbcool_softc *sc; 1298 int reg, error, newrpm, dividend; 1299 uint8_t chipreg; 1300 uint8_t newreg; 1301 1302 node = *rnode; 1303 sc = (struct dbcool_softc *)node.sysctl_data; 1304 chipreg = node.sysctl_num & 0xff; 1305 1306 /* retrieve two-byte limit */ 1307 reg = dbcool_read_rpm(sc, chipreg); 1308 1309 node.sysctl_data = ® 1310 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1311 1312 if (error || newp == NULL) 1313 return error; 1314 1315 /* 1316 * We were asked to update the value. Calculate the two-byte 1317 * limit and validate it. Due to the way fan RPM is calculated, 1318 * the new value must be at least 83 RPM (331 RPM for ADM1030)! 1319 * Allow a value of -1 or 0 to indicate no limit. 1320 */ 1321 newrpm = *(int *)node.sysctl_data; 1322 if (newrpm == 0 || newrpm == -1) 1323 newrpm = 0xffff; 1324 else { 1325 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) 1326 dividend = 11250 * 60; 1327 else 1328 dividend = 90000 * 60; 1329 newrpm = dividend / newrpm; 1330 if (newrpm & ~0xffff) 1331 return EINVAL; 1332 } 1333 1334 /* Update the on-chip registers with new value */ 1335 newreg = newrpm & 0xff; 1336 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1337 newreg = (newrpm >> 8) & 0xff; 1338 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg + 1, newreg); 1339 return 0; 1340 } 1341 1342 static int 1343 sysctl_dbcool_vid(SYSCTLFN_ARGS) 1344 { 1345 struct sysctlnode node; 1346 struct dbcool_softc *sc; 1347 int reg, error; 1348 uint8_t chipreg, newreg; 1349 1350 node = *rnode; 1351 sc = (struct dbcool_softc *)node.sysctl_data; 1352 chipreg = node.sysctl_num; 1353 1354 /* retrieve 5- or 6-bit value */ 1355 newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1356 if ((sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_VID_SEL) && 1357 (reg & 0x80)) 1358 reg = newreg & 0x3f; 1359 else 1360 reg = newreg & 0x1f; 1361 1362 node.sysctl_data = ® 1363 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1364 1365 if (error == 0 && newp != NULL) 1366 error = EINVAL; 1367 1368 return error; 1369 } 1370 1371 static int 1372 sysctl_dbcool_thyst(SYSCTLFN_ARGS) 1373 { 1374 struct sysctlnode node; 1375 struct dbcool_softc *sc; 1376 int reg, error; 1377 uint8_t chipreg; 1378 uint8_t newreg, newhyst; 1379 1380 node = *rnode; 1381 sc = (struct dbcool_softc *)node.sysctl_data; 1382 chipreg = node.sysctl_num & 0x7f; 1383 1384 /* retrieve 4-bit value */ 1385 newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1386 if ((node.sysctl_num & 0x80) == 0) 1387 reg = newreg >> 4; 1388 else 1389 reg = newreg; 1390 reg = reg & 0x0f; 1391 1392 node.sysctl_data = ® 1393 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1394 1395 if (error || newp == NULL) 1396 return error; 1397 1398 /* We were asked to update the value - sanity check before writing */ 1399 newhyst = *(int *)node.sysctl_data; 1400 if (newhyst > 0x0f) 1401 return EINVAL; 1402 1403 /* Insert new value into field and update register */ 1404 if ((node.sysctl_num & 0x80) == 0) { 1405 newreg &= 0x0f; 1406 newreg |= (newhyst << 4); 1407 } else { 1408 newreg &= 0xf0; 1409 newreg |= newhyst; 1410 } 1411 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1412 return 0; 1413 } 1414 1415 #ifdef DBCOOL_DEBUG 1416 1417 /* 1418 * These routines can be used for debugging. reg_select is used to 1419 * select any arbitrary register in the device. reg_access is used 1420 * to read (and optionally update) the selected register. 1421 * 1422 * No attempt is made to validate the data passed. If you use these 1423 * routines, you are assumed to know what you're doing! 1424 * 1425 * Caveat user 1426 */ 1427 static int 1428 sysctl_dbcool_reg_select(SYSCTLFN_ARGS) 1429 { 1430 struct sysctlnode node; 1431 struct dbcool_softc *sc; 1432 int reg, error; 1433 1434 node = *rnode; 1435 sc = (struct dbcool_softc *)node.sysctl_data; 1436 1437 reg = sc->sc_user_reg; 1438 node.sysctl_data = ® 1439 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1440 1441 if (error || newp == NULL) 1442 return error; 1443 1444 sc->sc_user_reg = *(int *)node.sysctl_data; 1445 return 0; 1446 } 1447 1448 static int 1449 sysctl_dbcool_reg_access(SYSCTLFN_ARGS) 1450 { 1451 struct sysctlnode node; 1452 struct dbcool_softc *sc; 1453 int reg, error; 1454 uint8_t chipreg; 1455 uint8_t newreg; 1456 1457 node = *rnode; 1458 sc = (struct dbcool_softc *)node.sysctl_data; 1459 chipreg = sc->sc_user_reg; 1460 1461 reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg); 1462 node.sysctl_data = ® 1463 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1464 1465 if (error || newp == NULL) 1466 return error; 1467 1468 newreg = *(int *)node.sysctl_data; 1469 sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg); 1470 return 0; 1471 } 1472 #endif /* DBCOOL_DEBUG */ 1473 1474 /* 1475 * Encode an index number and register number for use as a sysctl_num 1476 * so we can select the correct device register later. 1477 */ 1478 #define DBC_PWM_SYSCTL(seq, reg) ((seq << 8) | reg) 1479 1480 void 1481 dbcool_setup(device_t self) 1482 { 1483 struct dbcool_softc *sc = device_private(self); 1484 const struct sysctlnode *me = NULL; 1485 struct sysctlnode *node = NULL; 1486 uint8_t cfg_val, cfg_reg; 1487 int ro_flag, rw_flag, ret, error; 1488 1489 /* 1490 * Some chips are capable of reporting an extended temperature range 1491 * by default. On these models, config register 5 bit 0 can be set 1492 * to 1 for compatability with other chips that report 2s complement. 1493 */ 1494 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) { 1495 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) & 0x80) 1496 sc->sc_temp_offset = 64; 1497 else 1498 sc->sc_temp_offset = 0; 1499 } else if (sc->sc_dc.dc_chip->flags & DBCFLAG_TEMPOFFSET) { 1500 if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG5_REG) & 1501 DBCOOL_CFG5_TWOSCOMP) 1502 sc->sc_temp_offset = 0; 1503 else 1504 sc->sc_temp_offset = 64; 1505 } else 1506 sc->sc_temp_offset = 0; 1507 1508 /* Determine Vcc for this chip */ 1509 sc->sc_supply_voltage = dbcool_supply_voltage(sc); 1510 1511 sc->sc_sme = sysmon_envsys_create(); 1512 1513 ro_flag = dbcool_islocked(sc)?CTLFLAG_READONLY:CTLFLAG_READWRITE; 1514 ro_flag |= CTLFLAG_OWNDESC; 1515 rw_flag = CTLFLAG_READWRITE | CTLFLAG_OWNDESC; 1516 ret = sysctl_createv(NULL, 0, NULL, &me, 1517 CTLFLAG_READWRITE, 1518 CTLTYPE_NODE, device_xname(self), NULL, 1519 NULL, 0, NULL, 0, 1520 CTL_HW, CTL_CREATE, CTL_EOL); 1521 if (sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_VID) { 1522 ret = sysctl_createv(NULL, 0, NULL, 1523 (const struct sysctlnode **)&node, 1524 CTLFLAG_READONLY, CTLTYPE_INT, "CPU_VID_bits", NULL, 1525 sysctl_dbcool_vid, 1526 0, sc, sizeof(int), 1527 CTL_HW, me->sysctl_num, DBCOOL_VID_REG, CTL_EOL); 1528 if (node != NULL) 1529 node->sysctl_data = sc; 1530 } 1531 1532 #ifdef DBCOOL_DEBUG 1533 ret = sysctl_createv(NULL, 0, NULL, 1534 (const struct sysctlnode **)&node, 1535 CTLFLAG_READWRITE, CTLTYPE_INT, "reg_select", NULL, 1536 sysctl_dbcool_reg_select, 1537 0, sc, sizeof(int), 1538 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); 1539 if (node != NULL) 1540 node->sysctl_data = sc; 1541 1542 ret = sysctl_createv(NULL, 0, NULL, 1543 (const struct sysctlnode **)&node, 1544 CTLFLAG_READWRITE, CTLTYPE_INT, "reg_access", NULL, 1545 sysctl_dbcool_reg_access, 1546 0, sc, sizeof(int), 1547 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); 1548 if (node != NULL) 1549 node->sysctl_data = sc; 1550 #endif /* DBCOOL_DEBUG */ 1551 1552 /* Create the sensors for this device */ 1553 if (dbcool_setup_sensors(sc, me, rw_flag, ro_flag)) 1554 goto out; 1555 1556 /* If supported, create sysctl tree for fan PWM controllers */ 1557 if (sc->sc_dc.dc_chip->power != NULL) 1558 dbcool_setup_controllers(sc, me, rw_flag, ro_flag); 1559 1560 /* 1561 * Read and rewrite config register to activate device 1562 */ 1563 if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) 1564 cfg_reg = DBCOOL_ADM1030_CFG1; 1565 else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) 1566 cfg_reg = DBCOOL_ADT7466_CONFIG1; 1567 else 1568 cfg_reg = DBCOOL_CONFIG1_REG; 1569 cfg_val = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG); 1570 if ((cfg_val & DBCOOL_CFG1_START) == 0) { 1571 cfg_val |= DBCOOL_CFG1_START; 1572 sc->sc_dc.dc_writereg(&sc->sc_dc, cfg_reg, cfg_val); 1573 } 1574 if (dbcool_islocked(sc)) 1575 aprint_normal_dev(self, "configuration locked\n"); 1576 1577 sc->sc_sme->sme_name = device_xname(self); 1578 sc->sc_sme->sme_cookie = sc; 1579 sc->sc_sme->sme_refresh = dbcool_refresh; 1580 1581 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) { 1582 aprint_error_dev(self, 1583 "unable to register with sysmon (%d)\n", error); 1584 goto out; 1585 } 1586 1587 return; 1588 1589 out: 1590 sysmon_envsys_destroy(sc->sc_sme); 1591 } 1592 1593 static int 1594 dbcool_setup_sensors(struct dbcool_softc *sc, const struct sysctlnode *me, 1595 int rw_flag, int ro_flag) 1596 { 1597 int i, j, ret; 1598 int error = 0; 1599 uint8_t sysctl_reg; 1600 struct sysctlnode *node = NULL; 1601 int sysctl_index, sysctl_num; 1602 char name[SYSCTL_NAMELEN]; 1603 1604 for (i=0; sc->sc_dc.dc_chip->table[i].type != DBC_EOF; i++) { 1605 if (i >= DBCOOL_MAXSENSORS && 1606 sc->sc_dc.dc_chip->table[i].type != DBC_CTL) { 1607 aprint_normal_dev(sc->sc_dev, "chip table too big!\n"); 1608 break; 1609 } 1610 switch (sc->sc_dc.dc_chip->table[i].type) { 1611 case DBC_TEMP: 1612 sc->sc_sensor[i].units = ENVSYS_STEMP; 1613 error = dbcool_attach_sensor(sc, me, i, 1614 sysctl_dbcool_temp_limit); 1615 break; 1616 case DBC_VOLT: 1617 sc->sc_sensor[i].units = ENVSYS_SVOLTS_DC; 1618 error = dbcool_attach_sensor(sc, me, i, 1619 sysctl_dbcool_volt_limit); 1620 break; 1621 case DBC_FAN: 1622 sc->sc_sensor[i].units = ENVSYS_SFANRPM; 1623 error = dbcool_attach_sensor(sc, me, i, 1624 sysctl_dbcool_fan_limit); 1625 break; 1626 case DBC_CTL: 1627 /* 1628 * Search for the corresponding temp sensor 1629 * (temp sensors need to be created first!) 1630 */ 1631 sysctl_num = -1; 1632 for (j = 0; j < i; j++) { 1633 if (j > DBCOOL_MAXSENSORS || 1634 sc->sc_dc.dc_chip->table[j].type != DBC_TEMP) 1635 continue; 1636 if (sc->sc_dc.dc_chip->table[j].name_index == 1637 sc->sc_dc.dc_chip->table[i].name_index) { 1638 sysctl_num = sc->sc_sysctl_num[j]; 1639 break; 1640 } 1641 } 1642 if (sysctl_num == -1) 1643 break; 1644 sysctl_index = sc->sc_dc.dc_chip->table[i].sysctl_index; 1645 sysctl_reg = sc->sc_dc.dc_chip->table[i].reg.val_reg; 1646 strlcpy(name, dbc_sysctl_table[sysctl_index].name, 1647 sizeof(name)); 1648 ret = sysctl_createv(NULL, 0, NULL, 1649 (const struct sysctlnode **)&node, 1650 dbc_sysctl_table[sysctl_index].lockable? 1651 ro_flag:rw_flag, 1652 CTLTYPE_INT, name, 1653 dbc_sysctl_table[sysctl_index].desc, 1654 dbc_sysctl_table[sysctl_index].helper, 1655 0, sc, sizeof(int), 1656 CTL_HW, me->sysctl_num, sysctl_num, 1657 DBC_PWM_SYSCTL(i, sysctl_reg), CTL_EOL); 1658 if (node != NULL) 1659 node->sysctl_data = sc; 1660 break; 1661 default: 1662 aprint_error_dev(sc->sc_dev, 1663 "sensor_table index %d has bad type %d\n", 1664 i, sc->sc_dc.dc_chip->table[i].type); 1665 break; 1666 } 1667 if (error) 1668 break; 1669 } 1670 return error; 1671 } 1672 1673 static int 1674 dbcool_attach_sensor(struct dbcool_softc *sc, const struct sysctlnode *me, 1675 int idx, int (*helper)(SYSCTLFN_PROTO)) 1676 { 1677 struct sysctlnode *node = NULL; 1678 const struct sysctlnode *me2 = NULL; 1679 uint8_t sysctl_reg; 1680 int name_index; 1681 int ret; 1682 int error = 0; 1683 1684 name_index = sc->sc_dc.dc_chip->table[idx].name_index; 1685 strlcpy(sc->sc_sensor[idx].desc, dbc_sensor_names[name_index], 1686 sizeof(sc->sc_sensor[idx].desc)); 1687 sc->sc_regs[idx] = &sc->sc_dc.dc_chip->table[idx].reg; 1688 sc->sc_nom_volt[idx] = sc->sc_dc.dc_chip->table[idx].nom_volt_index; 1689 1690 sc->sc_sensor[idx].flags |= ENVSYS_FMONLIMITS; 1691 1692 error = sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[idx]); 1693 if (error) 1694 return error; 1695 1696 /* 1697 * create sysctl node for the sensor, and the nodes for 1698 * the sensor's high and low limit values 1699 */ 1700 ret = sysctl_createv(NULL, 0, NULL, &me2, CTLFLAG_READWRITE, 1701 CTLTYPE_NODE, sc->sc_sensor[idx].desc, NULL, 1702 NULL, 0, NULL, 0, 1703 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); 1704 if (me2 == NULL) 1705 return 0; 1706 1707 sc->sc_sysctl_num[idx] = me2->sysctl_num; 1708 1709 /* create sysctl node for the low limit */ 1710 sysctl_reg = sc->sc_regs[idx]->lo_lim_reg; 1711 ret = sysctl_createv(NULL, 0, NULL, 1712 (const struct sysctlnode **)&node, 1713 CTLFLAG_READWRITE, 1714 CTLTYPE_INT, "low_lim", NULL, helper, 0, sc, 0, 1715 CTL_HW, me->sysctl_num, me2->sysctl_num, 1716 DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL); 1717 if (node != NULL) 1718 node->sysctl_data = sc; 1719 1720 /* Fans do not have a high limit */ 1721 if (sc->sc_dc.dc_chip->table[idx].type == DBC_FAN) 1722 return 0; 1723 1724 sysctl_reg = sc->sc_regs[idx]->hi_lim_reg; 1725 ret = sysctl_createv(NULL, 0, NULL, 1726 (const struct sysctlnode **)&node, 1727 CTLFLAG_READWRITE, 1728 CTLTYPE_INT, "hi_lim", NULL, helper, 0, sc, 0, 1729 CTL_HW, me->sysctl_num, me2->sysctl_num, 1730 DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL); 1731 if (node != NULL) 1732 node->sysctl_data = sc; 1733 1734 return 0; 1735 } 1736 1737 static void 1738 dbcool_setup_controllers(struct dbcool_softc *sc, const struct sysctlnode *me, 1739 int rw_flag, int ro_flag) 1740 { 1741 int i, j, ret; 1742 uint8_t sysctl_reg; 1743 const struct sysctlnode *me2 = NULL; 1744 struct sysctlnode *node = NULL; 1745 char name[SYSCTL_NAMELEN]; 1746 1747 for (i = 0; sc->sc_dc.dc_chip->power[i].desc != NULL; i++) { 1748 snprintf(name, sizeof(name), "fan_ctl_%d", i); 1749 ret = sysctl_createv(NULL, 0, NULL, &me2, 1750 rw_flag, 1751 CTLTYPE_NODE, name, NULL, 1752 NULL, 0, NULL, 0, 1753 CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL); 1754 1755 for (j = DBC_PWM_BEHAVIOR; j < DBC_PWM_LAST_PARAM; j++) { 1756 if (j == DBC_PWM_MAX_DUTY && 1757 (sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_MAXDUTY) == 0) 1758 continue; 1759 sysctl_reg = sc->sc_dc.dc_chip->power[i].power_regs[j]; 1760 if (sysctl_reg == DBCOOL_NO_REG) 1761 continue; 1762 strlcpy(name, dbc_sysctl_table[j].name, sizeof(name)); 1763 ret = sysctl_createv(NULL, 0, NULL, 1764 (const struct sysctlnode **)&node, 1765 (dbc_sysctl_table[j].lockable)?ro_flag:rw_flag, 1766 (j == DBC_PWM_BEHAVIOR)? 1767 CTLTYPE_STRING:CTLTYPE_INT, 1768 name, 1769 dbc_sysctl_table[j].desc, 1770 dbc_sysctl_table[j].helper, 1771 0, sc, 1772 ( j == DBC_PWM_BEHAVIOR)? 1773 sizeof(dbcool_cur_behav): sizeof(int), 1774 CTL_HW, me->sysctl_num, me2->sysctl_num, 1775 DBC_PWM_SYSCTL(j, sysctl_reg), CTL_EOL); 1776 if (node != NULL) 1777 node->sysctl_data = sc; 1778 } 1779 } 1780 } 1781 1782 static void 1783 dbcool_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 1784 { 1785 struct dbcool_softc *sc=sme->sme_cookie; 1786 int i, nom_volt_idx; 1787 int cur, hi, low; 1788 struct reg_list *reg; 1789 1790 i = edata->sensor; 1791 reg = sc->sc_regs[i]; 1792 switch (edata->units) 1793 { 1794 case ENVSYS_STEMP: 1795 cur = dbcool_read_temp(sc, reg->val_reg, true); 1796 low = dbcool_read_temp(sc, reg->lo_lim_reg, false); 1797 hi = dbcool_read_temp(sc, reg->hi_lim_reg, false); 1798 break; 1799 case ENVSYS_SVOLTS_DC: 1800 nom_volt_idx = sc->sc_nom_volt[i]; 1801 cur = dbcool_read_volt(sc, reg->val_reg, nom_volt_idx, 1802 true); 1803 low = dbcool_read_volt(sc, reg->lo_lim_reg, 1804 nom_volt_idx, false); 1805 hi = dbcool_read_volt(sc, reg->hi_lim_reg, 1806 nom_volt_idx, false); 1807 break; 1808 case ENVSYS_SFANRPM: 1809 cur = dbcool_read_rpm(sc, reg->val_reg); 1810 low = dbcool_read_rpm(sc, reg->lo_lim_reg); 1811 hi = 1 << 16; 1812 break; 1813 default: 1814 edata->state = ENVSYS_SINVALID; 1815 return; 1816 } 1817 1818 if (cur == 0 && edata->units != ENVSYS_SFANRPM) 1819 edata->state = ENVSYS_SINVALID; 1820 1821 /* Make sure limits are sensible */ 1822 else if (hi <= low) 1823 edata->state = ENVSYS_SVALID; 1824 1825 /* 1826 * If fan is "stalled" but has no low limit, treat 1827 * it as though the fan is not installed. 1828 */ 1829 else if (edata->units == ENVSYS_SFANRPM && cur == 0 && 1830 (low == 0 || low == -1)) 1831 edata->state = ENVSYS_SINVALID; 1832 1833 /* 1834 * Compare current value against the limits 1835 */ 1836 else if (cur < low) 1837 edata->state = ENVSYS_SCRITUNDER; 1838 else if (cur > hi) 1839 edata->state = ENVSYS_SCRITOVER; 1840 else 1841 edata->state = ENVSYS_SVALID; 1842 1843 edata->value_cur = cur; 1844 } 1845 1846 int 1847 dbcool_chip_ident(struct dbcool_chipset *dc) 1848 { 1849 /* verify this is a supported dbCool chip */ 1850 uint8_t c_id, d_id, r_id; 1851 int i; 1852 1853 c_id = dc->dc_readreg(dc, DBCOOL_COMPANYID_REG); 1854 d_id = dc->dc_readreg(dc, DBCOOL_DEVICEID_REG); 1855 r_id = dc->dc_readreg(dc, DBCOOL_REVISION_REG); 1856 1857 for (i = 0; chip_table[i].company != 0; i++) 1858 if ((c_id == chip_table[i].company) && 1859 (d_id == chip_table[i].device || 1860 chip_table[i].device == 0xff) && 1861 (r_id == chip_table[i].rev || 1862 chip_table[i].rev == 0xff)) { 1863 dc->dc_chip = &chip_table[i]; 1864 return i; 1865 } 1866 1867 aprint_verbose("dbcool_chip_ident: addr 0x%02x c_id 0x%02x d_id 0x%02x" 1868 " r_id 0x%02x: No match.\n", dc->dc_addr, c_id, d_id, 1869 r_id); 1870 1871 return -1; 1872 } 1873