1 /*- 2 * Copyright (c) 2010 Andreas Tobler. 3 * Copyright (c) 2013-2014 Luiz Otavio O Souza <loos@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #include "opt_platform.h" 30 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/endian.h> 34 #include <sys/kernel.h> 35 #include <sys/module.h> 36 #include <sys/sysctl.h> 37 #include <sys/systm.h> 38 39 #include <machine/bus.h> 40 41 #include <dev/iicbus/iicbus.h> 42 #include <dev/iicbus/iiconf.h> 43 44 #ifdef FDT 45 #include <dev/ofw/openfirm.h> 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 #endif 49 50 /* LM75 registers. */ 51 #define LM75_TEMP 0x0 52 #define LM75_CONF 0x1 53 #define LM75_CONF_FSHIFT 3 54 #define LM75_CONF_FAULT 0x18 55 #define LM75_CONF_POL 0x04 56 #define LM75_CONF_MODE 0x02 57 #define LM75_CONF_SHUTD 0x01 58 #define LM75_CONF_MASK 0x1f 59 #define LM75_THYST 0x2 60 #define LM75_TOS 0x3 61 62 /* LM75 constants. */ 63 #define LM75_TEST_PATTERN 0xa 64 #define LM75_MIN_TEMP -55 65 #define LM75_MAX_TEMP 125 66 #define TZ_ZEROC 27315 67 #define TZ_ZEROC_DIVIDER 100 68 69 enum max_resolution{ 70 BITS_9 = 1, 71 BITS_11 72 }; 73 74 /* Regular bus attachment functions */ 75 static int lm75_probe(device_t); 76 static int lm75_attach(device_t); 77 78 struct lm75_softc { 79 device_t sc_dev; 80 struct intr_config_hook enum_hook; 81 uint32_t sc_addr; 82 uint32_t sc_conf; 83 uint8_t sc_resolution; 84 uint8_t sc_max_resolution; 85 uint16_t sc_multiplier; 86 }; 87 88 /* Utility functions */ 89 static int lm75_conf_read(struct lm75_softc *); 90 static int lm75_conf_write(struct lm75_softc *); 91 static int lm75_temp_read(struct lm75_softc *, uint8_t, int *); 92 static int lm75_temp_write(struct lm75_softc *, uint8_t, int); 93 static void lm75_start(void *); 94 static int lm75_read(device_t, uint32_t, uint8_t, uint8_t *, size_t); 95 static int lm75_write(device_t, uint32_t, uint8_t *, size_t); 96 static int lm75_str_mode(char *); 97 static int lm75_str_pol(char *); 98 static int lm75_temp_sysctl(SYSCTL_HANDLER_ARGS); 99 static int lm75_faults_sysctl(SYSCTL_HANDLER_ARGS); 100 static int lm75_mode_sysctl(SYSCTL_HANDLER_ARGS); 101 static int lm75_pol_sysctl(SYSCTL_HANDLER_ARGS); 102 static int lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS); 103 static int lm75_resolution_sysctl(SYSCTL_HANDLER_ARGS); 104 105 static device_method_t lm75_methods[] = { 106 /* Device interface */ 107 DEVMETHOD(device_probe, lm75_probe), 108 DEVMETHOD(device_attach, lm75_attach), 109 110 DEVMETHOD_END 111 }; 112 113 static driver_t lm75_driver = { 114 "lm75", 115 lm75_methods, 116 sizeof(struct lm75_softc) 117 }; 118 119 #ifdef FDT 120 static struct ofw_compat_data compat_data[] = { 121 {"national,lm75", BITS_9}, 122 {"ti,lm75", BITS_9}, 123 {0,0} 124 }; 125 #endif 126 127 DRIVER_MODULE(lm75, iicbus, lm75_driver, 0, 0); 128 129 static int 130 lm75_read(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data, size_t len) 131 { 132 struct iic_msg msg[2] = { 133 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 134 { addr, IIC_M_RD, len, data }, 135 }; 136 137 if (iicbus_transfer(dev, msg, nitems(msg)) != 0) 138 return (-1); 139 140 return (0); 141 } 142 143 static int 144 lm75_write(device_t dev, uint32_t addr, uint8_t *data, size_t len) 145 { 146 struct iic_msg msg[1] = { 147 { addr, IIC_M_WR, len, data }, 148 }; 149 150 if (iicbus_transfer(dev, msg, nitems(msg)) != 0) 151 return (-1); 152 153 return (0); 154 } 155 156 static int 157 lm75_probe(device_t dev) 158 { 159 #ifdef FDT 160 const struct ofw_compat_data *compat_ptr; 161 #endif 162 struct lm75_softc *sc; 163 164 sc = device_get_softc(dev); 165 sc->sc_max_resolution = 9; 166 167 #ifdef FDT 168 if (!ofw_bus_status_okay(dev)) 169 return (ENXIO); 170 171 compat_ptr = ofw_bus_search_compatible(dev, compat_data); 172 173 switch (compat_ptr->ocd_data){ 174 case BITS_9: 175 sc->sc_max_resolution = 9; 176 break; 177 case BITS_11: 178 sc->sc_max_resolution = 11; 179 break; 180 default: 181 return (ENXIO); 182 } 183 #endif 184 device_set_desc(dev, "LM75 temperature sensor"); 185 186 return (BUS_PROBE_GENERIC); 187 } 188 189 static int 190 lm75_attach(device_t dev) 191 { 192 struct lm75_softc *sc; 193 194 sc = device_get_softc(dev); 195 sc->sc_dev = dev; 196 sc->sc_addr = iicbus_get_addr(dev); 197 198 sc->enum_hook.ich_func = lm75_start; 199 sc->enum_hook.ich_arg = dev; 200 201 switch (sc->sc_max_resolution) { 202 case 9: 203 sc->sc_resolution = 9; 204 sc->sc_max_resolution = 9; 205 sc->sc_multiplier = 10; 206 break; 207 case 11: 208 sc->sc_resolution = 11; 209 sc->sc_max_resolution = 11; 210 sc->sc_multiplier = 1000; 211 break; 212 default: 213 return (ENXIO); 214 } 215 216 /* 217 * We have to wait until interrupts are enabled. Usually I2C read 218 * and write only works when the interrupts are available. 219 */ 220 if (config_intrhook_establish(&sc->enum_hook) != 0) 221 return (ENOMEM); 222 223 return (0); 224 } 225 226 static int 227 lm75_type_detect(struct lm75_softc *sc) 228 { 229 int i, lm75a; 230 uint8_t buf8; 231 uint32_t conf; 232 233 /* Save the contents of the configuration register. */ 234 if (lm75_conf_read(sc) != 0) 235 return (-1); 236 conf = sc->sc_conf; 237 238 /* 239 * Just write some pattern at configuration register so we can later 240 * verify. The test pattern should be pretty harmless. 241 */ 242 sc->sc_conf = LM75_TEST_PATTERN; 243 if (lm75_conf_write(sc) != 0) 244 return (-1); 245 246 /* 247 * Read the configuration register again and check for our test 248 * pattern. 249 */ 250 if (lm75_conf_read(sc) != 0) 251 return (-1); 252 if (sc->sc_conf != LM75_TEST_PATTERN) 253 return (-1); 254 255 /* 256 * Read from nonexistent registers (0x4 ~ 0x6). 257 * LM75A always return 0xff for nonexistent registers. 258 * LM75 will return the last read value - our test pattern written to 259 * configuration register. 260 */ 261 lm75a = 0; 262 for (i = 4; i <= 6; i++) { 263 if (lm75_read(sc->sc_dev, sc->sc_addr, i, 264 &buf8, sizeof(buf8)) < 0) 265 return (-1); 266 if (buf8 != LM75_TEST_PATTERN && buf8 != 0xff) 267 return (-1); 268 if (buf8 == 0xff) 269 lm75a++; 270 } 271 if (lm75a == 3){ 272 sc->sc_multiplier = 1000; 273 sc->sc_resolution = 11; 274 sc->sc_max_resolution = 11; 275 } 276 277 /* Restore the configuration register. */ 278 sc->sc_conf = conf; 279 if (lm75_conf_write(sc) != 0) 280 return (-1); 281 282 return (0); 283 } 284 285 static void 286 lm75_start(void *xdev) 287 { 288 device_t dev; 289 struct lm75_softc *sc; 290 struct sysctl_ctx_list *ctx; 291 struct sysctl_oid *tree_node; 292 struct sysctl_oid_list *tree; 293 char *mult_format; 294 295 dev = (device_t)xdev; 296 sc = device_get_softc(dev); 297 ctx = device_get_sysctl_ctx(dev); 298 tree_node = device_get_sysctl_tree(dev); 299 tree = SYSCTL_CHILDREN(tree_node); 300 301 config_intrhook_disestablish(&sc->enum_hook); 302 303 /* 304 * Detect the kind of chip we are attaching to. 305 * This may not work for LM75 clones. 306 */ 307 if (lm75_type_detect(sc) != 0) { 308 device_printf(dev, "cannot detect sensor.\n"); 309 #ifndef FDT 310 return; 311 #endif 312 } 313 314 device_printf(dev,"%d bit resolution sensor attached.\n", 315 sc->sc_resolution); 316 317 if (sc->sc_multiplier == 1000) 318 mult_format = "IK3"; 319 else 320 mult_format = "IK"; 321 322 /* Temperature. */ 323 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature", 324 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, LM75_TEMP, 325 lm75_temp_sysctl, mult_format, "Current temperature"); 326 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "thyst", 327 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_THYST, 328 lm75_temp_sysctl, mult_format, "Hysteresis temperature"); 329 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tos", 330 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_TOS, 331 lm75_temp_sysctl, mult_format, "Overtemperature"); 332 333 /* Configuration parameters. */ 334 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "faults", 335 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0, 336 lm75_faults_sysctl, "IU", "LM75 fault queue"); 337 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode", 338 CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0, 339 lm75_mode_sysctl, "A", "LM75 mode"); 340 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "polarity", 341 CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0, 342 lm75_pol_sysctl, "A", "LM75 OS polarity"); 343 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "shutdown", 344 CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0, 345 lm75_shutdown_sysctl, "IU", "LM75 shutdown"); 346 SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "resolution", 347 CTLFLAG_RW | CTLTYPE_INT | CTLFLAG_MPSAFE, dev, 0, 348 lm75_resolution_sysctl, "IU", "LM75 resolution"); 349 } 350 351 static int 352 lm75_conf_read(struct lm75_softc *sc) 353 { 354 uint8_t buf8; 355 356 if (lm75_read(sc->sc_dev, sc->sc_addr, LM75_CONF, 357 &buf8, sizeof(buf8)) < 0) 358 return (-1); 359 sc->sc_conf = (uint32_t)buf8; 360 361 return (0); 362 } 363 364 static int 365 lm75_conf_write(struct lm75_softc *sc) 366 { 367 uint8_t buf8[2]; 368 369 buf8[0] = LM75_CONF; 370 buf8[1] = (uint8_t)sc->sc_conf & LM75_CONF_MASK; 371 if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0) 372 return (-1); 373 374 return (0); 375 } 376 377 static int 378 lm75_temp_read(struct lm75_softc *sc, uint8_t reg, int32_t *temp) 379 { 380 int32_t buf; 381 uint8_t buf8[2]; 382 uint8_t resolution = sc->sc_resolution; 383 uint16_t multiplier = sc->sc_multiplier; 384 385 if (lm75_read(sc->sc_dev, sc->sc_addr, reg, buf8, sizeof(buf8)) < 0) 386 return (-1); 387 388 buf = (int16_t)((buf8[0] << 8) | buf8[1]); 389 *temp = ((buf >> (16 - resolution)) * multiplier) >> (resolution - 8); 390 391 *temp += TZ_ZEROC * sc->sc_multiplier / TZ_ZEROC_DIVIDER; 392 393 return (0); 394 } 395 396 static int 397 lm75_temp_write(struct lm75_softc *sc, uint8_t reg, int32_t temp) 398 { 399 int32_t buf; 400 uint8_t buf8[3], resolution = sc->sc_resolution; 401 uint16_t multiplier = sc->sc_multiplier; 402 403 temp -= TZ_ZEROC * multiplier / TZ_ZEROC_DIVIDER; 404 if (temp > LM75_MAX_TEMP * multiplier) 405 temp = LM75_MAX_TEMP * multiplier; 406 if (temp < LM75_MIN_TEMP * multiplier) 407 temp = LM75_MIN_TEMP * multiplier; 408 409 buf = ((temp << (resolution - 8)) / multiplier) << (16 - resolution); 410 411 buf8[0] = reg; 412 buf8[1] = (buf >> 8) & 0xff; 413 buf8[2] = buf & 0xff; 414 415 if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0) 416 return (-1); 417 418 return (0); 419 } 420 421 static int 422 lm75_str_mode(char *buf) 423 { 424 int len, rtrn; 425 426 rtrn = -1; 427 len = strlen(buf); 428 if (len > 2 && strncasecmp("interrupt", buf, len) == 0) 429 rtrn = 1; 430 else if (len > 2 && strncasecmp("comparator", buf, len) == 0) 431 rtrn = 0; 432 433 return (rtrn); 434 } 435 436 static int 437 lm75_str_pol(char *buf) 438 { 439 int len, rtrn; 440 441 rtrn = -1; 442 len = strlen(buf); 443 if (len > 1 && strncasecmp("high", buf, len) == 0) 444 rtrn = 1; 445 else if (len > 1 && strncasecmp("low", buf, len) == 0) 446 rtrn = 0; 447 else if (len > 8 && strncasecmp("active-high", buf, len) == 0) 448 rtrn = 1; 449 else if (len > 8 && strncasecmp("active-low", buf, len) == 0) 450 rtrn = 0; 451 452 return (rtrn); 453 } 454 455 static int 456 lm75_temp_sysctl(SYSCTL_HANDLER_ARGS) 457 { 458 device_t dev; 459 int error; 460 int32_t temp; 461 struct lm75_softc *sc; 462 uint8_t reg; 463 464 dev = (device_t)arg1; 465 reg = (uint8_t)arg2; 466 sc = device_get_softc(dev); 467 468 if (lm75_temp_read(sc, reg, &temp) != 0) 469 return (EIO); 470 471 error = sysctl_handle_int(oidp, &temp, 0, req); 472 if (error != 0 || req->newptr == NULL) 473 return (error); 474 475 if (lm75_temp_write(sc, reg, temp) != 0) 476 return (EIO); 477 478 return (error); 479 } 480 481 static int 482 lm75_faults_sysctl(SYSCTL_HANDLER_ARGS) 483 { 484 device_t dev; 485 int lm75_faults[] = { 1, 2, 4, 6 }; 486 int error, faults, i, newf, tmp; 487 struct lm75_softc *sc; 488 489 dev = (device_t)arg1; 490 sc = device_get_softc(dev); 491 tmp = (sc->sc_conf & LM75_CONF_FAULT) >> LM75_CONF_FSHIFT; 492 if (tmp >= nitems(lm75_faults)) 493 tmp = nitems(lm75_faults) - 1; 494 faults = lm75_faults[tmp]; 495 496 error = sysctl_handle_int(oidp, &faults, 0, req); 497 if (error != 0 || req->newptr == NULL) 498 return (error); 499 500 if (faults != lm75_faults[tmp]) { 501 newf = 0; 502 for (i = 0; i < nitems(lm75_faults); i++) 503 if (faults >= lm75_faults[i]) 504 newf = i; 505 sc->sc_conf &= ~LM75_CONF_FAULT; 506 sc->sc_conf |= newf << LM75_CONF_FSHIFT; 507 if (lm75_conf_write(sc) != 0) 508 return (EIO); 509 } 510 511 return (error); 512 } 513 514 static int 515 lm75_mode_sysctl(SYSCTL_HANDLER_ARGS) 516 { 517 char buf[16]; 518 device_t dev; 519 int error, mode, newm; 520 struct lm75_softc *sc; 521 522 dev = (device_t)arg1; 523 sc = device_get_softc(dev); 524 if (sc->sc_conf & LM75_CONF_MODE) { 525 mode = 1; 526 strlcpy(buf, "interrupt", sizeof(buf)); 527 } else { 528 mode = 0; 529 strlcpy(buf, "comparator", sizeof(buf)); 530 } 531 532 error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 533 if (error != 0 || req->newptr == NULL) 534 return (error); 535 536 newm = lm75_str_mode(buf); 537 if (newm != -1 && mode != newm) { 538 sc->sc_conf &= ~LM75_CONF_MODE; 539 if (newm == 1) 540 sc->sc_conf |= LM75_CONF_MODE; 541 if (lm75_conf_write(sc) != 0) 542 return (EIO); 543 } 544 545 return (error); 546 } 547 548 static int 549 lm75_pol_sysctl(SYSCTL_HANDLER_ARGS) 550 { 551 char buf[16]; 552 device_t dev; 553 int error, newp, pol; 554 struct lm75_softc *sc; 555 556 dev = (device_t)arg1; 557 sc = device_get_softc(dev); 558 if (sc->sc_conf & LM75_CONF_POL) { 559 pol = 1; 560 strlcpy(buf, "active-high", sizeof(buf)); 561 } else { 562 pol = 0; 563 strlcpy(buf, "active-low", sizeof(buf)); 564 } 565 566 error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 567 if (error != 0 || req->newptr == NULL) 568 return (error); 569 570 newp = lm75_str_pol(buf); 571 if (newp != -1 && pol != newp) { 572 sc->sc_conf &= ~LM75_CONF_POL; 573 if (newp == 1) 574 sc->sc_conf |= LM75_CONF_POL; 575 if (lm75_conf_write(sc) != 0) 576 return (EIO); 577 } 578 579 return (error); 580 } 581 582 static int 583 lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS) 584 { 585 device_t dev; 586 int error, shutdown, tmp; 587 struct lm75_softc *sc; 588 589 dev = (device_t)arg1; 590 sc = device_get_softc(dev); 591 tmp = shutdown = (sc->sc_conf & LM75_CONF_SHUTD) ? 1 : 0; 592 593 error = sysctl_handle_int(oidp, &shutdown, 0, req); 594 if (error != 0 || req->newptr == NULL) 595 return (error); 596 597 if (shutdown != tmp) { 598 sc->sc_conf &= ~LM75_CONF_SHUTD; 599 if (shutdown) 600 sc->sc_conf |= LM75_CONF_SHUTD; 601 if (lm75_conf_write(sc) != 0) 602 return (EIO); 603 } 604 605 return (error); 606 } 607 608 static int 609 lm75_resolution_sysctl(SYSCTL_HANDLER_ARGS) 610 { 611 device_t dev; 612 int error; 613 struct lm75_softc *sc; 614 int resolution; 615 616 dev = (device_t)arg1; 617 sc = device_get_softc(dev); 618 resolution = sc->sc_resolution; 619 620 error = sysctl_handle_int(oidp, &resolution, 0, req); 621 if (error != 0 || req->newptr == NULL) 622 return (error); 623 624 if (resolution > sc->sc_max_resolution || resolution < 9) 625 return (EINVAL); 626 627 sc->sc_resolution = (uint8_t) resolution; 628 629 return (0); 630 } 631