From 1d03db0216132dd801bb5f6bfdbec2c72818af2a Mon Sep 17 00:00:00 2001 From: Hasso Tepper Date: Tue, 2 Oct 2007 13:37:38 +0000 Subject: [PATCH] lm(4) and it(4) drivers for hardware sensors used in many motherboards. Ported from OpenBSD to FreeBSD by Constantine A. Murenin . Obtained-from: OpenBSD via FreeBSD GSoC 2007 project --- share/man/man4/Makefile | 4 +- share/man/man4/it.4 | 104 ++++ share/man/man4/lm.4 | 138 +++++ sys/conf/files | 5 +- sys/config/GENERIC | 8 +- sys/config/LINT | 8 +- sys/dev/powermng/it/it.c | 341 +++++++++++++ sys/dev/powermng/it/itvar.h | 95 ++++ sys/dev/powermng/lm/lm78.c | 906 +++++++++++++++++++++++++++++++++ sys/dev/powermng/lm/lm78_isa.c | 247 +++++++++ sys/dev/powermng/lm/lm78var.h | 158 ++++++ 11 files changed, 2010 insertions(+), 4 deletions(-) create mode 100644 share/man/man4/it.4 create mode 100644 share/man/man4/lm.4 create mode 100644 sys/dev/powermng/it/it.c create mode 100644 sys/dev/powermng/it/itvar.h create mode 100644 sys/dev/powermng/lm/lm78.c create mode 100644 sys/dev/powermng/lm/lm78_isa.c create mode 100644 sys/dev/powermng/lm/lm78var.h diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 33cd77fe2b..19187790c5 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,6 +1,6 @@ # @(#)Makefile 8.1 (Berkeley) 6/18/93 # $FreeBSD: src/share/man/man4/Makefile,v 1.83.2.66 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/share/man/man4/Makefile,v 1.68 2007/10/02 13:16:42 hasso Exp $ +# $DragonFly: src/share/man/man4/Makefile,v 1.69 2007/10/02 13:37:38 hasso Exp $ MAN= aac.4 \ acpi.4 \ @@ -99,6 +99,7 @@ MAN= aac.4 \ ipw.4 \ isp.4 \ ispfw.4 \ + it.4 \ iwi.4 \ joy.4 \ keyboard.4 \ @@ -106,6 +107,7 @@ MAN= aac.4 \ ktr.4 \ kue.4 \ lge.4 \ + lm.4 \ lo.4 \ lp.4 \ lpbb.4 \ diff --git a/share/man/man4/it.4 b/share/man/man4/it.4 new file mode 100644 index 0000000000..68b99d9a21 --- /dev/null +++ b/share/man/man4/it.4 @@ -0,0 +1,104 @@ +.\" $OpenBSD: it.4,v 1.8 2006/09/08 15:09:14 jmc Exp $ +.\" $DragonFly: src/share/man/man4/it.4,v 1.1 2007/10/02 13:37:38 hasso Exp $ +.\" +.\" Copyright (c) 2003 Julien Bordet +.\" 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. +.\" +.Dd 13 September 2007 +.Dt IT 4 +.Os +.Sh NAME +.Nm it +.Nd ITE IT8705F/12F/16F and SiS SiS950 Super I/O Hardware Monitor +.Sh SYNOPSIS +.Cd "device isa" +.Cd "device it" +.Pp +In +.Pa /boot/device.hints : +.Cd hint.it.0.at="isa" +.Cd hint.it.0.port="0x290" +.Cd hint.it.1.at="isa" +.Cd hint.it.1.port="0xc00" +.Cd hint.it.2.at="isa" +.Cd hint.it.2.port="0xd00" +.Sh DESCRIPTION +The +.Nm +driver provides support for the +.Tn IT8705F , IT8712F , IT8716F +and +.Tn SiS950 +hardware monitors. +The values are exposed through the +.Va HW_SENSORS +.Xr sysctl 3 +interface. +.Pp +Most supported devices possess 15 sensors: +.Bl -column "Sensor" "Units" "Typical" -offset indent +.It Sy "Sensor" Ta Sy "Units" Ta Sy "Typical Use" +.It Li "Fan0" Ta "RPM" Ta "CPU Fan" +.It Li "Fan1" Ta "RPM" Ta "Fan" +.It Li "Fan2" Ta "RPM" Ta "Fan" +.It Li "IN0" Ta "uV DC" Ta "Core voltage" +.It Li "IN1" Ta "uV DC" Ta "Core voltage" +.It Li "IN2" Ta "uV DC" Ta "+3.3V" +.It Li "IN3" Ta "uV DC" Ta "+5V" +.It Li "IN4" Ta "uV DC" Ta "+12V" +.It Li "IN5" Ta "uV DC" Ta "Unknown" +.It Li "IN6" Ta "uV DC" Ta "-12V" +.It Li "IN7" Ta "uV DC" Ta "-5V" +.It Li "IN8" Ta "uV DC" Ta "VBAT" +.It Li "Temp" Ta "uK" Ta "Motherboard Temperature" +.It Li "Temp" Ta "uK" Ta "Motherboard Temperature" +.It Li "Temp" Ta "uK" Ta "CPU Temperature" +.El +.Pp +For some devices, sensors' names and numbers will be different. +.Sh SEE ALSO +.Xr systat 1 , +.Xr sysctl 3 , +.Xr sensorsd 8 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Ox 3.4 . +.Fx +support was added in +.Fx 7.XXX . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Julien Bordet Aq zejames@greyhats.org . +It was ported to +.Fx +by +.An Constantine A. Murenin Aq cnst@FreeBSD.org +as a part of a Google Summer of Code 2007 project. +.Sh BUGS +Interrupt support is unimplemented. diff --git a/share/man/man4/lm.4 b/share/man/man4/lm.4 new file mode 100644 index 0000000000..a353ce5fb3 --- /dev/null +++ b/share/man/man4/lm.4 @@ -0,0 +1,138 @@ +.\" $OpenBSD: lm.4,v 1.16 2007/05/26 22:38:55 cnst Exp $ +.\" $NetBSD: lm.4,v 1.11 2001/09/22 01:22:49 wiz Exp $ +.\" $DragonFly: src/share/man/man4/lm.4,v 1.1 2007/10/02 13:37:38 hasso Exp $ +.\" +.\" Copyright (c) 2000 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Bill Squier. +.\" +.\" 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``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 FOUNDATION OR CONTRIBUTORS +.\" 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. +.\" +.Dd 19 August 2007 +.Dt LM 4 +.Os +.Sh NAME +.Nm lm +.Nd NatSemi LM78/79/81 and Winbond Super I/O Hardware Monitor +.Sh SYNOPSIS +.Cd "device isa" +.Cd "device lm" +.Pp +In +.Pa /boot/device.hints : +.Cd hint.lm.0.at="isa" +.Cd hint.lm.0.port="0x290" +.Cd hint.lm.1.at="isa" +.Cd hint.lm.1.port="0x280" +.Cd hint.lm.2.at="isa" +.Cd hint.lm.2.port="0x310" +.Sh DESCRIPTION +The +.Nm +driver provides support for the +.Tn National Semiconductor +LM 78/79/81 and +.Tn Winbond +Super I/O +hardware monitors, +and registers compatible chips under the +.Va HW_SENSORS +.Xr sysctl 3 +tree. +.Sh HARDWARE +Chips supported by the +.Nm +driver include: +.Pp +.Bl -dash -offset indent -compact +.It +National Semiconductor LM78 and LM78-J +.It +National Semiconductor LM79 +.It +National Semiconductor LM81 +.It +Winbond W83627HF, W83627THF, W83637HF and W83697HF +.It +Winbond W83627DHG and W83627EHF +.It +Winbond W83781D, W83782D and W83783S +.It +Winbond W83791D, W83791SD and W83792D +.It +ASUS AS99127F +.El +.Sh SEE ALSO +.Xr systat 1 , +.Xr sysctl 3 , +.Xr sensorsd 8 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Nx 1.5 ; +.Ox +support was added in +.Ox 3.4 ; +.Fx +support was added in +.Fx 7.XXX . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Bill Squier +and ported to +.Ox 3.4 +by +.An Alexander Yurchenko Aq grange@openbsd.org . +The driver was largely rewritten for +.Ox 3.9 +by +.An Mark Kettenis Aq kettenis@openbsd.org . +The driver was then ported to +.Fx +by +.An Constantine A. Murenin Aq cnst@FreeBSD.org +as a part of a Google Summer of Code 2007 project. +.Sh CAVEATS +Some vendors connect these chips to non-standard thermal diodes and +resistors. +This will result in bogus sensor values. +.Sh BUGS +Interrupt support is unimplemented. +.Pp +There are currently no known pnpbios IDs assigned to LM chips. +.Pp +This driver attaches to the Winbond W83791SD chip even though that +chip does not have any sensors. diff --git a/sys/conf/files b/sys/conf/files index 01c7d1635b..e230525d71 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,5 +1,5 @@ # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/sys/conf/files,v 1.183 2007/10/02 13:16:42 hasso Exp $ +# $DragonFly: src/sys/conf/files,v 1.184 2007/10/02 13:37:38 hasso Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -1346,6 +1346,9 @@ dev/drm/radeon/radeon_irq.c optional radeondrm dev/drm/radeon/radeon_mem.c optional radeondrm dev/drm/radeon/radeon_state.c optional radeondrm dev/drm/tdfx/tdfx_drv.c optional tdfxdrm +dev/powermng/it/it.c optional it isa +dev/powermng/lm/lm78.c optional lm isa +dev/powermng/lm/lm78_isa.c optional lm isa emulation/43bsd/43bsd_socket.c optional compat_43 emulation/43bsd/43bsd_stats.c optional compat_43 emulation/43bsd/43bsd_file.c optional compat_43 diff --git a/sys/config/GENERIC b/sys/config/GENERIC index 97cbf2f91c..a03b548b18 100644 --- a/sys/config/GENERIC +++ b/sys/config/GENERIC @@ -4,7 +4,7 @@ # Check the LINT configuration file in sys/config, for an # exhaustive list of options. # -# $DragonFly: src/sys/config/GENERIC,v 1.52 2007/06/09 17:56:27 swildner Exp $ +# $DragonFly: src/sys/config/GENERIC,v 1.53 2007/10/02 13:37:38 hasso Exp $ platform pc32 machine i386 @@ -177,6 +177,12 @@ device npx0 at nexus? port IO_NPX irq 13 # Power management support (see LINT for more options) device apm0 at nexus? disable flags 0x20 # Advanced Power Management +# HW monitoring devices +device lm0 at isa? port 0x290 +device it0 at isa? port 0x290 +device it1 at isa? port 0xc00 +device it2 at isa? port 0xd00 + # PCCARD (PCMCIA) support device pccard device cardbus diff --git a/sys/config/LINT b/sys/config/LINT index d167921438..ff06a19eb6 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -3,7 +3,7 @@ # as much of the source tree as it can. # # $FreeBSD: src/sys/i386/conf/LINT,v 1.749.2.144 2003/06/04 17:56:59 sam Exp $ -# $DragonFly: src/sys/config/LINT,v 1.132 2007/10/02 13:16:42 hasso Exp $ +# $DragonFly: src/sys/config/LINT,v 1.133 2007/10/02 13:37:38 hasso Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -2071,6 +2071,12 @@ device pcf0 at isa? port 0x320 irq 5 # Intel Core and newer CPUs on-die digital thermal sensor support device coretemp +# HW monitoring devices lm(4) and it(4). +device lm0 at isa? port 0x290 +device it0 at isa? port 0x290 +device it1 at isa? port 0xc00 +device it2 at isa? port 0xd00 + #--------------------------------------------------------------------------- # ISDN4BSD # diff --git a/sys/dev/powermng/it/it.c b/sys/dev/powermng/it/it.c new file mode 100644 index 0000000000..d684666f6d --- /dev/null +++ b/sys/dev/powermng/it/it.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2003 Julien Bordet + * 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. + * + * $OpenBSD: it.c,v 1.22 2007/03/22 16:55:31 deraadt Exp $ + * $DragonFly: src/sys/dev/powermng/it/it.c,v 1.1 2007/10/02 13:37:38 hasso Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "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; + } + + ksnprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc), + "VCORE_A"); + ksnprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc), + "VCORE_B"); + ksnprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc), + "+3.3V"); + ksnprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc), + "+5V"); + ksnprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc), + "+12V"); + ksnprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc), + "Unused"); + ksnprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc), + "-12V"); + ksnprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc), + "+5VSB"); + ksnprintf(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/powermng/it/itvar.h b/sys/dev/powermng/it/itvar.h new file mode 100644 index 0000000000..ed71960f68 --- /dev/null +++ b/sys/dev/powermng/it/itvar.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2003 Julien Bordet + * 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. + * + * $OpenBSD: itvar.h,v 1.4 2007/03/22 16:55:31 deraadt Exp $ + * $DragonFly: src/sys/dev/powermng/it/itvar.h,v 1.1 2007/10/02 13:37:38 hasso Exp $ + */ + +#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/powermng/lm/lm78.c b/sys/dev/powermng/lm/lm78.c new file mode 100644 index 0000000000..a5f7115f74 --- /dev/null +++ b/sys/dev/powermng/lm/lm78.c @@ -0,0 +1,906 @@ +/* + * 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. + * + * $OpenBSD: lm78.c,v 1.18 2007/05/26 22:47:39 cnst Exp $ + * $DragonFly: src/sys/dev/powermng/lm/lm78.c,v 1.1 2007/10/02 13:37:38 hasso Exp $ + */ + +#include +#include +#include +#include +#include + +#include "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; + } + ksnprintf(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; + ksnprintf(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) + ksnprintf(desc, sizeof(desc), + "W83792D rev %c", 'A' + devid - 0x10); + else + ksnprintf(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: + ksnprintf(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') + ksnprintf(fulldesc, sizeof(fulldesc), + "Winbond %s Hardware Monitor", cdesc); + else + ksnprintf(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/powermng/lm/lm78_isa.c b/sys/dev/powermng/lm/lm78_isa.c new file mode 100644 index 0000000000..2d73b32cf1 --- /dev/null +++ b/sys/dev/powermng/lm/lm78_isa.c @@ -0,0 +1,247 @@ +/* + * 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. + * + * $OpenBSD: lm78_isa.c,v 1.2 2007/07/01 21:48:57 cnst Exp $ + * $DragonFly: src/sys/dev/powermng/lm/lm78_isa.c,v 1.1 2007/10/02 13:37:38 hasso Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include "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/powermng/lm/lm78var.h b/sys/dev/powermng/lm/lm78var.h new file mode 100644 index 0000000000..67438ee54d --- /dev/null +++ b/sys/dev/powermng/lm/lm78var.h @@ -0,0 +1,158 @@ +/* + * 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. + * + * $OpenBSD: lm78var.h,v 1.12 2007/05/25 02:26:43 cnst Exp $ + * $DragonFly: src/sys/dev/powermng/lm/lm78var.h,v 1.1 2007/10/02 13:37:38 hasso Exp $ + */ + +/* + * 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 *); -- 2.41.0