1265813Sloos/*- 2265813Sloos * Copyright (c) 2010 Andreas Tobler. 3265813Sloos * Copyright (c) 2013-2014 Luiz Otavio O Souza <loos@freebsd.org> 4265813Sloos * All rights reserved. 5265813Sloos * 6265813Sloos * Redistribution and use in source and binary forms, with or without 7265813Sloos * modification, are permitted provided that the following conditions 8265813Sloos * are met: 9265813Sloos * 1. Redistributions of source code must retain the above copyright 10265813Sloos * notice, this list of conditions and the following disclaimer. 11265813Sloos * 2. Redistributions in binary form must reproduce the above copyright 12265813Sloos * notice, this list of conditions and the following disclaimer in the 13265813Sloos * documentation and/or other materials provided with the distribution. 14265813Sloos * 15265813Sloos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16265813Sloos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17265813Sloos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18265813Sloos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19265813Sloos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20265813Sloos * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21265813Sloos * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22265813Sloos * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23265813Sloos * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24265813Sloos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25265813Sloos * SUCH DAMAGE. 26265813Sloos */ 27265813Sloos 28265813Sloos#include <sys/cdefs.h> 29265813Sloos__FBSDID("$FreeBSD$"); 30265813Sloos 31265813Sloos#include "opt_platform.h" 32265813Sloos 33265813Sloos#include <sys/param.h> 34265813Sloos#include <sys/bus.h> 35265813Sloos#include <sys/endian.h> 36265813Sloos#include <sys/kernel.h> 37265813Sloos#include <sys/module.h> 38265813Sloos#include <sys/sysctl.h> 39265813Sloos#include <sys/systm.h> 40265813Sloos 41265813Sloos#include <machine/bus.h> 42265813Sloos 43265813Sloos#include <dev/iicbus/iicbus.h> 44265813Sloos#include <dev/iicbus/iiconf.h> 45265813Sloos 46265813Sloos#ifdef FDT 47265813Sloos#include <dev/ofw/openfirm.h> 48265813Sloos#include <dev/ofw/ofw_bus.h> 49265813Sloos#include <dev/ofw/ofw_bus_subr.h> 50265813Sloos#endif 51265813Sloos 52265813Sloos/* LM75 registers. */ 53265813Sloos#define LM75_TEMP 0x0 54278917Sloos#define LM75_TEMP_MASK 0xff80 55278917Sloos#define LM75A_TEMP_MASK 0xffe0 56265813Sloos#define LM75_CONF 0x1 57265813Sloos#define LM75_CONF_FSHIFT 3 58265813Sloos#define LM75_CONF_FAULT 0x18 59265813Sloos#define LM75_CONF_POL 0x04 60265813Sloos#define LM75_CONF_MODE 0x02 61265813Sloos#define LM75_CONF_SHUTD 0x01 62265813Sloos#define LM75_CONF_MASK 0x1f 63265813Sloos#define LM75_THYST 0x2 64265813Sloos#define LM75_TOS 0x3 65265813Sloos 66265813Sloos/* LM75 constants. */ 67265813Sloos#define LM75_TEST_PATTERN 0xa 68265813Sloos#define LM75_MIN_TEMP -55 69265813Sloos#define LM75_MAX_TEMP 125 70265813Sloos#define LM75_0500C 0x80 71265813Sloos#define LM75_0250C 0x40 72265813Sloos#define LM75_0125C 0x20 73265813Sloos#define LM75_MSB 0x8000 74265813Sloos#define LM75_NEG_BIT LM75_MSB 75300421Sloos#define TZ_ZEROC 2731 76265813Sloos 77265813Sloos/* LM75 supported models. */ 78265813Sloos#define HWTYPE_LM75 1 79265813Sloos#define HWTYPE_LM75A 2 80265813Sloos 81265813Sloos/* Regular bus attachment functions */ 82265813Sloosstatic int lm75_probe(device_t); 83265813Sloosstatic int lm75_attach(device_t); 84265813Sloos 85265813Sloosstruct lm75_softc { 86265813Sloos device_t sc_dev; 87265813Sloos struct intr_config_hook enum_hook; 88265813Sloos int32_t sc_hwtype; 89265813Sloos uint32_t sc_addr; 90265813Sloos uint32_t sc_conf; 91265813Sloos}; 92265813Sloos 93265813Sloos/* Utility functions */ 94265813Sloosstatic int lm75_conf_read(struct lm75_softc *); 95265813Sloosstatic int lm75_conf_write(struct lm75_softc *); 96265813Sloosstatic int lm75_temp_read(struct lm75_softc *, uint8_t, int *); 97265813Sloosstatic int lm75_temp_write(struct lm75_softc *, uint8_t, int); 98265813Sloosstatic void lm75_start(void *); 99265813Sloosstatic int lm75_read(device_t, uint32_t, uint8_t, uint8_t *, size_t); 100265813Sloosstatic int lm75_write(device_t, uint32_t, uint8_t *, size_t); 101265813Sloosstatic int lm75_str_mode(char *); 102265813Sloosstatic int lm75_str_pol(char *); 103265813Sloosstatic int lm75_temp_sysctl(SYSCTL_HANDLER_ARGS); 104265813Sloosstatic int lm75_faults_sysctl(SYSCTL_HANDLER_ARGS); 105265813Sloosstatic int lm75_mode_sysctl(SYSCTL_HANDLER_ARGS); 106265813Sloosstatic int lm75_pol_sysctl(SYSCTL_HANDLER_ARGS); 107265813Sloosstatic int lm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS); 108265813Sloos 109265813Sloosstatic device_method_t lm75_methods[] = { 110265813Sloos /* Device interface */ 111265813Sloos DEVMETHOD(device_probe, lm75_probe), 112265813Sloos DEVMETHOD(device_attach, lm75_attach), 113265813Sloos 114265813Sloos DEVMETHOD_END 115265813Sloos}; 116265813Sloos 117265813Sloosstatic driver_t lm75_driver = { 118265813Sloos "lm75", 119265813Sloos lm75_methods, 120265813Sloos sizeof(struct lm75_softc) 121265813Sloos}; 122265813Sloos 123265813Sloosstatic devclass_t lm75_devclass; 124265813Sloos 125265813SloosDRIVER_MODULE(lm75, iicbus, lm75_driver, lm75_devclass, 0, 0); 126265813Sloos 127265813Sloosstatic int 128265813Slooslm75_read(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data, size_t len) 129265813Sloos{ 130265813Sloos struct iic_msg msg[2] = { 131265813Sloos { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 132265813Sloos { addr, IIC_M_RD, len, data }, 133265813Sloos }; 134265813Sloos 135278918Sloos if (iicbus_transfer(dev, msg, nitems(msg)) != 0) 136265813Sloos return (-1); 137265813Sloos 138265813Sloos return (0); 139265813Sloos} 140265813Sloos 141265813Sloosstatic int 142265813Slooslm75_write(device_t dev, uint32_t addr, uint8_t *data, size_t len) 143265813Sloos{ 144265813Sloos struct iic_msg msg[1] = { 145265813Sloos { addr, IIC_M_WR, len, data }, 146265813Sloos }; 147265813Sloos 148278918Sloos if (iicbus_transfer(dev, msg, nitems(msg)) != 0) 149265813Sloos return (-1); 150265813Sloos 151265813Sloos return (0); 152265813Sloos} 153265813Sloos 154265813Sloosstatic int 155265813Slooslm75_probe(device_t dev) 156265813Sloos{ 157265813Sloos struct lm75_softc *sc; 158265813Sloos 159265813Sloos sc = device_get_softc(dev); 160265813Sloos sc->sc_hwtype = HWTYPE_LM75; 161265813Sloos#ifdef FDT 162265813Sloos if (!ofw_bus_is_compatible(dev, "national,lm75")) 163265813Sloos return (ENXIO); 164265813Sloos#endif 165265813Sloos device_set_desc(dev, "LM75 temperature sensor"); 166265813Sloos 167265813Sloos return (BUS_PROBE_GENERIC); 168265813Sloos} 169265813Sloos 170265813Sloosstatic int 171265813Slooslm75_attach(device_t dev) 172265813Sloos{ 173265813Sloos struct lm75_softc *sc; 174265813Sloos 175265813Sloos sc = device_get_softc(dev); 176265813Sloos sc->sc_dev = dev; 177265813Sloos sc->sc_addr = iicbus_get_addr(dev); 178265813Sloos 179265813Sloos sc->enum_hook.ich_func = lm75_start; 180265813Sloos sc->enum_hook.ich_arg = dev; 181265813Sloos 182265813Sloos /* 183265813Sloos * We have to wait until interrupts are enabled. Usually I2C read 184265813Sloos * and write only works when the interrupts are available. 185265813Sloos */ 186265813Sloos if (config_intrhook_establish(&sc->enum_hook) != 0) 187265813Sloos return (ENOMEM); 188265813Sloos 189265813Sloos return (0); 190265813Sloos} 191265813Sloos 192265813Sloosstatic int 193265813Slooslm75_type_detect(struct lm75_softc *sc) 194265813Sloos{ 195265813Sloos int i, lm75a; 196265813Sloos uint8_t buf8; 197265813Sloos uint32_t conf; 198265813Sloos 199265813Sloos /* Save the contents of the configuration register. */ 200265813Sloos if (lm75_conf_read(sc) != 0) 201265813Sloos return (-1); 202265813Sloos conf = sc->sc_conf; 203265813Sloos 204265813Sloos /* 205265813Sloos * Just write some pattern at configuration register so we can later 206265813Sloos * verify. The test pattern should be pretty harmless. 207265813Sloos */ 208265813Sloos sc->sc_conf = LM75_TEST_PATTERN; 209265813Sloos if (lm75_conf_write(sc) != 0) 210265813Sloos return (-1); 211265813Sloos 212265813Sloos /* 213265813Sloos * Read the configuration register again and check for our test 214265813Sloos * pattern. 215265813Sloos */ 216265813Sloos if (lm75_conf_read(sc) != 0) 217265813Sloos return (-1); 218265813Sloos if (sc->sc_conf != LM75_TEST_PATTERN) 219265813Sloos return (-1); 220265813Sloos 221265813Sloos /* 222265813Sloos * Read from nonexistent registers (0x4 ~ 0x6). 223265813Sloos * LM75A always return 0xff for nonexistent registers. 224265813Sloos * LM75 will return the last read value - our test pattern written to 225265813Sloos * configuration register. 226265813Sloos */ 227265813Sloos lm75a = 0; 228265813Sloos for (i = 4; i <= 6; i++) { 229278918Sloos if (lm75_read(sc->sc_dev, sc->sc_addr, i, 230278918Sloos &buf8, sizeof(buf8)) < 0) 231265813Sloos return (-1); 232265813Sloos if (buf8 != LM75_TEST_PATTERN && buf8 != 0xff) 233265813Sloos return (-1); 234265813Sloos if (buf8 == 0xff) 235265813Sloos lm75a++; 236265813Sloos } 237265813Sloos if (lm75a == 3) 238265813Sloos sc->sc_hwtype = HWTYPE_LM75A; 239265813Sloos 240265813Sloos /* Restore the configuration register. */ 241265813Sloos sc->sc_conf = conf; 242265813Sloos if (lm75_conf_write(sc) != 0) 243265813Sloos return (-1); 244265813Sloos 245265813Sloos return (0); 246265813Sloos} 247265813Sloos 248265813Sloosstatic void 249265813Slooslm75_start(void *xdev) 250265813Sloos{ 251265813Sloos device_t dev; 252265813Sloos struct lm75_softc *sc; 253265813Sloos struct sysctl_ctx_list *ctx; 254265813Sloos struct sysctl_oid *tree_node; 255265813Sloos struct sysctl_oid_list *tree; 256265813Sloos 257265813Sloos dev = (device_t)xdev; 258265813Sloos sc = device_get_softc(dev); 259265813Sloos ctx = device_get_sysctl_ctx(dev); 260265813Sloos tree_node = device_get_sysctl_tree(dev); 261265813Sloos tree = SYSCTL_CHILDREN(tree_node); 262265813Sloos 263265813Sloos config_intrhook_disestablish(&sc->enum_hook); 264265813Sloos 265265813Sloos /* 266265813Sloos * Detect the kind of chip we are attaching to. 267265813Sloos * This may not work for LM75 clones. 268265813Sloos */ 269265813Sloos if (lm75_type_detect(sc) != 0) { 270265813Sloos device_printf(dev, "cannot read from sensor.\n"); 271265813Sloos return; 272265813Sloos } 273265813Sloos if (sc->sc_hwtype == HWTYPE_LM75A) 274265813Sloos device_printf(dev, 275265813Sloos "LM75A type sensor detected (11bits resolution).\n"); 276265813Sloos 277265813Sloos /* Temperature. */ 278265813Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature", 279265813Sloos CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, LM75_TEMP, 280265813Sloos lm75_temp_sysctl, "IK", "Current temperature"); 281265813Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "thyst", 282265813Sloos CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_THYST, 283265813Sloos lm75_temp_sysctl, "IK", "Hysteresis temperature"); 284265813Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "tos", 285265813Sloos CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, LM75_TOS, 286265813Sloos lm75_temp_sysctl, "IK", "Overtemperature"); 287265813Sloos 288265813Sloos /* Configuration parameters. */ 289265813Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "faults", 290278918Sloos CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0, 291265813Sloos lm75_faults_sysctl, "IU", "LM75 fault queue"); 292265813Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "mode", 293278918Sloos CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0, 294265813Sloos lm75_mode_sysctl, "A", "LM75 mode"); 295265813Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "polarity", 296278918Sloos CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, dev, 0, 297265813Sloos lm75_pol_sysctl, "A", "LM75 OS polarity"); 298265813Sloos SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "shutdown", 299278918Sloos CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, dev, 0, 300265813Sloos lm75_shutdown_sysctl, "IU", "LM75 shutdown"); 301265813Sloos} 302265813Sloos 303265813Sloosstatic int 304265813Slooslm75_conf_read(struct lm75_softc *sc) 305265813Sloos{ 306265813Sloos uint8_t buf8; 307265813Sloos 308278918Sloos if (lm75_read(sc->sc_dev, sc->sc_addr, LM75_CONF, 309278918Sloos &buf8, sizeof(buf8)) < 0) 310265813Sloos return (-1); 311265813Sloos sc->sc_conf = (uint32_t)buf8; 312265813Sloos 313265813Sloos return (0); 314265813Sloos} 315265813Sloos 316265813Sloosstatic int 317265813Slooslm75_conf_write(struct lm75_softc *sc) 318265813Sloos{ 319265813Sloos uint8_t buf8[2]; 320265813Sloos 321265813Sloos buf8[0] = LM75_CONF; 322265813Sloos buf8[1] = (uint8_t)sc->sc_conf & LM75_CONF_MASK; 323278918Sloos if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0) 324265813Sloos return (-1); 325265813Sloos 326265813Sloos return (0); 327265813Sloos} 328265813Sloos 329265813Sloosstatic int 330265813Slooslm75_temp_read(struct lm75_softc *sc, uint8_t reg, int *temp) 331265813Sloos{ 332265813Sloos uint8_t buf8[2]; 333265813Sloos uint16_t buf; 334278917Sloos int neg, t; 335265813Sloos 336278918Sloos if (lm75_read(sc->sc_dev, sc->sc_addr, reg, buf8, sizeof(buf8)) < 0) 337265813Sloos return (-1); 338278917Sloos buf = (uint16_t)((buf8[0] << 8) | (buf8[1] & 0xff)); 339265813Sloos /* 340265813Sloos * LM75 has a 9 bit ADC with resolution of 0.5 C per bit. 341265813Sloos * LM75A has an 11 bit ADC with resolution of 0.125 C per bit. 342265813Sloos * Temperature is stored with two's complement. 343265813Sloos */ 344278917Sloos neg = 0; 345278917Sloos if (buf & LM75_NEG_BIT) { 346278917Sloos if (sc->sc_hwtype == HWTYPE_LM75A) 347278917Sloos buf = ~(buf & LM75A_TEMP_MASK) + 1; 348278917Sloos else 349278917Sloos buf = ~(buf & LM75_TEMP_MASK) + 1; 350278917Sloos neg = 1; 351278917Sloos } 352265813Sloos *temp = ((int16_t)buf >> 8) * 10; 353265813Sloos t = 0; 354265813Sloos if (sc->sc_hwtype == HWTYPE_LM75A) { 355265813Sloos if (buf & LM75_0125C) 356265813Sloos t += 125; 357265813Sloos if (buf & LM75_0250C) 358265813Sloos t += 250; 359265813Sloos } 360265813Sloos if (buf & LM75_0500C) 361265813Sloos t += 500; 362265813Sloos t /= 100; 363265813Sloos *temp += t; 364278917Sloos if (neg) 365265813Sloos *temp = -(*temp); 366265813Sloos *temp += TZ_ZEROC; 367265813Sloos 368265813Sloos return (0); 369265813Sloos} 370265813Sloos 371265813Sloosstatic int 372265813Slooslm75_temp_write(struct lm75_softc *sc, uint8_t reg, int temp) 373265813Sloos{ 374265813Sloos uint8_t buf8[3]; 375265813Sloos uint16_t buf; 376265813Sloos 377278917Sloos temp = (temp - TZ_ZEROC) / 10; 378265813Sloos if (temp > LM75_MAX_TEMP) 379265813Sloos temp = LM75_MAX_TEMP; 380265813Sloos if (temp < LM75_MIN_TEMP) 381265813Sloos temp = LM75_MIN_TEMP; 382265813Sloos 383265813Sloos buf = (uint16_t)temp; 384265813Sloos buf <<= 8; 385265813Sloos 386265813Sloos buf8[0] = reg; 387265813Sloos buf8[1] = buf >> 8; 388265813Sloos buf8[2] = buf & 0xff; 389278918Sloos if (lm75_write(sc->sc_dev, sc->sc_addr, buf8, sizeof(buf8)) < 0) 390265813Sloos return (-1); 391265813Sloos 392265813Sloos return (0); 393265813Sloos} 394265813Sloos 395265813Sloosstatic int 396265813Slooslm75_str_mode(char *buf) 397265813Sloos{ 398265813Sloos int len, rtrn; 399265813Sloos 400265813Sloos rtrn = -1; 401265813Sloos len = strlen(buf); 402265813Sloos if (len > 2 && strncasecmp("interrupt", buf, len) == 0) 403265813Sloos rtrn = 1; 404265813Sloos else if (len > 2 && strncasecmp("comparator", buf, len) == 0) 405265813Sloos rtrn = 0; 406265813Sloos 407265813Sloos return (rtrn); 408265813Sloos} 409265813Sloos 410265813Sloosstatic int 411265813Slooslm75_str_pol(char *buf) 412265813Sloos{ 413265813Sloos int len, rtrn; 414265813Sloos 415265813Sloos rtrn = -1; 416265813Sloos len = strlen(buf); 417265813Sloos if (len > 1 && strncasecmp("high", buf, len) == 0) 418265813Sloos rtrn = 1; 419265813Sloos else if (len > 1 && strncasecmp("low", buf, len) == 0) 420265813Sloos rtrn = 0; 421265813Sloos else if (len > 8 && strncasecmp("active-high", buf, len) == 0) 422265813Sloos rtrn = 1; 423265813Sloos else if (len > 8 && strncasecmp("active-low", buf, len) == 0) 424265813Sloos rtrn = 0; 425265813Sloos 426265813Sloos return (rtrn); 427265813Sloos} 428265813Sloos 429265813Sloosstatic int 430265813Slooslm75_temp_sysctl(SYSCTL_HANDLER_ARGS) 431265813Sloos{ 432265813Sloos device_t dev; 433265813Sloos int error, temp; 434265813Sloos struct lm75_softc *sc; 435265813Sloos uint8_t reg; 436265813Sloos 437265813Sloos dev = (device_t)arg1; 438265813Sloos reg = (uint8_t)arg2; 439265813Sloos sc = device_get_softc(dev); 440265813Sloos 441265813Sloos if (lm75_temp_read(sc, reg, &temp) != 0) 442265813Sloos return (EIO); 443265813Sloos 444265813Sloos error = sysctl_handle_int(oidp, &temp, 0, req); 445265813Sloos if (error != 0 || req->newptr == NULL) 446265813Sloos return (error); 447265813Sloos 448265813Sloos if (lm75_temp_write(sc, reg, temp) != 0) 449265813Sloos return (EIO); 450265813Sloos 451265813Sloos return (error); 452265813Sloos} 453265813Sloos 454265813Sloosstatic int 455265813Slooslm75_faults_sysctl(SYSCTL_HANDLER_ARGS) 456265813Sloos{ 457265813Sloos device_t dev; 458279852Sloos int lm75_faults[] = { 1, 2, 4, 6 }; 459265813Sloos int error, faults, i, newf, tmp; 460265813Sloos struct lm75_softc *sc; 461265813Sloos 462265813Sloos dev = (device_t)arg1; 463265813Sloos sc = device_get_softc(dev); 464265813Sloos tmp = (sc->sc_conf & LM75_CONF_FAULT) >> LM75_CONF_FSHIFT; 465279852Sloos if (tmp >= nitems(lm75_faults)) 466279852Sloos tmp = nitems(lm75_faults) - 1; 467265813Sloos faults = lm75_faults[tmp]; 468265813Sloos 469265813Sloos error = sysctl_handle_int(oidp, &faults, 0, req); 470265813Sloos if (error != 0 || req->newptr == NULL) 471265813Sloos return (error); 472265813Sloos 473265813Sloos if (faults != lm75_faults[tmp]) { 474265813Sloos newf = 0; 475265813Sloos for (i = 0; i < nitems(lm75_faults); i++) 476265813Sloos if (faults >= lm75_faults[i]) 477265813Sloos newf = i; 478265813Sloos sc->sc_conf &= ~LM75_CONF_FAULT; 479265813Sloos sc->sc_conf |= newf << LM75_CONF_FSHIFT; 480265813Sloos if (lm75_conf_write(sc) != 0) 481265813Sloos return (EIO); 482265813Sloos } 483265813Sloos 484265813Sloos return (error); 485265813Sloos} 486265813Sloos 487265813Sloosstatic int 488265813Slooslm75_mode_sysctl(SYSCTL_HANDLER_ARGS) 489265813Sloos{ 490265813Sloos char buf[16]; 491265813Sloos device_t dev; 492265813Sloos int error, mode, newm; 493265813Sloos struct lm75_softc *sc; 494265813Sloos 495265813Sloos dev = (device_t)arg1; 496265813Sloos sc = device_get_softc(dev); 497265813Sloos if (sc->sc_conf & LM75_CONF_MODE) { 498265813Sloos mode = 1; 499265813Sloos strlcpy(buf, "interrupt", sizeof(buf)); 500265813Sloos } else { 501265813Sloos mode = 0; 502265813Sloos strlcpy(buf, "comparator", sizeof(buf)); 503265813Sloos } 504265813Sloos 505265813Sloos error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 506265813Sloos if (error != 0 || req->newptr == NULL) 507265813Sloos return (error); 508265813Sloos 509265813Sloos newm = lm75_str_mode(buf); 510265813Sloos if (newm != -1 && mode != newm) { 511265813Sloos sc->sc_conf &= ~LM75_CONF_MODE; 512265813Sloos if (newm == 1) 513265813Sloos sc->sc_conf |= LM75_CONF_MODE; 514265813Sloos if (lm75_conf_write(sc) != 0) 515265813Sloos return (EIO); 516265813Sloos } 517265813Sloos 518265813Sloos return (error); 519265813Sloos} 520265813Sloos 521265813Sloosstatic int 522265813Slooslm75_pol_sysctl(SYSCTL_HANDLER_ARGS) 523265813Sloos{ 524265813Sloos char buf[16]; 525265813Sloos device_t dev; 526265813Sloos int error, newp, pol; 527265813Sloos struct lm75_softc *sc; 528265813Sloos 529265813Sloos dev = (device_t)arg1; 530265813Sloos sc = device_get_softc(dev); 531265813Sloos if (sc->sc_conf & LM75_CONF_POL) { 532265813Sloos pol = 1; 533265813Sloos strlcpy(buf, "active-high", sizeof(buf)); 534265813Sloos } else { 535265813Sloos pol = 0; 536265813Sloos strlcpy(buf, "active-low", sizeof(buf)); 537265813Sloos } 538265813Sloos 539265813Sloos error = sysctl_handle_string(oidp, buf, sizeof(buf), req); 540265813Sloos if (error != 0 || req->newptr == NULL) 541265813Sloos return (error); 542265813Sloos 543265813Sloos newp = lm75_str_pol(buf); 544265813Sloos if (newp != -1 && pol != newp) { 545265813Sloos sc->sc_conf &= ~LM75_CONF_POL; 546265813Sloos if (newp == 1) 547265813Sloos sc->sc_conf |= LM75_CONF_POL; 548265813Sloos if (lm75_conf_write(sc) != 0) 549265813Sloos return (EIO); 550265813Sloos } 551265813Sloos 552265813Sloos return (error); 553265813Sloos} 554265813Sloos 555265813Sloosstatic int 556265813Slooslm75_shutdown_sysctl(SYSCTL_HANDLER_ARGS) 557265813Sloos{ 558265813Sloos device_t dev; 559265813Sloos int error, shutdown, tmp; 560265813Sloos struct lm75_softc *sc; 561265813Sloos 562265813Sloos dev = (device_t)arg1; 563265813Sloos sc = device_get_softc(dev); 564265813Sloos tmp = shutdown = (sc->sc_conf & LM75_CONF_SHUTD) ? 1 : 0; 565265813Sloos 566265813Sloos error = sysctl_handle_int(oidp, &shutdown, 0, req); 567265813Sloos if (error != 0 || req->newptr == NULL) 568265813Sloos return (error); 569265813Sloos 570265813Sloos if (shutdown != tmp) { 571265813Sloos sc->sc_conf &= ~LM75_CONF_SHUTD; 572265813Sloos if (shutdown) 573265813Sloos sc->sc_conf |= LM75_CONF_SHUTD; 574265813Sloos if (lm75_conf_write(sc) != 0) 575265813Sloos return (EIO); 576265813Sloos } 577265813Sloos 578265813Sloos return (error); 579265813Sloos} 580