1 /* $NetBSD: lm87.c,v 1.7 2016/01/10 14:03:11 jdc Exp $ */ 2 /* $OpenBSD: lm87.c,v 1.20 2008/11/10 05:19:48 cnst Exp $ */ 3 4 /* 5 * Copyright (c) 2005 Mark Kettenis 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/cdefs.h> 21 __KERNEL_RCSID(0, "$NetBSD: lm87.c,v 1.7 2016/01/10 14:03:11 jdc Exp $"); 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/device.h> 26 #include <dev/sysmon/sysmonvar.h> 27 28 #include <dev/i2c/i2cvar.h> 29 30 /* LM87 registers */ 31 #define LM87_INT_HHIGH_L 0x13 /* Hardware int high limit (lockable) */ 32 #define LM87_EXT_HHIGH_L 0x14 /* Hardware ext high limit (lockable) */ 33 #define LM87_TEST 0x15 34 #define LM87_CHANNEL 0x16 /* Dual purpose pin and scaling */ 35 #define LM87_INT_HHIGH 0x17 /* Hardware int temp high limit */ 36 #define LM87_EXT_HHIGH 0x18 /* Hardware ext temp high limit */ 37 #define LM87_DAC_DATA 0x19 /* DAC output scaling */ 38 #define LM87_AIN1_LOW 0x1a /* Analog in 1 low limit */ 39 #define LM87_AIN2_LOW 0x1b /* Analog in 2 low limit */ 40 #define LM87_2_5V 0x20 /* +2.5V or ext temp 2 reading */ 41 #define LM87_VCCP1 0x21 /* Vccp1 reading */ 42 #define LM87_VCC 0x22 /* +Vcc reading */ 43 #define LM87_5V 0x23 /* +5V reading */ 44 #define LM87_12V 0x24 /* +12V reading */ 45 #define LM87_VCCP2 0x25 /* Vccp2 reading */ 46 #define LM87_EXT_TEMP 0x26 /* External tempurature 1 reading */ 47 #define LM87_INT_TEMP 0x27 /* Internal temperature reading */ 48 #define LM87_FAN1 0x28 /* Fan1 or AIN1 reading */ 49 #define LM87_FAN2 0x29 /* Fan2 or AIN2 reading */ 50 #define LM87_2_5V_HIGH 0x2b /* +2.5V or ext temp 2 high limit */ 51 #define LM87_2_5V_LOW 0x2c /* +2.5V or ext temp 2 low limit */ 52 #define LM87_VCCP1_HIGH 0x2d /* Vccp1 high limit */ 53 #define LM87_VCCP1_LOW 0x2e /* Vccp1 low limit */ 54 #define LM87_VCC_HIGH 0x2f /* +3.3V (Vcc) high limit */ 55 #define LM87_VCC_LOW 0x30 /* +3.3V (Vcc) low limit */ 56 #define LM87_5V_HIGH 0x31 /* +5V high limit */ 57 #define LM87_5V_LOW 0x32 /* +5V low limit */ 58 #define LM87_12V_HIGH 0x33 /* +12V high limit */ 59 #define LM87_12V_LOW 0x34 /* +12V low limit */ 60 #define LM87_VCCP2_HIGH 0x35 /* Vccp2 high limit */ 61 #define LM87_VCCP2_LOW 0x36 /* Vccp2 low limit */ 62 #define LM87_EXT_HIGH 0x37 /* External tempurature 1 high limit */ 63 #define LM87_EXT_LOW 0x38 /* External tempurature low limit */ 64 #define LM87_INT_HIGH 0x39 /* Internal tempurature 1 high limit */ 65 #define LM87_INT_LOW 0x3a /* Internal tempurature low limit */ 66 #define LM87_FAN1_HIGH 0x3b /* Fan 1 count or AIN1 high limit */ 67 #define LM87_FAN2_HIGH 0x3c /* Fan 2 count or AIN2 high limit */ 68 #define LM87_COMPANY_ID 0x3e /* Company ID */ 69 #define LM87_REVISION 0x3f /* Revision */ 70 #define LM87_CONFIG1 0x40 /* Configuration 1 */ 71 #define LM87_INT_STAT1 0x41 /* Interrupt status 1 */ 72 #define LM87_INT_STAT2 0x42 /* Interrupt status 2 */ 73 #define LM87_INT_MASK1 0x43 /* Interrupt mask 1 */ 74 #define LM87_INT_MASK2 0x44 /* Interrupt mask 2 */ 75 #define LM87_CI_CLEAR 0x46 /* Chassis intrusion */ 76 #define LM87_FANDIV 0x47 /* Fan divisor + VID 0-3 */ 77 #define LM87_VID4 0x48 /* VID4 */ 78 #define LM87_CONFIG2 0x4a /* Configuration 2 */ 79 #define LM87_INT_MIRR1 0x4c /* Interrupt status 1 mirror */ 80 #define LM87_INT_MIRR2 0x4d /* Interrupt status 2 mirror */ 81 #define LM87_ALERT 0x80 /* SMB Alert enable */ 82 83 /* Register contents */ 84 #define LM87_CONFIG1_START 0x01 85 #define LM87_CONFIG1_INTCLR 0x08 86 87 #define LM87_CHANNEL_AIN1 0x01 88 #define LM87_CHANNEL_AIN2 0x02 89 #define LM87_CHANNEL_TEMP2 0x04 90 #define LM87_CHANNEL_VCC5 0x08 91 92 struct lmenv_id { 93 u_int8_t id, family; 94 const char *name; 95 }; 96 97 static const struct lmenv_id lmenv_ids[] = { 98 { 0x01, 81, "LM81" }, 99 { 0x02, 87, "LM87" }, /* LM87 or LM87CIMT */ 100 { 0x23, 81, "ADM9240" }, 101 { 0xda, 81, "DSL780" }, 102 { 0x00, 0, NULL } 103 }; 104 105 /* Sensors */ 106 #define LMENV_2_5V 0 107 #define LMENV_VCCP1 1 108 #define LMENV_VCC 2 109 #define LMENV_5V 3 110 #define LMENV_12V 4 111 #define LMENV_VCCP2 5 112 #define LMENV_EXT_TEMP 6 113 #define LMENV_INT_TEMP 7 114 #define LMENV_FAN1 8 115 #define LMENV_FAN2 9 116 #define LMENV_NUM_SENSORS 10 117 118 struct lmenv_softc { 119 i2c_tag_t sc_tag; 120 i2c_addr_t sc_addr; 121 122 int sc_fan1_div, sc_fan2_div; 123 int sc_family; 124 uint8_t sc_channel; 125 126 struct sysmon_envsys *sc_sme; 127 envsys_data_t sc_sensor[LMENV_NUM_SENSORS]; 128 }; 129 130 int lmenv_match(device_t, cfdata_t, void *); 131 void lmenv_attach(device_t, device_t, void *); 132 133 void lmenv_refresh(struct sysmon_envsys *, envsys_data_t *); 134 135 CFATTACH_DECL_NEW(lmenv, sizeof(struct lmenv_softc), 136 lmenv_match, lmenv_attach, NULL, NULL); 137 138 static const char * lmenv_compats[] = { 139 "lm87", 140 "lm87cimt", 141 "adm9240", 142 "lm81", 143 "ds1780", 144 NULL 145 }; 146 147 int 148 lmenv_match(device_t parent, cfdata_t match, void *aux) 149 { 150 struct i2c_attach_args *ia = aux; 151 u_int8_t cmd, val; 152 int error, i; 153 154 if (ia->ia_name == NULL) { 155 /* 156 * Indirect config - not much we can do! 157 * Check typical addresses and read the Company ID register 158 */ 159 if ((ia->ia_addr < 0x2c) || (ia->ia_addr > 0x2f)) 160 return 0; 161 162 cmd = LM87_COMPANY_ID; 163 iic_acquire_bus(ia->ia_tag, 0); 164 error = iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr, 165 &cmd, 1, &val, 1, I2C_F_POLL); 166 iic_release_bus(ia->ia_tag, 0); 167 168 if (error) 169 return 0; 170 171 for (i = 0; lmenv_ids[i].id != 0; i++) 172 if (lmenv_ids[i].id == val) 173 return 1; 174 } else { 175 /* 176 * Direct config - match via the list of compatible 177 * hardware or simply match the device name. 178 */ 179 if (ia->ia_ncompat > 0) { 180 if (iic_compat_match(ia, lmenv_compats)) 181 return 1; 182 } else { 183 if (strcmp(ia->ia_name, "lmenv") == 0) 184 return 1; 185 } 186 } 187 188 return 0; 189 } 190 191 void 192 lmenv_attach(device_t parent, device_t self, void *aux) 193 { 194 struct lmenv_softc *sc = device_private(self); 195 struct i2c_attach_args *ia = aux; 196 u_int8_t cmd, data, data2; 197 int i; 198 199 sc->sc_tag = ia->ia_tag; 200 sc->sc_addr = ia->ia_addr; 201 202 iic_acquire_bus(sc->sc_tag, 0); 203 204 cmd = LM87_COMPANY_ID; 205 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 206 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 207 iic_release_bus(sc->sc_tag, 0); 208 printf(": cannot read ID register\n"); 209 return; 210 } 211 for (i = 0; lmenv_ids[i].id != 0; i++) 212 if (lmenv_ids[i].id == data) 213 break; 214 215 cmd = LM87_REVISION; 216 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 217 sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data, 0)) { 218 iic_release_bus(sc->sc_tag, 0); 219 printf(": cannot read revision register\n"); 220 return; 221 } 222 printf(": %s rev %x\n", lmenv_ids[i].name, data2); 223 sc->sc_family = lmenv_ids[i].family; 224 225 cmd = LM87_FANDIV; 226 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 227 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 228 iic_release_bus(sc->sc_tag, 0); 229 printf(", cannot read Fan Divisor register\n"); 230 return; 231 } 232 sc->sc_fan1_div = 1 << ((data >> 4) & 0x03); 233 sc->sc_fan2_div = 1 << ((data >> 6) & 0x03); 234 235 if (sc->sc_family == 87) { 236 cmd = LM87_CHANNEL; 237 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 238 sc->sc_addr, &cmd, sizeof cmd, &sc->sc_channel, 239 sizeof sc->sc_channel, 0)) { 240 iic_release_bus(sc->sc_tag, 0); 241 printf(", cannot read Channel register\n"); 242 return; 243 } 244 } else 245 sc->sc_channel = 0; 246 247 cmd = LM87_CONFIG1; 248 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 249 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 250 iic_release_bus(sc->sc_tag, 0); 251 printf(", cannot read Configuration Register 1\n"); 252 return; 253 } 254 255 /* 256 * if chip is not running, try to start it. 257 * if it is stalled doing an interrupt, unstall it 258 */ 259 data2 = (data | LM87_CONFIG1_START); 260 data2 = data2 & ~LM87_CONFIG1_INTCLR; 261 262 if (data != data2) { 263 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 264 sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) { 265 iic_release_bus(sc->sc_tag, 0); 266 printf(", cannot write Configuration Register 1\n"); 267 return; 268 } 269 } 270 iic_release_bus(sc->sc_tag, 0); 271 272 /* Initialize sensor data. */ 273 sc->sc_sensor[LMENV_2_5V].state = ENVSYS_SINVALID; 274 if (sc->sc_channel & LM87_CHANNEL_TEMP2) { 275 sc->sc_sensor[LMENV_INT_TEMP].units = ENVSYS_STEMP; 276 strlcpy(sc->sc_sensor[LMENV_2_5V].desc, "External 2", 277 sizeof(sc->sc_sensor[LMENV_2_5V].desc)); 278 } else { 279 sc->sc_sensor[LMENV_2_5V].units = ENVSYS_SVOLTS_DC; 280 strlcpy(sc->sc_sensor[LMENV_2_5V].desc, "+2.5Vin", 281 sizeof(sc->sc_sensor[LMENV_2_5V].desc)); 282 } 283 284 sc->sc_sensor[LMENV_VCCP1].state = ENVSYS_SINVALID; 285 sc->sc_sensor[LMENV_VCCP1].units = ENVSYS_SVOLTS_DC; 286 strlcpy(sc->sc_sensor[LMENV_VCCP1].desc, "Vccp1", 287 sizeof(sc->sc_sensor[LMENV_VCCP1].desc)); 288 289 sc->sc_sensor[LMENV_VCC].state = ENVSYS_SINVALID; 290 sc->sc_sensor[LMENV_VCC].units = ENVSYS_SVOLTS_DC; 291 strlcpy(sc->sc_sensor[LMENV_VCC].desc, "+Vcc", 292 sizeof(sc->sc_sensor[LMENV_VCC].desc)); 293 294 sc->sc_sensor[LMENV_5V].state = ENVSYS_SINVALID; 295 sc->sc_sensor[LMENV_5V].units = ENVSYS_SVOLTS_DC; 296 strlcpy(sc->sc_sensor[LMENV_5V].desc, "+5Vin/Vcc", 297 sizeof(sc->sc_sensor[LMENV_5V].desc)); 298 299 sc->sc_sensor[LMENV_12V].state = ENVSYS_SINVALID; 300 sc->sc_sensor[LMENV_12V].units = ENVSYS_SVOLTS_DC; 301 strlcpy(sc->sc_sensor[LMENV_12V].desc, "+12Vin", 302 sizeof(sc->sc_sensor[LMENV_12V].desc)); 303 304 sc->sc_sensor[LMENV_VCCP2].state = ENVSYS_SINVALID; 305 if (!(sc->sc_channel & LM87_CHANNEL_TEMP2)) { 306 sc->sc_sensor[LMENV_VCCP2].units = ENVSYS_SVOLTS_DC; 307 strlcpy(sc->sc_sensor[LMENV_VCCP2].desc, "Vccp2", 308 sizeof(sc->sc_sensor[LMENV_VCCP2].desc)); 309 } 310 311 sc->sc_sensor[LMENV_EXT_TEMP].state = ENVSYS_SINVALID; 312 sc->sc_sensor[LMENV_EXT_TEMP].units = ENVSYS_STEMP; 313 if (sc->sc_channel & LM87_CHANNEL_TEMP2) 314 strlcpy(sc->sc_sensor[LMENV_EXT_TEMP].desc, "External 1", 315 sizeof(sc->sc_sensor[LMENV_EXT_TEMP].desc)); 316 else 317 strlcpy(sc->sc_sensor[LMENV_EXT_TEMP].desc, "External", 318 sizeof(sc->sc_sensor[LMENV_EXT_TEMP].desc)); 319 320 sc->sc_sensor[LMENV_INT_TEMP].state = ENVSYS_SINVALID; 321 sc->sc_sensor[LMENV_INT_TEMP].units = ENVSYS_STEMP; 322 strlcpy(sc->sc_sensor[LMENV_INT_TEMP].desc, "Internal", 323 sizeof(sc->sc_sensor[LMENV_INT_TEMP].desc)); 324 325 sc->sc_sensor[LMENV_FAN1].state = ENVSYS_SINVALID; 326 if (sc->sc_channel & LM87_CHANNEL_AIN1) { 327 sc->sc_sensor[LMENV_FAN1].units = ENVSYS_SVOLTS_DC; 328 strlcpy(sc->sc_sensor[LMENV_FAN1].desc, "AIN1", 329 sizeof(sc->sc_sensor[LMENV_FAN1].desc)); 330 } else { 331 sc->sc_sensor[LMENV_FAN1].units = ENVSYS_SFANRPM; 332 strlcpy(sc->sc_sensor[LMENV_FAN1].desc, "FAN1", 333 sizeof(sc->sc_sensor[LMENV_FAN1].desc)); 334 } 335 336 sc->sc_sensor[LMENV_FAN2].state = ENVSYS_SINVALID; 337 if (sc->sc_channel & LM87_CHANNEL_AIN2) { 338 sc->sc_sensor[LMENV_FAN2].units = ENVSYS_SVOLTS_DC; 339 strlcpy(sc->sc_sensor[LMENV_FAN2].desc, "AIN2", 340 sizeof(sc->sc_sensor[LMENV_FAN2].desc)); 341 } else { 342 sc->sc_sensor[LMENV_FAN2].units = ENVSYS_SFANRPM; 343 strlcpy(sc->sc_sensor[LMENV_FAN2].desc, "FAN2", 344 sizeof(sc->sc_sensor[LMENV_FAN2].desc)); 345 } 346 347 sc->sc_sme = sysmon_envsys_create(); 348 for (i = 0; i < LMENV_NUM_SENSORS; i++) 349 if (sysmon_envsys_sensor_attach(sc->sc_sme, 350 &sc->sc_sensor[i])) { 351 sysmon_envsys_destroy(sc->sc_sme); 352 aprint_error_dev(self, 353 "unable to attach sensor %d at sysmon\n", i); 354 return; 355 } 356 sc->sc_sme->sme_name = device_xname(self); 357 sc->sc_sme->sme_cookie = sc; 358 sc->sc_sme->sme_refresh = lmenv_refresh; 359 if (sysmon_envsys_register(sc->sc_sme)) { 360 aprint_error_dev(self, 361 "unable to register with sysmon\n"); 362 sysmon_envsys_destroy(sc->sc_sme); 363 return; 364 } 365 } 366 367 void 368 lmenv_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 369 { 370 struct lmenv_softc *sc = sme->sme_cookie; 371 u_int8_t cmd, data; 372 u_int tmp; 373 374 iic_acquire_bus(sc->sc_tag, 0); 375 376 cmd = LM87_2_5V + edata->sensor; 377 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 378 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 379 edata->state = ENVSYS_SINVALID; 380 return; 381 } 382 383 switch (edata->sensor) { 384 case LMENV_2_5V: 385 /* Might be external temperature 2 */ 386 if (sc->sc_channel & LM87_CHANNEL_TEMP2) { 387 if (data == 0x80) 388 edata->state = ENVSYS_SINVALID; 389 else { 390 edata->value_cur = 391 (int8_t)data * 1000000 + 273150000; 392 edata->state = ENVSYS_SVALID; 393 } 394 break; 395 } 396 edata->value_cur = 2500000 * data / 192; 397 edata->state = ENVSYS_SVALID; 398 break; 399 case LMENV_5V: 400 edata->value_cur = 5000000 * data / 192; 401 edata->state = ENVSYS_SVALID; 402 break; 403 case LMENV_12V: 404 edata->value_cur = 12000000 * data / 192; 405 edata->state = ENVSYS_SVALID; 406 break; 407 case LMENV_VCCP1: 408 edata->value_cur = 2700000 * data / 192; 409 edata->state = ENVSYS_SVALID; 410 break; 411 case LMENV_VCCP2: 412 /* If monitoring external temperature 2, this isn't monitored */ 413 if (sc->sc_channel & LM87_CHANNEL_TEMP2) { 414 edata->state = ENVSYS_SINVALID; 415 break; 416 } 417 edata->value_cur = 2700000 * data / 192; 418 edata->state = ENVSYS_SVALID; 419 break; 420 case LMENV_VCC: 421 /* Voltage scale selectable (5V or 3.3V) */ 422 edata->value_cur = 423 (LM87_CHANNEL_VCC5 ? 5000000 : 3300000) * data / 192; 424 edata->state = ENVSYS_SVALID; 425 break; 426 case LMENV_EXT_TEMP: 427 if (sc->sc_family == 81) { 428 edata->state = ENVSYS_SINVALID; 429 break; /* missing on LM81 */ 430 } 431 /* FALLTHROUGH */ 432 case LMENV_INT_TEMP: 433 if (data == 0x80) 434 edata->state = ENVSYS_SINVALID; 435 else { 436 edata->value_cur = (int8_t)data * 1000000 + 273150000; 437 edata->state = ENVSYS_SVALID; 438 } 439 break; 440 case LMENV_FAN1: 441 /* Might be analogue input 1 */ 442 if (sc->sc_channel & LM87_CHANNEL_AIN1) { 443 edata->value_cur = 1870000 * data / 192; 444 edata->state = ENVSYS_SVALID; 445 break; 446 } 447 if (data == 0xff) { 448 edata->state = ENVSYS_SINVALID; 449 break; 450 } 451 tmp = data * sc->sc_fan1_div; 452 if (tmp == 0) 453 edata->state = ENVSYS_SINVALID; 454 else { 455 edata->value_cur = 1350000 / tmp; 456 edata->state = ENVSYS_SVALID; 457 } 458 break; 459 case LMENV_FAN2: 460 /* Might be analogue input 2 */ 461 if (sc->sc_channel & LM87_CHANNEL_AIN2) { 462 edata->value_cur = 1870000 * data / 192; 463 edata->state = ENVSYS_SVALID; 464 break; 465 } 466 if (data == 0xff) { 467 edata->state = ENVSYS_SINVALID; 468 break; 469 } 470 tmp = data * sc->sc_fan2_div; 471 if (tmp == 0) 472 edata->state = ENVSYS_SINVALID; 473 else { 474 edata->value_cur = 1350000 / tmp; 475 edata->state = ENVSYS_SVALID; 476 } 477 break; 478 default: 479 edata->state = ENVSYS_SINVALID; 480 break; 481 } 482 483 iic_release_bus(sc->sc_tag, 0); 484 } 485