diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2010-02-23 21:04:17 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2010-02-23 21:04:17 +0000 |
commit | aab571f6ba429ac0a816e6d586e80a99f56cbe0e (patch) | |
tree | 3d52bb51b8d3d236f9e871a5b3408f7b1eac29bf /sys/arch | |
parent | dc07dcdb13d83e0bd90779224df9e92d727cb04e (diff) |
ykbec(4), a driver to read fan, temperature and battery status using
the kb3310b embedded controller chip on the yeeloong. With help & ok miod@
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/loongson/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/arch/loongson/conf/files.loongson | 7 | ||||
-rw-r--r-- | sys/arch/loongson/dev/kb3310.c | 298 | ||||
-rw-r--r-- | sys/arch/loongson/loongson/yeeloong_machdep.c | 4 |
4 files changed, 309 insertions, 3 deletions
diff --git a/sys/arch/loongson/conf/GENERIC b/sys/arch/loongson/conf/GENERIC index 00e522f1ecc..a1e49082624 100644 --- a/sys/arch/loongson/conf/GENERIC +++ b/sys/arch/loongson/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.12 2010/02/19 15:14:19 miod Exp $ +# $OpenBSD: GENERIC,v 1.13 2010/02/23 21:04:16 otto Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -44,6 +44,7 @@ pckbd* at pckbc? # Yeeloong only wskbd* at pckbd? mux 1 # Yeeloong only pmsi* at pckbc? # Yeeloong only wsmouse* at pmsi? mux 0 # Yeeloong only +ykbec0 at isa? port 0x381 # Yeeloong only com0 at isa? port 0x2f8 irq 3 # Fuloong 2F only pciide* at pci? wd* at pciide? flags 0x0000 diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson index e154a67395c..6e020c959c2 100644 --- a/sys/arch/loongson/conf/files.loongson +++ b/sys/arch/loongson/conf/files.loongson @@ -1,4 +1,4 @@ -# $OpenBSD: files.loongson,v 1.4 2010/02/19 00:21:43 miod Exp $ +# $OpenBSD: files.loongson,v 1.5 2010/02/23 21:04:16 otto Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -73,6 +73,11 @@ attach mcclock at isa with mcclock_isa file arch/loongson/dev/mcclock.c mcclock file arch/loongson/dev/mcclock_isa.c mcclock_isa +# Lemote Yeeloong KB3310B Embedded Controller +device ykbec +attach ykbec at isa +file arch/loongson/dev/kb3310.c ykbec + # Silicon Motion SM502 master device device voyager {}: gpiobus attach voyager at pci diff --git a/sys/arch/loongson/dev/kb3310.c b/sys/arch/loongson/dev/kb3310.c new file mode 100644 index 00000000000..84ba918be34 --- /dev/null +++ b/sys/arch/loongson/dev/kb3310.c @@ -0,0 +1,298 @@ +/* $OpenBSD: kb3310.c,v 1.1 2010/02/23 21:04:16 otto Exp $ */ +/* + * Copyright (c) 2010 Otto Moerbeek <otto@drijf.net> + * + * 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/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/sensors.h> + +#include <machine/bus.h> +#include <dev/isa/isavar.h> + +struct cfdriver ykbec_cd = { + NULL, "ykbec", DV_DULL, +}; + +#define IO_YKBEC 0x381 +#define IO_YKBECSIZE 0x3 + +#define KB3310_NUM_SENSORS 10 + +struct ykbec_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + struct ksensor sc_sensor[KB3310_NUM_SENSORS]; + struct ksensordev sc_sensordev; + +}; + +int ykbec_match(struct device *, void *, void *); +void ykbec_attach(struct device *, struct device *, void *); +void ykbec_refresh(void *arg); + +const struct cfattach ykbec_ca = { + sizeof(struct ykbec_softc), ykbec_match, ykbec_attach +}; + +void ykbec_write(struct ykbec_softc *, u_int, u_int); +u_int ykbec_read(struct ykbec_softc *, u_int); +u_int ykbec_read16(struct ykbec_softc *, u_int); + +int +ykbec_match(struct device *parent, void *match, void *aux) +{ + struct isa_attach_args *ia = aux; + bus_space_handle_t ioh; + + if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_YKBEC) || + /* (ia->ia_iosize != 0 && ia->ia_iosize != IO_YKBECSIZE) || XXX isa.c */ + ia->ia_maddr != MADDRUNK || ia->ia_msize != 0 || + ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK) + return (0); + + if (bus_space_map(ia->ia_iot, IO_YKBEC, IO_YKBECSIZE, 0, &ioh)) + return (0); + + bus_space_unmap(ia->ia_iot, ioh, IO_YKBECSIZE); + + ia->ia_iobase = IO_YKBEC; + ia->ia_iosize = IO_YKBECSIZE; + + return (1); +} + + +void +ykbec_attach( struct device *parent, struct device *self, void *aux) +{ + struct isa_attach_args *ia = aux; + struct ykbec_softc *sc = (struct ykbec_softc *)self; + + sc->sc_iot = ia->ia_iot; + if (bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, 0, + &sc->sc_ioh)) { + printf(": couldn't map I/O space"); + return; + } + + /* Initialize sensor data. */ + strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, + sizeof(sc->sc_sensordev.xname)); + if (sensor_task_register(sc, ykbec_refresh, 5) == NULL) { + printf(", unable to register update task\n"); + return; + } + sc->sc_sensor[0].type = SENSOR_FANRPM; + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[0]); + + sc->sc_sensor[1].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[1].desc, "Internal temperature", + sizeof(sc->sc_sensor[1].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[1]); + + sc->sc_sensor[2].type = SENSOR_AMPHOUR; + strlcpy(sc->sc_sensor[2].desc, "Battery design capacity", + sizeof(sc->sc_sensor[2].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[2]); + + sc->sc_sensor[3].type = SENSOR_AMPHOUR; + strlcpy(sc->sc_sensor[3].desc, "Battery full charge capacity", + sizeof(sc->sc_sensor[3].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[3]); + + sc->sc_sensor[4].type = SENSOR_VOLTS_DC; + strlcpy(sc->sc_sensor[4].desc, "Battery design voltage", + sizeof(sc->sc_sensor[4].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[4]); + + sc->sc_sensor[5].type = SENSOR_AMPS; + strlcpy(sc->sc_sensor[5].desc, "Battery current", + sizeof(sc->sc_sensor[5].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[5]); + + sc->sc_sensor[6].type = SENSOR_VOLTS_DC; + strlcpy(sc->sc_sensor[6].desc, "Battery voltage", + sizeof(sc->sc_sensor[6].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[6]); + + sc->sc_sensor[7].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[7].desc, "Battery temperature", + sizeof(sc->sc_sensor[7].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[7]); + + sc->sc_sensor[8].type = SENSOR_PERCENT; + strlcpy(sc->sc_sensor[8].desc, "Battery capacity", + sizeof(sc->sc_sensor[8].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[8]); + + sc->sc_sensor[9].type = SENSOR_INTEGER; + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[9]); + + sensordev_install(&sc->sc_sensordev); + + printf("\n"); +} + +void +ykbec_write(struct ykbec_softc *mcsc, u_int reg, u_int datum) +{ + struct ykbec_softc *sc = (struct ykbec_softc *)mcsc; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff); + bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff); + bus_space_write_1(iot, ioh, 2, datum); +} + +u_int +ykbec_read(struct ykbec_softc *mcsc, u_int reg) +{ + struct ykbec_softc *sc = (struct ykbec_softc *)mcsc; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + bus_space_write_1(iot, ioh, 0, (reg >> 8) & 0xff); + bus_space_write_1(iot, ioh, 1, (reg >> 0) & 0xff); + return bus_space_read_1(iot, ioh, 2); +} + +u_int +ykbec_read16(struct ykbec_softc *mcsc, u_int reg) +{ + u_int val; + + val = ykbec_read(mcsc, reg); + return (val << 8) | ykbec_read(mcsc, reg + 1); +} + +#define KB3310_FAN_SPEED_DIVIDER 480000 + +#define ECTEMP_CURRENT_REG 0xf458 +#define REG_FAN_SPEED_HIGH 0xfe22 +#define REG_FAN_SPEED_LOW 0xfe23 + +#define REG_DESIGN_CAP_HIGH 0xf77d +#define REG_DESIGN_CAP_LOW 0xf77e +#define REG_FULLCHG_CAP_HIGH 0xf780 +#define REG_FULLCHG_CAP_LOW 0xf781 + +#define REG_DESIGN_VOL_HIGH 0xf782 +#define REG_DESIGN_VOL_LOW 0xf783 +#define REG_CURRENT_HIGH 0xf784 +#define REG_CURRENT_LOW 0xf785 +#define REG_VOLTAGE_HIGH 0xf786 +#define REG_VOLTAGE_LOW 0xf787 +#define REG_TEMPERATURE_HIGH 0xf788 +#define REG_TEMPERATURE_LOW 0xf789 +#define REG_RELATIVE_CAT_HIGH 0xf492 +#define REG_RELATIVE_CAT_LOW 0xf493 +#define REG_BAT_VENDOR 0xf4c4 +#define REG_BAT_CELL_COUNT 0xf4c6 +#define REG_BAT_CHARGE 0xf4a2 +#define REG_POWER_FLAG 0xf440 + +#define REG_BAT_STATUS 0xf4b0 +#define BAT_STATUS_BAT_EXISTS (1<<0) +#define BAT_STATUS_BAT_FULL (1<<1) +#define BAT_STATUS_BAT_DESTROY (1<<2) +#define BAT_STATUS_BAT_LOW (1<<5) + +#define REG_CHARGE_STATUS 0xf4b1 +#define CHARGE_STATUS_PRECHARGE (1<<1) +#define CHARGE_STATUS_OVERHEAT (1<<2) + +#define REG_BAT_STATE 0xf482 +#define BAT_STATE_DISCHARGING (1<<0) +#define BAT_STATE_CHARGING (1<<1) + +const char *REG_BAT_CHARGE_state[] = { + "AC-power", "Battery discharging", "Battery charging" +}; + +#define STATUS(a, i) ((i) >= nitems(a) ? "unknown" : (a)[i]) + +void +ykbec_refresh(void *arg) +{ + struct ykbec_softc *sc = (struct ykbec_softc *)arg; + u_int val; + int current; + + val = ykbec_read16(sc, REG_FAN_SPEED_HIGH); + if (val != 0) + val = KB3310_FAN_SPEED_DIVIDER / val; + else + val = UINT_MAX; + sc->sc_sensor[0].value = val; + + val = ykbec_read(sc, ECTEMP_CURRENT_REG); + sc->sc_sensor[1].value = val * 1000000 + 273150000; + + sc->sc_sensor[2].value = ykbec_read16(sc, REG_DESIGN_CAP_HIGH) * 1000; + sc->sc_sensor[3].value = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH) * 1000; + sc->sc_sensor[4].value = ykbec_read16(sc, REG_DESIGN_VOL_HIGH) * 1000; + current = ykbec_read16(sc, REG_CURRENT_HIGH); + if (current & 0x8000) + sc->sc_sensor[5].value = (0xffff - current) * 1000; + else + sc->sc_sensor[5].value = current * 1000; + sc->sc_sensor[6].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) * 1000; + + val = ykbec_read16(sc, REG_TEMPERATURE_HIGH); + sc->sc_sensor[7].value = val * 1000000 + 273150000; + + sc->sc_sensor[8].value = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH) * 1000; + + val = ykbec_read(sc, REG_BAT_CHARGE); + strlcpy(sc->sc_sensor[9].desc, STATUS(REG_BAT_CHARGE_state, val), + sizeof(sc->sc_sensor[9].desc)); + + val = (val << 8) | ykbec_read(sc, REG_BAT_STATUS); + if (!(val & BAT_STATUS_BAT_EXISTS)) + strlcat(sc->sc_sensor[9].desc, ",not available", + sizeof(sc->sc_sensor[9].desc)); + if (val & BAT_STATUS_BAT_FULL) + strlcat(sc->sc_sensor[9].desc, ",full", + sizeof(sc->sc_sensor[9].desc)); + if (val & BAT_STATUS_BAT_DESTROY) + strlcat(sc->sc_sensor[9].desc, ",bad", + sizeof(sc->sc_sensor[9].desc)); + if (val & BAT_STATUS_BAT_LOW) + strlcat(sc->sc_sensor[9].desc, ",low", + sizeof(sc->sc_sensor[9].desc)); + + val = (val << 8) | ykbec_read(sc, REG_CHARGE_STATUS); + if (val & CHARGE_STATUS_PRECHARGE) + strlcat(sc->sc_sensor[9].desc, ",precharge", + sizeof(sc->sc_sensor[9].desc)); + if (val & CHARGE_STATUS_OVERHEAT) + strlcat(sc->sc_sensor[9].desc, ",overheat", + sizeof(sc->sc_sensor[9].desc)); +#if 0 + val = ykbec_read(sc, REG_BAT_STATE); + if (val & BAT_STATE_CHARGING) + strlcat(sc->sc_sensor[9].desc, ",charging", + sizeof(sc->sc_sensor[9].desc)); + if (val & BAT_STATE_DISCHARGING) + strlcat(sc->sc_sensor[9].desc, ",discharging", + sizeof(sc->sc_sensor[9].desc)); +#endif + sc->sc_sensor[9].value = val; +} diff --git a/sys/arch/loongson/loongson/yeeloong_machdep.c b/sys/arch/loongson/loongson/yeeloong_machdep.c index f8407469b63..6b658684bd0 100644 --- a/sys/arch/loongson/loongson/yeeloong_machdep.c +++ b/sys/arch/loongson/loongson/yeeloong_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: yeeloong_machdep.c,v 1.6 2010/02/16 21:31:36 miod Exp $ */ +/* $OpenBSD: yeeloong_machdep.c,v 1.7 2010/02/23 21:04:16 otto Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -103,6 +103,8 @@ const struct legacy_io_range yeeloong_legacy_ranges[] = { { 0x1f0, 0x1f0 + 7 }, { 0x376, 0x376 }, { 0x3f6, 0x3f6 }, + /* kb3110b embedded controller */ + { 0x381, 0x383 }, { 0 } }; |