diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-03-19 19:33:13 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-03-19 19:33:13 +0000 |
commit | bca7dc9919620723627d081efe61087b7891051a (patch) | |
tree | d63ab83b15cac9d4bde8fabdaa1392f9c5307c46 | |
parent | 12418e0de2c157eeeb1327c96be267760732809f (diff) |
Driver for Fintek F71805F LPC sensor based on lm78 driver code;
written by Geoff Steckel
-rw-r--r-- | share/man/man4/Makefile | 4 | ||||
-rw-r--r-- | share/man/man4/fins.4 | 50 | ||||
-rw-r--r-- | share/man/man4/isa.4 | 6 | ||||
-rw-r--r-- | sys/dev/isa/files.isa | 7 | ||||
-rw-r--r-- | sys/dev/isa/fins.c | 416 |
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; + } +} |