--- /dev/null
+.\" $OpenBSD: gpiocharger.4,v 1.1 2021/09/25 18:40:07 kn Exp $
+.\"
+.\" Copyright (c) 2021 Klemens Nanni <kn@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.
+.\"
+.Dd $Mdocdate: September 25 2021 $
+.Dt GPIOCHARGER 4
+.Os
+.Sh NAME
+.Nm gpiocharger
+.Nd GPIO battery charger
+.Sh SYNOPSIS
+.Cd "gpiocharger* at fdt?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for battery chargers connected to GPIO pins.
+Currently, only power supply status events are supported.
+.Pp
+The power supply status (connected or disconnected) is set up as a sensor
+and can be monitored using
+.Xr sysctl 8
+or
+.Xr sensorsd 8 .
+.Sh SEE ALSO
+.Xr gpio 4 ,
+.Xr intro 4 ,
+.Xr sensorsd 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 7.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Klemens Nanni Aq Mt kn@openbsd.org .
--- /dev/null
+/* $OpenBSD: gpiocharger.c,v 1.1 2021/09/25 18:40:08 kn Exp $ */
+/*
+ * Copyright (c) 2021 Klemens Nanni <kn@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/gpio.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/gpio/gpiovar.h>
+#include <dev/ofw/ofw_gpio.h>
+#include <dev/ofw/ofw_pinctrl.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+#include <sys/sensors.h>
+
+struct gpiocharger_softc {
+ struct device sc_dev;
+ int sc_node;
+ uint32_t *sc_charger_pin;
+ struct ksensor sc_sensor;
+ struct ksensordev sc_sensordev;
+};
+
+int gpiocharger_match(struct device *, void *, void *);
+void gpiocharger_attach(struct device *, struct device *, void *);
+
+struct cfattach gpiocharger_ca = {
+ sizeof (struct gpiocharger_softc), gpiocharger_match, gpiocharger_attach
+};
+
+struct cfdriver gpiocharger_cd = {
+ NULL, "gpiocharger", DV_DULL
+};
+
+void gpiocharger_update_charger(void *);
+
+int
+gpiocharger_match(struct device *parent, void *match, void *aux)
+{
+ const struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "gpio-charger");
+}
+
+void
+gpiocharger_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gpiocharger_softc *sc = (struct gpiocharger_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ char *charger_type, *gpios_property;
+ int charger_type_len, gpios_len;
+ int node = faa->fa_node;
+
+ pinctrl_byname(node, "default");
+
+ charger_type_len = OF_getproplen(node, "charger-type");
+ if (charger_type_len <= 0)
+ goto nocharger;
+ gpios_property = "gpios";
+ gpios_len = OF_getproplen(node, gpios_property);
+ if (gpios_len <= 0) {
+ gpios_property = "charger-status-gpios";
+ gpios_len = OF_getproplen(node, gpios_property);
+ if (gpios_len <= 0)
+ goto nocharger;
+ }
+
+ charger_type = malloc(charger_type_len, M_TEMP, M_WAITOK);
+ OF_getprop(node, "charger-type", charger_type, charger_type_len);
+ sc->sc_charger_pin = malloc(gpios_len, M_DEVBUF, M_WAITOK);
+ OF_getpropintarray(node, gpios_property, sc->sc_charger_pin, gpios_len);
+ gpio_controller_config_pin(sc->sc_charger_pin, GPIO_CONFIG_INPUT);
+
+ strlcpy(sc->sc_sensor.desc, charger_type, sizeof(sc->sc_sensor.desc));
+ strlcat(sc->sc_sensor.desc, " power supply",
+ sizeof(sc->sc_sensor.desc));
+ sc->sc_sensor.type = SENSOR_INDICATOR;
+ sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
+ strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
+ sizeof(sc->sc_sensordev.xname));
+ sensordev_install(&sc->sc_sensordev);
+ sensor_task_register(sc, gpiocharger_update_charger, 5);
+
+ printf(": \"%s\"\n", charger_type);
+ free(charger_type, M_TEMP, charger_type_len);
+ return;
+
+nocharger:
+ printf(": no charger\n");
+}
+
+void
+gpiocharger_update_charger(void *arg)
+{
+ struct gpiocharger_softc *sc = arg;
+
+ sc->sc_sensor.value = gpio_controller_get_pin(sc->sc_charger_pin);
+}