xref: /openbsd/sys/dev/fdt/qcpon.c (revision 2da80933)
1*2da80933Spatrick /*	$OpenBSD: qcpon.c,v 1.2 2022/11/10 16:20:54 patrick Exp $	*/
2c756b8eeSpatrick /*
3c756b8eeSpatrick  * Copyright (c) 2022 Patrick Wildt <patrick@blueri.se>
4c756b8eeSpatrick  *
5c756b8eeSpatrick  * Permission to use, copy, modify, and distribute this software for any
6c756b8eeSpatrick  * purpose with or without fee is hereby granted, provided that the above
7c756b8eeSpatrick  * copyright notice and this permission notice appear in all copies.
8c756b8eeSpatrick  *
9c756b8eeSpatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c756b8eeSpatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c756b8eeSpatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c756b8eeSpatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c756b8eeSpatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c756b8eeSpatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c756b8eeSpatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c756b8eeSpatrick  */
17c756b8eeSpatrick 
18c756b8eeSpatrick #include <sys/param.h>
19c756b8eeSpatrick #include <sys/malloc.h>
20c756b8eeSpatrick #include <sys/systm.h>
21c756b8eeSpatrick #include <sys/task.h>
22c756b8eeSpatrick #include <sys/proc.h>
23c756b8eeSpatrick #include <sys/signalvar.h>
24c756b8eeSpatrick 
25c756b8eeSpatrick #include <machine/bus.h>
26c756b8eeSpatrick #include <machine/fdt.h>
27c756b8eeSpatrick 
28c756b8eeSpatrick #include <dev/fdt/spmivar.h>
29c756b8eeSpatrick 
30c756b8eeSpatrick #include <dev/ofw/openfirm.h>
31c756b8eeSpatrick #include <dev/ofw/ofw_clock.h>
32c756b8eeSpatrick #include <dev/ofw/ofw_power.h>
33c756b8eeSpatrick #include <dev/ofw/fdt.h>
34c756b8eeSpatrick 
35c756b8eeSpatrick struct qcpon_softc {
36c756b8eeSpatrick 	struct device		sc_dev;
37c756b8eeSpatrick 	int			sc_node;
38c756b8eeSpatrick 
39c756b8eeSpatrick 	spmi_tag_t		sc_tag;
40c756b8eeSpatrick 	int8_t			sc_sid;
41c756b8eeSpatrick 
42c756b8eeSpatrick 	void			*sc_pwrkey_ih;
43*2da80933Spatrick 	int			sc_pwrkey_debounce;
44c756b8eeSpatrick 	struct task		sc_powerdown_task;
45c756b8eeSpatrick };
46c756b8eeSpatrick 
47c756b8eeSpatrick int	qcpon_match(struct device *, void *, void *);
48c756b8eeSpatrick void	qcpon_attach(struct device *, struct device *, void *);
49c756b8eeSpatrick 
50c756b8eeSpatrick int	qcpon_pwrkey_intr(void *);
51c756b8eeSpatrick void	qcpon_powerdown_task(void *);
52c756b8eeSpatrick 
53c756b8eeSpatrick const struct cfattach qcpon_ca = {
54c756b8eeSpatrick 	sizeof(struct qcpon_softc), qcpon_match, qcpon_attach
55c756b8eeSpatrick };
56c756b8eeSpatrick 
57c756b8eeSpatrick struct cfdriver qcpon_cd = {
58c756b8eeSpatrick 	NULL, "qcpon", DV_DULL
59c756b8eeSpatrick };
60c756b8eeSpatrick 
61c756b8eeSpatrick int
62c756b8eeSpatrick qcpon_match(struct device *parent, void *match, void *aux)
63c756b8eeSpatrick {
64c756b8eeSpatrick 	struct spmi_attach_args *saa = aux;
65c756b8eeSpatrick 
66c756b8eeSpatrick 	return OF_is_compatible(saa->sa_node, "qcom,pm8998-pon");
67c756b8eeSpatrick }
68c756b8eeSpatrick 
69c756b8eeSpatrick void
70c756b8eeSpatrick qcpon_attach(struct device *parent, struct device *self, void *aux)
71c756b8eeSpatrick {
72c756b8eeSpatrick 	struct spmi_attach_args *saa = aux;
73c756b8eeSpatrick 	struct qcpon_softc *sc = (struct qcpon_softc *)self;
74c756b8eeSpatrick 	int node, reg;
75c756b8eeSpatrick 
76c756b8eeSpatrick 	reg = OF_getpropint(saa->sa_node, "reg", -1);
77c756b8eeSpatrick 	if (reg < 0) {
78c756b8eeSpatrick 		printf(": can't find registers\n");
79c756b8eeSpatrick 		return;
80c756b8eeSpatrick 	}
81c756b8eeSpatrick 
82c756b8eeSpatrick 	sc->sc_node = saa->sa_node;
83c756b8eeSpatrick 	sc->sc_tag = saa->sa_tag;
84c756b8eeSpatrick 	sc->sc_sid = saa->sa_sid;
85c756b8eeSpatrick 
86c756b8eeSpatrick 	task_set(&sc->sc_powerdown_task, qcpon_powerdown_task, sc);
87c756b8eeSpatrick 
88c756b8eeSpatrick 	printf("\n");
89c756b8eeSpatrick 
90c756b8eeSpatrick 	for (node = OF_child(saa->sa_node); node; node = OF_peer(node)) {
91c756b8eeSpatrick 		if (OF_is_compatible(node, "qcom,pmk8350-pwrkey")) {
92c756b8eeSpatrick 			sc->sc_pwrkey_ih = fdt_intr_establish(node, IPL_BIO,
93c756b8eeSpatrick 			    qcpon_pwrkey_intr, sc, sc->sc_dev.dv_xname);
94c756b8eeSpatrick 			if (sc->sc_pwrkey_ih == NULL) {
95c756b8eeSpatrick 				printf("%s: can't establish interrupt\n",
96c756b8eeSpatrick 				    sc->sc_dev.dv_xname);
97c756b8eeSpatrick 				continue;
98c756b8eeSpatrick 			}
99c756b8eeSpatrick 		}
100c756b8eeSpatrick 	}
101c756b8eeSpatrick }
102c756b8eeSpatrick 
103c756b8eeSpatrick int
104c756b8eeSpatrick qcpon_pwrkey_intr(void *arg)
105c756b8eeSpatrick {
106c756b8eeSpatrick 	struct qcpon_softc *sc = arg;
107c756b8eeSpatrick 
108*2da80933Spatrick 	/* Ignore presses, handle releases. */
109*2da80933Spatrick 	sc->sc_pwrkey_debounce = (sc->sc_pwrkey_debounce + 1) % 2;
110*2da80933Spatrick 	if (sc->sc_pwrkey_debounce == 1)
111*2da80933Spatrick 		return 1;
112*2da80933Spatrick 
113c756b8eeSpatrick 	task_add(systq, &sc->sc_powerdown_task);
114c756b8eeSpatrick 	return 1;
115c756b8eeSpatrick }
116c756b8eeSpatrick 
117c756b8eeSpatrick void
118c756b8eeSpatrick qcpon_powerdown_task(void *arg)
119c756b8eeSpatrick {
120c756b8eeSpatrick 	extern int allowpowerdown;
121c756b8eeSpatrick 
122c756b8eeSpatrick 	if (allowpowerdown == 1) {
123c756b8eeSpatrick 		allowpowerdown = 0;
124c756b8eeSpatrick 		prsignal(initprocess, SIGUSR2);
125c756b8eeSpatrick 	}
126c756b8eeSpatrick }
127