1 /* $OpenBSD: lm78.c,v 1.20 2007/06/25 22:50:18 cnst Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006 Mark Kettenis 5 * Copyright (c) 2006, 2007 Constantine A. Murenin 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/bus.h> 23 #include <sys/sensors.h> 24 25 #include "lm78var.h" 26 #include "../wbsio/wbsioreg.h" 27 28 #if defined(LMDEBUG) 29 #define DPRINTF(x) do { kprintf x; } while (0) 30 #else 31 #define DPRINTF(x) 32 #endif 33 34 /* 35 * LM78-compatible chips can typically measure voltages up to 4.096 V. 36 * To measure higher voltages the input is attenuated with (external) 37 * resistors. Negative voltages are measured using inverting op amps 38 * and resistors. So we have to convert the sensor values back to 39 * real voltages by applying the appropriate resistor factor. 40 */ 41 #define RFACT_NONE 10000 42 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) 43 #define NRFACT(x, y) (-RFACT_NONE * (x) / (y)) 44 45 int lm_match(struct lm_softc *); 46 int wb_match(struct lm_softc *); 47 int def_match(struct lm_softc *); 48 49 void lm_setup_sensors(struct lm_softc *, struct lm_sensor *); 50 void lm_refresh(void *); 51 52 void lm_refresh_sensor_data(struct lm_softc *); 53 void lm_refresh_volt(struct lm_softc *, int); 54 void lm_refresh_temp(struct lm_softc *, int); 55 void lm_refresh_fanrpm(struct lm_softc *, int); 56 57 void wb_refresh_sensor_data(struct lm_softc *); 58 void wb_w83637hf_refresh_vcore(struct lm_softc *, int); 59 void wb_refresh_nvolt(struct lm_softc *, int); 60 void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int); 61 void wb_refresh_temp(struct lm_softc *, int); 62 void wb_refresh_fanrpm(struct lm_softc *, int); 63 void wb_nct6776f_refresh_fanrpm(struct lm_softc *, int); 64 void wb_w83792d_refresh_fanrpm(struct lm_softc *, int); 65 66 void as_refresh_temp(struct lm_softc *, int); 67 68 struct lm_chip { 69 int (*chip_match)(struct lm_softc *); 70 }; 71 72 struct lm_chip lm_chips[] = { 73 { wb_match }, 74 { lm_match }, 75 { def_match } /* Must be last */ 76 }; 77 78 struct lm_sensor lm78_sensors[] = { 79 /* Voltage */ 80 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 81 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, 82 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 83 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) }, 84 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) }, 85 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) }, 86 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) }, 87 88 /* Temperature */ 89 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 90 91 /* Fans */ 92 { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm }, 93 { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm }, 94 { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm }, 95 96 { NULL } 97 }; 98 99 struct lm_sensor w83627hf_sensors[] = { 100 /* Voltage */ 101 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 102 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, 103 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 104 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, 105 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 106 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, 107 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, 108 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) }, 109 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, 110 111 /* Temperature */ 112 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 113 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 114 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, 115 116 /* Fans */ 117 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 118 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 119 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, 120 121 { NULL } 122 }; 123 124 /* 125 * The W83627EHF can measure voltages up to 2.048 V instead of the 126 * traditional 4.096 V. For measuring positive voltages, this can be 127 * accounted for by halving the resistor factor. Negative voltages 128 * need special treatment, also because the reference voltage is 2.048 V 129 * instead of the traditional 3.6 V. 130 */ 131 struct lm_sensor w83627ehf_sensors[] = { 132 /* Voltage */ 133 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2}, 134 { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 }, 135 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 }, 136 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 }, 137 { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt }, 138 { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 }, 139 { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 }, 140 { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 }, 141 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 }, 142 { "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 }, 143 144 /* Temperature */ 145 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 146 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 147 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, 148 149 /* Fans */ 150 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 151 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 152 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, 153 154 { NULL } 155 }; 156 157 /* 158 * w83627dhg is almost identical to w83627ehf, except that 159 * it has 9 instead of 10 voltage sensors 160 */ 161 struct lm_sensor w83627dhg_sensors[] = { 162 /* Voltage */ 163 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2}, 164 { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 }, 165 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 }, 166 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 }, 167 { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt }, 168 { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 }, 169 { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 }, 170 { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 }, 171 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 }, 172 173 /* Temperature */ 174 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 175 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 176 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, 177 178 /* Fans */ 179 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 180 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 181 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, 182 183 { NULL } 184 }; 185 186 struct lm_sensor nct6776f_sensors[] = { 187 /* Voltage */ 188 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2}, 189 { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 }, 190 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 }, 191 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 }, 192 { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt }, 193 { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 }, 194 { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 }, 195 { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 }, 196 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 }, 197 198 /* Temperature */ 199 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 200 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 201 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, 202 203 /* Fans */ 204 { "", SENSOR_FANRPM, 6, 0x56, wb_nct6776f_refresh_fanrpm }, 205 { "", SENSOR_FANRPM, 6, 0x58, wb_nct6776f_refresh_fanrpm }, 206 { "", SENSOR_FANRPM, 6, 0x5a, wb_nct6776f_refresh_fanrpm }, 207 { "", SENSOR_FANRPM, 6, 0x5c, wb_nct6776f_refresh_fanrpm }, 208 { "", SENSOR_FANRPM, 6, 0x5e, wb_nct6776f_refresh_fanrpm }, 209 210 { NULL } 211 }; 212 213 struct lm_sensor w83637hf_sensors[] = { 214 /* Voltage */ 215 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore }, 216 { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) }, 217 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 218 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) }, 219 { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) }, 220 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) }, 221 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, 222 223 /* Temperature */ 224 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 225 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 226 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, 227 228 /* Fans */ 229 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 230 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 231 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, 232 233 { NULL } 234 }; 235 236 struct lm_sensor w83697hf_sensors[] = { 237 /* Voltage */ 238 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 239 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 240 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, 241 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 242 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, 243 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, 244 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) }, 245 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, 246 247 /* Temperature */ 248 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 249 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 250 251 /* Fans */ 252 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 253 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 254 255 { NULL } 256 }; 257 258 /* 259 * The datasheet doesn't mention the (internal) resistors used for the 260 * +5V, but using the values from the W83782D datasheets seems to 261 * provide sensible results. 262 */ 263 struct lm_sensor w83781d_sensors[] = { 264 /* Voltage */ 265 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 266 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, 267 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 268 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, 269 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 270 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) }, 271 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) }, 272 273 /* Temperature */ 274 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 275 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 276 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, 277 278 /* Fans */ 279 { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm }, 280 { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm }, 281 { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm }, 282 283 { NULL } 284 }; 285 286 struct lm_sensor w83782d_sensors[] = { 287 /* Voltage */ 288 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 289 { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, 290 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 291 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, 292 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 293 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, 294 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, 295 { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) }, 296 { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, 297 298 /* Temperature */ 299 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 300 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 301 { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, 302 303 /* Fans */ 304 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 305 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 306 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, 307 308 { NULL } 309 }; 310 311 struct lm_sensor w83783s_sensors[] = { 312 /* Voltage */ 313 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 314 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 315 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, 316 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 317 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, 318 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, 319 320 /* Temperature */ 321 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 322 { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, 323 324 /* Fans */ 325 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 326 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 327 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, 328 329 { NULL } 330 }; 331 332 struct lm_sensor w83791d_sensors[] = { 333 /* Voltage */ 334 { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 335 { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, 336 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 337 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, 338 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 339 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, 340 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, 341 { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) }, 342 { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE }, 343 { "VINR1", SENSOR_VOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE }, 344 345 /* Temperature */ 346 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 347 { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp }, 348 { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp }, 349 350 /* Fans */ 351 { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, 352 { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, 353 { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, 354 { "", SENSOR_FANRPM, 0, 0xba, wb_refresh_fanrpm }, 355 { "", SENSOR_FANRPM, 0, 0xbb, wb_refresh_fanrpm }, 356 357 { NULL } 358 }; 359 360 struct lm_sensor w83792d_sensors[] = { 361 /* Voltage */ 362 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 363 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, 364 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 365 { "-5V", SENSOR_VOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) }, 366 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 367 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, 368 { "+5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) }, 369 { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) }, 370 { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE }, 371 372 /* Temperature */ 373 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 374 { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp }, 375 { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp }, 376 377 /* Fans */ 378 { "", SENSOR_FANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm }, 379 { "", SENSOR_FANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm }, 380 { "", SENSOR_FANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm }, 381 { "", SENSOR_FANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm }, 382 { "", SENSOR_FANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm }, 383 { "", SENSOR_FANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm }, 384 { "", SENSOR_FANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm }, 385 386 { NULL } 387 }; 388 389 struct lm_sensor as99127f_sensors[] = { 390 /* Voltage */ 391 { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, 392 { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, 393 { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, 394 { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, 395 { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, 396 { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, 397 { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, 398 399 /* Temperature */ 400 { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, 401 { "", SENSOR_TEMP, 1, 0x50, as_refresh_temp }, 402 { "", SENSOR_TEMP, 2, 0x50, as_refresh_temp }, 403 404 /* Fans */ 405 { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm }, 406 { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm }, 407 { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm }, 408 409 { NULL } 410 }; 411 412 void 413 lm_probe(struct lm_softc *sc) 414 { 415 int i; 416 417 for (i = 0; i < NELEM(lm_chips); i++) 418 if (lm_chips[i].chip_match(sc)) 419 break; 420 } 421 422 void 423 lm_attach(struct lm_softc *sc) 424 { 425 u_int i, config; 426 427 /* No point in doing anything if we don't have any sensors. */ 428 if (sc->numsensors == 0) 429 return; 430 431 sensor_task_register(sc, lm_refresh, 5); 432 433 /* Start the monitoring loop */ 434 config = sc->lm_readreg(sc, LM_CONFIG); 435 sc->lm_writereg(sc, LM_CONFIG, config | 0x01); 436 437 /* Add sensors */ 438 strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev), 439 sizeof(sc->sensordev.xname)); 440 for (i = 0; i < sc->numsensors; ++i) 441 sensor_attach(&sc->sensordev, &sc->sensors[i]); 442 sensordev_install(&sc->sensordev); 443 } 444 445 int 446 lm_detach(struct lm_softc *sc) 447 { 448 int i; 449 450 /* Remove sensors */ 451 sensordev_deinstall(&sc->sensordev); 452 for (i = 0; i < sc->numsensors; i++) 453 sensor_detach(&sc->sensordev, &sc->sensors[i]); 454 455 sensor_task_unregister(sc); 456 457 return 0; 458 } 459 460 int 461 lm_match(struct lm_softc *sc) 462 { 463 int chipid; 464 const char *cdesc; 465 char fulldesc[64]; 466 467 /* See if we have an LM78 or LM79. */ 468 chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK; 469 switch(chipid) { 470 case LM_CHIPID_LM78: 471 cdesc = "LM78"; 472 break; 473 case LM_CHIPID_LM78J: 474 cdesc = "LM78J"; 475 break; 476 case LM_CHIPID_LM79: 477 cdesc = "LM79"; 478 break; 479 case LM_CHIPID_LM81: 480 cdesc = "LM81"; 481 break; 482 default: 483 return 0; 484 } 485 ksnprintf(fulldesc, sizeof(fulldesc), 486 "National Semiconductor %s Hardware Monitor", cdesc); 487 device_set_desc_copy(sc->sc_dev, fulldesc); 488 489 lm_setup_sensors(sc, lm78_sensors); 490 sc->refresh_sensor_data = lm_refresh_sensor_data; 491 return 1; 492 } 493 494 int 495 def_match(struct lm_softc *sc) 496 { 497 int chipid; 498 char fulldesc[64]; 499 500 chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK; 501 ksnprintf(fulldesc, sizeof(fulldesc), 502 "unknown Hardware Monitor (ID 0x%x)", chipid); 503 device_set_desc_copy(sc->sc_dev, fulldesc); 504 505 lm_setup_sensors(sc, lm78_sensors); 506 sc->refresh_sensor_data = lm_refresh_sensor_data; 507 return 1; 508 } 509 510 int 511 wb_match(struct lm_softc *sc) 512 { 513 int banksel, vendid, devid; 514 const char *cdesc; 515 char desc[64]; 516 char fulldesc[64]; 517 518 /* Read vendor ID */ 519 banksel = sc->lm_readreg(sc, WB_BANKSEL); 520 sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC); 521 vendid = sc->lm_readreg(sc, WB_VENDID) << 8; 522 sc->lm_writereg(sc, WB_BANKSEL, 0); 523 vendid |= sc->lm_readreg(sc, WB_VENDID); 524 sc->lm_writereg(sc, WB_BANKSEL, banksel); 525 DPRINTF((" winbond vend id 0x%x\n", vendid)); 526 if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS) 527 return 0; 528 529 /* Read device/chip ID */ 530 sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 531 devid = sc->lm_readreg(sc, LM_CHIPID); 532 sc->chipid = sc->lm_readreg(sc, WB_BANK0_CHIPID); 533 sc->lm_writereg(sc, WB_BANKSEL, banksel); 534 DPRINTF((" winbond chip id 0x%x\n", sc->chipid)); 535 switch(sc->chipid) { 536 case WB_CHIPID_W83627HF: 537 cdesc = "W83627HF"; 538 lm_setup_sensors(sc, w83627hf_sensors); 539 break; 540 case WB_CHIPID_W83627THF: 541 cdesc = "W83627THF"; 542 lm_setup_sensors(sc, w83637hf_sensors); 543 break; 544 case WB_CHIPID_W83627EHF_A: 545 cdesc = "W83627EHF-A"; 546 lm_setup_sensors(sc, w83627ehf_sensors); 547 break; 548 case WB_CHIPID_W83627EHF: 549 cdesc = "W83627EHF"; 550 lm_setup_sensors(sc, w83627ehf_sensors); 551 break; 552 case WB_CHIPID_W83627DHG: 553 if (sc->sioid == WBSIO_ID_NCT6776F) { 554 cdesc = "NCT6776F"; 555 lm_setup_sensors(sc, nct6776f_sensors); 556 } else { 557 cdesc = "W83627DHG"; 558 lm_setup_sensors(sc, w83627dhg_sensors); 559 } 560 break; 561 case WB_CHIPID_W83637HF: 562 cdesc = "W83637HF"; 563 sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 564 if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9) 565 sc->vrm9 = 1; 566 sc->lm_writereg(sc, WB_BANKSEL, banksel); 567 lm_setup_sensors(sc, w83637hf_sensors); 568 break; 569 case WB_CHIPID_W83697HF: 570 cdesc = "W83697HF"; 571 lm_setup_sensors(sc, w83697hf_sensors); 572 break; 573 case WB_CHIPID_W83781D: 574 case WB_CHIPID_W83781D_2: 575 cdesc = "W83781D"; 576 lm_setup_sensors(sc, w83781d_sensors); 577 break; 578 case WB_CHIPID_W83782D: 579 cdesc = "W83782D"; 580 lm_setup_sensors(sc, w83782d_sensors); 581 break; 582 case WB_CHIPID_W83783S: 583 cdesc = "W83783S"; 584 lm_setup_sensors(sc, w83783s_sensors); 585 break; 586 case WB_CHIPID_W83791D: 587 cdesc = "W83791D"; 588 lm_setup_sensors(sc, w83791d_sensors); 589 break; 590 case WB_CHIPID_W83791SD: 591 cdesc = "W83791SD"; 592 break; 593 case WB_CHIPID_W83792D: 594 if (devid >= 0x10 && devid <= 0x29) 595 ksnprintf(desc, sizeof(desc), 596 "W83792D rev %c", 'A' + devid - 0x10); 597 else 598 ksnprintf(desc, sizeof(desc), 599 "W83792D rev 0x%x", devid); 600 cdesc = desc; 601 lm_setup_sensors(sc, w83792d_sensors); 602 break; 603 case WB_CHIPID_AS99127F: 604 if (vendid == WB_VENDID_ASUS) { 605 cdesc = "AS99127F"; 606 lm_setup_sensors(sc, w83781d_sensors); 607 } else { 608 cdesc = "AS99127F rev 2"; 609 lm_setup_sensors(sc, as99127f_sensors); 610 } 611 break; 612 default: 613 ksnprintf(fulldesc, sizeof(fulldesc), 614 "unknown Winbond Hardware Monitor (Chip ID 0x%x)", 615 sc->chipid); 616 device_set_desc_copy(sc->sc_dev, fulldesc); 617 /* Handle as a standard LM78. */ 618 lm_setup_sensors(sc, lm78_sensors); 619 sc->refresh_sensor_data = lm_refresh_sensor_data; 620 return 1; 621 } 622 623 if (cdesc[0] == 'W') 624 ksnprintf(fulldesc, sizeof(fulldesc), 625 "Winbond %s Hardware Monitor", cdesc); 626 else 627 ksnprintf(fulldesc, sizeof(fulldesc), 628 "ASUS %s Hardware Monitor", cdesc); 629 device_set_desc_copy(sc->sc_dev, fulldesc); 630 631 sc->refresh_sensor_data = wb_refresh_sensor_data; 632 return 1; 633 } 634 635 void 636 lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors) 637 { 638 int i; 639 640 for (i = 0; sensors[i].desc; i++) { 641 sc->sensors[i].type = sensors[i].type; 642 strlcpy(sc->sensors[i].desc, sensors[i].desc, 643 sizeof(sc->sensors[i].desc)); 644 sc->numsensors++; 645 } 646 sc->lm_sensors = sensors; 647 } 648 649 void 650 lm_refresh(void *arg) 651 { 652 struct lm_softc *sc = arg; 653 654 sc->refresh_sensor_data(sc); 655 } 656 657 void 658 lm_refresh_sensor_data(struct lm_softc *sc) 659 { 660 int i; 661 662 for (i = 0; i < sc->numsensors; i++) 663 sc->lm_sensors[i].refresh(sc, i); 664 } 665 666 void 667 lm_refresh_volt(struct lm_softc *sc, int n) 668 { 669 struct ksensor *sensor = &sc->sensors[n]; 670 int data; 671 672 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 673 sensor->value = (data << 4); 674 sensor->value *= sc->lm_sensors[n].rfact; 675 sensor->value /= 10; 676 } 677 678 void 679 lm_refresh_temp(struct lm_softc *sc, int n) 680 { 681 struct ksensor *sensor = &sc->sensors[n]; 682 int sdata; 683 684 /* 685 * The data sheet suggests that the range of the temperature 686 * sensor is between -55 degC and +125 degC. 687 */ 688 sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 689 if (sdata > 0x7d && sdata < 0xc9) { 690 sensor->flags |= SENSOR_FINVALID; 691 sensor->value = 0; 692 } else { 693 if (sdata & 0x80) 694 sdata -= 0x100; 695 sensor->flags &= ~SENSOR_FINVALID; 696 sensor->value = sdata * 1000000 + 273150000; 697 } 698 } 699 700 void 701 lm_refresh_fanrpm(struct lm_softc *sc, int n) 702 { 703 struct ksensor *sensor = &sc->sensors[n]; 704 int data, divisor = 1; 705 706 /* 707 * We might get more accurate fan readings by adjusting the 708 * divisor, but that might interfere with APM or other SMM 709 * BIOS code reading the fan speeds. 710 */ 711 712 /* FAN3 has a fixed fan divisor. */ 713 if (sc->lm_sensors[n].reg == LM_FAN1 || 714 sc->lm_sensors[n].reg == LM_FAN2) { 715 data = sc->lm_readreg(sc, LM_VIDFAN); 716 if (sc->lm_sensors[n].reg == LM_FAN1) 717 divisor = (data >> 4) & 0x03; 718 else 719 divisor = (data >> 6) & 0x03; 720 } 721 722 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 723 if (data == 0xff || data == 0x00) { 724 sensor->flags |= SENSOR_FINVALID; 725 sensor->value = 0; 726 } else { 727 sensor->flags &= ~SENSOR_FINVALID; 728 sensor->value = 1350000 / (data << divisor); 729 } 730 } 731 732 void 733 wb_refresh_sensor_data(struct lm_softc *sc) 734 { 735 int banksel, bank, i; 736 737 /* 738 * Properly save and restore bank selection register. 739 */ 740 741 banksel = bank = sc->lm_readreg(sc, WB_BANKSEL); 742 for (i = 0; i < sc->numsensors; i++) { 743 if (bank != sc->lm_sensors[i].bank) { 744 bank = sc->lm_sensors[i].bank; 745 sc->lm_writereg(sc, WB_BANKSEL, bank); 746 } 747 sc->lm_sensors[i].refresh(sc, i); 748 } 749 sc->lm_writereg(sc, WB_BANKSEL, banksel); 750 } 751 752 void 753 wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n) 754 { 755 struct ksensor *sensor = &sc->sensors[n]; 756 int data; 757 758 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 759 760 /* 761 * Depending on the voltage detection method, 762 * one of the following formulas is used: 763 * VRM8 method: value = raw * 0.016V 764 * VRM9 method: value = raw * 0.00488V + 0.70V 765 */ 766 if (sc->vrm9) 767 sensor->value = (data * 4880) + 700000; 768 else 769 sensor->value = (data * 16000); 770 } 771 772 void 773 wb_refresh_nvolt(struct lm_softc *sc, int n) 774 { 775 struct ksensor *sensor = &sc->sensors[n]; 776 int data; 777 778 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 779 sensor->value = ((data << 4) - WB_VREF); 780 sensor->value *= sc->lm_sensors[n].rfact; 781 sensor->value /= 10; 782 sensor->value += WB_VREF * 1000; 783 } 784 785 void 786 wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n) 787 { 788 struct ksensor *sensor = &sc->sensors[n]; 789 int data; 790 791 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 792 sensor->value = ((data << 3) - WB_W83627EHF_VREF); 793 sensor->value *= RFACT(232, 10); 794 sensor->value /= 10; 795 sensor->value += WB_W83627EHF_VREF * 1000; 796 } 797 798 void 799 wb_refresh_temp(struct lm_softc *sc, int n) 800 { 801 struct ksensor *sensor = &sc->sensors[n]; 802 int sdata; 803 804 /* 805 * The data sheet suggests that the range of the temperature 806 * sensor is between -55 degC and +125 degC. However, values 807 * around -48 degC seem to be a very common bogus values. 808 * Since such values are unreasonably low, we use -45 degC for 809 * the lower limit instead. 810 */ 811 sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1; 812 sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7; 813 if (sdata > 0x0fa && sdata < 0x1a6) { 814 sensor->flags |= SENSOR_FINVALID; 815 sensor->value = 0; 816 } else { 817 if (sdata & 0x100) 818 sdata -= 0x200; 819 sensor->flags &= ~SENSOR_FINVALID; 820 sensor->value = sdata * 500000 + 273150000; 821 } 822 } 823 824 void 825 wb_refresh_fanrpm(struct lm_softc *sc, int n) 826 { 827 struct ksensor *sensor = &sc->sensors[n]; 828 int fan, data, divisor = 0; 829 830 /* 831 * This is madness; the fan divisor bits are scattered all 832 * over the place. 833 */ 834 835 if (sc->lm_sensors[n].reg == LM_FAN1 || 836 sc->lm_sensors[n].reg == LM_FAN2 || 837 sc->lm_sensors[n].reg == LM_FAN3) { 838 data = sc->lm_readreg(sc, WB_BANK0_VBAT); 839 fan = (sc->lm_sensors[n].reg - LM_FAN1); 840 if ((data >> 5) & (1 << fan)) 841 divisor |= 0x04; 842 } 843 844 if (sc->lm_sensors[n].reg == LM_FAN1 || 845 sc->lm_sensors[n].reg == LM_FAN2) { 846 data = sc->lm_readreg(sc, LM_VIDFAN); 847 if (sc->lm_sensors[n].reg == LM_FAN1) 848 divisor |= (data >> 4) & 0x03; 849 else 850 divisor |= (data >> 6) & 0x03; 851 } else if (sc->lm_sensors[n].reg == LM_FAN3) { 852 data = sc->lm_readreg(sc, WB_PIN); 853 divisor |= (data >> 6) & 0x03; 854 } else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 || 855 sc->lm_sensors[n].reg == WB_BANK0_FAN5) { 856 data = sc->lm_readreg(sc, WB_BANK0_FAN45); 857 if (sc->lm_sensors[n].reg == WB_BANK0_FAN4) 858 divisor |= (data >> 0) & 0x07; 859 else 860 divisor |= (data >> 4) & 0x07; 861 } 862 863 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 864 if (data == 0xff || data == 0x00) { 865 sensor->flags |= SENSOR_FINVALID; 866 sensor->value = 0; 867 } else { 868 sensor->flags &= ~SENSOR_FINVALID; 869 sensor->value = 1350000 / (data << divisor); 870 } 871 } 872 873 void 874 wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n) 875 { 876 struct ksensor *sensor = &sc->sensors[n]; 877 int reg, shift, data, divisor = 1; 878 879 switch (sc->lm_sensors[n].reg) { 880 case 0x28: 881 reg = 0x47; shift = 0; 882 break; 883 case 0x29: 884 reg = 0x47; shift = 4; 885 break; 886 case 0x2a: 887 reg = 0x5b; shift = 0; 888 break; 889 case 0xb8: 890 reg = 0x5b; shift = 4; 891 break; 892 case 0xb9: 893 reg = 0x5c; shift = 0; 894 break; 895 case 0xba: 896 reg = 0x5c; shift = 4; 897 break; 898 case 0xbe: 899 reg = 0x9e; shift = 0; 900 break; 901 default: 902 reg = 0; shift = 0; 903 break; 904 } 905 906 data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 907 if (data == 0xff || data == 0x00) { 908 sensor->flags |= SENSOR_FINVALID; 909 sensor->value = 0; 910 } else { 911 if (reg != 0) 912 divisor = (sc->lm_readreg(sc, reg) >> shift) & 0x7; 913 sensor->flags &= ~SENSOR_FINVALID; 914 sensor->value = 1350000 / (data << divisor); 915 } 916 } 917 918 void 919 wb_nct6776f_refresh_fanrpm(struct lm_softc *sc, int n) 920 { 921 struct ksensor *sensor = &sc->sensors[n]; 922 int datah, datal; 923 924 datah = sc->lm_readreg(sc, sc->lm_sensors[n].reg); 925 datal = sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1); 926 927 if (datah == 0xff) { 928 sensor->flags |= SENSOR_FINVALID; 929 sensor->value = 0; 930 } else { 931 sensor->flags &= ~SENSOR_FINVALID; 932 sensor->value = (datah << 8) | datal; 933 } 934 } 935 936 void 937 as_refresh_temp(struct lm_softc *sc, int n) 938 { 939 struct ksensor *sensor = &sc->sensors[n]; 940 int sdata; 941 942 /* 943 * It seems a shorted temperature diode produces an all-ones 944 * bit pattern. 945 */ 946 sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1; 947 sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7; 948 if (sdata == 0x1ff) { 949 sensor->flags |= SENSOR_FINVALID; 950 sensor->value = 0; 951 } else { 952 if (sdata & 0x100) 953 sdata -= 0x200; 954 sensor->flags &= ~SENSOR_FINVALID; 955 sensor->value = sdata * 500000 + 273150000; 956 } 957 } 958