diff options
author | Joshua Stein <jcs@cvs.openbsd.org> | 2017-02-22 16:39:57 +0000 |
---|---|---|
committer | Joshua Stein <jcs@cvs.openbsd.org> | 2017-02-22 16:39:57 +0000 |
commit | bf890000abe81f1160ca6077c200c133653ea16b (patch) | |
tree | 44cbd8ae5618d73c47197a6da85890f083cb2f76 /sys/dev | |
parent | 1cd64697377454ba86cbd0e110d3c87eb59fe5ab (diff) |
add acpisbs, an acpi smart battery subsystem driver reading data
over smbus
currently disabled because it conflicts with acpibat
ok deraadt, kettenis
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpi/acpi.c | 39 | ||||
-rw-r--r-- | sys/dev/acpi/acpidev.h | 56 | ||||
-rw-r--r-- | sys/dev/acpi/acpisbs.c | 436 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 10 | ||||
-rw-r--r-- | sys/dev/acpi/files.acpi | 7 | ||||
-rw-r--r-- | sys/dev/acpi/smbus.h | 301 |
6 files changed, 841 insertions, 8 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 46d5558629b..7837f52dcc1 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.320 2017/01/14 11:32:00 kettenis Exp $ */ +/* $OpenBSD: acpi.c,v 1.321 2017/02/22 16:39:56 jcs Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -1113,6 +1113,12 @@ acpi_attach(struct device *parent, struct device *self, void *aux) bat = malloc(sizeof(*bat), M_DEVBUF, M_WAITOK | M_ZERO); bat->aba_softc = (struct acpibat_softc *)dev; SLIST_INSERT_HEAD(&sc->sc_bat, bat, aba_link); + } else if (!strcmp(dev->dv_cfdata->cf_driver->cd_name, "acpisbs")) { + struct acpi_sbs *sbs; + + sbs = malloc(sizeof(*sbs), M_DEVBUF, M_WAITOK | M_ZERO); + sbs->asbs_softc = (struct acpisbs_softc *)dev; + SLIST_INSERT_HEAD(&sc->sc_sbs, sbs, asbs_link); } } @@ -1759,17 +1765,18 @@ acpi_sleep_task(void *arg0, int sleepmode) struct acpi_softc *sc = arg0; struct acpi_ac *ac; struct acpi_bat *bat; + struct acpi_sbs *sbs; /* System goes to sleep here.. */ acpi_sleep_state(sc, sleepmode); /* AC and battery information needs refreshing */ SLIST_FOREACH(ac, &sc->sc_ac, aac_link) - aml_notify(ac->aac_softc->sc_devnode, - 0x80); + aml_notify(ac->aac_softc->sc_devnode, 0x80); SLIST_FOREACH(bat, &sc->sc_bat, aba_link) - aml_notify(bat->aba_softc->sc_devnode, - 0x80); + aml_notify(bat->aba_softc->sc_devnode, 0x80); + SLIST_FOREACH(sbs, &sc->sc_sbs, asbs_link) + aml_notify(sbs->asbs_softc->sc_devnode, 0x80); } #endif /* SMALL_KERNEL */ @@ -2976,6 +2983,7 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) struct acpi_softc *sc; struct acpi_ac *ac; struct acpi_bat *bat; + struct acpi_sbs *sbs; struct apm_power_info *pi = (struct apm_power_info *)data; int bats; unsigned int remaining, rem, minutes, rate; @@ -3054,6 +3062,27 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) minutes += bat->aba_softc->sc_bst.bst_capacity; } + SLIST_FOREACH(sbs, &sc->sc_sbs, asbs_link) { + if (sbs->asbs_softc->sc_batteries_present == 0) + continue; + + if (sbs->asbs_softc->sc_battery.rel_charge == 0) + continue; + + bats++; + rem = sbs->asbs_softc->sc_battery.rel_charge; + if (rem > 100) + rem = 100; + remaining += rem; + + if (sbs->asbs_softc->sc_battery.run_time == + ACPISBS_VALUE_UNKNOWN) + continue; + + rate = 60; /* XXX */ + minutes += sbs->asbs_softc->sc_battery.run_time; + } + if (bats == 0) { pi->battery_state = APM_BATTERY_ABSENT; pi->battery_life = 0; diff --git a/sys/dev/acpi/acpidev.h b/sys/dev/acpi/acpidev.h index 38b3694edea..9f1b43f0bf7 100644 --- a/sys/dev/acpi/acpidev.h +++ b/sys/dev/acpi/acpidev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpidev.h,v 1.39 2016/10/25 06:55:59 pirofti Exp $ */ +/* $OpenBSD: acpidev.h,v 1.40 2017/02/22 16:39:56 jcs Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> @@ -22,6 +22,7 @@ #include <sys/sensors.h> #include <sys/rwlock.h> #include <dev/acpi/acpireg.h> +#include <dev/acpi/smbus.h> #define DEVNAME(s) ((s)->sc_dev.dv_xname) @@ -343,4 +344,57 @@ struct acpiec_softc { void acpibtn_disable_psw(void); void acpibtn_enable_psw(void); int acpibtn_numopenlids(void); + +struct acpisbs_battery { + uint16_t mode; /* bit flags */ + int units; +#define ACPISBS_UNITS_MW 0 +#define ACPISBS_UNITS_MA 1 + uint16_t at_rate; /* mAh or mWh */ + uint16_t temperature; /* 0.1 degK */ + uint16_t voltage; /* mV */ + uint16_t current; /* mA */ + uint16_t avg_current; /* mA */ + uint16_t rel_charge; /* percent of last_capacity */ + uint16_t abs_charge; /* percent of design_capacity */ + uint16_t capacity; /* mAh */ + uint16_t full_capacity; /* mAh, when fully charged */ + uint16_t run_time; /* minutes */ + uint16_t avg_empty_time; /* minutes */ + uint16_t avg_full_time; /* minutes until full */ + uint16_t charge_current; /* mA */ + uint16_t charge_voltage; /* mV */ + uint16_t status; /* bit flags */ + uint16_t cycle_count; /* cycles */ + uint16_t design_capacity; /* mAh */ + uint16_t design_voltage; /* mV */ + uint16_t spec; /* formatted */ + uint16_t manufacture_date; /* formatted */ + uint16_t serial; /* number */ + +#define ACPISBS_VALUE_UNKNOWN 65535 + + char manufacturer[SMBUS_DATA_SIZE]; + char device_name[SMBUS_DATA_SIZE]; + char device_chemistry[SMBUS_DATA_SIZE]; + char oem_data[SMBUS_DATA_SIZE]; +}; + +struct acpisbs_softc { + struct device sc_dev; + + struct acpi_softc *sc_acpi; + struct aml_node *sc_devnode; + struct acpiec_softc *sc_ec; + uint8_t sc_ec_base; + + struct acpisbs_battery sc_battery; + int sc_batteries_present; + + struct ksensor *sc_sensors; + struct ksensordev sc_sensordev; + struct sensor_task *sc_sensor_task; + struct timeval sc_lastpoll; +}; + #endif /* __DEV_ACPI_ACPIDEV_H__ */ diff --git a/sys/dev/acpi/acpisbs.c b/sys/dev/acpi/acpisbs.c new file mode 100644 index 00000000000..fddb6b7aa34 --- /dev/null +++ b/sys/dev/acpi/acpisbs.c @@ -0,0 +1,436 @@ +/* $OpenBSD: acpisbs.c,v 1.1 2017/02/22 16:39:56 jcs Exp $ */ +/* + * Smart Battery Subsystem device driver + * ACPI 5.0 spec section 10 + * + * Copyright (c) 2016-2017 joshua stein <jcs@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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#include <dev/acpi/acpidev.h> +#include <dev/acpi/amltypes.h> +#include <dev/acpi/dsdt.h> + +#include <sys/sensors.h> + +/* #define ACPISBS_DEBUG */ + +#ifdef ACPISBS_DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) +#endif + +/* how often (in seconds) to re-poll data */ +#define ACPISBS_POLL_FREQ 30 + +/* number of polls for reading data */ +#define SMBUS_TIMEOUT 50 + +#define CHECK(kind, cmd, val, senst, sens) { \ + SMBUS_READ_##kind, SMBATT_CMD_##cmd, \ + offsetof(struct acpisbs_battery, val), \ + (SMBUS_READ_##kind == SMBUS_READ_BLOCK ? SMBUS_DATA_SIZE : 2), \ + #val, senst, sens } + +struct acpisbs_battery_check { + uint8_t mode; + uint8_t command; + size_t offset; + int len; + char *name; + int sensor_type; + char *sensor_desc; +} acpisbs_battery_checks[] = { + /* mode must be checked first */ + CHECK(WORD, BATTERY_MODE, mode, -1, + "mode flags"), + CHECK(WORD, TEMPERATURE, temperature, SENSOR_TEMP, + "internal temperature"), + CHECK(WORD, VOLTAGE, voltage, SENSOR_VOLTS_DC, + "voltage"), + CHECK(WORD, CURRENT, current, SENSOR_AMPS, + "current being supplied"), + CHECK(WORD, AVERAGE_CURRENT, avg_current, SENSOR_AMPS, + "average current supplied"), + CHECK(WORD, RELATIVE_STATE_OF_CHARGE, rel_charge, SENSOR_PERCENT, + "remaining capacity"), + CHECK(WORD, ABSOLUTE_STATE_OF_CHARGE, abs_charge, SENSOR_PERCENT, + "remaining of design capacity"), + CHECK(WORD, REMAINING_CAPACITY, capacity, SENSOR_AMPHOUR, + "remaining capacity"), + CHECK(WORD, FULL_CHARGE_CAPACITY, full_capacity, SENSOR_AMPHOUR, + "capacity when fully charged"), + CHECK(WORD, RUN_TIME_TO_EMPTY, run_time, SENSOR_INTEGER, + "remaining run time minutes"), + CHECK(WORD, AVERAGE_TIME_TO_EMPTY, avg_empty_time, SENSOR_INTEGER, + "avg remaining minutes"), + CHECK(WORD, AVERAGE_TIME_TO_FULL, avg_full_time, SENSOR_INTEGER, + "avg minutes until full charge"), + CHECK(WORD, CHARGING_CURRENT, charge_current, SENSOR_AMPS, + "desired charging rate"), + CHECK(WORD, CHARGING_VOLTAGE, charge_voltage, SENSOR_VOLTS_DC, + "desired charging voltage"), + CHECK(WORD, BATTERY_STATUS, status, -1, + "status"), + CHECK(WORD, CYCLE_COUNT, cycle_count, SENSOR_INTEGER, + "charge and discharge cycles"), + CHECK(WORD, DESIGN_CAPACITY, design_capacity, SENSOR_AMPHOUR, + "capacity of new battery"), + CHECK(WORD, DESIGN_VOLTAGE, design_voltage, SENSOR_VOLTS_DC, + "voltage of new battery"), + CHECK(WORD, SERIAL_NUMBER, serial, -1, + "serial number"), + + CHECK(BLOCK, MANUFACTURER_NAME, manufacturer, -1, + "manufacturer name"), + CHECK(BLOCK, DEVICE_NAME, device_name, -1, + "battery model number"), + CHECK(BLOCK, DEVICE_CHEMISTRY, device_chemistry, -1, + "battery chemistry"), +#if 0 + CHECK(WORD, SPECIFICATION_INFO, spec, -1, + NULL), + CHECK(WORD, MANUFACTURE_DATE, manufacture_date, -1, + "date battery was manufactured"), + CHECK(BLOCK, MANUFACTURER_DATA, oem_data, -1, + "manufacturer-specific data"), +#endif +}; + +extern void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *); +extern void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *); + +int acpisbs_match(struct device *, void *, void *); +void acpisbs_attach(struct device *, struct device *, void *); +void acpisbs_setup_sensors(struct acpisbs_softc *); +void acpisbs_refresh_sensors(struct acpisbs_softc *); +void acpisbs_read(struct acpisbs_softc *); +int acpisbs_notify(struct aml_node *, int, void *); + +int acpi_smbus_read(struct acpisbs_softc *, uint8_t, uint8_t, int, void *); + +struct cfattach acpisbs_ca = { + sizeof(struct acpisbs_softc), + acpisbs_match, + acpisbs_attach, +}; + +struct cfdriver acpisbs_cd = { + NULL, "acpisbs", DV_DULL +}; + +const char *acpisbs_hids[] = { + "ACPI0002", + NULL +}; + +int +acpisbs_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aa = aux; + struct cfdata *cf = match; + + return (acpi_matchhids(aa, acpisbs_hids, cf->cf_driver->cd_name)); +} + +void +acpisbs_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpisbs_softc *sc = (struct acpisbs_softc *)self; + struct acpi_attach_args *aa = aux; + int64_t sbs, val; + + sc->sc_acpi = (struct acpi_softc *)parent; + sc->sc_devnode = aa->aaa_node; + sc->sc_batteries_present = 0; + + memset(&sc->sc_battery, 0, sizeof(sc->sc_battery)); + + getmicrotime(&sc->sc_lastpoll); + + if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_SBS", 0, NULL, &sbs)) + return; + + /* + * The parent node of the device block containing the _HID must also + * have an _EC node, which contains the base address and query value. + */ + if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode->parent, "_EC", 0, + NULL, &val)) + return; + sc->sc_ec_base = (val >> 8) & 0xff; + + if (!sc->sc_acpi->sc_ec) + return; + sc->sc_ec = sc->sc_acpi->sc_ec; + + printf(": %s", sc->sc_devnode->name); + + if (sbs > 0) + acpisbs_read(sc); + + if (sc->sc_batteries_present) { + if (sc->sc_battery.device_name[0]) + printf(" model \"%s\"", sc->sc_battery.device_name); + if (sc->sc_battery.serial) + printf(" serial %d", sc->sc_battery.serial); + if (sc->sc_battery.device_chemistry[0]) + printf(" type %s", sc->sc_battery.device_chemistry); + if (sc->sc_battery.manufacturer[0]) + printf(" oem \"%s\"", sc->sc_battery.manufacturer); + } + + printf("\n"); + + acpisbs_setup_sensors(sc); + acpisbs_refresh_sensors(sc); + + aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpisbs_notify, + sc, ACPIDEV_POLL); +} + +void +acpisbs_read(struct acpisbs_softc *sc) +{ + int i; + + for (i = 0; i < nitems(acpisbs_battery_checks); i++) { + struct acpisbs_battery_check check = acpisbs_battery_checks[i]; + void *p = (void *)&sc->sc_battery + check.offset; + + acpi_smbus_read(sc, check.mode, check.command, check.len, p); + + if (check.mode == SMBUS_READ_BLOCK) + DPRINTF(("%s: %s: %s\n", sc->sc_dev.dv_xname, + check.name, (char *)p)); + else + DPRINTF(("%s: %s: %u\n", sc->sc_dev.dv_xname, + check.name, *(uint16_t *)p)); + + if (check.command == SMBATT_CMD_BATTERY_MODE) { + uint16_t *ival = (uint16_t *)p; + if (*ival == 0) { + /* battery not present, skip further checks */ + sc->sc_batteries_present = 0; + break; + } + + /* TODO: support multiple batteries based on _SBS */ + sc->sc_batteries_present = 1; + + if (*ival & SMBATT_BM_CAPACITY_MODE) + sc->sc_battery.units = ACPISBS_UNITS_MW; + else + sc->sc_battery.units = ACPISBS_UNITS_MA; + } + } +} + +void +acpisbs_setup_sensors(struct acpisbs_softc *sc) +{ + int i; + + memset(&sc->sc_sensordev, 0, sizeof(sc->sc_sensordev)); + strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), + sizeof(sc->sc_sensordev.xname)); + + sc->sc_sensors = mallocarray(sizeof(struct ksensor), + nitems(acpisbs_battery_checks), M_DEVBUF, M_WAITOK | M_ZERO); + + for (i = 0; i < nitems(acpisbs_battery_checks); i++) { + struct acpisbs_battery_check check = acpisbs_battery_checks[i]; + + if (check.sensor_type < 0) + continue; + + strlcpy(sc->sc_sensors[i].desc, check.sensor_desc, + sizeof(sc->sc_sensors[i].desc)); + + if (check.sensor_type == SENSOR_AMPHOUR && + sc->sc_battery.units == ACPISBS_UNITS_MW) + /* translate to watt-hours */ + sc->sc_sensors[i].type = SENSOR_WATTHOUR; + else + sc->sc_sensors[i].type = check.sensor_type; + + sc->sc_sensors[i].value = 0; + sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); + } + + sensordev_install(&sc->sc_sensordev); +} + +void +acpisbs_refresh_sensors(struct acpisbs_softc *sc) +{ + int i; + + for (i = 0; i < nitems(acpisbs_battery_checks); i++) { + struct acpisbs_battery_check check = acpisbs_battery_checks[i]; + void *p = (void *)&sc->sc_battery + check.offset; + uint16_t *ival = (uint16_t *)p; + + if (check.sensor_type < 0) + continue; + + if (sc->sc_batteries_present) { + sc->sc_sensors[i].flags = 0; + sc->sc_sensors[i].status = SENSOR_S_OK; + + switch (check.sensor_type) { + case SENSOR_AMPS: + sc->sc_sensors[i].value = *ival * 100; + break; + + case SENSOR_AMPHOUR: + case SENSOR_WATTHOUR: + sc->sc_sensors[i].value = *ival * 10000; + break; + + case SENSOR_PERCENT: + sc->sc_sensors[i].value = *ival * 1000; + break; + +#if 0 + case SENSOR_STRING: + strlcpy(sc->sc_sensors[i].string, (char *)p, + sizeof(sc->sc_sensors[i].string)); + break; +#endif + case SENSOR_TEMP: + /* .1 degK */ + sc->sc_sensors[i].value = (*ival * 10000) + + 273150000; + break; + + case SENSOR_VOLTS_DC: + sc->sc_sensors[i].value = *ival * 1000; + break; + + default: + if (*ival == ACPISBS_VALUE_UNKNOWN) { + sc->sc_sensors[i].value = 0; + sc->sc_sensors[i].status = + SENSOR_S_UNKNOWN; + sc->sc_sensors[i].flags = + SENSOR_FUNKNOWN; + } else + sc->sc_sensors[i].value = *ival; + } + } else { + sc->sc_sensors[i].value = 0; + sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; + sc->sc_sensors[i].flags = SENSOR_FUNKNOWN; + } + } +} + +int +acpisbs_notify(struct aml_node *node, int notify_type, void *arg) +{ + struct acpisbs_softc *sc = arg; + struct timeval tv; + + DPRINTF(("%s: %s: %d\n", sc->sc_dev.dv_xname, __func__, notify_type)); + + getmicrotime(&tv); + + if (tv.tv_sec - sc->sc_lastpoll.tv_sec > ACPISBS_POLL_FREQ) { + acpisbs_read(sc); + getmicrotime(&sc->sc_lastpoll); + } + + acpisbs_refresh_sensors(sc); + + return 0; +} + +int +acpi_smbus_read(struct acpisbs_softc *sc, uint8_t type, uint8_t cmd, int len, + void *buf) +{ + int j; + uint8_t addr = SMBATT_ADDRESS; + uint8_t val; + + acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_ADDR, 1, &addr); + acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_CMD, 1, &cmd); + acpiec_write(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &type); + + for (j = SMBUS_TIMEOUT; j < 0; j--) { + acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_PRTCL, 1, &val); + if (val == 0) + break; + } + if (j == 0) { + printf("%s: %s: timeout reading 0x%x\n", sc->sc_dev.dv_xname, + __func__, addr); + return 1; + } + + if (cold) + DELAY(1000); + + acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_STS, 1, &val); + if (val & SMBUS_STS_MASK) { + printf("%s: %s: error reading status: 0x%x\n", + sc->sc_dev.dv_xname, __func__, addr); + return 1; + } + + if (cold) + DELAY(1000); + + switch (type) { + case SMBUS_READ_WORD: { + uint8_t word[2]; + acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA, 2, + (uint8_t *)&word); + + *(uint16_t *)buf = (word[1] << 8) | word[0]; + + break; + } + case SMBUS_READ_BLOCK: + bzero(buf, len); + + /* find number of bytes to read */ + acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_BCNT, 1, &val); + val &= 0x1f; + if (len > val) + len = val; + + for (j = 0; j < len; j++) { + acpiec_read(sc->sc_ec, sc->sc_ec_base + SMBUS_DATA + j, + 1, &val); + ((char *)buf)[j] = val; + } + break; + default: + printf("%s: %s: unknown mode 0x%x\n", sc->sc_dev.dv_xname, + __func__, type); + return 1; + } + + return 0; +} diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h index aaf35fa030c..bb6404ed0ed 100644 --- a/sys/dev/acpi/acpivar.h +++ b/sys/dev/acpi/acpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpivar.h,v 1.83 2016/07/28 21:57:56 kettenis Exp $ */ +/* $OpenBSD: acpivar.h,v 1.84 2017/02/22 16:39:56 jcs Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * @@ -191,6 +191,13 @@ struct acpi_bat { SLIST_HEAD(acpi_bat_head, acpi_bat); +struct acpi_sbs { + struct acpisbs_softc *asbs_softc; + SLIST_ENTRY(acpi_sbs) asbs_link; +}; + +SLIST_HEAD(acpi_sbs_head, acpi_sbs); + struct acpi_softc { struct device sc_dev; @@ -250,6 +257,7 @@ struct acpi_softc { struct acpi_ac_head sc_ac; struct acpi_bat_head sc_bat; + struct acpi_sbs_head sc_sbs; struct timeout sc_dev_timeout; diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi index 8c60193dc69..6b29a281851 100644 --- a/sys/dev/acpi/files.acpi +++ b/sys/dev/acpi/files.acpi @@ -1,4 +1,4 @@ -# $OpenBSD: files.acpi,v 1.36 2017/01/10 08:54:14 jsg Exp $ +# $OpenBSD: files.acpi,v 1.37 2017/02/22 16:39:56 jcs Exp $ # # Config file and device description for machine-independent ACPI code. # Included by ports that need it. @@ -150,3 +150,8 @@ file dev/acpi/tpm.c tpm device acpihve attach acpihve at acpi file dev/acpi/acpihve.c acpihve + +# Smart Battery Subsystem +device acpisbs +attach acpisbs at acpi +file dev/acpi/acpisbs.c acpisbs diff --git a/sys/dev/acpi/smbus.h b/sys/dev/acpi/smbus.h new file mode 100644 index 00000000000..f49d2c29901 --- /dev/null +++ b/sys/dev/acpi/smbus.h @@ -0,0 +1,301 @@ +/*- + * Copyright (c) 2005 Hans Petter Selasky + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _ACPI_SMBUS_H_ +#define _ACPI_SMBUS_H_ + +enum { + SMBUS_WRITE_QUICK = 2, + SMBUS_READ_QUICK = 3, + SMBUS_SEND_BYTE = 4, + SMBUS_RECEIVE_BYTE = 5, + SMBUS_WRITE_BYTE = 6, + SMBUS_READ_BYTE = 7, + SMBUS_WRITE_WORD = 8, + SMBUS_READ_WORD = 9, + SMBUS_WRITE_BLOCK = 0xa, + SMBUS_READ_BLOCK = 0xb, + SMBUS_PROCESS_CALL = 0xc, + SMBUS_BLOCK_PROCESS_CALL = 0xd, +}; + +/* + * System Management Bus register offsets + */ +#define SMBUS_PRTCL 0 +#define SMBUS_STS 1 +#define SMBUS_STS_MASK 0x1f +#define SMBUS_ADDR 2 +#define SMBUS_CMD 3 +#define SMBUS_DATA 4 /* SMBUS_DATA_SIZE bytes */ +#define SMBUS_DATA_SIZE 32 +#define SMBUS_BCNT 36 +#define SMBUS_ALRM_ADDR 37 +#define SMBUS_ALRM_DATA 38 /* 2 bytes */ + +/* + * Smart-Battery commands and definitions + */ + +/* Base address */ +#define SMBATT_ADDRESS 0x16 + + +/* access: READ WRITE WORD */ +#define SMBATT_CMD_MANUFACTURER_ACCESS 0 + +/* + * access: READ WRITE WORD + * unit : mAh (CAPACITY_MODE=0) or 10 mWh (CAPACITY_MODE=1) + * range : 0 .. 65535 inclusively + */ +#define SMBATT_CMD_REMAINING_CAPACITY_ALARM 0x1 + +/* + * access: READ WRITE WORD + * unit : minutes + * range : 0 .. 65535 inclusively + */ +#define SMBATT_CMD_REMAINING_TIME_ALARM 0x2 + +/* access: READ WRITE WORD */ +#define SMBATT_CMD_BATTERY_MODE 0x3 + +#define SMBATT_BM_INTERNAL_CHARGE_CONTROLLER (1 << 0) /* READ */ +#define SMBATT_BM_PRIMARY_BATTERY_SUPPORT (1 << 1) /* READ */ +#define SMBATT_BM_CONDITION_FLAG (1 << 7) /* READ */ +#define SMBATT_BM_CHARGE_CONTROLLER_ENABLED (1 << 8) /* READ WRITE */ +#define SMBATT_BM_PRIMARY_BATTERY (1 << 9) /* READ WRITE */ +#define SMBATT_BM_ALARM_MODE (1 << 13) /* READ WRITE */ +#define SMBATT_BM_CHARGER_MODE (1 << 14) /* READ WRITE */ +#define SMBATT_BM_CAPACITY_MODE (1 << 15) /* READ WRITE */ + +/* + * access: READ WRITE WORD + * unit : mAh (CAPACITY_MODE=0) or 10 mWh (CAPACITY_MODE=1) + * range : signed WORD + */ +#define SMBATT_CMD_AT_RATE 0x4 + +/* + * access: READ WORD + * unit : minutes + * range : 0 .. 65534, 65535 has special meaning + */ +#define SMBATT_CMD_AT_RATE_TIME_TO_FULL 0x5 + +/* + * access: READ WORD + * unit : minutes + * range : 0 .. 65534, 65535 has special meaning + */ +#define SMBATT_CMD_AT_RATE_TIME_TO_EMPTY 0x6 + +/* + * access: READ WORD */ +#define SMBATT_CMD_AT_RATE_OK 0x7 + +/* + * access: READ WORD + * unit : 0.1 degrees Kelvin + * range : 0 .. 6553.5 Kelvin + */ +#define SMBATT_CMD_TEMPERATURE 0x8 + +/* + * access: READ WORD + * unit : mV + * range : 0 .. 65535 inclusively + */ +#define SMBATT_CMD_VOLTAGE 0x9 + +/* + * access: READ WORD + * unit : mA + * range : signed WORD + */ +#define SMBATT_CMD_CURRENT 0xa + +/* + * access: READ WORD + * unit : mA + * range : signed WORD + */ +#define SMBATT_CMD_AVERAGE_CURRENT 0xb + +/* + * access: READ WORD + * unit : percent + * range : 0..100 inclusively + */ +#define SMBATT_CMD_MAX_ERROR 0xc + +/* + * access: READ WORD + * unit : percent + * range : 0..100 inclusively + */ +#define SMBATT_CMD_RELATIVE_STATE_OF_CHARGE 0xd + +/* + * access: READ WORD + * unit : percent + * range : 0..100 inclusively + */ +#define SMBATT_CMD_ABSOLUTE_STATE_OF_CHARGE 0xe + +/* + * access: READ WORD + * unit : mAh (CAPACITY_MODE=0) or 10 mWh (CAPACITY_MODE=1) + * range : 0..65535 inclusively + */ +#define SMBATT_CMD_REMAINING_CAPACITY 0xf + +/* + * access: READ WORD + * unit : mAh (CAPACITY_MODE=0) or 10 mWh (CAPACITY_MODE=1) + * range : 0..65535 inclusively + */ +#define SMBATT_CMD_FULL_CHARGE_CAPACITY 0x10 + +/* + * access: READ WORD + * unit : minutes + * range : 0..65534, 65535 is reserved + */ +#define SMBATT_CMD_RUN_TIME_TO_EMPTY 0x11 + +/* + * access: READ WORD + * unit : minutes + * range : 0..65534, 65535 is reserved + */ +#define SMBATT_CMD_AVERAGE_TIME_TO_EMPTY 0x12 + +/* + * access: READ WORD + * unit : minutes + * range : 0..65534, 65535 is reserved + */ +#define SMBATT_CMD_AVERAGE_TIME_TO_FULL 0x13 + +/* + * access: READ WORD + * unit : mA + */ +#define SMBATT_CMD_CHARGING_CURRENT 0x14 + +/* + * access: READ WORD + * unit : mV + * range : 0 .. 65534, 65535 reserved + */ +#define SMBATT_CMD_CHARGING_VOLTAGE 0x15 + +/* access: READ WORD */ +#define SMBATT_CMD_BATTERY_STATUS 0x16 + +/* alarm bits */ +#define SMBATT_BS_OVER_CHARGED_ALARM (1 << 15) +#define SMBATT_BS_TERMINATE_CHARGE_ALARM (1 << 14) +#define SMBATT_BS_RESERVED_2 (1 << 13) +#define SMBATT_BS_OVER_TEMP_ALARM (1 << 12) +#define SMBATT_BS_TERMINATE_DISCHARGE_ALARM (1 << 11) +#define SMBATT_BS_RESERVED_1 (1 << 10) +#define SMBATT_BS_REMAINING_CAPACITY_ALARM (1 << 9) +#define SMBATT_BS_REMAINING_TIME_ALARM (1 << 8) + +/* status bits */ +#define SMBATT_BS_INITIALIZED (1 << 7) +#define SMBATT_BS_DISCHARGING (1 << 6) +#define SMBATT_BS_FULLY_CHARGED (1 << 5) +#define SMBATT_BS_FULLY_DISCHARGED (1 << 4) + +/* error bits */ +#define SMBATT_BS_GET_ERROR(x) ((x) & 0xf) +#define SMBATT_BS_ERROR_OK 0 +#define SMBATT_BS_ERROR_BUSY 1 +#define SMBATT_BS_ERROR_RESERVED_COMMAND 2 +#define SMBATT_BS_ERROR_UNSUPPORTED_COMMAND 3 +#define SMBATT_BS_ERROR_ACCESS_DENIED 4 +#define SMBATT_BS_ERROR_OVER_UNDER_FLOW 5 +#define SMBATT_BS_ERROR_BADSIZE 6 +#define SMBATT_BS_ERROR_UNKNOWN 7 + +/* + * access: READ WORD + * unit : cycle(s) + * range : 0 .. 65534, 65535 reserved + */ +#define SMBATT_CMD_CYCLE_COUNT 0x17 + +/* + * access: READ WORD + * unit : mAh (CAPACITY_MODE=0) or 10 mWh (CAPACITY_MODE=1) + * range : 0..65535 inclusively + */ +#define SMBATT_CMD_DESIGN_CAPACITY 0x18 + +/* + * access: READ WORD + * unit : mV + * range : 0..65535 mV + */ +#define SMBATT_CMD_DESIGN_VOLTAGE 0x19 + +/* access: READ WORD */ +#define SMBATT_CMD_SPECIFICATION_INFO 0x1a + +#define SMBATT_SI_GET_REVISION(x) (((x) >> 0) & 0xf) +#define SMBATT_SI_GET_VERSION(x) (((x) >> 4) & 0xf) +#define SMBATT_SI_GET_VSCALE(x) (((x) >> 8) & 0xf) +#define SMBATT_SI_GET_IPSCALE(x) (((x) >> 12) & 0xf) + +/* access: READ WORD */ +#define SMBATT_CMD_MANUFACTURE_DATE 0x1b + +#define SMBATT_MD_GET_DAY(x) (((x) >> 0) & 0x1f) +#define SMBATT_MD_GET_MONTH(x) (((x) >> 5) & 0xf) +#define SMBATT_MD_GET_YEAR(x) ((((x) >> 9) & 0x7f) + 1980) + +/* access: READ WORD */ +#define SMBATT_CMD_SERIAL_NUMBER 0x1c + +/* access: READ BLOCK */ +#define SMBATT_CMD_MANUFACTURER_NAME 0x20 + +/* access: READ BLOCK */ +#define SMBATT_CMD_DEVICE_NAME 0x21 + +/* access: READ BLOCK */ +#define SMBATT_CMD_DEVICE_CHEMISTRY 0x22 + +/* access: READ BLOCK */ +#define SMBATT_CMD_MANUFACTURER_DATA 0x23 + +#endif /* !_ACPI_SMBUS_H_ */ |