From c756b8ee6ddeeb017558d39149859297b090b4cc Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 8 Nov 2022 19:44:28 +0000 Subject: [PATCH] Add qcpon(4), a driver for the Qualcomm PMIC block that hosts the powerkey and reset input. With this I can use the power button on my x13s to power off the machine. ok kettenis@ --- sys/dev/fdt/qcpon.c | 120 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 sys/dev/fdt/qcpon.c diff --git a/sys/dev/fdt/qcpon.c b/sys/dev/fdt/qcpon.c new file mode 100644 index 00000000000..0e23d507eb1 --- /dev/null +++ b/sys/dev/fdt/qcpon.c @@ -0,0 +1,120 @@ +/* $OpenBSD: qcpon.c,v 1.1 2022/11/08 19:44:28 patrick Exp $ */ +/* + * Copyright (c) 2022 Patrick Wildt + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +struct qcpon_softc { + struct device sc_dev; + int sc_node; + + spmi_tag_t sc_tag; + int8_t sc_sid; + + void *sc_pwrkey_ih; + struct task sc_powerdown_task; +}; + +int qcpon_match(struct device *, void *, void *); +void qcpon_attach(struct device *, struct device *, void *); + +int qcpon_pwrkey_intr(void *); +void qcpon_powerdown_task(void *); + +const struct cfattach qcpon_ca = { + sizeof(struct qcpon_softc), qcpon_match, qcpon_attach +}; + +struct cfdriver qcpon_cd = { + NULL, "qcpon", DV_DULL +}; + +int +qcpon_match(struct device *parent, void *match, void *aux) +{ + struct spmi_attach_args *saa = aux; + + return OF_is_compatible(saa->sa_node, "qcom,pm8998-pon"); +} + +void +qcpon_attach(struct device *parent, struct device *self, void *aux) +{ + struct spmi_attach_args *saa = aux; + struct qcpon_softc *sc = (struct qcpon_softc *)self; + int node, reg; + + reg = OF_getpropint(saa->sa_node, "reg", -1); + if (reg < 0) { + printf(": can't find registers\n"); + return; + } + + sc->sc_node = saa->sa_node; + sc->sc_tag = saa->sa_tag; + sc->sc_sid = saa->sa_sid; + + task_set(&sc->sc_powerdown_task, qcpon_powerdown_task, sc); + + printf("\n"); + + for (node = OF_child(saa->sa_node); node; node = OF_peer(node)) { + if (OF_is_compatible(node, "qcom,pmk8350-pwrkey")) { + sc->sc_pwrkey_ih = fdt_intr_establish(node, IPL_BIO, + qcpon_pwrkey_intr, sc, sc->sc_dev.dv_xname); + if (sc->sc_pwrkey_ih == NULL) { + printf("%s: can't establish interrupt\n", + sc->sc_dev.dv_xname); + continue; + } + } + } +} + +int +qcpon_pwrkey_intr(void *arg) +{ + struct qcpon_softc *sc = arg; + + task_add(systq, &sc->sc_powerdown_task); + return 1; +} + +void +qcpon_powerdown_task(void *arg) +{ + extern int allowpowerdown; + + if (allowpowerdown == 1) { + allowpowerdown = 0; + prsignal(initprocess, SIGUSR2); + } +} -- 2.20.1