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