From bedaba59b1c344e0da7df29fe067b93537791c6d Mon Sep 17 00:00:00 2001 From: Sascha Wildner Date: Wed, 29 Aug 2012 00:08:24 +0200 Subject: [PATCH] kernel/acpi: Add smart battery support. I don't know which laptops have them, as far as I can tell, none of mine do. But as some seem to have it, it's worth supporting. https://en.wikipedia.org/wiki/Smart_Battery_System This is the patch from the tracker with some later updates FreeBSD did. Taken-from: FreeBSD Dragonfly-bug: Submitted-by: Dmitry Komissaroff --- sys/conf/files | 1 + sys/dev/acpica5/Makefile | 2 +- sys/dev/acpica5/acpi_smbat.c | 492 +++++++++++++++++++++++++++++++++++ sys/dev/acpica5/acpi_smbus.h | 285 ++++++++++++++++++++ 4 files changed, 779 insertions(+), 1 deletion(-) create mode 100644 sys/dev/acpica5/acpi_smbat.c create mode 100644 sys/dev/acpica5/acpi_smbus.h diff --git a/sys/conf/files b/sys/conf/files index c21ceca279..a2f789b427 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1989,6 +1989,7 @@ ${OSACPI_MI_DIR}/acpi_pcib_acpi.c optional acpi pci ${OSACPI_MI_DIR}/acpi_pcib_pci.c optional acpi pci ${OSACPI_MI_DIR}/acpi_powerres.c optional acpi ${OSACPI_MI_DIR}/acpi_resource.c optional acpi +${OSACPI_MI_DIR}/acpi_smbat.c optional acpi ${OSACPI_MI_DIR}/acpi_thermal.c optional acpi ${OSACPI_MI_DIR}/acpi_timer.c optional acpi ${OSACPI_MI_DIR}/acpi_wmi_if.m optional acpi diff --git a/sys/dev/acpica5/Makefile b/sys/dev/acpica5/Makefile index 56b83ba2f5..e992b48bd8 100644 --- a/sys/dev/acpica5/Makefile +++ b/sys/dev/acpica5/Makefile @@ -62,7 +62,7 @@ SRCS+= utresrc.c utstate.c utxface.c utdecode.c utids.c utosi.c utxferror.c # OSD layer # SRCS+= acpi.c acpi_acad.c acpi_battery.c acpi_button.c acpi_cmbat.c -SRCS+= acpi_cpu.c acpi_cpu_cstate.c acpi_cpu_pstate.c +SRCS+= acpi_cpu.c acpi_cpu_cstate.c acpi_cpu_pstate.c acpi_smbat.c SRCS+= acpi_ec.c acpi_isab.c acpi_lid.c SRCS+= acpi_package.c # The PCI part of ACPI5 doesn't work with the current infrastructure diff --git a/sys/dev/acpica5/acpi_smbat.c b/sys/dev/acpica5/acpi_smbat.c new file mode 100644 index 0000000000..b903fe68fc --- /dev/null +++ b/sys/dev/acpica5/acpi_smbat.c @@ -0,0 +1,492 @@ +/*- + * 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: src/sys/dev/acpica/acpi_smbat.c,v 1.11 2011/11/07 15:43:11 ed Exp $ + */ + +#include "opt_acpi.h" +#include +#include +#include +#include + +#include "acpi.h" +#include +#include +#include + +/* Transactions have failed after 500 ms. */ +#define SMBUS_TIMEOUT 50 + +struct acpi_smbat_softc { + uint8_t sb_base_addr; + device_t ec_dev; + + struct acpi_bif bif; + struct acpi_bst bst; + struct timespec bif_lastupdated; + struct timespec bst_lastupdated; +}; + +static int acpi_smbat_probe(device_t dev); +static int acpi_smbat_attach(device_t dev); +static int acpi_smbat_shutdown(device_t dev); +static int acpi_smbat_info_expired(struct timespec *lastupdated); +static void acpi_smbat_info_updated(struct timespec *lastupdated); +static int acpi_smbat_get_bif(device_t dev, struct acpi_bif *bif); +static int acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst); + +ACPI_SERIAL_DECL(smbat, "ACPI Smart Battery"); + +SYSCTL_DECL(_debug_acpi); +static SYSCTL_NODE(_debug_acpi, OID_AUTO, batt, CTLFLAG_RD, NULL, + "Battery debugging"); + +/* On some laptops with smart batteries, enabling battery monitoring + * software causes keystrokes from atkbd to be lost. This has also been + * reported on Linux, and is apparently due to the keyboard and I2C line + * for the battery being routed through the same chip. Whether that's + * accurate or not, adding extra sleeps to the status checking code + * causes the problem to go away. + * + * If you experience that problem, try a value of 10ms and move up + * from there. + */ +static int batt_sleep_ms; +SYSCTL_INT(_debug_acpi_batt, OID_AUTO, batt_sleep_ms, CTLFLAG_RW, &batt_sleep_ms, 0, + "Sleep during battery status updates to prevent keystroke loss."); + +static device_method_t acpi_smbat_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, acpi_smbat_probe), + DEVMETHOD(device_attach, acpi_smbat_attach), + DEVMETHOD(device_shutdown, acpi_smbat_shutdown), + + /* ACPI battery interface */ + DEVMETHOD(acpi_batt_get_status, acpi_smbat_get_bst), + DEVMETHOD(acpi_batt_get_info, acpi_smbat_get_bif), + + {0, 0} +}; + +static driver_t acpi_smbat_driver = { + "battery", + acpi_smbat_methods, + sizeof(struct acpi_smbat_softc), +}; + +static devclass_t acpi_smbat_devclass; +DRIVER_MODULE(acpi_smbat, acpi, acpi_smbat_driver, acpi_smbat_devclass, 0, 0); +MODULE_DEPEND(acpi_smbat, acpi, 1, 1, 1); + +static int +acpi_smbat_probe(device_t dev) +{ + static char *smbat_ids[] = {"ACPI0001", "ACPI0005", NULL}; + ACPI_STATUS status; + + if (acpi_disabled("smbat") || + ACPI_ID_PROBE(device_get_parent(dev), dev, smbat_ids) == NULL) + return (ENXIO); + status = AcpiEvaluateObject(acpi_get_handle(dev), "_EC", NULL, NULL); + if (ACPI_FAILURE(status)) + return (ENXIO); + + device_set_desc(dev, "ACPI Smart Battery"); + return (0); +} + +static int +acpi_smbat_attach(device_t dev) +{ + struct acpi_smbat_softc *sc; + uint32_t base; + + sc = device_get_softc(dev); + if (ACPI_FAILURE(acpi_GetInteger(acpi_get_handle(dev), "_EC", &base))) { + device_printf(dev, "cannot get EC base address\n"); + return (ENXIO); + } + sc->sb_base_addr = (base >> 8) & 0xff; + + /* XXX Only works with one EC, but nearly all systems only have one. */ + sc->ec_dev = devclass_get_device(devclass_find("acpi_ec"), 0); + if (sc->ec_dev == NULL) { + device_printf(dev, "cannot find EC device\n"); + return (ENXIO); + } + + timespecclear(&sc->bif_lastupdated); + timespecclear(&sc->bst_lastupdated); + + if (acpi_battery_register(dev) != 0) { + device_printf(dev, "cannot register battery\n"); + return (ENXIO); + } + return (0); +} + +static int +acpi_smbat_shutdown(device_t dev) +{ + + acpi_battery_remove(dev); + return (0); +} + +static int +acpi_smbat_info_expired(struct timespec *lastupdated) +{ + struct timespec curtime; + + ACPI_SERIAL_ASSERT(smbat); + + if (lastupdated == NULL) + return (TRUE); + if (!timespecisset(lastupdated)) + return (TRUE); + + getnanotime(&curtime); + timespecsub(&curtime, lastupdated); + return (curtime.tv_sec < 0 || + curtime.tv_sec > acpi_battery_get_info_expire()); +} + +static void +acpi_smbat_info_updated(struct timespec *lastupdated) +{ + + ACPI_SERIAL_ASSERT(smbat); + + if (lastupdated != NULL) + getnanotime(lastupdated); +} + +static int +acpi_smbus_read_2(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, + uint16_t *ptr) +{ + int error, to; + UINT64 val; + + ACPI_SERIAL_ASSERT(smbat); + + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + + val = addr; + error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_ADDR, + val, 1); + if (error) + goto out; + + val = cmd; + error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_CMD, + val, 1); + if (error) + goto out; + + val = 0x09; /* | 0x80 if PEC */ + error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, + val, 1); + if (error) + goto out; + + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + + for (to = SMBUS_TIMEOUT; to != 0; to--) { + error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, + &val, 1); + if (error) + goto out; + if (val == 0) + break; + AcpiOsSleep(10); + } + if (to == 0) { + error = ETIMEDOUT; + goto out; + } + + error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_STS, &val, 1); + if (error) + goto out; + if (val & SMBUS_STS_MASK) { + kprintf("%s: AE_ERROR 0x%x\n", + __FUNCTION__, (int)(val & SMBUS_STS_MASK)); + error = EIO; + goto out; + } + + error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_DATA, + &val, 2); + if (error) + goto out; + + *ptr = val; + +out: + return (error); +} + +static int +acpi_smbus_read_multi_1(struct acpi_smbat_softc *sc, uint8_t addr, uint8_t cmd, + uint8_t *ptr, uint16_t len) +{ + UINT64 val; + uint8_t to; + int error; + + ACPI_SERIAL_ASSERT(smbat); + + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + + val = addr; + error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_ADDR, + val, 1); + if (error) + goto out; + + val = cmd; + error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_CMD, + val, 1); + if (error) + goto out; + + val = 0x0B /* | 0x80 if PEC */ ; + error = ACPI_EC_WRITE(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, + val, 1); + if (error) + goto out; + + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + + for (to = SMBUS_TIMEOUT; to != 0; to--) { + error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_PRTCL, + &val, 1); + if (error) + goto out; + if (val == 0) + break; + AcpiOsSleep(10); + } + if (to == 0) { + error = ETIMEDOUT; + goto out; + } + + error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_STS, &val, 1); + if (error) + goto out; + if (val & SMBUS_STS_MASK) { + kprintf("%s: AE_ERROR 0x%x\n", + __FUNCTION__, (int)(val & SMBUS_STS_MASK)); + error = EIO; + goto out; + } + + /* get length */ + error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_BCNT, + &val, 1); + if (error) + goto out; + val = (val & 0x1f) + 1; + + bzero(ptr, len); + if (len > val) + len = val; + + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + + while (len--) { + error = ACPI_EC_READ(sc->ec_dev, sc->sb_base_addr + SMBUS_DATA + + len, &val, 1); + if (error) + goto out; + + ptr[len] = val; + if (batt_sleep_ms) + AcpiOsSleep(batt_sleep_ms); + } + +out: + return (error); +} + +static int +acpi_smbat_get_bst(device_t dev, struct acpi_bst *bst) +{ + struct acpi_smbat_softc *sc; + int error; + uint32_t cap_units, factor; + int16_t val; + uint8_t addr; + + ACPI_SERIAL_BEGIN(smbat); + + addr = SMBATT_ADDRESS; + error = ENXIO; + sc = device_get_softc(dev); + + if (!acpi_smbat_info_expired(&sc->bst_lastupdated)) { + error = 0; + goto out; + } + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val)) + goto out; + if (val & SMBATT_BM_CAPACITY_MODE) { + factor = 10; + cap_units = ACPI_BIF_UNITS_MW; + } else { + factor = 1; + cap_units = ACPI_BIF_UNITS_MA; + } + + /* get battery status */ + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_STATUS, &val)) + goto out; + + sc->bst.state = 0; + if (val & SMBATT_BS_DISCHARGING) + sc->bst.state |= ACPI_BATT_STAT_DISCHARG; + + if (val & SMBATT_BS_REMAINING_CAPACITY_ALARM) + sc->bst.state |= ACPI_BATT_STAT_CRITICAL; + + /* + * If the rate is negative, it is discharging. Otherwise, + * it is charging. + */ + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_CURRENT, &val)) + goto out; + + if (val > 0) { + sc->bst.rate = val * factor; + sc->bst.state &= ~SMBATT_BS_DISCHARGING; + sc->bst.state |= ACPI_BATT_STAT_CHARGING; + } else if (val < 0) + sc->bst.rate = (-val) * factor; + else + sc->bst.rate = 0; + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_REMAINING_CAPACITY, &val)) + goto out; + sc->bst.cap = val * factor; + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_VOLTAGE, &val)) + goto out; + sc->bst.volt = val; + + acpi_smbat_info_updated(&sc->bst_lastupdated); + error = 0; + +out: + if (error == 0) + memcpy(bst, &sc->bst, sizeof(sc->bst)); + ACPI_SERIAL_END(smbat); + return (error); +} + +static int +acpi_smbat_get_bif(device_t dev, struct acpi_bif *bif) +{ + struct acpi_smbat_softc *sc; + int error; + uint32_t factor; + uint16_t val; + uint8_t addr; + + ACPI_SERIAL_BEGIN(smbat); + + addr = SMBATT_ADDRESS; + error = ENXIO; + sc = device_get_softc(dev); + + if (!acpi_smbat_info_expired(&sc->bif_lastupdated)) { + error = 0; + goto out; + } + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_BATTERY_MODE, &val)) + goto out; + if (val & SMBATT_BM_CAPACITY_MODE) { + factor = 10; + sc->bif.units = ACPI_BIF_UNITS_MW; + } else { + factor = 1; + sc->bif.units = ACPI_BIF_UNITS_MA; + } + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_CAPACITY, &val)) + goto out; + sc->bif.dcap = val * factor; + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_FULL_CHARGE_CAPACITY, &val)) + goto out; + sc->bif.lfcap = val * factor; + sc->bif.btech = 1; /* secondary (rechargeable) */ + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_DESIGN_VOLTAGE, &val)) + goto out; + sc->bif.dvol = val; + + sc->bif.wcap = sc->bif.dcap / 10; + sc->bif.lcap = sc->bif.dcap / 10; + + sc->bif.gra1 = factor; /* not supported */ + sc->bif.gra2 = factor; /* not supported */ + + if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_NAME, + sc->bif.model, sizeof(sc->bif.model))) + goto out; + + if (acpi_smbus_read_2(sc, addr, SMBATT_CMD_SERIAL_NUMBER, &val)) + goto out; + ksnprintf(sc->bif.serial, sizeof(sc->bif.serial), "0x%04x", val); + + if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_DEVICE_CHEMISTRY, + sc->bif.type, sizeof(sc->bif.type))) + goto out; + + if (acpi_smbus_read_multi_1(sc, addr, SMBATT_CMD_MANUFACTURER_DATA, + sc->bif.oeminfo, sizeof(sc->bif.oeminfo))) + goto out; + + /* XXX check if device was replugged during read? */ + + acpi_smbat_info_updated(&sc->bif_lastupdated); + error = 0; + +out: + if (error == 0) + memcpy(bif, &sc->bif, sizeof(sc->bif)); + ACPI_SERIAL_END(smbat); + return (error); +} diff --git a/sys/dev/acpica5/acpi_smbus.h b/sys/dev/acpica5/acpi_smbus.h new file mode 100644 index 0000000000..6a2898cb81 --- /dev/null +++ b/sys/dev/acpica5/acpi_smbus.h @@ -0,0 +1,285 @@ +/*- + * 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: src/sys/dev/acpica/acpi_smbus.h,v 1.1 2005/10/23 00:20:13 njl Exp $ + */ + +#ifndef _ACPI_SMBUS_H_ +#define _ACPI_SMBUS_H_ + +/* + * 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 /* 32 bytes */ +#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_ */ -- 2.41.0