diff options
author | Alexander Yurchenko <grange@cvs.openbsd.org> | 2003-04-25 21:24:16 +0000 |
---|---|---|
committer | Alexander Yurchenko <grange@cvs.openbsd.org> | 2003-04-25 21:24:16 +0000 |
commit | 466ee8c6198a516a8f1b939ae30f5655d0a62d8f (patch) | |
tree | 2b9e26a3ecf3055afb02d8b4138d925faf365388 /sys/dev/ic/nslm7x.c | |
parent | 55ec66eda5c4342eb5a7c9502876e3d6ac6a0464 (diff) |
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/dev/ic/nslm7x.c')
-rw-r--r-- | sys/dev/ic/nslm7x.c | 850 |
1 files changed, 850 insertions, 0 deletions
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); +} |