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