diff options
author | 2003-04-25 21:24:15 +0000 | |
---|---|---|
committer | 2003-04-25 21:24:15 +0000 | |
commit | 5355ba14089d06914326b12a58d772853a48e28b (patch) | |
tree | 7f39336c2d370fc8a5c06c0a4ffcef26accf97d4 /sys | |
parent | strings... ok tedu@, millert@ (diff) | |
download | wireguard-openbsd-5355ba14089d06914326b12a58d772853a48e28b.tar.xz wireguard-openbsd-5355ba14089d06914326b12a58d772853a48e28b.zip |
lm(4) driver from NetBSD adapted for sysctl interface.
The lm driver provides support for the National Semiconductor LM series
hardware monitors and register compatible chips. It supports LM78,
LM78-J, LM79, Winbond W83697HF, W83627HF, W83781D and W83782D chips.
Tested and ok'ed by millert@ and henning@.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/files | 6 | ||||
-rw-r--r-- | sys/dev/ic/nslm7x.c | 850 | ||||
-rw-r--r-- | sys/dev/ic/nslm7xvar.h | 140 | ||||
-rw-r--r-- | sys/dev/isa/files.isa | 6 | ||||
-rw-r--r-- | sys/dev/isa/lm_isa.c | 148 |
5 files changed, 1148 insertions, 2 deletions
diff --git a/sys/conf/files b/sys/conf/files index 78bbe96330b..23f21ffbe0c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.270 2003/03/29 00:51:38 mickey Exp $ +# $OpenBSD: files,v 1.271 2003/04/25 21:24:15 grange Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -283,6 +283,10 @@ file dev/ic/iha.c iha device trm: scsi file dev/ic/trm.c trm +# National Semiconductor LM7[89] and compatible hardware monitors +device lm +file dev/ic/nslm7x.c lm + # Attributes which machine-independent bus support can be attached to. # These should be defined here, because some of these busses can have # devices which provide these attributes, and we'd like to avoid hairy diff --git a/sys/dev/ic/nslm7x.c b/sys/dev/ic/nslm7x.c new file mode 100644 index 00000000000..4de9a93b329 --- /dev/null +++ b/sys/dev/ic/nslm7x.c @@ -0,0 +1,850 @@ +/* $OpenBSD: nslm7x.c,v 1.1 2003/04/25 21:24:15 grange Exp $ */ +/* $NetBSD: nslm7x.c,v 1.17 2002/11/15 14:55:41 ad 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/queue.h> +#include <sys/sensors.h> +#include <sys/timeout.h> +#include <machine/bus.h> + +#include <dev/ic/nslm7xvar.h> + +#if defined(LMDEBUG) +#define DPRINTF(x) do { printf x; } while (0) +#else +#define DPRINTF(x) +#endif + +struct cfdriver lm_cd = { + NULL, "lm", DV_DULL +}; + +void setup_fan(struct lm_softc *, int, int); +void setup_temp(struct lm_softc *, int, int); +void wb_setup_volt(struct lm_softc *); + +int lm_match(struct lm_softc *); +int wb_match(struct lm_softc *); +int def_match(struct lm_softc *); +void lm_common_match(struct lm_softc *); +int lm_generic_banksel(struct lm_softc *, int); + +void generic_stemp(struct lm_softc *, struct sensor *); +void generic_svolt(struct lm_softc *, struct sensor *); +void generic_fanrpm(struct lm_softc *, struct sensor *); + +void lm_refresh_sensor_data(struct lm_softc *); + +void wb_svolt(struct lm_softc *); +void wb_stemp(struct lm_softc *, struct sensor *, int); +void wb781_fanrpm(struct lm_softc *, struct sensor *); +void wb_fanrpm(struct lm_softc *, struct sensor *); + +void wb781_refresh_sensor_data(struct lm_softc *); +void wb782_refresh_sensor_data(struct lm_softc *); +void wb697_refresh_sensor_data(struct lm_softc *); + +void lm_refresh(void *); + +#if 0 +int lm_gtredata(struct sysmon_envsys *, struct envsys_tre_data *); + +int generic_streinfo_fan(struct lm_softc *, struct envsys_basic_info *, + int, struct envsys_basic_info *); +int lm_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); +int wb781_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); +int wb782_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); +#endif + +struct lm_chip { + int (*chip_match)(struct lm_softc *); +}; + +struct lm_chip lm_chips[] = { + { wb_match }, + { lm_match }, + { def_match } /* Must be last */ +}; + +struct timeout lm_timeout; + +int +lm_generic_banksel(struct lm_softc *lmsc, int bank) +{ + (*lmsc->lm_writereg)(lmsc, WB_BANKSEL, bank); + return (0); +} + +/* + * bus independent probe + */ +int +lm_probe(bus_space_tag_t iot, bus_space_handle_t ioh) +{ + u_int8_t cr; + int rv; + + /* Check for some power-on defaults */ + bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG); + + /* Perform LM78 reset */ + bus_space_write_1(iot, ioh, LMC_DATA, 0x80); + + /* XXX - Why do I have to reselect the register? */ + bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG); + cr = bus_space_read_1(iot, ioh, LMC_DATA); + + /* XXX - spec says *only* 0x08! */ + if ((cr == 0x08) || (cr == 0x01)) + rv = 1; + else + rv = 0; + + DPRINTF(("lm: rv = %d, cr = %x\n", rv, cr)); + + return (rv); +} + +/* + * pre: lmsc contains valid busspace tag and handle + */ +void +lm_attach(struct lm_softc *lmsc) +{ + u_int i; + extern int nsensors; + extern struct sensors_head sensors; + + /* Install default bank selection routine, if none given. */ + if (lmsc->lm_banksel == NULL) + lmsc->lm_banksel = lm_generic_banksel; + + for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++) + if (lm_chips[i].chip_match(lmsc)) + break; + + /* Start the monitoring loop */ + (*lmsc->lm_writereg)(lmsc, LMD_CONFIG, 0x01); + + /* Initialize sensors */ + for (i = 0; i < lmsc->numsensors; ++i) { + strlcpy(lmsc->sensors[i].device, lmsc->sc_dev.dv_xname, + sizeof(lmsc->sensors[i].device)); + lmsc->sensors[i].num = nsensors++; + SLIST_INSERT_HEAD(&sensors, &lmsc->sensors[i], list); + } + + /* Refresh sensors data every 1.5 seconds */ + timeout_set(&lm_timeout, lm_refresh, lmsc); + timeout_add(&lm_timeout, (15 * hz) / 10); +} + +int +lm_match(struct lm_softc *sc) +{ + int i; + + /* See if we have an LM78 or LM79 */ + i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK; + switch(i) { + case LM_ID_LM78: + printf(": LM78\n"); + break; + case LM_ID_LM78J: + printf(": LM78J\n"); + break; + case LM_ID_LM79: + printf(": LM79\n"); + break; + case LM_ID_LM81: + printf(": LM81\n"); + break; + default: + return 0; + } + lm_common_match(sc); + return 1; +} + +int +def_match(struct lm_softc *sc) +{ + int i; + + i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK; + printf(": Unknown chip (ID %d)\n", i); + lm_common_match(sc); + return 1; +} + +void +lm_common_match(struct lm_softc *sc) +{ + int i; + sc->numsensors = LM_NUM_SENSORS; + sc->refresh_sensor_data = lm_refresh_sensor_data; + + for (i = 0; i < 7; ++i) { + sc->sensors[i].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[i].desc, sizeof(sc->sensors[i].desc), + "IN%d", i); + } + + /* default correction factors for resistors on higher voltage inputs */ + sc->sensors[0].rfact = sc->sensors[1].rfact = + sc->sensors[2].rfact = 10000; + sc->sensors[3].rfact = (int)(( 90.9 / 60.4) * 10000); + sc->sensors[4].rfact = (int)(( 38.0 / 10.0) * 10000); + sc->sensors[5].rfact = (int)((210.0 / 60.4) * 10000); + sc->sensors[6].rfact = (int)(( 90.9 / 60.4) * 10000); + + sc->sensors[7].type = SENSOR_TEMP; + strlcpy(sc->sensors[7].desc, "Temp", sizeof(sc->sensors[7].desc)); + + setup_fan(sc, 8, 3); +} + +int +wb_match(struct lm_softc *sc) +{ + int i, j; + + (*sc->lm_writereg)(sc, WB_BANKSEL, WB_BANKSEL_HBAC); + j = (*sc->lm_readreg)(sc, WB_VENDID) << 8; + (*sc->lm_writereg)(sc, WB_BANKSEL, 0); + j |= (*sc->lm_readreg)(sc, WB_VENDID); + DPRINTF(("winbond vend id 0x%x\n", j)); + if (j != WB_VENDID_WINBOND) + return 0; + /* read device ID */ + (*sc->lm_banksel)(sc, 0); + j = (*sc->lm_readreg)(sc, WB_BANK0_CHIPID); + DPRINTF(("winbond chip id 0x%x\n", j)); + switch(j) { + case WB_CHIPID_83781: + case WB_CHIPID_83781_2: + printf(": W83781D\n"); + + for (i = 0; i < 7; ++i) { + sc->sensors[i].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[i].desc, + sizeof(sc->sensors[i].desc), "IN%d", i); + } + + /* default correction factors for higher voltage inputs */ + sc->sensors[0].rfact = sc->sensors[1].rfact = + sc->sensors[2].rfact = 10000; + sc->sensors[3].rfact = (int)(( 90.9 / 60.4) * 10000); + sc->sensors[4].rfact = (int)(( 38.0 / 10.0) * 10000); + sc->sensors[5].rfact = (int)((210.0 / 60.4) * 10000); + sc->sensors[6].rfact = (int)(( 90.9 / 60.4) * 10000); + + setup_temp(sc, 7, 3); + setup_fan(sc, 10, 3); + + sc->numsensors = WB83781_NUM_SENSORS; + sc->refresh_sensor_data = wb781_refresh_sensor_data; + return 1; + case WB_CHIPID_83697: + printf(": W83697HF\n"); + wb_setup_volt(sc); + setup_temp(sc, 9, 2); + setup_fan(sc, 11, 3); + sc->numsensors = WB83697_NUM_SENSORS; + sc->refresh_sensor_data = wb697_refresh_sensor_data; + return 1; + case WB_CHIPID_83782: + printf(": W83782D\n"); + break; + case WB_CHIPID_83627: + printf(": W83627HF\n"); + break; + default: + printf(": unknow winbond chip ID 0x%x\n", j); + /* handle as a standart lm7x */ + lm_common_match(sc); + return 1; + } + /* common code for the W83782D and W83627HF */ + wb_setup_volt(sc); + setup_temp(sc, 9, 3); + setup_fan(sc, 12, 3); + sc->numsensors = WB_NUM_SENSORS; + sc->refresh_sensor_data = wb782_refresh_sensor_data; + return 1; +} + +void +wb_setup_volt(struct lm_softc *sc) +{ + sc->sensors[0].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[0].desc, sizeof(sc->sensors[0].desc), "VCORE_A"); + sc->sensors[0].rfact = 10000; + sc->sensors[1].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[1].desc, sizeof(sc->sensors[1].desc), "VCORE_B"); + sc->sensors[1].rfact = 10000; + sc->sensors[2].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[2].desc, sizeof(sc->sensors[2].desc), "+3.3V"); + sc->sensors[2].rfact = 10000; + sc->sensors[3].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[3].desc, sizeof(sc->sensors[3].desc), "+5V"); + sc->sensors[3].rfact = 16778; + sc->sensors[4].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[4].desc, sizeof(sc->sensors[4].desc), "+12V"); + sc->sensors[4].rfact = 38000; + sc->sensors[5].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[5].desc, sizeof(sc->sensors[5].desc), "-12V"); + sc->sensors[5].rfact = 10000; + sc->sensors[6].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[6].desc, sizeof(sc->sensors[6].desc), "-5V"); + sc->sensors[6].rfact = 10000; + sc->sensors[7].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[7].desc, sizeof(sc->sensors[7].desc), "+5VSB"); + sc->sensors[7].rfact = 15151; + sc->sensors[8].type = SENSOR_VOLTS_DC; + snprintf(sc->sensors[8].desc, sizeof(sc->sensors[8].desc), "VBAT"); + sc->sensors[8].rfact = 10000; +} + +void +setup_temp(struct lm_softc *sc, int start, int n) +{ + int i; + + for (i = 0; i < n; i++) { + sc->sensors[start + i].type = SENSOR_TEMP; + snprintf(sc->sensors[start + i].desc, + sizeof(sc->sensors[start + i].desc), "Temp%d", i + 1); + } +} + +void +setup_fan(struct lm_softc *sc, int start, int n) +{ + int i; + + for (i = 0; i < n; ++i) { + sc->sensors[start + i].type = SENSOR_FANRPM; + snprintf(sc->sensors[start + i].desc, + sizeof(sc->sensors[start + i].desc), "Fan%d", i + 1); + } +} + +#if 0 +int +lm_gtredata(sme, tred) + struct sysmon_envsys *sme; + struct envsys_tre_data *tred; +{ + static const struct timeval onepointfive = { 1, 500000 }; + struct timeval t; + struct lm_softc *sc = sme->sme_cookie; + int i, s; + + /* read new values at most once every 1.5 seconds */ + timeradd(&sc->lastread, &onepointfive, &t); + s = splclock(); + i = timercmp(&mono_time, &t, >); + if (i) { + sc->lastread.tv_sec = mono_time.tv_sec; + sc->lastread.tv_usec = mono_time.tv_usec; + } + splx(s); + + if (i) + sc->refresh_sensor_data(sc); + + *tred = sc->sensors[tred->sensor]; + + return (0); +} + +int +generic_streinfo_fan(sc, info, n, binfo) + struct lm_softc *sc; + struct envsys_basic_info *info; + int n; + struct envsys_basic_info *binfo; +{ + u_int8_t sdata; + int divisor; + + /* FAN1 and FAN2 can have divisors set, but not FAN3 */ + if ((sc->sensors[binfo->sensor].type == SENSOR_FANRPM) + && (n < 2)) { + if (binfo->rpms == 0) { + binfo->validflags = 0; + return (0); + } + + /* write back the nominal FAN speed */ + info->rpms = binfo->rpms; + + /* 153 is the nominal FAN speed value */ + divisor = 1350000 / (binfo->rpms * 153); + + /* ...but we need lg(divisor) */ + if (divisor <= 1) + divisor = 0; + else if (divisor <= 2) + divisor = 1; + else if (divisor <= 4) + divisor = 2; + else + divisor = 3; + + /* + * FAN1 div is in bits <5:4>, FAN2 div is + * in <7:6> + */ + sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN); + if ( n == 0 ) { /* FAN1 */ + divisor <<= 4; + sdata = (sdata & 0xCF) | divisor; + } else { /* FAN2 */ + divisor <<= 6; + sdata = (sdata & 0x3F) | divisor; + } + + (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata); + } + return (0); + +} + +int +lm_streinfo(sme, binfo) + struct sysmon_envsys *sme; + struct envsys_basic_info *binfo; +{ + struct lm_softc *sc = sme->sme_cookie; + + if (sc->sensors[binfo->sensor].type == SENSOR_VOLTS_DC) + sc->sensors[binfo->sensor].rfact = binfo->rfact; + else { + if (sc->sensors[binfo->sensor].type == SENSOR_FANRPM) { + generic_streinfo_fan(sc, &sc->sensors[binfo->sensor], + binfo->sensor - 8, binfo); + } + memcpy(sc->sensors[binfo->sensor].desc, binfo->desc, + sizeof(sc->sensors[binfo->sensor].desc)); + sc->sensors[binfo->sensor].desc[ + sizeof(sc->sensors[binfo->sensor].desc) - 1] = '\0'; + + binfo->validflags = ENVSYS_FVALID; + } + return (0); +} + +int +wb781_streinfo(sme, binfo) + struct sysmon_envsys *sme; + struct envsys_basic_info *binfo; +{ + struct lm_softc *sc = sme->sme_cookie; + int divisor; + u_int8_t sdata; + int i; + + if (sc->sensors[binfo->sensor].type == SENSOR_VOLTS_DC) + sc->sensors[binfo->sensor].rfact = binfo->rfact; + else { + if (sc->sensors[binfo->sensor].type == SENSOR_FANRPM) { + if (binfo->rpms == 0) { + binfo->validflags = 0; + return (0); + } + + /* write back the nominal FAN speed */ + sc->sensors[binfo->sensor].rpms = binfo->rpms; + + /* 153 is the nominal FAN speed value */ + divisor = 1350000 / (binfo->rpms * 153); + + /* ...but we need lg(divisor) */ + for (i = 0; i < 7; i++) { + if (divisor <= (1 << i)) + break; + } + divisor = i; + + if (binfo->sensor == 10 || binfo->sensor == 11) { + /* + * FAN1 div is in bits <5:4>, FAN2 div + * is in <7:6> + */ + sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN); + if ( binfo->sensor == 10 ) { /* FAN1 */ + sdata = (sdata & 0xCF) | + ((divisor & 0x3) << 4); + } else { /* FAN2 */ + sdata = (sdata & 0x3F) | + ((divisor & 0x3) << 6); + } + (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata); + } else { + /* FAN3 is in WB_PIN <7:6> */ + sdata = (*sc->lm_readreg)(sc, WB_PIN); + sdata = (sdata & 0x3F) | + ((divisor & 0x3) << 6); + (*sc->lm_writereg)(sc, WB_PIN, sdata); + } + } + memcpy(sc->sensors[binfo->sensor].desc, binfo->desc, + sizeof(sc->sensors[binfo->sensor].desc)); + sc->sensors[binfo->sensor].desc[ + sizeof(sc->sensors[binfo->sensor].desc) - 1] = '\0'; + + binfo->validflags = ENVSYS_FVALID; + } + return (0); +} + +int +wb782_streinfo(sme, binfo) + struct sysmon_envsys *sme; + struct envsys_basic_info *binfo; +{ + struct lm_softc *sc = sme->sme_cookie; + int divisor; + u_int8_t sdata; + int i; + + if (sc->sensors[binfo->sensor].type == SENSOR_VOLTS_DC) + sc->sensors[binfo->sensor].rfact = binfo->rfact; + else { + if (sc->sensors[binfo->sensor].type == SENSOR_FANRPM) { + if (binfo->rpms == 0) { + binfo->validflags = 0; + return (0); + } + + /* write back the nominal FAN speed */ + sc->sensors[binfo->sensor].rpms = binfo->rpms; + + /* 153 is the nominal FAN speed value */ + divisor = 1350000 / (binfo->rpms * 153); + + /* ...but we need lg(divisor) */ + for (i = 0; i < 7; i++) { + if (divisor <= (1 << i)) + break; + } + divisor = i; + + if (binfo->sensor == 12 || binfo->sensor == 13) { + /* + * FAN1 div is in bits <5:4>, FAN2 div + * is in <7:6> + */ + sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN); + if ( binfo->sensor == 12 ) { /* FAN1 */ + sdata = (sdata & 0xCF) | + ((divisor & 0x3) << 4); + } else { /* FAN2 */ + sdata = (sdata & 0x3F) | + ((divisor & 0x3) << 6); + } + (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata); + } else { + /* FAN3 is in WB_PIN <7:6> */ + sdata = (*sc->lm_readreg)(sc, WB_PIN); + sdata = (sdata & 0x3F) | + ((divisor & 0x3) << 6); + (*sc->lm_writereg)(sc, WB_PIN, sdata); + } + /* Bit 2 of divisor is in WB_BANK0_FANBAT */ + (*sc->lm_banksel)(sc, 0); + sdata = (*sc->lm_readreg)(sc, WB_BANK0_FANBAT); + sdata &= ~(0x20 << (binfo->sensor - 12)); + sdata |= (divisor & 0x4) << (binfo->sensor - 9); + (*sc->lm_writereg)(sc, WB_BANK0_FANBAT, sdata); + } + + memcpy(sc->sensors[binfo->sensor].desc, binfo->desc, + sizeof(sc->sensors[binfo->sensor].desc)); + sc->sensors[binfo->sensor].desc[ + sizeof(sc->sensors[binfo->sensor].desc) - 1] = '\0'; + + binfo->validflags = ENVSYS_FVALID; + } + return (0); +} +#endif + +void +generic_stemp(struct lm_softc *sc, struct sensor *sensor) +{ + int sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7); + + DPRINTF(("sdata[temp] 0x%x\n", sdata)); + /* temp is given in deg. C, we convert to uK */ + sensor->value = sdata * 1000000 + 273150000; +} + +void +generic_svolt(struct lm_softc *sc, struct sensor *sensors) +{ + int i, sdata; + + for (i = 0; i < 7; i++) { + sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i); + DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); + /* voltage returned as (mV >> 4), we convert to uVDC */ + sensors[i].value = (sdata << 4); + /* rfact is (factor * 10^4) */ + sensors[i].value *= sensors[i].rfact; + /* division by 10 gets us back to uVDC */ + sensors[i].value /= 10; + + /* these two are negative voltages */ + if ( (i == 5) || (i == 6) ) + sensors[i].value *= -1; + } +} + +void +generic_fanrpm(struct lm_softc *sc, struct sensor *sensors) +{ + int i, sdata, divisor; + + for (i = 0; i < 3; i++) { + sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 8 + i); + DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); + if (i == 2) + divisor = 2; /* Fixed divisor for FAN3 */ + else if (i == 1) /* Bits 7 & 6 of VID/FAN */ + divisor = ((*sc->lm_readreg)(sc, + LMD_VIDFAN) >> 6) & 0x3; + else + divisor = ((*sc->lm_readreg)(sc, + LMD_VIDFAN) >> 4) & 0x3; + + if (sdata == 0xff || sdata == 0x00) { + sensors[i].value = 0; + } else { + sensors[i].value = 1350000 / (sdata << divisor); + } + } +} + +/* + * pre: last read occurred >= 1.5 seconds ago + * post: sensors[] current data are the latest from the chip + */ +void +lm_refresh_sensor_data(struct lm_softc *sc) +{ + /* Refresh our stored data for every sensor */ + generic_stemp(sc, &sc->sensors[7]); + generic_svolt(sc, &sc->sensors[0]); + generic_fanrpm(sc, &sc->sensors[8]); +} + +void +wb_svolt(struct lm_softc *sc) +{ + int i, sdata; + + for (i = 0; i < 9; ++i) { + if (i < 7) { + sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i); + } else { + /* from bank5 */ + (*sc->lm_banksel)(sc, 5); + sdata = (*sc->lm_readreg)(sc, (i == 7) ? + WB_BANK5_5VSB : WB_BANK5_VBAT); + } + DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); + /* voltage returned as (mV >> 4), we convert to uV */ + sdata = sdata << 4; + /* special case for negative voltages */ + if (i == 5) { + /* + * -12Vdc, assume Winbond recommended values for + * resistors + */ + sdata = ((sdata * 1000) - (3600 * 805)) / 195; + } else if (i == 6) { + /* + * -5Vdc, assume Winbond recommended values for + * resistors + */ + sdata = ((sdata * 1000) - (3600 * 682)) / 318; + } + /* rfact is (factor * 10^4) */ + sc->sensors[i].value = sdata * sc->sensors[i].rfact; + /* division by 10 gets us back to uVDC */ + sc->sensors[i].value /= 10; + } +} + +void +wb_stemp(struct lm_softc *sc, struct sensor *sensors, int n) +{ + int sdata; + + /* temperatures. Given in dC, we convert to uK */ + sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7); + DPRINTF(("sdata[temp0] 0x%x\n", sdata)); + sensors[0].value = sdata * 1000000 + 273150000; + /* from bank1 */ + if ((*sc->lm_banksel)(sc, 1)) { +#if 0 + sensors[1].validflags &= ~ENVSYS_FCURVALID; +#endif + } else { + sdata = (*sc->lm_readreg)(sc, WB_BANK1_T2H) << 1; + sdata |= ((*sc->lm_readreg)(sc, WB_BANK1_T2L) & 0x80) >> 7; + DPRINTF(("sdata[temp1] 0x%x\n", sdata)); + sensors[1].value = (sdata * 1000000) / 2 + 273150000; + } + if (n < 3) + return; + /* from bank2 */ + if ((*sc->lm_banksel)(sc, 2)) { +#if 0 + sensors[2].validflags &= ~ENVSYS_FCURVALID; +#endif + } else { + sdata = (*sc->lm_readreg)(sc, WB_BANK2_T3H) << 1; + sdata |= ((*sc->lm_readreg)(sc, WB_BANK2_T3L) & 0x80) >> 7; + DPRINTF(("sdata[temp2] 0x%x\n", sdata)); + sensors[2].value = (sdata * 1000000) / 2 + 273150000; + } +} + +void +wb781_fanrpm(struct lm_softc *sc, struct sensor *sensors) +{ + int i, divisor, sdata; + + (*sc->lm_banksel)(sc, 0); + for (i = 0; i < 3; i++) { + sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8); + DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); + if (i == 0) + divisor = ((*sc->lm_readreg)(sc, + LMD_VIDFAN) >> 4) & 0x3; + else if (i == 1) + divisor = ((*sc->lm_readreg)(sc, + LMD_VIDFAN) >> 6) & 0x3; + else + divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3; + + DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor)); + if (sdata == 0xff || sdata == 0x00) { + sensors[i].value = 0; + } else { + sensors[i].value = 1350000 / (sdata << divisor); + } + } +} + +void +wb_fanrpm(struct lm_softc *sc, struct sensor *sensors) +{ + int i, divisor, sdata; + + (*sc->lm_banksel)(sc, 0); + for (i = 0; i < 3; i++) { + sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8); + DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); + if (i == 0) + divisor = ((*sc->lm_readreg)(sc, + LMD_VIDFAN) >> 4) & 0x3; + else if (i == 1) + divisor = ((*sc->lm_readreg)(sc, + LMD_VIDFAN) >> 6) & 0x3; + else + divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3; + divisor |= ((*sc->lm_readreg)(sc, + WB_BANK0_FANBAT) >> (i + 3)) & 0x4; + + DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor)); + if (sdata == 0xff || sdata == 0x00) { + sensors[i].value = 0; + } else { + sensors[i].value = 1350000 / (sdata << divisor); + } + } +} + +void +wb781_refresh_sensor_data(struct lm_softc *sc) +{ + /* Refresh our stored data for every sensor */ + /* we need to reselect bank0 to access common registers */ + (*sc->lm_banksel)(sc, 0); + generic_svolt(sc, &sc->sensors[0]); + (*sc->lm_banksel)(sc, 0); + wb_stemp(sc, &sc->sensors[7], 3); + (*sc->lm_banksel)(sc, 0); + wb781_fanrpm(sc, &sc->sensors[10]); +} + +void +wb782_refresh_sensor_data(struct lm_softc *sc) +{ + /* Refresh our stored data for every sensor */ + wb_svolt(sc); + wb_stemp(sc, &sc->sensors[9], 3); + wb_fanrpm(sc, &sc->sensors[12]); +} + +void +wb697_refresh_sensor_data(struct lm_softc *sc) +{ + /* Refresh our stored data for every sensor */ + wb_svolt(sc); + wb_stemp(sc, &sc->sensors[9], 2); + wb_fanrpm(sc, &sc->sensors[11]); +} + +void +lm_refresh(void *arg) +{ + struct lm_softc *sc = (struct lm_softc *)arg; + + sc->refresh_sensor_data(sc); + timeout_add(&lm_timeout, (15 * hz) / 10); +} diff --git a/sys/dev/ic/nslm7xvar.h b/sys/dev/ic/nslm7xvar.h new file mode 100644 index 00000000000..483993fc1e7 --- /dev/null +++ b/sys/dev/ic/nslm7xvar.h @@ -0,0 +1,140 @@ +/* $OpenBSD: nslm7xvar.h,v 1.1 2003/04/25 21:24:15 grange Exp $ */ +/* $NetBSD: nslm7xvar.h,v 1.10 2002/11/15 14:55:42 ad 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. + */ + +#ifndef _DEV_ISA_NSLM7XVAR_H_ +#define _DEV_ISA_NSLM7XVAR_H_ + +/* ctl registers */ + +#define LMC_ADDR 0x05 +#define LMC_DATA 0x06 + +/* data registers */ + +#define LMD_SENSORBASE 0x20 /* Sensors occupy 0x20 -- 0x2a */ + +#define LMD_CONFIG 0x40 /* Configuration */ +#define LMD_ISR1 0x41 /* Interrupt Status 1 */ +#define LMD_ISR2 0x42 /* Interrupt Status 2 */ +#define LMD_SMI1 0x43 /* SMI Mask 1 */ +#define LMD_SMI2 0x44 /* SMI Mask 2 */ +#define LMD_NMI1 0x45 /* NMI Mask 1 */ +#define LMD_NMI2 0x46 /* NMI Mask 2 */ +#define LMD_VIDFAN 0x47 /* VID/Fan Divisor */ +#define LMD_SBUSADDR 0x48 /* Serial Bus Address */ +#define LMD_CHIPID 0x49 /* Chip Reset/ID */ + +/* misc constants */ + +#define LM_NUM_SENSORS 11 +#define LM_ID_LM78 0x00 +#define LM_ID_LM78J 0x40 +#define LM_ID_LM79 0xC0 +#define LM_ID_LM81 0x80 +#define LM_ID_MASK 0xFE + +/* + * additionnal registers for the Winbond chips: + * WB83781D: mostly lm7x compatible; extra temp sensors in bank1 & 2 + * WB83782D & WB83627HF: voltage sensors needs different handling, more FAN + * dividers; mode voltage sensors, more temp sensors. + */ +#define WB_T23ADDR 0x4A /* temp sens 2/3 I2C addr */ +#define WB_PIN 0x4B /* pin & fan3 divider */ +#define WB_BANKSEL 0x4E /* banck select register */ +#define WB_BANKSEL_B0 0x00 /* select bank 0 */ +#define WB_BANKSEL_B1 0x01 /* select bank 1 */ +#define WB_BANKSEL_B2 0x02 /* select bank 2 */ +#define WB_BANKSEL_B3 0x03 /* select bank 3 */ +#define WB_BANKSEL_B4 0x04 /* select bank 4 */ +#define WB_BANKSEL_B5 0x05 /* select bank 5 */ +#define WB_BANKSEL_HBAC 0x80 /* hight byte access */ + +#define WB_VENDID 0x4F /* vendor ID register */ +#define WB_VENDID_WINBOND 0x5CA3 +/* Bank0 regs */ +#define WB_BANK0_CHIPID 0x58 +#define WB_CHIPID_83781 0x10 +#define WB_CHIPID_83781_2 0x11 +#define WB_CHIPID_83782 0x30 +#define WB_CHIPID_83627 0x21 +#define WB_CHIPID_83697 0x60 +#define WB_BANK0_FANBAT 0x5D +/* Bank1 regs */ +#define WB_BANK1_T2H 0x50 +#define WB_BANK1_T2L 0x51 + +/* Bank2 regs */ +#define WB_BANK2_T3H 0x50 +#define WB_BANK2_T3L 0x51 + +/* Bank4 regs 83782/83627 only */ +#define WB_BANK4_T1OFF 0x54 +#define WB_BANK4_T2OFF 0x55 +#define WB_BANK4_T3OFF 0x56 + +/* Bank5 regs 83782/83627 only */ +#define WB_BANK5_5VSB 0x50 +#define WB_BANK5_VBAT 0x51 + +#define WB83781_NUM_SENSORS 13 +#define WB83697_NUM_SENSORS 14 +#define WB_NUM_SENSORS 15 + +struct lm_softc { + struct device sc_dev; + + int lm_iobase; + bus_space_tag_t lm_iot; + bus_space_handle_t lm_ioh; + + int sc_flags; + struct sensor sensors[WB_NUM_SENSORS]; + u_int numsensors; + void (*refresh_sensor_data) (struct lm_softc *); + + int (*lm_banksel)(struct lm_softc *, int); + u_int8_t (*lm_readreg)(struct lm_softc *, int); + void (*lm_writereg)(struct lm_softc *, int, int); +}; + +void lm_attach(struct lm_softc *); +int lm_probe(bus_space_tag_t, bus_space_handle_t); + +#endif /* _DEV_ISA_NSLM7XVAR_H_ */ diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index 88460e81030..f72f71bd10d 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $OpenBSD: files.isa,v 1.82 2002/11/30 15:44:38 mickey Exp $ +# $OpenBSD: files.isa,v 1.83 2003/04/25 21:24:15 grange Exp $ # $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $ # # Config file and device description for machine-independent ISA code. @@ -384,6 +384,10 @@ file dev/isa/midi_pcppi.c midi_pcppi attach lpt at isa with lpt_isa file dev/isa/lpt_isa.c lpt_isa needs-flag +# National Semiconductor LM7[89] and compatible hardware monitors +attach lm at isa with lm_isa +file dev/isa/lm_isa.c lm_isa + # # PCMCIA PCIC (i82365SL and compatibles): # diff --git a/sys/dev/isa/lm_isa.c b/sys/dev/isa/lm_isa.c new file mode 100644 index 00000000000..e9637a78a17 --- /dev/null +++ b/sys/dev/isa/lm_isa.c @@ -0,0 +1,148 @@ +/* $OpenBSD: lm_isa.c,v 1.1 2003/04/25 21:24:15 grange Exp $ */ +/* $NetBSD: lm_isa.c,v 1.9 2002/11/15 14:55:44 ad 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/sensors.h> +#include <machine/bus.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> + +#include <dev/ic/nslm7xvar.h> + +#if defined(LMDEBUG) +#define DPRINTF(x) do { printf x; } while (0) +#else +#define DPRINTF(x) +#endif + +int lm_isa_match(struct device *, void *, void *); +void lm_isa_attach(struct device *, struct device *, void *); +u_int8_t lm_isa_readreg(struct lm_softc *, int); +void lm_isa_writereg(struct lm_softc *, int, int); + +struct cfattach lm_isa_ca = { + sizeof(struct lm_softc), + lm_isa_match, + lm_isa_attach +}; + +int +lm_isa_match(struct device *parent, void *match, void *aux) +{ + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct isa_attach_args *ia = aux; + int iobase; + int rv; + + /* Must supply an address */ + if (ia->ipa_nio < 1) + return (0); + +#ifdef __NetBSD__ + if (ISA_DIRECT_CONFIG(ia)) + return (0); + + if (ia->ipa_io[0].ir_addr == ISACF_PORT_DEFAULT) + return (0); +#endif + + iot = ia->ia_iot; + iobase = ia->ipa_io[0].base; + + if (bus_space_map(iot, iobase, 8, 0, &ioh)) + return (0); + + + /* Bus independent probe */ + rv = lm_probe(iot, ioh); + + bus_space_unmap(iot, ioh, 8); + + if (rv) { + ia->ipa_nio = 1; + ia->ipa_io[0].length = 8; + + ia->ipa_nmem = 0; + ia->ipa_nirq = 0; + ia->ipa_ndrq = 0; + } + + return (rv); +} + +void +lm_isa_attach(struct device *parent, struct device *self, void *aux) +{ + struct lm_softc *lmsc = (void *)self; + int iobase; + bus_space_tag_t iot; + struct isa_attach_args *ia = aux; + + iobase = ia->ipa_io[0].base; + iot = lmsc->lm_iot = ia->ia_iot; + + if (bus_space_map(iot, iobase, 8, 0, &lmsc->lm_ioh)) { + printf(": can't map i/o space\n"); + return; + } + + /* Bus-independant attachment */ + lmsc->lm_writereg = lm_isa_writereg; + lmsc->lm_readreg = lm_isa_readreg; + + lm_attach(lmsc); +} + +u_int8_t +lm_isa_readreg(struct lm_softc *sc, int reg) +{ + bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_ADDR, reg); + return (bus_space_read_1(sc->lm_iot, sc->lm_ioh, LMC_DATA)); +} + +void +lm_isa_writereg(struct lm_softc *sc, int reg, int val) +{ + bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_ADDR, reg); + bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_DATA, val); +} |