diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-05-20 12:02:47 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-05-20 12:02:47 +0000 |
commit | 08f563726411c64235b14f42d5f34d47c1bd2f5f (patch) | |
tree | c76c3c04e65fba57fb70d0fe626f8840878286eb /sys | |
parent | 1780ccdcf753ea7cfe46f5757a3367a6b5d8c7e3 (diff) |
Implement battery charge control.
ok patrick@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/acpi/acpithinkpad.c | 187 |
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; +} |