summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2023-05-27 19:35:56 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2023-05-27 19:35:56 +0000
commit421d27ed572d9cd6e6c4156d8d8a30ecb91f263d (patch)
tree12386f070c4f1d09d58233dfc30b69e50a2fb124 /sys
parent7aa1e2a90b4f988a8f1182f0c6d905bb44a8a183 (diff)
Implement battery charge control.
ok patrick@, tobhe@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm64/dev/aplsmc.c123
1 files changed, 122 insertions, 1 deletions
diff --git a/sys/arch/arm64/dev/aplsmc.c b/sys/arch/arm64/dev/aplsmc.c
index 4117cb38e36..d365f81c072 100644
--- a/sys/arch/arm64/dev/aplsmc.c
+++ b/sys/arch/arm64/dev/aplsmc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aplsmc.c,v 1.21 2023/01/09 20:29:35 kettenis Exp $ */
+/* $OpenBSD: aplsmc.c,v 1.22 2023/05/27 19:35:55 kettenis Exp $ */
/*
* Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
*
@@ -43,6 +43,13 @@ extern void (*simplefb_burn_hook)(u_int);
extern void (*cpuresetfn)(void);
extern void (*powerdownfn)(void);
+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;
+
/* SMC mailbox endpoint */
#define SMC_EP 32
@@ -133,6 +140,9 @@ struct aplsmc_softc {
struct ksensordev sc_sensordev;
};
+#define CH0I_DISCHARGE (1 << 0)
+#define CH0C_INHIBIT (1 << 0)
+
struct aplsmc_softc *aplsmc_sc;
#ifndef SMALL_KERNEL
@@ -187,6 +197,10 @@ int aplsmc_settime(struct todr_chip_handle *, struct timeval *);
void aplsmc_reset(void);
void aplsmc_powerdown(void);
void aplsmc_reboot_attachhook(struct device *);
+void aplsmc_battery_init(struct aplsmc_softc *);
+int aplsmc_battery_setchargemode(int);
+int aplsmc_battery_setchargestart(int);
+int aplsmc_battery_setchargestop(int);
int
aplsmc_match(struct device *parent, void *match, void *aux)
@@ -337,11 +351,13 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux)
apm_setinfohook(aplsmc_apminfo);
#endif
+ aplsmc_battery_init(sc);
#endif
#ifdef SUSPEND
device_register_wakeup(&sc->sc_dev);
#endif
+
}
void
@@ -763,3 +779,108 @@ aplsmc_powerdown(void)
&shutdown_flag, sizeof(shutdown_flag));
aplsmc_write_key(sc, key, &off1, sizeof(off1));
}
+
+void
+aplsmc_battery_init(struct aplsmc_softc *sc)
+{
+ uint8_t ch0i, ch0c;
+ int error;
+
+ error = aplsmc_read_key(sc, SMC_KEY("CH0I"), &ch0i, sizeof(ch0i));
+ if (error)
+ return;
+ error = aplsmc_read_key(sc, SMC_KEY("CH0C"), &ch0c, sizeof(ch0c));
+ if (error)
+ return;
+
+ if (ch0i & CH0I_DISCHARGE)
+ hw_battery_chargemode = -1;
+ else if (ch0c & CH0C_INHIBIT)
+ hw_battery_chargemode = 0;
+ else
+ hw_battery_chargemode = 1;
+
+ hw_battery_chargestart = 0;
+ hw_battery_chargestop = 100;
+
+ hw_battery_setchargemode = aplsmc_battery_setchargemode;
+ hw_battery_setchargestart = aplsmc_battery_setchargestart;
+ hw_battery_setchargestop = aplsmc_battery_setchargestop;
+}
+
+int
+aplsmc_battery_setchargemode(int mode)
+{
+ struct aplsmc_softc *sc = aplsmc_sc;
+ uint8_t val;
+ int error;
+
+ switch (mode) {
+ case -1:
+ val = 0;
+ error = aplsmc_write_key(sc, SMC_KEY("CH0C"),
+ &val, sizeof(val));
+ if (error)
+ return error;
+ val = 1;
+ error = aplsmc_write_key(sc, SMC_KEY("CH0I"),
+ &val, sizeof(val));
+ if (error)
+ return error;
+ break;
+ case 0:
+ val = 0;
+ error = aplsmc_write_key(sc, SMC_KEY("CH0I"),
+ &val, sizeof(val));
+ if (error)
+ return error;
+ val = 1;
+ error = aplsmc_write_key(sc, SMC_KEY("CH0C"),
+ &val, sizeof(val));
+ if (error)
+ return error;
+ break;
+ case 1:
+ val = 0;
+ error = aplsmc_write_key(sc, SMC_KEY("CH0I"),
+ &val, sizeof(val));
+ if (error)
+ return error;
+ val = 0;
+ error = aplsmc_write_key(sc, SMC_KEY("CH0C"),
+ &val, sizeof(val));
+ if (error)
+ return error;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ hw_battery_chargemode = mode;
+ return 0;
+}
+
+int
+aplsmc_battery_setchargestart(int start)
+{
+ return EOPNOTSUPP;
+}
+
+int
+aplsmc_battery_setchargestop(int stop)
+{
+ struct aplsmc_softc *sc = aplsmc_sc;
+ uint8_t chwa;
+
+ if (stop <= 80) {
+ hw_battery_chargestart = 75;
+ hw_battery_chargestop = 80;
+ chwa = 1;
+ } else {
+ hw_battery_chargestart = 95;
+ hw_battery_chargestop = 100;
+ chwa = 0;
+ }
+
+ return aplsmc_write_key(sc, SMC_KEY("CHWA"), &chwa, sizeof(chwa));
+}