diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2010-02-28 08:30:28 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2010-02-28 08:30:28 +0000 |
commit | c518dd2600807e5276d21b9657745e6d5f4a9deb (patch) | |
tree | 959188edada0f5d7d75c046e952d1dd1c6507700 /sys/arch/loongson/dev/kb3310.c | |
parent | 79999529fca020d754c68793ff897c9230212875 (diff) |
Basic apm(4), providing battery/power status and events. apm(4) is the
generic part, ykbec(4) provides the device specific parts. Other
battery/power status drivers can easily hook to adb(4). With help
from miod@; ok matthieu@ miod@ jasper@
Diffstat (limited to 'sys/arch/loongson/dev/kb3310.c')
-rw-r--r-- | sys/arch/loongson/dev/kb3310.c | 223 |
1 files changed, 147 insertions, 76 deletions
diff --git a/sys/arch/loongson/dev/kb3310.c b/sys/arch/loongson/dev/kb3310.c index 600a5c24cac..38d1842dbbb 100644 --- a/sys/arch/loongson/dev/kb3310.c +++ b/sys/arch/loongson/dev/kb3310.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kb3310.c,v 1.4 2010/02/24 18:29:39 otto Exp $ */ +/* $OpenBSD: kb3310.c,v 1.5 2010/02/28 08:30:27 otto Exp $ */ /* * Copyright (c) 2010 Otto Moerbeek <otto@drijf.net> * @@ -21,9 +21,12 @@ #include <sys/device.h> #include <sys/sensors.h> +#include <machine/apmvar.h> #include <machine/bus.h> #include <dev/isa/isavar.h> +#include "apm.h" + struct cfdriver ykbec_cd = { NULL, "ykbec", DV_DULL, }; @@ -31,13 +34,40 @@ struct cfdriver ykbec_cd = { #define IO_YKBEC 0x381 #define IO_YKBECSIZE 0x3 -#define KB3310_NUM_SENSORS 12 +static const struct { + const char *desc; + int type; +} ykbec_table[] = { +#define YKBEC_FAN 0 + { NULL, SENSOR_FANRPM }, +#define YKBEC_ITEMP 1 + { "Internal temperature", SENSOR_TEMP }, +#define YKBEC_DCAP 2 + { "Battery design capacity", SENSOR_AMPHOUR }, +#define YKBEC_FCAP 3 + { "Battery full charge capacity", SENSOR_AMPHOUR }, +#define YKBEC_DVOLT 4 + { "Battery design voltage", SENSOR_VOLTS_DC }, +#define YKBEC_BCURRENT 5 + { "Battery current", SENSOR_AMPS }, +#define YKBEC_BVOLT 6 + { "Battery voltage", SENSOR_VOLTS_DC }, +#define YKBEC_BTEMP 7 + { "Battery temperature", SENSOR_TEMP }, +#define YKBEC_CAP 8 + { "Battery capacity", SENSOR_PERCENT }, +#define YKBEC_CHARGING 9 + { "Battery charging", SENSOR_INDICATOR }, +#define YKBEC_AC 10 + { "AC-Power", SENSOR_INDICATOR } +#define YKBEC_NSENSORS 11 +}; 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 ksensor sc_sensor[YKBEC_NSENSORS]; struct ksensordev sc_sensordev; }; @@ -54,6 +84,21 @@ 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); +#if NAPM > 0 +int ykbec_apminfo(struct apm_power_info *); +struct apm_power_info ykbec_apmdata; +const char *ykbec_batstate[] = { + "high", + "low", + "critical", + "charging", + "unknown" +}; +#define BATTERY_STRING(x) ((x) < nitems(ykbec_batstate) ? \ + ykbec_batstate[x] : ykbec_batstate[4]) +#endif + + int ykbec_match(struct device *parent, void *match, void *aux) { @@ -83,6 +128,7 @@ ykbec_attach( struct device *parent, struct device *self, void *aux) { struct isa_attach_args *ia = aux; struct ykbec_softc *sc = (struct ykbec_softc *)self; + int i; sc->sc_iot = ia->ia_iot; if (bus_space_map(sc->sc_iot, ia->ia_iobase, ia->ia_iosize, 0, @@ -98,66 +144,20 @@ ykbec_attach( struct device *parent, struct device *self, void *aux) 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_INDICATOR; - strlcpy(sc->sc_sensor[9].desc, "Battery charging", - sizeof(sc->sc_sensor[9].desc)); - sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[9]); - - sc->sc_sensor[10].type = SENSOR_INDICATOR; - strlcpy(sc->sc_sensor[10].desc, "AC-Power", - sizeof(sc->sc_sensor[10].desc)); - sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[10]); - - sc->sc_sensor[11].type = SENSOR_INTEGER; - strlcpy(sc->sc_sensor[11].desc, "Battery low-level status", - sizeof(sc->sc_sensor[11].desc)); - sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[11]); + + for (i = 0; i < YKBEC_NSENSORS; i++) { + sc->sc_sensor[i].type = ykbec_table[i].type; + if (ykbec_table[i].desc) + strlcpy(sc->sc_sensor[i].desc, ykbec_table[i].desc, + sizeof(sc->sc_sensor[i].desc)); + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); + } sensordev_install(&sc->sc_sensordev); +#if NAPM > 0 + apm_setinfohook(ykbec_apminfo); +#endif printf("\n"); } @@ -247,33 +247,43 @@ ykbec_refresh(void *arg) { struct ykbec_softc *sc = (struct ykbec_softc *)arg; u_int val, bat_charge, bat_status, charge_status, bat_state, power_flag; + u_int cap_pct, fullcap; int current; +#if NAPM > 0 + struct apm_power_info old; +#endif val = ykbec_read16(sc, REG_FAN_SPEED_HIGH) & 0xfffff; - if (val != 0) + if (val != 0) { val = KB3310_FAN_SPEED_DIVIDER / val; - else - val = UINT_MAX; - sc->sc_sensor[0].value = val; + sc->sc_sensor[YKBEC_FAN].value = val; + sc->sc_sensor[YKBEC_FAN].flags &= ~SENSOR_FINVALID; + } else + sc->sc_sensor[YKBEC_FAN].flags |= SENSOR_FINVALID; val = ykbec_read(sc, ECTEMP_CURRENT_REG); - sc->sc_sensor[1].value = val * 1000000 + 273150000; + sc->sc_sensor[YKBEC_ITEMP].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; + sc->sc_sensor[YKBEC_DCAP].value = ykbec_read16(sc, REG_DESIGN_CAP_HIGH) + * 1000; + fullcap = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH); + sc->sc_sensor[YKBEC_FCAP].value = fullcap * 1000; + sc->sc_sensor[YKBEC_DVOLT].value = ykbec_read16(sc, REG_DESIGN_VOL_HIGH) + * 1000; current = ykbec_read16(sc, REG_CURRENT_HIGH); /* sign extend short -> int, int -> int64 will be done next statement */ current |= -(current & 0x8000); - sc->sc_sensor[5].value = current * -1000; + sc->sc_sensor[YKBEC_BCURRENT].value = -1000 * current; - sc->sc_sensor[6].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) * 1000; + sc->sc_sensor[YKBEC_BVOLT].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[YKBEC_BTEMP].value = val * 1000000 + 273150000; - sc->sc_sensor[8].value = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH) * 1000; + cap_pct = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH); + sc->sc_sensor[YKBEC_CAP].value = cap_pct * 1000; bat_charge = ykbec_read(sc, REG_BAT_CHARGE); bat_status = ykbec_read(sc, REG_BAT_STATUS); @@ -281,8 +291,69 @@ ykbec_refresh(void *arg) bat_state = ykbec_read(sc, REG_BAT_STATE); power_flag = ykbec_read(sc, REG_POWER_FLAG); - sc->sc_sensor[9].value = (bat_state & BAT_STATE_CHARGING) ? 1 : 0; - sc->sc_sensor[10].value = (power_flag & POWER_FLAG_ADAPTER_IN) ? 1 : 0; - sc->sc_sensor[11].value = (bat_state << 24) | (charge_status << 16) | - (bat_status << 8) | bat_charge; + sc->sc_sensor[YKBEC_CHARGING].value = (bat_state & BAT_STATE_CHARGING) ? + 1 : 0; + sc->sc_sensor[YKBEC_AC].value = (power_flag & POWER_FLAG_ADAPTER_IN) ? + 1 : 0; + +#if NAPM > 0 + bcopy(&ykbec_apmdata, &old, sizeof(old)); + ykbec_apmdata.battery_life = cap_pct; + ykbec_apmdata.ac_state = (power_flag & POWER_FLAG_ADAPTER_IN) ? + APM_AC_ON : APM_AC_OFF; + if ((bat_status & BAT_STATUS_BAT_EXISTS) == 0) { + ykbec_apmdata.battery_state = APM_BATTERY_ABSENT; + ykbec_apmdata.minutes_left = 0; + ykbec_apmdata.battery_life = 0; + } else { + /* if charging, return the minutes until full */ + if (bat_state & BAT_STATE_CHARGING) { + ykbec_apmdata.battery_state = APM_BATT_CHARGING; + if (current > 0) { + fullcap = (100 - cap_pct) * 60 * fullcap / 100; + ykbec_apmdata.minutes_left = fullcap / current; + } else + ykbec_apmdata.minutes_left = 0; + } else { + /* arbitrary */ + if (cap_pct > 60) + ykbec_apmdata.battery_state = APM_BATT_HIGH; + else if (cap_pct < 10) + ykbec_apmdata.battery_state = APM_BATT_CRITICAL; + else + ykbec_apmdata.battery_state = APM_BATT_LOW; + + current = -current; + /* Yeeloong draw is about 1A */ + if (current <= 0) + current = 1000; + /* at 5?%, the Yeeloong shuts down */ + if (cap_pct <= 5) + cap_pct = 0; + else + cap_pct -= 5; + fullcap = cap_pct * 60 * fullcap / 100; + ykbec_apmdata.minutes_left = fullcap / current; + } + + } + if (old.ac_state != ykbec_apmdata.ac_state) + apm_record_event(APM_POWER_CHANGE, "AC power", + ykbec_apmdata.ac_state ? "restored" : "lost"); + if (old.battery_state != ykbec_apmdata.battery_state) + apm_record_event(APM_POWER_CHANGE, "battery", + BATTERY_STRING(ykbec_apmdata.battery_state)); +#endif +} + + +#if NAPM > 0 + +int +ykbec_apminfo(struct apm_power_info *info) +{ + bcopy(&ykbec_apmdata, info, sizeof(struct apm_power_info)); + return 0; } + +#endif |