This populates `systat sensors' with the correct lid status on my Pinebook Pro:
-gpio-key-lid at mainbus0 not configured -gpio-key-power at mainbus0 not configured +gpiokeys0 at mainbus0: "Lid" +gpiokeys0 at mainbus0: "Power" 0/1 <-> closed/open is mapped exactly like acpibtn(4) already does on other machines, to maintain consistent user experience across devices. Next steps are: - hook up lid status with `machdep.lidaction', see acpibtn(4) - handle power button -> hook up machdep.pwraction, see acpibtn(4) Sort gpio{led,charger,keys} while here. Feedback? OK? diff 83b213946bcaccd148d4a46b6ebda89b120fc778 refs/heads/master blob - ab52b74cf7e9895cbcb29532b9898cdaf33e89f3 blob + 0891a80caf135b983dea282f281d7f6089b52e30 --- distrib/sets/lists/man/mi +++ distrib/sets/lists/man/mi @@ -1423,6 +1423,7 @@ ./usr/share/man/man4/gpiocharger.4 ./usr/share/man/man4/gpiodcf.4 ./usr/share/man/man4/gpioiic.4 +./usr/share/man/man4/gpiokeys.4 ./usr/share/man/man4/gpioleds.4 ./usr/share/man/man4/gpioow.4 ./usr/share/man/man4/graphaudio.4 blob - c32bc8962cd103da4ed17ad63a2162f63a16e639 blob + 6057d2a559120ada9f43ae0f5e5e6eb63a514be8 --- share/man/man4/Makefile +++ share/man/man4/Makefile @@ -37,7 +37,7 @@ MAN= aac.4 abcrtc.4 abl.4 ac97.4 acphy.4 acrtc.4 \ fuse.4 fxp.4 \ gdt.4 gentbi.4 gem.4 gfrtc.4 gif.4 glenv.4 glkgpio.4 gpio.4 \ gpiocharger.4 gpiodcf.4 \ - gpioiic.4 gpioleds.4 gpioow.4 graphaudio.4 gre.4 gscsio.4 \ + gpioiic.4 gpiokeys.4 gpioleds.4 gpioow.4 graphaudio.4 gre.4 gscsio.4 \ hds.4 hiclock.4 hidwusb.4 hil.4 hilid.4 hilkbd.4 hilms.4 \ hireset.4 hitemp.4 hme.4 hotplug.4 hsq.4 \ hvn.4 hvs.4 hyperv.4 \ blob - /dev/null blob + 44c147f04672fa1b72820ebd7692d7efbe17ceae (mode 644) --- /dev/null +++ share/man/man4/gpiokeys.4 @@ -0,0 +1,50 @@ +.\" $OpenBSD: $ +.\" +.\" Copyright (c) 2021 Klemens Nanni <k...@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 02 2021 $ +.Dt GPIOKEYS 4 +.Os +.Sh NAME +.Nm gpiokeys +.Nd GPIO keys +.Sh SYNOPSIS +.Cd "gpiokeys* at fdt?" +.Sh DESCRIPTION +The +.Nm +driver handles events triggered by GPIO keys. +Currently, only lid status events are supported. +.Pp +The lid status 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 k...@openbsd.org . blob - 809ece860c07df596da208638f2f3facc829cb72 blob + 0ceac9b6159e5cfe43fc4e601274100df1c40ffa --- sys/arch/arm64/conf/GENERIC +++ sys/arch/arm64/conf/GENERIC @@ -131,8 +131,9 @@ amdgpu* at pci? drm* at amdgpu? wsdisplay* at amdgpu? -gpioleds* at fdt? gpiocharger* at fdt? +gpiokeys* at fdt? +gpioleds* at fdt? # Apple apldart* at fdt? blob - 301500e9b0c6501be4d55feb5135ca223d6337cc blob + 3d73e22edf7802172b29a26cb8b503eaeb8f3aa9 --- sys/dev/fdt/files.fdt +++ sys/dev/fdt/files.fdt @@ -589,10 +589,14 @@ device dapmic attach dapmic at i2c file dev/fdt/dapmic.c dapmic -device gpioleds -attach gpioleds at fdt -file dev/fdt/gpioleds.c gpioleds - device gpiocharger attach gpiocharger at fdt file dev/fdt/gpiocharger.c gpiocharger + +device gpioleds +attach gpioleds at fdt +file dev/fdt/gpioleds.c gpioleds + +device gpiokeys +attach gpiokeys at fdt +file dev/fdt/gpiokeys.c gpiokeys blob - /dev/null blob + 4b4ca55a5c825ad8d66fbc8ec198bbcd13352b7c (mode 644) --- /dev/null +++ sys/dev/fdt/gpiokeys.c @@ -0,0 +1,179 @@ +/* $OpenBSD: $ */ +/* + * Copyright (c) 2021 Klemens Nanni <k...@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 <sys/queue.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> + +#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) + +/* + * Defines from Linux, see: + * Documentation/input/event-codes.rst + * include/dt-bindings/input/linux-event-codes.h + */ +enum gpiokeys_event_type { + GPIOKEYS_EV_KEY = 1, + GPIOKEYS_EV_SW = 5, +}; + +enum gpiokeys_switch_event { + GPIOKEYS_SW_LID = 0, /* set = lid closed */ +}; + +struct gpiokeys_key { + uint32_t *key_pin; + uint32_t key_input_type; + uint32_t key_code; + struct ksensor key_sensor; + SLIST_ENTRY(gpiokeys_key) entries; +}; + +struct gpiokeys_softc { + struct device sc_dev; + int sc_node; + struct ksensordev sc_sensordev; + SLIST_HEAD(, gpiokeys_key) sc_keys; +}; + +int gpiokeys_match(struct device *, void *, void *); +void gpiokeys_attach(struct device *, struct device *, void *); + +const struct cfattach gpiokeys_ca = { + sizeof (struct gpiokeys_softc), gpiokeys_match, gpiokeys_attach +}; + +struct cfdriver gpiokeys_cd = { + NULL, "gpiokeys", DV_DULL +}; + +void gpiokeys_update_key(void *); + +int +gpiokeys_match(struct device *parent, void *match, void *aux) +{ + const struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "gpio-keys") || + OF_is_compatible(faa->fa_node, "gpio-keys-polled"); +} + +void +gpiokeys_attach(struct device *parent, struct device *self, void *aux) +{ + struct gpiokeys_softc *sc = (struct gpiokeys_softc *)self; + struct fdt_attach_args *faa = aux; + struct gpiokeys_key *key; + char *label; + uint32_t code; + int node, len, gpios_len, have_sensors = 0; + + SLIST_INIT(&sc->sc_keys); + + pinctrl_byname(faa->fa_node, "default"); + + for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { + if (OF_getprop(node, "linux,code", &code, sizeof(code)) == -1) + continue; + gpios_len = OF_getproplen(node, "gpios"); + if (gpios_len <= 0) + continue; + len = OF_getproplen(node, "label"); + if (len <= 0) + continue; + label = malloc(len, M_TEMP, M_WAITOK); + if (OF_getprop(node, "label", label, len) != len) { + free(label, M_TEMP, len); + continue; + } + key = malloc(sizeof(*key), M_DEVBUF, M_WAITOK | M_ZERO); + key->key_input_type = OF_getpropint(node, "linux,input-type", + GPIOKEYS_EV_KEY); + key->key_code = code; + key->key_pin = malloc(gpios_len, M_DEVBUF, M_WAITOK); + OF_getpropintarray(node, "gpios", key->key_pin, gpios_len); + gpio_controller_config_pin(key->key_pin, GPIO_CONFIG_INPUT); + + switch (key->key_input_type) { + case GPIOKEYS_EV_SW: + switch (key->key_code) { + case GPIOKEYS_SW_LID: + strlcpy(key->key_sensor.desc, "lid open", + sizeof(key->key_sensor.desc)); + key->key_sensor.type = SENSOR_INDICATOR; + sensor_attach(&sc->sc_sensordev, &key->key_sensor); + sensor_task_register(key, gpiokeys_update_key, 1); + have_sensors = 1; + break; + } + break; + } + + printf("%s \"%s\"", SLIST_EMPTY(&sc->sc_keys) ? ":" : ",", + label); + free(label, M_TEMP, len); + + SLIST_INSERT_HEAD(&sc->sc_keys, key, entries); + } + + if (have_sensors) { + strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), + sizeof(sc->sc_sensordev.xname)); + sensordev_install(&sc->sc_sensordev); + } + + if (SLIST_EMPTY(&sc->sc_keys)) + printf(": no keys"); + printf("\n"); +} + +void +gpiokeys_update_key(void *arg) +{ + struct gpiokeys_key *key = arg; + int val; + + val = gpio_controller_get_pin(key->key_pin); + + switch (key->key_input_type) { + case GPIOKEYS_EV_SW: + switch (key->key_code) { + case GPIOKEYS_SW_LID: + /* + * Match acpibtn(4), i.e. closed ThinkPad lid yields + * hw.sensors.acpibtn1.indicator0=Off (lid open) + */ + key->key_sensor.value = !val; + break; + } + break; + } +}