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;
+       }
+}

Reply via email to