diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2010-02-24 22:16:19 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2010-02-24 22:16:19 +0000 |
commit | 27eac0f18d023d2641718dc61a7941f49fcc5ac0 (patch) | |
tree | 0f89006c83a9a0521a666cdfa7f4b1c945a2e463 /sys/arch/loongson | |
parent | ce5d5d099626cc7dc30d665b5d8094e26f7b238d (diff) |
Minimal support for the ST7 chip found on Gdium Liberty, brings us battery
information and a few other things not yet wired.
Diffstat (limited to 'sys/arch/loongson')
-rw-r--r-- | sys/arch/loongson/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/loongson/conf/files.loongson | 7 | ||||
-rw-r--r-- | sys/arch/loongson/dev/gdiumiic.c | 9 | ||||
-rw-r--r-- | sys/arch/loongson/dev/stsec.c | 273 |
4 files changed, 289 insertions, 4 deletions
diff --git a/sys/arch/loongson/conf/GENERIC b/sys/arch/loongson/conf/GENERIC index a1e49082624..2876a9b4d37 100644 --- a/sys/arch/loongson/conf/GENERIC +++ b/sys/arch/loongson/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.13 2010/02/23 21:04:16 otto Exp $ +# $OpenBSD: GENERIC,v 1.14 2010/02/24 22:16:18 miod Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -58,12 +58,12 @@ gpio0 at voyager? gdiumiic0 at gpio0 offset 6 mask 0x81 # pins 6 and 13 gdiumiic0 at gpio0 offset 46 mask 0x03 # pins 46 and 47 iic0 at gdiumiic0 +stsec0 at iic0 # ST7 Embedded Controller lmtemp0 at iic0 # National Semiconductor LM75 mfokclock0 at iic0 # M41T8x todclock #iic* at voyager? #ohci* at voyager? smfb* at voyager? - wsdisplay* at smfb? # USB Controllers diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson index 6e020c959c2..6cdb10f0ce7 100644 --- a/sys/arch/loongson/conf/files.loongson +++ b/sys/arch/loongson/conf/files.loongson @@ -1,4 +1,4 @@ -# $OpenBSD: files.loongson,v 1.5 2010/02/23 21:04:16 otto Exp $ +# $OpenBSD: files.loongson,v 1.6 2010/02/24 22:16:18 miod Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -88,6 +88,11 @@ device gdiumiic: i2cbus, i2c_bitbang attach gdiumiic at gpio file arch/loongson/dev/gdiumiic.c gdiumiic +# Gdium ST7 controller +device stsec +attach stsec at i2c +file arch/loongson/dev/stsec.c stsec + # Gdium M41T8x RTC device mfokclock attach mfokclock at i2c diff --git a/sys/arch/loongson/dev/gdiumiic.c b/sys/arch/loongson/dev/gdiumiic.c index db0ca7d78eb..f550f05c9f4 100644 --- a/sys/arch/loongson/dev/gdiumiic.c +++ b/sys/arch/loongson/dev/gdiumiic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gdiumiic.c,v 1.3 2010/02/23 12:21:01 otto Exp $ */ +/* $OpenBSD: gdiumiic.c,v 1.4 2010/02/24 22:16:18 miod Exp $ */ /* * Copyright (c) 2010 Miodrag Vallat. @@ -352,6 +352,13 @@ gdiumiic_sensors_scan(struct device *iicdev, struct i2cbus_attach_args *iba, bzero(&ia, sizeof ia); ia.ia_tag = iba->iba_tag; + ia.ia_addr = 0x40; + ia.ia_size = 1; + ia.ia_name = "stsec"; + config_found(iicdev, &ia, iic_print); + + bzero(&ia, sizeof ia); + ia.ia_tag = iba->iba_tag; ia.ia_addr = 0x48; ia.ia_size = 1; ia.ia_name = "lm75"; diff --git a/sys/arch/loongson/dev/stsec.c b/sys/arch/loongson/dev/stsec.c new file mode 100644 index 00000000000..878f8d2e2c6 --- /dev/null +++ b/sys/arch/loongson/dev/stsec.c @@ -0,0 +1,273 @@ +/* $OpenBSD: stsec.c,v 1.1 2010/02/24 22:16:18 miod Exp $ */ + +/* + * Copyright (c) 2010 Miodrag Vallat. + * + * 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. + */ + +/* + * Gdium ST7 Embedded Controller I2C interface + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/sensors.h> + +#include <dev/i2c/i2cvar.h> + +extern int gdium_revision; + +#define ST7_VERSION 0x00 /* only on later mobos */ + +#define ST7_STATUS 0x00 +#define STS_LID_CLOSED 0x01 +#define STS_POWER_BTN_DOWN 0x02 +#define STS_BATTERY_PRESENT 0x04 /* not available on old mobo */ +#define STS_POWER_AVAILABLE 0x08 +#define STS_WAVELAN_BTN_DOWN 0x10 /* ``enable'' on old mobo */ +#define STS_AC_AVAILABLE 0x20 +#define ST7_CONTROL 0x01 +#define STC_DDR_CLOCK 0x01 +#define STC_CHARGE_LED_LIT 0x02 +#define STC_BEEP 0x04 +#define STC_DDR_POWER 0x08 +#define STC_TRICKLE 0x10 /* trickle charge rate */ +#define STC_RADIO_ENABLE 0x20 /* enable wavelan rf, later mobos */ +#define STC_MAIN_POWER 0x40 +#define STC_CHARGE_ENABLE 0x80 +#define ST7_BATTERY_L 0x02 +#define ST7_BATTERY_H 0x03 +#define STB_VALUE(h,l) (((h) << 2) | ((l) & 0x03)) +#define ST7_SIGNATURE 0x04 +#define STSIG_EC_CONTROL 0x00 +#define STSIG_OS_CONTROL 0xae + +const struct { + const char *desc; + enum sensor_type type; +} stsec_sensors_template[] = { +#define STSEC_SENSOR_AC_PRESENCE 0 + { + .desc = "AC present", + .type = SENSOR_INDICATOR, + }, +#define STSEC_SENSOR_BATTERY_PRESENCE 1 + { + .desc = "Battery present", + .type = SENSOR_INDICATOR, + }, +#define STSEC_SENSOR_BATTERY_STATE 2 + { + .desc = "Battery charging", + .type = SENSOR_INDICATOR, + }, +#define STSEC_SENSOR_BATTERY_VOLTAGE 3 + { + .desc = "Battery voltage", + .type = SENSOR_VOLTS_DC, + } +}; + +struct stsec_softc { + struct device sc_dev; + i2c_tag_t sc_tag; + i2c_addr_t sc_addr; + uint sc_base; + + struct ksensor sc_sensors[nitems(stsec_sensors_template)]; + struct ksensordev sc_sensordev; + struct sensor_task *sc_sensors_update_task; +}; + +int stsec_match(struct device *, void *, void *); +void stsec_attach(struct device *, struct device *, void *); + +const struct cfattach stsec_ca = { + sizeof(struct stsec_softc), stsec_match, stsec_attach +}; + +struct cfdriver stsec_cd = { + NULL, "stsec", DV_DULL +}; + +int stsec_read(struct stsec_softc *, uint, int *); +int stsec_write(struct stsec_softc *, uint, int); +void stsec_sensors_update(void *); + +int +stsec_match(struct device *parent, void *vcf, void *aux) +{ + struct i2c_attach_args *ia = (struct i2c_attach_args *)aux; + struct cfdata *cf = (struct cfdata *)vcf; + + return strcmp(ia->ia_name, cf->cf_driver->cd_name) == 0; +} + +void +stsec_attach(struct device *parent, struct device *self, void *aux) +{ + struct stsec_softc *sc = (struct stsec_softc *)self; + struct i2c_attach_args *ia = (struct i2c_attach_args *)aux; + int rev, sig; + int rc; + uint i; + + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + /* + * Figure out where to get our information, and display microcode + * version for geek value if available. + */ + + sc->sc_base = 0; + switch (gdium_revision) { + case 0: + break; + default: + /* read version before sc_base is set */ + rc = stsec_read(sc, ST7_VERSION, &rev); + if (rc != 0) { + printf(": can't read microcode revision\n"); + return; + } + printf(": revision %d.%d", (rev >> 4) & 0x0f, rev & 0x0f); + sc->sc_base = ST7_VERSION + 1; + break; + } + + printf("\n"); + + /* + * Better trust the ST7 firmware to control charge operation. + */ + + rc = stsec_read(sc, ST7_SIGNATURE, &sig); + if (rc != 0) { + printf("%s: can't verify charge policy\n", self->dv_xname); + /* not fatal */ + } else { + if (sig != STSIG_EC_CONTROL) + stsec_write(sc, ST7_SIGNATURE, STSIG_EC_CONTROL); + } + + /* + * Setup sensors. We use a quite short refresh interval to react + * quickly enough to button presses. + * XXX but we don't do anything on lid or button presses... yet + */ + + strlcpy(sc->sc_sensordev.xname, self->dv_xname, + sizeof(sc->sc_sensordev.xname)); + sc->sc_sensors_update_task = + sensor_task_register(sc, stsec_sensors_update, 2); + if (sc->sc_sensors_update_task == NULL) { + printf("%s: can't initialize refresh task\n", self->dv_xname); + return; + } + + for (i = 0; i < nitems(sc->sc_sensors); i++) { + sc->sc_sensors[i].type = stsec_sensors_template[i].type; + strlcpy(sc->sc_sensors[i].desc, stsec_sensors_template[i].desc, + sizeof(sc->sc_sensors[i].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); + } + sensordev_install(&sc->sc_sensordev); +} + +int +stsec_read(struct stsec_softc *sc, uint reg, int *value) +{ + uint8_t regno, data; + int rc; + + regno = sc->sc_base + reg; + iic_acquire_bus(sc->sc_tag, 0); + rc = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, + ®no, sizeof regno, &data, sizeof data, 0); + iic_release_bus(sc->sc_tag, 0); + + if (rc == 0) + *value = (int)data; + return rc; +} + +int +stsec_write(struct stsec_softc *sc, uint reg, int val) +{ + uint8_t regno, data[1]; + int rc; + + regno = sc->sc_base + reg; + data[0] = (uint8_t)val; + iic_acquire_bus(sc->sc_tag, 0); + rc = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, + ®no, sizeof regno, data, sizeof data[0], 0); + iic_release_bus(sc->sc_tag, 0); + return rc; +} + +void +stsec_sensors_update(void *vsc) +{ + struct stsec_softc *sc = (struct stsec_softc *)vsc; + int status, control, batl, bath; + ulong batuv; + struct ksensor *ks; + uint i; + + for (i = 0; i < nitems(sc->sc_sensors); i++) + sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; + + if (stsec_read(sc, ST7_STATUS, &status) != 0 || + stsec_read(sc, ST7_CONTROL, &control) != 0 || + stsec_read(sc, ST7_BATTERY_L, &batl) != 0 || + stsec_read(sc, ST7_BATTERY_H, &bath) != 0) + return; + + /* + * Battery voltage is in 10/1024V units, in the 0-1023 range. + */ + batuv = ((ulong)STB_VALUE(bath, batl) * 10 * 1000000) / 1024; + + ks = &sc->sc_sensors[STSEC_SENSOR_AC_PRESENCE]; + ks->value = !!ISSET(status, STS_AC_AVAILABLE); + ks->status = SENSOR_S_OK; + + /* + * Old mobo design does not have a battery presence bit; the Linux + * code decides there is no battery if the reported battery voltage + * is too low, we'll do the same. + */ + ks = &sc->sc_sensors[STSEC_SENSOR_BATTERY_PRESENCE]; + switch (gdium_revision) { + case 0: + ks->value = batuv > 500000; /* 0.5V */ + break; + default: + ks->value = !!ISSET(status, STS_BATTERY_PRESENT); + break; + } + ks->status = SENSOR_S_OK; + + ks = &sc->sc_sensors[STSEC_SENSOR_BATTERY_STATE]; + ks->value = !!ISSET(control, STC_CHARGE_ENABLE); + ks->status = SENSOR_S_OK; + + ks = &sc->sc_sensors[STSEC_SENSOR_BATTERY_VOLTAGE]; + ks->value = (int64_t)batuv; + ks->status = SENSOR_S_OK; +} |