summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2023-05-20 12:02:47 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2023-05-20 12:02:47 +0000
commit08f563726411c64235b14f42d5f34d47c1bd2f5f (patch)
treec76c3c04e65fba57fb70d0fe626f8840878286eb /sys
parent1780ccdcf753ea7cfe46f5757a3367a6b5d8c7e3 (diff)
Implement battery charge control.
ok patrick@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/acpi/acpithinkpad.c187
1 files changed, 186 insertions, 1 deletions
diff --git a/sys/dev/acpi/acpithinkpad.c b/sys/dev/acpi/acpithinkpad.c
index d749588f27e..13ea8d8fd23 100644
--- a/sys/dev/acpi/acpithinkpad.c
+++ b/sys/dev/acpi/acpithinkpad.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpithinkpad.c,v 1.72 2023/04/27 19:06:57 miod Exp $ */
+/* $OpenBSD: acpithinkpad.c,v 1.73 2023/05/20 12:02:46 kettenis Exp $ */
/*
* Copyright (c) 2008 joshua stein <jcs@openbsd.org>
*
@@ -130,6 +130,11 @@
#define THINKPAD_MASK_BRIGHTNESS_DOWN (1 << 16)
#define THINKPAD_MASK_KBD_BACKLIGHT (1 << 17)
+#define THINKPAD_BATTERY_ERROR 0x80000000
+#define THINKPAD_BATTERY_SUPPORT 0x00000100
+#define THINKPAD_BATTERY_SUPPORT_BICG 0x00000020
+#define THINKPAD_BATTERY_SHIFT 8
+
struct acpithinkpad_softc {
struct device sc_dev;
@@ -190,6 +195,17 @@ extern int wskbd_set_mixermute(long, long);
extern int wskbd_set_mixervolume(long, long);
#endif
+int thinkpad_battery_setchargemode(int);
+int thinkpad_battery_setchargestart(int);
+int thinkpad_battery_setchargestop(int);
+
+extern int (*hw_battery_setchargemode)(int);
+extern int (*hw_battery_setchargestart)(int);
+extern int (*hw_battery_setchargestop)(int);
+extern int hw_battery_chargemode;
+extern int hw_battery_chargestart;
+extern int hw_battery_chargestop;
+
const struct cfattach acpithinkpad_ca = {
sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach,
NULL, thinkpad_activate
@@ -300,6 +316,8 @@ thinkpad_attach(struct device *parent, struct device *self, void *aux)
{
struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
struct acpi_attach_args *aa = aux;
+ struct aml_value arg;
+ uint64_t ret;
sc->sc_acpi = (struct acpi_softc *)parent;
sc->sc_devnode = aa->aaa_node;
@@ -344,6 +362,52 @@ thinkpad_attach(struct device *parent, struct device *self, void *aux)
ws_set_param = thinkpad_set_param;
}
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = 1;
+
+ hw_battery_chargemode = 1;
+ hw_battery_chargestart = 0;
+ hw_battery_chargestop = 100;
+
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCTG",
+ 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) {
+ if (ret & THINKPAD_BATTERY_SUPPORT) {
+ hw_battery_chargestart = ret & 0xff;
+ hw_battery_setchargestart =
+ thinkpad_battery_setchargestart;
+ }
+ }
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCSG",
+ 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) {
+ if (ret & THINKPAD_BATTERY_SUPPORT) {
+ if ((ret & 0xff) == 0)
+ hw_battery_chargestop = 100;
+ else
+ hw_battery_chargestop = ret & 0xff;
+ hw_battery_setchargestop =
+ thinkpad_battery_setchargestop;
+ }
+ }
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BDSG",
+ 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) {
+ if (ret & THINKPAD_BATTERY_SUPPORT) {
+ if (ret & 0x1)
+ hw_battery_chargemode = -1;
+ hw_battery_setchargemode =
+ thinkpad_battery_setchargemode;
+ }
+ }
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BICG",
+ 1, &arg, &ret) == 0 && (ret & THINKPAD_BATTERY_ERROR) == 0) {
+ if (ret & THINKPAD_BATTERY_SUPPORT_BICG) {
+ if (ret & 0x1)
+ hw_battery_chargemode = 0;
+ hw_battery_setchargemode =
+ thinkpad_battery_setchargemode;
+ }
+ }
+
/* Run thinkpad_hotkey on button presses */
aml_register_notify(sc->sc_devnode, aa->aaa_dev,
thinkpad_hotkey, sc, ACPIDEV_POLL);
@@ -836,3 +900,124 @@ thinkpad_get_volume_mute(struct acpithinkpad_softc *sc)
THINKPAD_ECOFFSET_VOLUME_MUTE_MASK);
}
#endif
+
+int
+thinkpad_battery_inhibit_charge(int state)
+{
+ struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
+ struct aml_value arg;
+ int battery = 1;
+ uint64_t ret;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = (0xffff << 8) | (battery << 4) | state;
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BICS",
+ 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR))
+ return EIO;
+
+ return 0;
+}
+
+int
+thinkpad_battery_force_discharge(int state)
+{
+ struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
+ struct aml_value arg;
+ int battery = 1;
+ uint64_t ret;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = (battery << THINKPAD_BATTERY_SHIFT) | state;
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BDSS",
+ 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR))
+ return EIO;
+
+ return 0;
+}
+
+int
+thinkpad_battery_setchargemode(int mode)
+{
+ int error;
+
+ switch (mode) {
+ case -1:
+ error = thinkpad_battery_inhibit_charge(1);
+ if (error)
+ return error;
+ error = thinkpad_battery_force_discharge(1);
+ if (error)
+ return error;
+ break;
+ case 0:
+ error = thinkpad_battery_force_discharge(0);
+ if (error)
+ return error;
+ error = thinkpad_battery_inhibit_charge(1);
+ if (error)
+ return error;
+ break;
+ case 1:
+ error = thinkpad_battery_force_discharge(0);
+ if (error)
+ return error;
+ error = thinkpad_battery_inhibit_charge(0);
+ if (error)
+ return error;
+ break;
+ default:
+ return EOPNOTSUPP;
+ }
+
+ hw_battery_chargemode = mode;
+ return 0;
+}
+
+int
+thinkpad_battery_setchargestart(int start)
+{
+ struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
+ struct aml_value arg;
+ int battery = 1;
+ uint64_t ret;
+
+ if (start >= hw_battery_chargestop)
+ return EINVAL;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = (battery << THINKPAD_BATTERY_SHIFT) | start;
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCCS",
+ 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR))
+ return EIO;
+
+ hw_battery_chargestart = start;
+ return 0;
+}
+
+int
+thinkpad_battery_setchargestop(int stop)
+{
+ struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
+ struct aml_value arg;
+ int battery = 1;
+ uint64_t ret;
+
+ if (stop <= hw_battery_chargestart)
+ return EINVAL;
+
+ if (stop == 100)
+ stop = 0;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = (battery << THINKPAD_BATTERY_SHIFT) | stop;
+ if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "BCSS",
+ 1, &arg, &ret) || (ret & THINKPAD_BATTERY_ERROR))
+ return EIO;
+
+ hw_battery_chargestop = (stop == 0) ? 100 : stop;
+ return 0;
+}