diff options
author | netchild <netchild@FreeBSD.org> | 2007-10-14 10:55:50 +0000 |
---|---|---|
committer | netchild <netchild@FreeBSD.org> | 2007-10-14 10:55:50 +0000 |
commit | 8423df3d9411c6e4e79b3a3b06ea1c3c6aaaa81f (patch) | |
tree | e4b345443d79b791d5fbc3088afe36b5cdb70868 /sys | |
parent | 4af9918bc0e8f388ffda416ed716c9b17ca6c0fd (diff) | |
download | FreeBSD-src-8423df3d9411c6e4e79b3a3b06ea1c3c6aaaa81f.zip FreeBSD-src-8423df3d9411c6e4e79b3a3b06ea1c3c6aaaa81f.tar.gz |
Import it(4) and lm(4), supporting most popular Super I/O Hardware Monitors.
Submitted by: Constantine A. Murenin <cnst@FreeBSD.org>
Sponsored by: Google Summer of Code 2007 (GSoC2007/cnst-sensors)
Mentored by: syrinx
Tested by: many
OKed by: kensmith
Obtained from: OpenBSD (parts)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/conf/GENERIC.hints | 8 | ||||
-rw-r--r-- | sys/conf/files | 2 | ||||
-rw-r--r-- | sys/conf/files.amd64 | 1 | ||||
-rw-r--r-- | sys/conf/files.i386 | 1 | ||||
-rw-r--r-- | sys/dev/it/it.c | 346 | ||||
-rw-r--r-- | sys/dev/it/itvar.h | 95 | ||||
-rw-r--r-- | sys/dev/lm/lm78.c | 909 | ||||
-rw-r--r-- | sys/dev/lm/lm78_isa.c | 251 | ||||
-rw-r--r-- | sys/dev/lm/lm78var.h | 158 | ||||
-rw-r--r-- | sys/i386/conf/GENERIC.hints | 8 | ||||
-rw-r--r-- | sys/modules/Makefile | 6 | ||||
-rw-r--r-- | sys/modules/it/Makefile | 9 | ||||
-rw-r--r-- | sys/modules/lm/Makefile | 9 |
13 files changed, 1803 insertions, 0 deletions
diff --git a/sys/amd64/conf/GENERIC.hints b/sys/amd64/conf/GENERIC.hints index 9400343..594d9ca 100644 --- a/sys/amd64/conf/GENERIC.hints +++ b/sys/amd64/conf/GENERIC.hints @@ -33,3 +33,11 @@ hint.sio.3.port="0x2E8" hint.sio.3.irq="9" hint.ppc.0.at="isa" hint.ppc.0.irq="7" +hint.lm.0.at="isa" +hint.lm.0.port="0x290" +hint.it.0.at="isa" +hint.it.0.port="0x290" +hint.it.1.at="isa" +hint.it.1.port="0xc00" +hint.it.2.at="isa" +hint.it.2.port="0xd00" diff --git a/sys/conf/files b/sys/conf/files index 5089ef3..af6b58d 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -758,6 +758,8 @@ dev/le/if_le_pci.c optional le pci dev/le/lance.c optional le dev/led/led.c standard dev/lge/if_lge.c optional lge +dev/lm/lm78.c optional lm +dev/lm/lm78_isa.c optional lm isa dev/lmc/if_lmc.c optional lmc dev/mc146818/mc146818.c optional mc146818 dev/mca/mca_bus.c optional mca diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 2a9a60a..d4ff130 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -169,6 +169,7 @@ dev/ipmi/ipmi_smbus.c optional ipmi smbus dev/ipmi/ipmi_smbios.c optional ipmi dev/ipmi/ipmi_ssif.c optional ipmi smbus dev/ipmi/ipmi_pci.c optional ipmi pci +dev/it/it.c optional it isa dev/fdc/fdc.c optional fdc dev/fdc/fdc_acpi.c optional fdc dev/fdc/fdc_isa.c optional fdc isa diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index fc47798..9122c4a 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -204,6 +204,7 @@ dev/ipmi/ipmi_smbus.c optional ipmi smbus dev/ipmi/ipmi_smbios.c optional ipmi dev/ipmi/ipmi_ssif.c optional ipmi smbus dev/ipmi/ipmi_pci.c optional ipmi pci +dev/it/it.c optional it isa dev/kbd/kbd.c optional atkbd | sc | ukbd | vt dev/le/if_le_isa.c optional le isa dev/mem/memutil.c optional mem diff --git a/sys/dev/it/it.c b/sys/dev/it/it.c new file mode 100644 index 0000000..a5f0a8e --- /dev/null +++ b/sys/dev/it/it.c @@ -0,0 +1,346 @@ +/* $FreeBSD$ */ +/* $OpenBSD: it.c,v 1.22 2007/03/22 16:55:31 deraadt Exp $ */ + +/*- + * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <machine/bus.h> +#include <machine/resource.h> + +#include <sys/rman.h> + +#include <isa/isavar.h> +#include <sys/systm.h> + +#include <sys/sensors.h> + +#include <dev/it/itvar.h> + +#if defined(ITDEBUG) +#define DPRINTF(x) do { printf x; } while (0) +#else +#define DPRINTF(x) +#endif + +/* + * IT87-compatible chips can typically measure voltages up to 4.096 V. + * To measure higher voltages the input is attenuated with (external) + * resistors. Negative voltages are measured using a reference + * voltage. So we have to convert the sensor values back to real + * voltages by applying the appropriate resistor factor. + */ +#define RFACT_NONE 10000 +#define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) + +int it_probe(struct device *); +int it_attach(struct device *); +int it_detach(struct device *); +u_int8_t it_readreg(struct it_softc *, int); +void it_writereg(struct it_softc *, int, int); +void it_setup_volt(struct it_softc *, int, int); +void it_setup_temp(struct it_softc *, int, int); +void it_setup_fan(struct it_softc *, int, int); + +void it_generic_stemp(struct it_softc *, struct ksensor *); +void it_generic_svolt(struct it_softc *, struct ksensor *); +void it_generic_fanrpm(struct it_softc *, struct ksensor *); + +void it_refresh_sensor_data(struct it_softc *); +void it_refresh(void *); + +extern struct cfdriver it_cd; + +static device_method_t it_methods[] = { + /* Methods from the device interface */ + DEVMETHOD(device_probe, it_probe), + DEVMETHOD(device_attach, it_attach), + DEVMETHOD(device_detach, it_detach), + + /* Terminate method list */ + { 0, 0 } +}; + +static driver_t it_driver = { + "it", + it_methods, + sizeof (struct it_softc) +}; + +static devclass_t it_devclass; + +DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL); + + +const int it_vrfact[] = { + RFACT_NONE, + RFACT_NONE, + RFACT_NONE, + RFACT(68, 100), + RFACT(30, 10), + RFACT(21, 10), + RFACT(83, 20), + RFACT(68, 100), + RFACT_NONE +}; + +int +it_probe(struct device *dev) +{ + struct resource *iores; + int iorid = 0; + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int8_t cr; + + iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, + 0ul, ~0ul, 8, RF_ACTIVE); + if (iores == NULL) { + DPRINTF(("%s: can't map i/o space\n", __func__)); + return 1; + } + iot = rman_get_bustag(iores); + ioh = rman_get_bushandle(iores); + + /* Check Vendor ID */ + bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID); + cr = bus_space_read_1(iot, ioh, ITC_DATA); + bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); + DPRINTF(("it: vendor id 0x%x\n", cr)); + if (cr != IT_ID_IT87) + return 1; + + return 0; +} + +int +it_attach(struct device *dev) +{ + struct it_softc *sc = device_get_softc(dev); + int i; + u_int8_t cr; + + sc->sc_dev = dev; + sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, + 0ul, ~0ul, 8, RF_ACTIVE); + if (sc->sc_iores == NULL) { + device_printf(dev, "can't map i/o space\n"); + return 1; + } + sc->sc_iot = rman_get_bustag(sc->sc_iores); + sc->sc_ioh = rman_get_bushandle(sc->sc_iores); + + sc->numsensors = IT_NUM_SENSORS; + + it_setup_fan(sc, 0, 3); + it_setup_volt(sc, 3, 9); + it_setup_temp(sc, 12, 3); + + if (sensor_task_register(sc, it_refresh, 5)) { + device_printf(sc->sc_dev, "unable to register update task\n"); + return 1; + } + + /* Activate monitoring */ + cr = it_readreg(sc, ITD_CONFIG); + cr |= 0x01 | 0x08; + it_writereg(sc, ITD_CONFIG, cr); + + /* Initialize sensors */ + strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev), + sizeof(sc->sensordev.xname)); + for (i = 0; i < sc->numsensors; ++i) + sensor_attach(&sc->sensordev, &sc->sensors[i]); + sensordev_install(&sc->sensordev); + + return 0; +} + +int +it_detach(struct device *dev) +{ + struct it_softc *sc = device_get_softc(dev); + int error; + + sensordev_deinstall(&sc->sensordev); + sensor_task_unregister(sc); + + error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid, + sc->sc_iores); + if (error) + return error; + + return 0; +} + +u_int8_t +it_readreg(struct it_softc *sc, int reg) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg); + return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, ITC_DATA)); +} + +void +it_writereg(struct it_softc *sc, int reg, int val) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_DATA, val); +} + +void +it_setup_volt(struct it_softc *sc, int start, int n) +{ + int i; + + for (i = 0; i < n; ++i) { + sc->sensors[start + i].type = SENSOR_VOLTS_DC; + } + + snprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc), + "VCORE_A"); + snprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc), + "VCORE_B"); + snprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc), + "+3.3V"); + snprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc), + "+5V"); + snprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc), + "+12V"); + snprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc), + "Unused"); + snprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc), + "-12V"); + snprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc), + "+5VSB"); + snprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc), + "VBAT"); +} + +void +it_setup_temp(struct it_softc *sc, int start, int n) +{ + int i; + + for (i = 0; i < n; ++i) + sc->sensors[start + i].type = SENSOR_TEMP; +} + +void +it_setup_fan(struct it_softc *sc, int start, int n) +{ + int i; + + for (i = 0; i < n; ++i) + sc->sensors[start + i].type = SENSOR_FANRPM; +} + +void +it_generic_stemp(struct it_softc *sc, struct ksensor *sensors) +{ + int i, sdata; + + for (i = 0; i < 3; i++) { + sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i); + /* Convert temperature to Fahrenheit degres */ + sensors[i].value = sdata * 1000000 + 273150000; + } +} + +void +it_generic_svolt(struct it_softc *sc, struct ksensor *sensors) +{ + int i, sdata; + + for (i = 0; i < 9; i++) { + sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i); + DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); + /* voltage returned as (mV >> 4) */ + sensors[i].value = (sdata << 4); + /* these two values are negative and formula is different */ + if (i == 5 || i == 6) + sensors[i].value = ((sdata << 4) - IT_VREF); + /* rfact is (factor * 10^4) */ + sensors[i].value *= it_vrfact[i]; + /* division by 10 gets us back to uVDC */ + sensors[i].value /= 10; + if (i == 5 || i == 6) + sensors[i].value += IT_VREF * 1000; + } +} + +void +it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors) +{ + int i, sdata, divisor, odivisor, ndivisor; + + odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN); + for (i = 0; i < 3; i++, divisor >>= 3) { + sensors[i].flags &= ~SENSOR_FINVALID; + if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) { + sensors[i].flags |= SENSOR_FINVALID; + if (i == 2) + ndivisor ^= 0x40; + else { + ndivisor &= ~(7 << (i * 3)); + ndivisor |= ((divisor + 1) & 7) << (i * 3); + } + } else if (sdata == 0) { + sensors[i].value = 0; + } else { + if (i == 2) + divisor = divisor & 1 ? 3 : 1; + sensors[i].value = 1350000 / (sdata << (divisor & 7)); + } + } + if (ndivisor != odivisor) + it_writereg(sc, ITD_FAN, ndivisor); +} + +/* + * pre: last read occurred >= 1.5 seconds ago + * post: sensors[] current data are the latest from the chip + */ +void +it_refresh_sensor_data(struct it_softc *sc) +{ + /* Refresh our stored data for every sensor */ + it_generic_stemp(sc, &sc->sensors[12]); + it_generic_svolt(sc, &sc->sensors[3]); + it_generic_fanrpm(sc, &sc->sensors[0]); +} + +void +it_refresh(void *arg) +{ + struct it_softc *sc = (struct it_softc *)arg; + + it_refresh_sensor_data(sc); +} diff --git a/sys/dev/it/itvar.h b/sys/dev/it/itvar.h new file mode 100644 index 0000000..2395db3 --- /dev/null +++ b/sys/dev/it/itvar.h @@ -0,0 +1,95 @@ +/* $FreeBSD$ */ +/* $OpenBSD: itvar.h,v 1.4 2007/03/22 16:55:31 deraadt Exp $ */ + +/*- + * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_ISA_ITVAR_H +#define _DEV_ISA_ITVAR_H + +#define IT_NUM_SENSORS 15 + +/* chip ids */ +#define IT_ID_IT87 0x90 + +/* ctl registers */ + +#define ITC_ADDR 0x05 +#define ITC_DATA 0x06 + +/* data registers */ + +#define ITD_CONFIG 0x00 +#define ITD_ISR1 0x01 +#define ITD_ISR2 0x02 +#define ITD_ISR3 0x03 +#define ITD_SMI1 0x04 +#define ITD_SMI2 0x05 +#define ITD_SMI3 0x06 +#define ITD_IMR1 0x07 +#define ITD_IMR2 0x08 +#define ITD_IMR3 0x09 +#define ITD_VID 0x0a +#define ITD_FAN 0x0b + +#define ITD_FANMINBASE 0x10 +#define ITD_FANENABLE 0x13 + +#define ITD_SENSORFANBASE 0x0d /* Fan from 0x0d to 0x0f */ +#define ITD_SENSORVOLTBASE 0x20 /* Fan from 0x20 to 0x28 */ +#define ITD_SENSORTEMPBASE 0x29 /* Fan from 0x29 to 0x2b */ + +#define ITD_VOLTMAXBASE 0x30 +#define ITD_VOLTMINBASE 0x31 + +#define ITD_TEMPMAXBASE 0x40 +#define ITD_TEMPMINBASE 0x41 + +#define ITD_SBUSADDR 0x48 +#define ITD_VOLTENABLE 0x50 +#define ITD_TEMPENABLE 0x51 + +#define ITD_CHIPID 0x58 + +#define IT_VREF (4096) /* Vref = 4.096 V */ + +struct it_softc { + struct device *sc_dev; + + struct resource *sc_iores; + int sc_iorid; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + struct ksensor sensors[IT_NUM_SENSORS]; + struct ksensordev sensordev; + u_int numsensors; + void (*refresh_sensor_data)(struct it_softc *); + + u_int8_t (*it_readreg)(struct it_softc *, int); + void (*it_writereg)(struct it_softc *, int, int); +}; + +#endif diff --git a/sys/dev/lm/lm78.c b/sys/dev/lm/lm78.c new file mode 100644 index 0000000..311a789 --- /dev/null +++ b/sys/dev/lm/lm78.c @@ -0,0 +1,909 @@ +/* $FreeBSD$ */ +/* $OpenBSD: lm78.c,v 1.18 2007/05/26 22:47:39 cnst Exp $ */ + +/*- + * Copyright (c) 2005, 2006 Mark Kettenis + * Copyright (c) 2006, 2007 Constantine A. Murenin + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/sensors.h> +#include <machine/bus.h> + +#include <dev/lm/lm78var.h> + +#if defined(LMDEBUG) +#define DPRINTF(x) do { printf x; } while (0) +#else +#define DPRINTF(x) +#endif + +/* + * LM78-compatible chips can typically measure voltages up to 4.096 V. + * To measure higher voltages the input is attenuated with (external) + * resistors. Negative voltages are measured using inverting op amps + * and resistors. So we have to convert the sensor values back to + * real voltages by applying the appropriate resistor factor. + */ +#define RFACT_NONE 10000 +#define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) +#define NRFACT(x, y) (-RFACT_NONE * (x) / (y)) + +int lm_match(struct lm_softc *); +int wb_match(struct lm_softc *); +int def_match(struct lm_softc *); + +void lm_setup_sensors(struct lm_softc *, struct lm_sensor *); +void lm_refresh(void *); + +void lm_refresh_sensor_data(struct lm_softc *); +void lm_refresh_volt(struct lm_softc *, int); +void lm_refresh_temp(struct lm_softc *, int); +void lm_refresh_fanrpm(struct lm_softc *, int); + +void wb_refresh_sensor_data(struct lm_softc *); +void wb_w83637hf_refresh_vcore(struct lm_softc *, int); +void wb_refresh_nvolt(struct lm_softc *, int); +void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int); +void wb_refresh_temp(struct lm_softc *, int); +void wb_refresh_fanrpm(struct lm_softc *, int); +void wb_w83792d_refresh_fanrpm(struct lm_softc *, int); + +void as_refresh_temp(struct lm_softc *, int); + +struct lm_chip { + int (*chip_match)(struct lm_softc *); +}; + +struct lm_chip lm_chips[] = { + { wb_match }, + { lm_match }, + { def_match } /* Must be last */ +}; + +struct lm_sensor lm78_sensors[] = { + /* Voltage */ + { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(68, 100) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(30, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(240, 60) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(100, 60) }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor w83627hf_sensors[] = { + /* Voltage */ + { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, + { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) }, + { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + + { NULL } +}; + +/* + * The W83627EHF can measure voltages up to 2.048 V instead of the + * traditional 4.096 V. For measuring positive voltages, this can be + * accounted for by halving the resistor factor. Negative voltages + * need special treatment, also because the reference voltage is 2.048 V + * instead of the traditional 3.6 V. + */ +struct lm_sensor w83627ehf_sensors[] = { + /* Voltage */ + { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2}, + { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt }, + { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 }, + { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 }, + { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 }, + { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 }, + { "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + + { NULL } +}; + +/* + * w83627dhg is almost identical to w83627ehf, except that + * it has 9 instead of 10 voltage sensors + */ +struct lm_sensor w83627dhg_sensors[] = { + /* Voltage */ + { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2}, + { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt }, + { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 }, + { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 }, + { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 }, + { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor w83637hf_sensors[] = { + /* Voltage */ + { "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) }, + { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) }, + { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor w83697hf_sensors[] = { + /* Voltage */ + { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, + { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) }, + { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + + { NULL } +}; + +/* + * The datasheet doesn't mention the (internal) resistors used for the + * +5V, but using the values from the W83782D datasheets seems to + * provide sensible results. + */ +struct lm_sensor w83781d_sensors[] = { + /* Voltage */ + { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, NRFACT(2100, 604) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, NRFACT(909, 604) }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor w83782d_sensors[] = { + /* Voltage */ + { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, + { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(17, 33) }, + { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor w83783s_sensors[] = { + /* Voltage */ + { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor w83791d_sensors[] = { + /* Voltage */ + { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "VINR0", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, + { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) }, + { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE }, + { "VINR1", SENSOR_VOLTS_DC, 0, 0xb2, lm_refresh_volt, RFACT_NONE }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp }, + { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0xba, wb_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0xbb, wb_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor w83792d_sensors[] = { + /* Voltage */ + { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x23, wb_refresh_nvolt, RFACT(120, 56) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT(34, 50) }, + { "5VSB", SENSOR_VOLTS_DC, 0, 0xb0, lm_refresh_volt, RFACT(17, 33) }, + { "VBAT", SENSOR_VOLTS_DC, 0, 0xb1, lm_refresh_volt, RFACT_NONE }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 0, 0xc0, wb_refresh_temp }, + { "", SENSOR_TEMP, 0, 0xc8, wb_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, wb_w83792d_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, wb_w83792d_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, wb_w83792d_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0xb8, wb_w83792d_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0xb9, wb_w83792d_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0xba, wb_w83792d_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0xbe, wb_w83792d_refresh_fanrpm }, + + { NULL } +}; + +struct lm_sensor as99127f_sensors[] = { + /* Voltage */ + { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, + { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, + { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, + { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, + { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, + { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, + { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, + + /* Temperature */ + { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "", SENSOR_TEMP, 1, 0x50, as_refresh_temp }, + { "", SENSOR_TEMP, 2, 0x50, as_refresh_temp }, + + /* Fans */ + { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm }, + { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm }, + + { NULL } +}; + +void +lm_probe(struct lm_softc *sc) +{ + int i; + + for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++) + if (lm_chips[i].chip_match(sc)) + break; +} + +void +lm_attach(struct lm_softc *sc) +{ + u_int i, config; + + /* No point in doing anything if we don't have any sensors. */ + if (sc->numsensors == 0) + return; + + if (sensor_task_register(sc, lm_refresh, 5)) { + device_printf(sc->sc_dev, "unable to register update task\n"); + return; + } + + /* Start the monitoring loop */ + config = sc->lm_readreg(sc, LM_CONFIG); + sc->lm_writereg(sc, LM_CONFIG, config | 0x01); + + /* Add sensors */ + strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev), + sizeof(sc->sensordev.xname)); + for (i = 0; i < sc->numsensors; ++i) + sensor_attach(&sc->sensordev, &sc->sensors[i]); + sensordev_install(&sc->sensordev); +} + +int +lm_detach(struct lm_softc *sc) +{ + int i; + + /* Remove sensors */ + sensordev_deinstall(&sc->sensordev); + for (i = 0; i < sc->numsensors; i++) + sensor_detach(&sc->sensordev, &sc->sensors[i]); + + sensor_task_unregister(sc); + + return 0; +} + +int +lm_match(struct lm_softc *sc) +{ + int chipid; + const char *cdesc; + char fulldesc[64]; + + /* See if we have an LM78 or LM79. */ + chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK; + switch(chipid) { + case LM_CHIPID_LM78: + cdesc = "LM78"; + break; + case LM_CHIPID_LM78J: + cdesc = "LM78J"; + break; + case LM_CHIPID_LM79: + cdesc = "LM79"; + break; + case LM_CHIPID_LM81: + cdesc = "LM81"; + break; + default: + return 0; + } + snprintf(fulldesc, sizeof(fulldesc), + "National Semiconductor %s Hardware Monitor", cdesc); + device_set_desc_copy(sc->sc_dev, fulldesc); + + lm_setup_sensors(sc, lm78_sensors); + sc->refresh_sensor_data = lm_refresh_sensor_data; + return 1; +} + +int +def_match(struct lm_softc *sc) +{ + int chipid; + char fulldesc[64]; + + chipid = sc->lm_readreg(sc, LM_CHIPID) & LM_CHIPID_MASK; + snprintf(fulldesc, sizeof(fulldesc), + "unknown Hardware Monitor (ID 0x%x)", chipid); + device_set_desc_copy(sc->sc_dev, fulldesc); + + lm_setup_sensors(sc, lm78_sensors); + sc->refresh_sensor_data = lm_refresh_sensor_data; + return 1; +} + +int +wb_match(struct lm_softc *sc) +{ + int banksel, vendid, devid; + const char *cdesc; + char desc[64]; + char fulldesc[64]; + + /* Read vendor ID */ + banksel = sc->lm_readreg(sc, WB_BANKSEL); + sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC); + vendid = sc->lm_readreg(sc, WB_VENDID) << 8; + sc->lm_writereg(sc, WB_BANKSEL, 0); + vendid |= sc->lm_readreg(sc, WB_VENDID); + sc->lm_writereg(sc, WB_BANKSEL, banksel); + DPRINTF((" winbond vend id 0x%x\n", vendid)); + if (vendid != WB_VENDID_WINBOND && vendid != WB_VENDID_ASUS) + return 0; + + /* Read device/chip ID */ + sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); + devid = sc->lm_readreg(sc, LM_CHIPID); + sc->chipid = sc->lm_readreg(sc, WB_BANK0_CHIPID); + sc->lm_writereg(sc, WB_BANKSEL, banksel); + DPRINTF((" winbond chip id 0x%x\n", sc->chipid)); + switch(sc->chipid) { + case WB_CHIPID_W83627HF: + cdesc = "W83627HF"; + lm_setup_sensors(sc, w83627hf_sensors); + break; + case WB_CHIPID_W83627THF: + cdesc = "W83627THF"; + lm_setup_sensors(sc, w83637hf_sensors); + break; + case WB_CHIPID_W83627EHF: + cdesc = "W83627EHF"; + lm_setup_sensors(sc, w83627ehf_sensors); + break; + case WB_CHIPID_W83627DHG: + cdesc = "W83627DHG"; + lm_setup_sensors(sc, w83627dhg_sensors); + break; + case WB_CHIPID_W83637HF: + cdesc = "W83637HF"; + sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); + if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9) + sc->vrm9 = 1; + sc->lm_writereg(sc, WB_BANKSEL, banksel); + lm_setup_sensors(sc, w83637hf_sensors); + break; + case WB_CHIPID_W83697HF: + cdesc = "W83697HF"; + lm_setup_sensors(sc, w83697hf_sensors); + break; + case WB_CHIPID_W83781D: + case WB_CHIPID_W83781D_2: + cdesc = "W83781D"; + lm_setup_sensors(sc, w83781d_sensors); + break; + case WB_CHIPID_W83782D: + cdesc = "W83782D"; + lm_setup_sensors(sc, w83782d_sensors); + break; + case WB_CHIPID_W83783S: + cdesc = "W83783S"; + lm_setup_sensors(sc, w83783s_sensors); + break; + case WB_CHIPID_W83791D: + cdesc = "W83791D"; + lm_setup_sensors(sc, w83791d_sensors); + break; + case WB_CHIPID_W83791SD: + cdesc = "W83791SD"; + break; + case WB_CHIPID_W83792D: + if (devid >= 0x10 && devid <= 0x29) + snprintf(desc, sizeof(desc), + "W83792D rev %c", 'A' + devid - 0x10); + else + snprintf(desc, sizeof(desc), + "W83792D rev 0x%x", devid); + cdesc = desc; + lm_setup_sensors(sc, w83792d_sensors); + break; + case WB_CHIPID_AS99127F: + if (vendid == WB_VENDID_ASUS) { + cdesc = "AS99127F"; + lm_setup_sensors(sc, w83781d_sensors); + } else { + cdesc = "AS99127F rev 2"; + lm_setup_sensors(sc, as99127f_sensors); + } + break; + default: + snprintf(fulldesc, sizeof(fulldesc), + "unknown Winbond Hardware Monitor (Chip ID 0x%x)", + sc->chipid); + device_set_desc_copy(sc->sc_dev, fulldesc); + /* Handle as a standard LM78. */ + lm_setup_sensors(sc, lm78_sensors); + sc->refresh_sensor_data = lm_refresh_sensor_data; + return 1; + } + + if (cdesc[0] == 'W') + snprintf(fulldesc, sizeof(fulldesc), + "Winbond %s Hardware Monitor", cdesc); + else + snprintf(fulldesc, sizeof(fulldesc), + "ASUS %s Hardware Monitor", cdesc); + device_set_desc_copy(sc->sc_dev, fulldesc); + + sc->refresh_sensor_data = wb_refresh_sensor_data; + return 1; +} + +void +lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors) +{ + int i; + + for (i = 0; sensors[i].desc; i++) { + sc->sensors[i].type = sensors[i].type; + strlcpy(sc->sensors[i].desc, sensors[i].desc, + sizeof(sc->sensors[i].desc)); + sc->numsensors++; + } + sc->lm_sensors = sensors; +} + +void +lm_refresh(void *arg) +{ + struct lm_softc *sc = arg; + + sc->refresh_sensor_data(sc); +} + +void +lm_refresh_sensor_data(struct lm_softc *sc) +{ + int i; + + for (i = 0; i < sc->numsensors; i++) + sc->lm_sensors[i].refresh(sc, i); +} + +void +lm_refresh_volt(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int data; + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + sensor->value = (data << 4); + sensor->value *= sc->lm_sensors[n].rfact; + sensor->value /= 10; +} + +void +lm_refresh_temp(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int sdata; + + /* + * The data sheet suggests that the range of the temperature + * sensor is between -55 degC and +125 degC. + */ + sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + if (sdata > 0x7d && sdata < 0xc9) { + sensor->flags |= SENSOR_FINVALID; + sensor->value = 0; + } else { + if (sdata & 0x80) + sdata -= 0x100; + sensor->flags &= ~SENSOR_FINVALID; + sensor->value = sdata * 1000000 + 273150000; + } +} + +void +lm_refresh_fanrpm(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int data, divisor = 1; + + /* + * We might get more accurate fan readings by adjusting the + * divisor, but that might interfere with APM or other SMM + * BIOS code reading the fan speeds. + */ + + /* FAN3 has a fixed fan divisor. */ + if (sc->lm_sensors[n].reg == LM_FAN1 || + sc->lm_sensors[n].reg == LM_FAN2) { + data = sc->lm_readreg(sc, LM_VIDFAN); + if (sc->lm_sensors[n].reg == LM_FAN1) + divisor = (data >> 4) & 0x03; + else + divisor = (data >> 6) & 0x03; + } + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + if (data == 0xff || data == 0x00) { + sensor->flags |= SENSOR_FINVALID; + sensor->value = 0; + } else { + sensor->flags &= ~SENSOR_FINVALID; + sensor->value = 1350000 / (data << divisor); + } +} + +void +wb_refresh_sensor_data(struct lm_softc *sc) +{ + int banksel, bank, i; + + /* + * Properly save and restore bank selection register. + */ + + banksel = bank = sc->lm_readreg(sc, WB_BANKSEL); + for (i = 0; i < sc->numsensors; i++) { + if (bank != sc->lm_sensors[i].bank) { + bank = sc->lm_sensors[i].bank; + sc->lm_writereg(sc, WB_BANKSEL, bank); + } + sc->lm_sensors[i].refresh(sc, i); + } + sc->lm_writereg(sc, WB_BANKSEL, banksel); +} + +void +wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int data; + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + + /* + * Depending on the voltage detection method, + * one of the following formulas is used: + * VRM8 method: value = raw * 0.016V + * VRM9 method: value = raw * 0.00488V + 0.70V + */ + if (sc->vrm9) + sensor->value = (data * 4880) + 700000; + else + sensor->value = (data * 16000); +} + +void +wb_refresh_nvolt(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int data; + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + sensor->value = ((data << 4) - WB_VREF); + sensor->value *= sc->lm_sensors[n].rfact; + sensor->value /= 10; + sensor->value += WB_VREF * 1000; +} + +void +wb_w83627ehf_refresh_nvolt(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int data; + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + sensor->value = ((data << 3) - WB_W83627EHF_VREF); + sensor->value *= RFACT(232, 10); + sensor->value /= 10; + sensor->value += WB_W83627EHF_VREF * 1000; +} + +void +wb_refresh_temp(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int sdata; + + /* + * The data sheet suggests that the range of the temperature + * sensor is between -55 degC and +125 degC. However, values + * around -48 degC seem to be a very common bogus values. + * Since such values are unreasonably low, we use -45 degC for + * the lower limit instead. + */ + sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1; + sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7; + if (sdata > 0x0fa && sdata < 0x1a6) { + sensor->flags |= SENSOR_FINVALID; + sensor->value = 0; + } else { + if (sdata & 0x100) + sdata -= 0x200; + sensor->flags &= ~SENSOR_FINVALID; + sensor->value = sdata * 500000 + 273150000; + } +} + +void +wb_refresh_fanrpm(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int fan, data, divisor = 0; + + /* + * This is madness; the fan divisor bits are scattered all + * over the place. + */ + + if (sc->lm_sensors[n].reg == LM_FAN1 || + sc->lm_sensors[n].reg == LM_FAN2 || + sc->lm_sensors[n].reg == LM_FAN3) { + data = sc->lm_readreg(sc, WB_BANK0_VBAT); + fan = (sc->lm_sensors[n].reg - LM_FAN1); + if ((data >> 5) & (1 << fan)) + divisor |= 0x04; + } + + if (sc->lm_sensors[n].reg == LM_FAN1 || + sc->lm_sensors[n].reg == LM_FAN2) { + data = sc->lm_readreg(sc, LM_VIDFAN); + if (sc->lm_sensors[n].reg == LM_FAN1) + divisor |= (data >> 4) & 0x03; + else + divisor |= (data >> 6) & 0x03; + } else if (sc->lm_sensors[n].reg == LM_FAN3) { + data = sc->lm_readreg(sc, WB_PIN); + divisor |= (data >> 6) & 0x03; + } else if (sc->lm_sensors[n].reg == WB_BANK0_FAN4 || + sc->lm_sensors[n].reg == WB_BANK0_FAN5) { + data = sc->lm_readreg(sc, WB_BANK0_FAN45); + if (sc->lm_sensors[n].reg == WB_BANK0_FAN4) + divisor |= (data >> 0) & 0x07; + else + divisor |= (data >> 4) & 0x07; + } + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + if (data == 0xff || data == 0x00) { + sensor->flags |= SENSOR_FINVALID; + sensor->value = 0; + } else { + sensor->flags &= ~SENSOR_FINVALID; + sensor->value = 1350000 / (data << divisor); + } +} + +void +wb_w83792d_refresh_fanrpm(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int reg, shift, data, divisor = 1; + + switch (sc->lm_sensors[n].reg) { + case 0x28: + reg = 0x47; shift = 0; + break; + case 0x29: + reg = 0x47; shift = 4; + break; + case 0x2a: + reg = 0x5b; shift = 0; + break; + case 0xb8: + reg = 0x5b; shift = 4; + break; + case 0xb9: + reg = 0x5c; shift = 0; + break; + case 0xba: + reg = 0x5c; shift = 4; + break; + case 0xbe: + reg = 0x9e; shift = 0; + break; + default: + reg = 0; shift = 0; + break; + } + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + if (data == 0xff || data == 0x00) { + sensor->flags |= SENSOR_FINVALID; + sensor->value = 0; + } else { + if (reg != 0) + divisor = (sc->lm_readreg(sc, reg) >> shift) & 0x7; + sensor->flags &= ~SENSOR_FINVALID; + sensor->value = 1350000 / (data << divisor); + } +} + +void +as_refresh_temp(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int sdata; + + /* + * It seems a shorted temperature diode produces an all-ones + * bit pattern. + */ + sdata = sc->lm_readreg(sc, sc->lm_sensors[n].reg) << 1; + sdata += sc->lm_readreg(sc, sc->lm_sensors[n].reg + 1) >> 7; + if (sdata == 0x1ff) { + sensor->flags |= SENSOR_FINVALID; + sensor->value = 0; + } else { + if (sdata & 0x100) + sdata -= 0x200; + sensor->flags &= ~SENSOR_FINVALID; + sensor->value = sdata * 500000 + 273150000; + } +} diff --git a/sys/dev/lm/lm78_isa.c b/sys/dev/lm/lm78_isa.c new file mode 100644 index 0000000..7449d00 --- /dev/null +++ b/sys/dev/lm/lm78_isa.c @@ -0,0 +1,251 @@ +/* $FreeBSD$ */ +/* $OpenBSD: lm78_isa.c,v 1.2 2007/07/01 21:48:57 cnst Exp $ */ + +/*- + * Copyright (c) 2005, 2006 Mark Kettenis + * Copyright (c) 2007 Constantine A. Murenin, Google Summer of Code + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <isa/isavar.h> + +#include <sys/systm.h> + +#include <sys/sensors.h> + +#include <dev/lm/lm78var.h> + +/* ISA registers */ +#define LMC_ADDR 0x05 +#define LMC_DATA 0x06 + +extern struct cfdriver lm_cd; + +#if defined(LMDEBUG) +#define DPRINTF(x) do { printf x; } while (0) +#else +#define DPRINTF(x) +#endif + +struct lm_isa_softc { + struct lm_softc sc_lmsc; + + struct resource *sc_iores; + int sc_iorid; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +static int lm_isa_probe(struct device *); +static int lm_isa_attach(struct device *); +static int lm_isa_detach(struct device *); +u_int8_t lm_isa_readreg(struct lm_softc *, int); +void lm_isa_writereg(struct lm_softc *, int, int); + +static device_method_t lm_isa_methods[] = { + /* Methods from the device interface */ + DEVMETHOD(device_probe, lm_isa_probe), + DEVMETHOD(device_attach, lm_isa_attach), + DEVMETHOD(device_detach, lm_isa_detach), + + /* Terminate method list */ + { 0, 0 } +}; + +static driver_t lm_isa_driver = { + "lm", + lm_isa_methods, + sizeof (struct lm_isa_softc) +}; + +static devclass_t lm_devclass; + +DRIVER_MODULE(lm, isa, lm_isa_driver, lm_devclass, NULL, NULL); + +int +lm_isa_probe(struct device *dev) +{ + struct lm_isa_softc *sc = device_get_softc(dev); + struct resource *iores; + int iorid = 0; + bus_space_tag_t iot; + bus_space_handle_t ioh; + int banksel, vendid, chipid, addr; + + iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, + 0ul, ~0ul, 8, RF_ACTIVE); + if (iores == NULL) { + DPRINTF(("%s: can't map i/o space\n", __func__)); + return (1); + } + iot = rman_get_bustag(iores); + ioh = rman_get_bushandle(iores); + + /* Probe for Winbond chips. */ + bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL); + banksel = bus_space_read_1(iot, ioh, LMC_DATA); + bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID); + vendid = bus_space_read_1(iot, ioh, LMC_DATA); + if (((banksel & 0x80) && vendid == (WB_VENDID_WINBOND >> 8)) || + (!(banksel & 0x80) && vendid == (WB_VENDID_WINBOND & 0xff))) + goto found; + + /* Probe for ITE chips (and don't attach if we find one). */ + bus_space_write_1(iot, ioh, LMC_ADDR, 0x58 /*ITD_CHIPID*/); + vendid = bus_space_read_1(iot, ioh, LMC_DATA); + if (vendid == 0x90 /*IT_ID_IT87*/) + goto notfound; + + /* + * Probe for National Semiconductor LM78/79/81. + * + * XXX This assumes the address has not been changed from the + * power up default. This is probably a reasonable + * assumption, and if it isn't true, we should be able to + * access the chip using the serial bus. + */ + bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR); + addr = bus_space_read_1(iot, ioh, LMC_DATA); + if ((addr & 0xfc) == 0x2c) { + bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID); + chipid = bus_space_read_1(iot, ioh, LMC_DATA); + + switch (chipid & LM_CHIPID_MASK) { + case LM_CHIPID_LM78: + case LM_CHIPID_LM78J: + case LM_CHIPID_LM79: + case LM_CHIPID_LM81: + goto found; + } + } + + notfound: + bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); + + return (1); + + found: + /* Bus-independent probe */ + sc->sc_lmsc.sc_dev = dev; + sc->sc_iot = iot; + sc->sc_ioh = ioh; + sc->sc_lmsc.lm_writereg = lm_isa_writereg; + sc->sc_lmsc.lm_readreg = lm_isa_readreg; + lm_probe(&sc->sc_lmsc); + + bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); + sc->sc_iot = 0; + sc->sc_ioh = 0; + + return (0); +} + +int +lm_isa_attach(struct device *dev) +{ + struct lm_isa_softc *sc = device_get_softc(dev); +#ifdef notyet + struct lm_softc *lmsc; + int i; + u_int8_t sbusaddr; +#endif + + sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, + 0ul, ~0ul, 8, RF_ACTIVE); + if (sc->sc_iores == NULL) { + device_printf(dev, "can't map i/o space\n"); + return (1); + } + sc->sc_iot = rman_get_bustag(sc->sc_iores); + sc->sc_ioh = rman_get_bushandle(sc->sc_iores); + + /* Bus-independent attachment */ + lm_attach(&sc->sc_lmsc); + +#ifdef notyet + /* + * Most devices supported by this driver can attach to iic(4) + * as well. However, we prefer to attach them to isa(4) since + * that causes less overhead and is more reliable. We look + * through all previously attached devices, and if we find an + * identical chip at the same serial bus address, we stop + * updating its sensors and mark them as invalid. + */ + + sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR); + if (sbusaddr == 0) + return (0); + + for (i = 0; i < lm_cd.cd_ndevs; i++) { + lmsc = lm_cd.cd_devs[i]; + if (lmsc == &sc->sc_lmsc) + continue; + if (lmsc && lmsc->sbusaddr == sbusaddr && + lmsc->chipid == sc->sc_lmsc.chipid) + config_detach(&lmsc->sc_dev, 0); + } +#endif + return (0); +} + +int +lm_isa_detach(struct device *dev) +{ + struct lm_isa_softc *sc = device_get_softc(dev); + int error; + + /* Bus-independent detachment */ + error = lm_detach(&sc->sc_lmsc); + if (error) + return (error); + + error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid, + sc->sc_iores); + if (error) + return (error); + + return (0); +} + +u_int8_t +lm_isa_readreg(struct lm_softc *lmsc, int reg) +{ + struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); + return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA)); +} + +void +lm_isa_writereg(struct lm_softc *lmsc, int reg, int val) +{ + struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc; + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val); +} diff --git a/sys/dev/lm/lm78var.h b/sys/dev/lm/lm78var.h new file mode 100644 index 0000000..1b0ce32 --- /dev/null +++ b/sys/dev/lm/lm78var.h @@ -0,0 +1,158 @@ +/* $FreeBSD$ */ +/* $OpenBSD: lm78var.h,v 1.12 2007/05/25 02:26:43 cnst Exp $ */ + +/*- + * Copyright (c) 2005, 2006 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * National Semiconductor LM78/79/81 registers + */ + +#define LM_POST_RAM 0x00 /* POST RAM occupies 0x00 -- 0x1f */ +#define LM_VALUE_RAM 0x20 /* Value RAM occupies 0x20 -- 0x3f */ +#define LM_FAN1 0x28 /* FAN1 reading */ +#define LM_FAN2 0x29 /* FAN2 reading */ +#define LM_FAN3 0x2a /* FAN3 reading */ + +#define LM_CONFIG 0x40 /* Configuration */ +#define LM_ISR1 0x41 /* Interrupt Status 1 */ +#define LM_ISR2 0x42 /* Interrupt Status 2 */ +#define LM_SMI1 0x43 /* SMI# Mask 1 */ +#define LM_SMI2 0x44 /* SMI# Mask 2 */ +#define LM_NMI1 0x45 /* NMI Mask 1 */ +#define LM_NMI2 0x46 /* NMI Mask 2 */ +#define LM_VIDFAN 0x47 /* VID/Fan Divisor */ +#define LM_SBUSADDR 0x48 /* Serial Bus Address */ +#define LM_CHIPID 0x49 /* Chip Reset/ID */ + +/* Chip IDs */ + +#define LM_CHIPID_LM78 0x00 +#define LM_CHIPID_LM78J 0x40 +#define LM_CHIPID_LM79 0xC0 +#define LM_CHIPID_LM81 0x80 +#define LM_CHIPID_MASK 0xfe + +/* + * Winbond registers + * + * Several models exists. The W83781D is mostly compatible with the + * LM78, but has two extra temperatures. Later models add extra + * voltage sensors, fans and bigger fan divisors to accomodate slow + * running fans. To accomodate the extra sensors some models have + * different memory banks. + */ + +#define WB_T23ADDR 0x4a /* Temperature 2 and 3 Serial Bus Address */ +#define WB_PIN 0x4b /* Pin Control */ +#define WB_BANKSEL 0x4e /* Bank Select */ +#define WB_VENDID 0x4f /* Vendor ID */ + +/* Bank 0 regs */ +#define WB_BANK0_CHIPID 0x58 /* Chip ID */ +#define WB_BANK0_FAN45 0x5c /* Fan 4/5 Divisor Control (W83791D only) */ +#define WB_BANK0_VBAT 0x5d /* VBAT Monitor Control */ +#define WB_BANK0_FAN4 0xba /* Fan 4 reading (W83791D only) */ +#define WB_BANK0_FAN5 0xbb /* Fan 5 reading (W83791D only) */ + +#define WB_BANK0_CONFIG 0x18 /* VRM & OVT Config (W83627THF/W83637HF) */ + +/* Bank 1 registers */ +#define WB_BANK1_T2H 0x50 /* Temperature 2 High Byte */ +#define WB_BANK1_T2L 0x51 /* Temperature 2 Low Byte */ + +/* Bank 2 registers */ +#define WB_BANK2_T3H 0x50 /* Temperature 3 High Byte */ +#define WB_BANK2_T3L 0x51 /* Temperature 3 Low Byte */ + +/* Bank 4 registers (W83782D/W83627HF and later models only) */ +#define WB_BANK4_T1OFF 0x54 /* Temperature 1 Offset */ +#define WB_BANK4_T2OFF 0x55 /* Temperature 2 Offset */ +#define WB_BANK4_T3OFF 0x56 /* Temperature 3 Offset */ + +/* Bank 5 registers (W83782D/W83627HF and later models only) */ +#define WB_BANK5_5VSB 0x50 /* 5VSB reading */ +#define WB_BANK5_VBAT 0x51 /* VBAT reading */ + +/* Bank selection */ +#define WB_BANKSEL_B0 0x00 /* Bank 0 */ +#define WB_BANKSEL_B1 0x01 /* Bank 1 */ +#define WB_BANKSEL_B2 0x02 /* Bank 2 */ +#define WB_BANKSEL_B3 0x03 /* Bank 3 */ +#define WB_BANKSEL_B4 0x04 /* Bank 4 */ +#define WB_BANKSEL_B5 0x05 /* Bank 5 */ +#define WB_BANKSEL_HBAC 0x80 /* Register 0x4f High Byte Access */ + +/* Vendor IDs */ +#define WB_VENDID_WINBOND 0x5ca3 /* Winbond */ +#define WB_VENDID_ASUS 0x12c3 /* ASUS */ + +/* Chip IDs */ +#define WB_CHIPID_W83781D 0x10 +#define WB_CHIPID_W83781D_2 0x11 +#define WB_CHIPID_W83627HF 0x21 +#define WB_CHIPID_AS99127F 0x31 /* Asus W83781D clone */ +#define WB_CHIPID_W83782D 0x30 +#define WB_CHIPID_W83783S 0x40 +#define WB_CHIPID_W83697HF 0x60 +#define WB_CHIPID_W83791D 0x71 +#define WB_CHIPID_W83791SD 0x72 +#define WB_CHIPID_W83792D 0x7a +#define WB_CHIPID_W83637HF 0x80 +#define WB_CHIPID_W83627THF 0x90 +#define WB_CHIPID_W83627EHF 0xa1 +#define WB_CHIPID_W83627DHG 0xc1 + +/* Config bits */ +#define WB_CONFIG_VMR9 0x01 + +/* Reference voltage (mV) */ +#define WB_VREF 3600 +#define WB_W83627EHF_VREF 2048 + +#define WB_MAX_SENSORS 19 + +struct lm_softc; + +struct lm_sensor { + char *desc; + enum sensor_type type; + u_int8_t bank; + u_int8_t reg; + void (*refresh)(struct lm_softc *, int); + int rfact; +}; + +struct lm_softc { + struct device *sc_dev; + + struct ksensor sensors[WB_MAX_SENSORS]; + struct ksensordev sensordev; + struct lm_sensor *lm_sensors; + u_int numsensors; + void (*refresh_sensor_data) (struct lm_softc *); + + u_int8_t (*lm_readreg)(struct lm_softc *, int); + void (*lm_writereg)(struct lm_softc *, int, int); + + u_int8_t sbusaddr; + u_int8_t chipid; + u_int8_t vrm9; +}; + +void lm_probe(struct lm_softc *); +void lm_attach(struct lm_softc *); +int lm_detach(struct lm_softc *); diff --git a/sys/i386/conf/GENERIC.hints b/sys/i386/conf/GENERIC.hints index ed1faa7..e1567b2 100644 --- a/sys/i386/conf/GENERIC.hints +++ b/sys/i386/conf/GENERIC.hints @@ -76,3 +76,11 @@ hint.le.0.disabled="1" hint.le.0.port="0x280" hint.le.0.irq="10" hint.le.0.drq="0" +hint.lm.0.at="isa" +hint.lm.0.port="0x290" +hint.it.0.at="isa" +hint.it.0.port="0x290" +hint.it.1.at="isa" +hint.it.1.port="0xc00" +hint.it.2.at="isa" +hint.it.2.port="0xd00" diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 4c47167..2ac0894 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -131,6 +131,7 @@ SUBDIR= ${_3dfx} \ iscsi \ isp \ ispfw \ + ${_it} \ ${_iwi} \ ${_iwifw} \ ${_ixgb} \ @@ -146,6 +147,7 @@ SUBDIR= ${_3dfx} \ ${_linprocfs} \ ${_linsysfs} \ ${_linux} \ + ${_lm} \ lmc \ lpt \ mac_biba \ @@ -453,9 +455,11 @@ _ipmi= ipmi _ips= ips _ipw= ipw _ipwfw= ipwfw +_it= it _iwi= iwi _iwifw= iwifw _ixgb= ixgb +_lm= lm _mly= mly _nfe= nfe _nve= nve @@ -511,10 +515,12 @@ _ipmi= ipmi _ips= ips _ipw= ipw _ipwfw= ipwfw +_it= it _ixgb= ixgb _linprocfs= linprocfs _linsysfs= linsysfs _linux= linux +_lm= lm _mly= mly _ndis= ndis _nfe= nfe diff --git a/sys/modules/it/Makefile b/sys/modules/it/Makefile new file mode 100644 index 0000000..f2f064b --- /dev/null +++ b/sys/modules/it/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/it + +KMOD= it +SRCS= it.c +SRCS+= device_if.h bus_if.h isa_if.h + +.include <bsd.kmod.mk> diff --git a/sys/modules/lm/Makefile b/sys/modules/lm/Makefile new file mode 100644 index 0000000..cb0791a --- /dev/null +++ b/sys/modules/lm/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/lm + +KMOD= lm +SRCS= lm78.c lm78_isa.c +SRCS+= device_if.h bus_if.h isa_if.h + +.include <bsd.kmod.mk> |