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