summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2008-03-19 19:33:13 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2008-03-19 19:33:13 +0000
commitbca7dc9919620723627d081efe61087b7891051a (patch)
treed63ab83b15cac9d4bde8fabdaa1392f9c5307c46
parent12418e0de2c157eeeb1327c96be267760732809f (diff)
Driver for Fintek F71805F LPC sensor based on lm78 driver code;
written by Geoff Steckel
-rw-r--r--share/man/man4/Makefile4
-rw-r--r--share/man/man4/fins.450
-rw-r--r--share/man/man4/isa.46
-rw-r--r--sys/dev/isa/files.isa7
-rw-r--r--sys/dev/isa/fins.c416
5 files changed, 478 insertions, 5 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index bd97fce082c..db7f45f0527 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.442 2008/02/17 15:12:30 kettenis Exp $
+# $OpenBSD: Makefile,v 1.443 2008/03/19 19:33:12 deraadt Exp $
MAN= aac.4 ac97.4 acphy.4 \
acpi.4 acpiac.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \
@@ -18,7 +18,7 @@ MAN= aac.4 ac97.4 acphy.4 \
drum.4 eap.4 ec.4 eephy.4 ef.4 eg.4 ehci.4 eisa.4 el.4 em.4 \
emu.4 enc.4 envy.4 ep.4 epic.4 esa.4 \
eso.4 ess.4 et.4 etphy.4 ex.4 exphy.4 \
- faith.4 fd.4 fdc.4 fintek.4 fms.4 fpa.4 fxp.4 gdt.4 \
+ faith.4 fd.4 fdc.4 fins.4 fintek.4 fms.4 fpa.4 fxp.4 gdt.4 \
gentbi.4 gem.4 gif.4 \
glenv.4 gpio.4 gpioiic.4 gpioow.4 gpr.4 gre.4 gscsio.4 gtp.4 \
hifn.4 hil.4 hilid.4 hilkbd.4 hilms.4 hme.4 hotplug.4 hsq.4 \
diff --git a/share/man/man4/fins.4 b/share/man/man4/fins.4
new file mode 100644
index 00000000000..87e34398908
--- /dev/null
+++ b/share/man/man4/fins.4
@@ -0,0 +1,50 @@
+.\" $OpenBSD: fins.4,v 1.1 2008/03/19 19:33:12 deraadt Exp $
+.\"
+.\" Copyright (c) 2005 Alexander Yurchenko <grange@openbsd.org>
+.\"
+.\" 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.
+.\"
+.Dd $Mdocdate: March 19 2008 $
+.Dt FINS 4
+.Os
+.Sh NAME
+.Nm fins
+.Nd Fintek F71805F LPC Super I/O
+.Sh SYNOPSIS
+.Cd "fins0 at isa? port 0x4e"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the Fintek F71805F LPC Super I/O IC.
+.Pp
+The hardware monitor provides hardware monitoring capabilities
+to be used with the
+.Xr sysctl 8
+interface.
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr isa 4 ,
+.Xr watchdog 4 ,
+.Xr sensorsd 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 3.8 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Geoff Steckel .
+
diff --git a/share/man/man4/isa.4 b/share/man/man4/isa.4
index 0165ba62a27..a211140283c 100644
--- a/share/man/man4/isa.4
+++ b/share/man/man4/isa.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: isa.4,v 1.59 2008/02/17 16:48:47 jmc Exp $
+.\" $OpenBSD: isa.4,v 1.60 2008/03/19 19:33:12 deraadt Exp $
.\" $NetBSD: isa.4,v 1.19 2000/03/18 16:54:37 augustss Exp $
.\"
.\" Copyright (c) 2000 Theo de Raadt. All rights reserved.
@@ -31,7 +31,7 @@
.\" (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 $Mdocdate: February 17 2008 $
+.Dd $Mdocdate: March 19 2008 $
.Dt ISA 4
.Os
.Sh NAME
@@ -191,6 +191,8 @@ SoundForte RadioLink SF16-FMR2 FM radio device
.Bl -tag -width 12n -offset ind -compact
.It Xr aps 4
ThinkPad Active Protection System accelerometer
+.It Xr fins 4
+Fintek F71805F LPC Super I/O
.It Xr it 4
ITE IT8705F/IT8712F/IT8716F/IT8718F/IT8726F and SiS SiS950
temperature, voltage, and fan sensor with watchdog timer
diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa
index c9c510baaca..dfb691729eb 100644
--- a/sys/dev/isa/files.isa
+++ b/sys/dev/isa/files.isa
@@ -1,4 +1,4 @@
-# $OpenBSD: files.isa,v 1.101 2008/02/17 15:04:08 kettenis Exp $
+# $OpenBSD: files.isa,v 1.102 2008/03/19 19:33:09 deraadt 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.
@@ -346,6 +346,11 @@ attach lm at isa with lm_isa
attach lm at wbsio with lm_wbsio
file dev/isa/lm78_isa.c lm_isa | lm_wbsio
+# Fintek (Feature Integration Technology) F71805F hardware monitor subfunction
+device fins
+attach fins at isa
+file dev/isa/fins.c fins
+
# NSC PC87366 Super IO / monitor chip
device nsclpcsio: gpiobus
attach nsclpcsio at isa with nsclpcsio_isa
diff --git a/sys/dev/isa/fins.c b/sys/dev/isa/fins.c
new file mode 100644
index 00000000000..04e3674d406
--- /dev/null
+++ b/sys/dev/isa/fins.c
@@ -0,0 +1,416 @@
+/* $OpenBSD: fins.c,v 1.1 2008/03/19 19:33:09 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2005, 2006 Mark Kettenis
+ * Copyright (c) 2007, 2008 Geoff Steckel
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/sensors.h>
+#include <machine/bus.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+
+/* Derived from LM78 code. Only handles chips attached to ISA bus */
+
+/*
+ * Fintek F71805 registers and constants
+ * http://www.fintek.com.tw/files/productfiles/F71805F_V025.pdf
+ * This chip is a multi-io chip with many functions.
+ * Each function may be relocated in I/O space by the BIOS.
+ * The base address (2E or 4E) accesses a configuration space which
+ * has pointers to the individual functions. The config space must be
+ * unlocked with a cookie and relocked afterwards. The chip ID is stored
+ * in config space so it is not normally visible.
+ *
+ * We assume that the monitor is enabled. We don't try to start or stop it.
+ * The voltage dividers specified are from reading the chips on one board.
+ * There is no way to determine what they are in the general case.
+ * This section of the chip controls the fans. We don't do anything to them.
+ */
+
+
+#define FINS_UNLOCK 0x87 /* magic constant - write 2x to select chip */
+#define FINS_LOCK 0xaa /* magic constant - write 1x to deselect reg */
+
+#define FINS_FUNC_SEL 0x07 /* select which subchip to access */
+# define FINS_FUNC_SENSORS 0x4
+
+/* ISA registers index to an internal register space on chip */
+#define FINS_ADDR 0x00
+#define FINS_DATA 0x01
+
+/* Chip identification regs and values in bank 0 */
+#define FINS_MANUF 0x23 /* manufacturer ID */
+# define FINTEK_ID 0x1934
+#define FINS_CHIP 0x20 /* chip ID */
+# define FINS_ID 0x0406
+
+/* in bank sensors of config space */
+#define FINS_SENSADDR 0x60 /* sensors assigned I/O address (2 bytes) */
+
+/* in sensors space */
+#define FINS_TMODE 0x01 /* temperature mode reg */
+
+#define FINS_MAX_SENSORS 20
+/*
+ * Fintek chips typically measure voltages using 8mv steps.
+ * 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 FRFACT_NONE 8000
+#define FRFACT(x, y) (FRFACT_NONE * ((x) + (y)) / (y))
+#define FNRFACT(x, y) (-FRFACT_NONE * (x) / (y))
+
+#if defined(FINSDEBUG)
+#define DPRINTF(x) do { printf x; } while (0)
+#else
+#define DPRINTF(x)
+#endif
+
+struct fins_softc;
+
+struct fins_sensor {
+ char *fs_desc;
+ enum sensor_type fs_type;
+ u_int8_t fs_aux;
+ u_int8_t fs_reg;
+ void (*fs_refresh)(struct fins_softc *, int);
+ int fs_rfact;
+};
+
+struct fins_softc {
+ struct device sc_dev;
+
+ struct ksensor fins_ksensors[FINS_MAX_SENSORS];
+ struct ksensordev fins_sensordev;
+ struct sensor_task *fins_sensortask;
+ struct fins_sensor *fins_sensors;
+ u_int fins_numsensors;
+ void (*refresh_sensor_data) (struct fins_softc *);
+
+ u_int8_t (*fins_readreg)(struct fins_softc *, int);
+ void (*fins_writereg)(struct fins_softc *, int, int);
+ u_int fins_tempsel;
+};
+
+
+struct fins_isa_softc {
+ struct fins_softc sc_finssc;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+int fins_isa_match(struct device *, void *, void *);
+void fins_isa_attach(struct device *, struct device *, void *);
+u_int8_t fins_isa_readreg(struct fins_softc *, int);
+void fins_isa_writereg(struct fins_softc *, int, int);
+
+void fins_setup_sensors(struct fins_softc *, struct fins_sensor *);
+void fins_refresh(void *);
+
+void fins_refresh_volt(struct fins_softc *, int);
+void fins_refresh_temp(struct fins_softc *, int);
+void fins_refresh_offset(struct fins_softc *, int);
+void fins_refresh_fanrpm(struct fins_softc *, int);
+void fins_attach(struct fins_softc *);
+int fins_detach(struct fins_softc *);
+
+struct cfattach fins_ca = {
+ sizeof(struct fins_isa_softc),
+ fins_isa_match,
+ fins_isa_attach
+};
+
+struct cfdriver fins_cd = {
+ NULL, "fins", DV_DULL
+};
+
+struct fins_sensor fins_sensors[] = {
+ /* Voltage */
+ { "+3.3V", SENSOR_VOLTS_DC, 0, 0x10, fins_refresh_volt, FRFACT(100, 100) },
+ { "Vtt", SENSOR_VOLTS_DC, 0, 0x11, fins_refresh_volt, FRFACT_NONE },
+ { "Vram", SENSOR_VOLTS_DC, 0, 0x12, fins_refresh_volt, FRFACT(100, 100) },
+ { "Vchips", SENSOR_VOLTS_DC, 0, 0x13, fins_refresh_volt, FRFACT(47, 100) },
+ { "+5V", SENSOR_VOLTS_DC, 0, 0x14, fins_refresh_volt, FRFACT(200, 47) },
+ { "+12V", SENSOR_VOLTS_DC, 0, 0x15, fins_refresh_volt, FRFACT(200, 20) },
+ { "Vcc 1.5V", SENSOR_VOLTS_DC, 0, 0x16, fins_refresh_volt, FRFACT_NONE },
+ { "VCore", SENSOR_VOLTS_DC, 0, 0x17, fins_refresh_volt, FRFACT_NONE },
+ { "Vsb", SENSOR_VOLTS_DC, 0, 0x18, fins_refresh_volt, FRFACT(200, 47) },
+ { "Vsbint", SENSOR_VOLTS_DC, 0, 0x19, fins_refresh_volt, FRFACT(200, 47) },
+ { "Vbat", SENSOR_VOLTS_DC, 0, 0x1A, fins_refresh_volt, FRFACT(200, 47) },
+
+ /* Temperature */
+ { "Temp1", SENSOR_TEMP, 0x01, 0x1B, fins_refresh_temp },
+ { "Temp2", SENSOR_TEMP, 0x02, 0x1C, fins_refresh_temp },
+ { "Temp3", SENSOR_TEMP, 0x04, 0x1D, fins_refresh_temp },
+
+ /* Fans */
+ { "Fan1", SENSOR_FANRPM, 0, 0x20, fins_refresh_fanrpm },
+ { "Fan2", SENSOR_FANRPM, 0, 0x22, fins_refresh_fanrpm },
+ { "Fan3", SENSOR_FANRPM, 0, 0x24, fins_refresh_fanrpm },
+
+ { NULL }
+};
+
+
+int
+fins_isa_match(struct device *parent, void *match, void *aux)
+{
+ bus_space_tag_t iot;
+ bus_addr_t iobase;
+ bus_space_handle_t ioh;
+ struct isa_attach_args *ia = aux;
+ u_int val;
+
+ iot = ia->ia_iot;
+ iobase = ia->ipa_io[0].base;
+
+ if (bus_space_map(iot, iobase, 2, 0, &ioh))
+ return (0);
+
+ /* Fintek uses magic cookie locks to distinguish their chips */
+ bus_space_write_1(iot, ioh, 0, FINS_UNLOCK);
+ bus_space_write_1(iot, ioh, 0, FINS_UNLOCK);
+ bus_space_write_1(iot, ioh, 0, FINS_FUNC_SEL);
+ bus_space_write_1(iot, ioh, 1, 0); /* IDs appear only in space 0 */
+ bus_space_write_1(iot, ioh, 0, FINS_MANUF);
+ val = bus_space_read_1(iot, ioh, 1) << 8;
+ bus_space_write_1(iot, ioh, 0, FINS_MANUF + 1);
+ val |= bus_space_read_1(iot, ioh, 1);
+ if (val != FINTEK_ID) {
+ bus_space_write_1(iot, ioh, 0, FINS_LOCK);
+ goto notfound;
+ }
+ bus_space_write_1(iot, ioh, 0, FINS_CHIP);
+ val = bus_space_read_1(iot, ioh, 1) << 8;
+ bus_space_write_1(iot, ioh, 0, FINS_CHIP + 1);
+ val |= bus_space_read_1(iot, ioh, 1);
+ /* If we cared which Fintek chip this was we would save the chip ID here */
+ if (val != FINS_ID) {
+ bus_space_write_1(iot, ioh, 0, FINS_LOCK);
+ goto notfound;
+ }
+ /* select sensor function of the chip */
+ bus_space_write_1(iot, ioh, FINS_ADDR, FINS_FUNC_SEL);
+ bus_space_write_1(iot, ioh, FINS_DATA, FINS_FUNC_SENSORS);
+ /* read I/O address assigned by BIOS to this function */
+ bus_space_write_1(iot, ioh, FINS_ADDR, FINS_SENSADDR);
+ val = bus_space_read_1(iot, ioh, FINS_DATA) << 8;
+ bus_space_write_1(iot, ioh, FINS_ADDR, FINS_SENSADDR + 1);
+ val |= bus_space_read_1(iot, ioh, FINS_DATA);
+ bus_space_write_1(iot, ioh, 0, FINS_LOCK);
+ ia->ipa_io[1].length = 2;
+ ia->ipa_io[1].base = val;
+
+ bus_space_unmap(iot, ioh, 2);
+ ia->ipa_nio = 2;
+ ia->ipa_io[0].length = 2;
+ ia->ipa_nmem = 0;
+ ia->ipa_nirq = 0;
+ ia->ipa_ndrq = 0;
+ return (1);
+
+ notfound:
+ bus_space_unmap(iot, ioh, 2);
+ return (0);
+}
+
+void
+fins_isa_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fins_isa_softc *sc = (struct fins_isa_softc *)self;
+ struct isa_attach_args *ia = aux;
+ bus_addr_t iobase;
+
+ sc->sc_iot = ia->ia_iot;
+ iobase = ia->ipa_io[1].base;
+ sc->sc_finssc.fins_writereg = fins_isa_writereg;
+ sc->sc_finssc.fins_readreg = fins_isa_readreg;
+ if (bus_space_map(sc->sc_iot, iobase, 2, 0, &sc->sc_ioh)) {
+ printf(": can't map i/o space\n");
+ return;
+ }
+ fins_attach(&sc->sc_finssc);
+}
+
+u_int8_t
+fins_isa_readreg(struct fins_softc *lmsc, int reg)
+{
+ struct fins_isa_softc *sc = (struct fins_isa_softc *)lmsc;
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, FINS_ADDR, reg);
+ return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, FINS_DATA));
+}
+
+void
+fins_isa_writereg(struct fins_softc *lmsc, int reg, int val)
+{
+ struct fins_isa_softc *sc = (struct fins_isa_softc *)lmsc;
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, FINS_ADDR, reg);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, FINS_DATA, val);
+}
+
+void
+fins_attach(struct fins_softc *sc)
+{
+ u_int i;
+
+ fins_setup_sensors(sc, fins_sensors);
+ sc->fins_sensortask = sensor_task_register(sc, fins_refresh, 5);
+ if (sc->fins_sensortask == NULL) {
+ printf(": unable to register update task\n");
+ return;
+ }
+
+ printf("\n");
+ /* Add sensors */
+ for (i = 0; i < sc->fins_numsensors; ++i)
+ sensor_attach(&sc->fins_sensordev, &sc->fins_ksensors[i]);
+ sensordev_install(&sc->fins_sensordev);
+}
+
+int
+fins_detach(struct fins_softc *sc)
+{
+ int i;
+
+ /* Remove sensors */
+ sensordev_deinstall(&sc->fins_sensordev);
+ for (i = 0; i < sc->fins_numsensors; i++)
+ sensor_detach(&sc->fins_sensordev, &sc->fins_ksensors[i]);
+
+ if (sc->fins_sensortask != NULL)
+ sensor_task_unregister(sc->fins_sensortask);
+
+ return 0;
+}
+
+
+void
+fins_setup_sensors(struct fins_softc *sc, struct fins_sensor *sensors)
+{
+ int i;
+ struct ksensor *ksensor = sc->fins_ksensors;
+
+ strlcpy(sc->fins_sensordev.xname, sc->sc_dev.dv_xname,
+ sizeof(sc->fins_sensordev.xname));
+
+ for (i = 0; sensors[i].fs_desc; i++) {
+ ksensor[i].type = sensors[i].fs_type;
+ strlcpy(ksensor[i].desc, sensors[i].fs_desc,
+ sizeof(ksensor[i].desc));
+ }
+ sc->fins_numsensors = i;
+ sc->fins_sensors = sensors;
+ sc->fins_tempsel = sc->fins_readreg(sc, FINS_TMODE);
+}
+
+void
+fins_refresh(void *arg)
+{
+ struct fins_softc *sc = arg;
+ int i;
+
+ for (i = 0; i < sc->fins_numsensors; i++)
+ sc->fins_sensors[i].fs_refresh(sc, i);
+}
+
+void
+fins_refresh_volt(struct fins_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->fins_ksensors[n];
+ struct fins_sensor *fs = &sc->fins_sensors[n];
+ int data;
+
+ data = sc->fins_readreg(sc, fs->fs_reg);
+ if (data == 0xff || data == 0) {
+ sensor->flags |= SENSOR_FINVALID;
+ sensor->value = 0;
+ } else {
+ sensor->flags &= ~SENSOR_FINVALID;
+ sensor->value = data * fs->fs_rfact;
+ }
+}
+
+/* The BIOS seems to add a fudge factor to the CPU temp of +5C */
+void
+fins_refresh_temp(struct fins_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->fins_ksensors[n];
+ struct fins_sensor *fs = &sc->fins_sensors[n];
+ u_int data;
+ u_int max;
+
+ /*
+ * The data sheet says that the range of the temperature
+ * sensor is between 0 and 127 or 140 degrees C depending on
+ * what kind of sensor is used.
+ * A disconnected sensor seems to read over 110 or so.
+ */
+ data = sc->fins_readreg(sc, fs->fs_reg) & 0xFF;
+ max = (sc->fins_tempsel & fs->fs_aux) ? 111 : 128;
+ if (data == 0 || data >= max) { /* disconnected? */
+ sensor->flags |= SENSOR_FINVALID;
+ sensor->value = 0;
+ } else {
+ sensor->flags &= ~SENSOR_FINVALID;
+ sensor->value = data * 1000000 + 273150000;
+ }
+}
+
+/* The chip holds a fudge factor for BJT sensors */
+/* this is currently unused but might be reenabled */
+void
+fins_refresh_offset(struct fins_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->fins_ksensors[n];
+ struct fins_sensor *fs = &sc->fins_sensors[n];
+ u_int data;
+
+ sensor->flags &= ~SENSOR_FINVALID;
+ data = sc->fins_readreg(sc, fs->fs_reg);
+ data |= ~0 * (data & 0x40); /* sign extend 7-bit value */
+ sensor->value = data * 1000000 + 273150000;
+}
+
+
+/* fan speed appears to be a 12-bit number */
+void
+fins_refresh_fanrpm(struct fins_softc *sc, int n)
+{
+ struct ksensor *sensor = &sc->fins_ksensors[n];
+ struct fins_sensor *fs = &sc->fins_sensors[n];
+ int data;
+
+ data = sc->fins_readreg(sc, fs->fs_reg) << 8;
+ data |= sc->fins_readreg(sc, fs->fs_reg + 1);
+ if (data >= 0xfff) {
+ sensor->value = 0;
+ sensor->flags |= SENSOR_FINVALID;
+ } else {
+ sensor->value = 1500000 / data;
+ sensor->flags &= ~SENSOR_FINVALID;
+ }
+}