xref: /openbsd-src/sys/dev/acpi/aplgpio.c (revision c1a45aed656e7d5627c30c92421893a76f370ccb)
1 /*	$OpenBSD: aplgpio.c,v 1.5 2022/04/06 18:59:27 naddy Exp $	*/
2 /*
3  * Copyright (c) 2016 Mark Kettenis
4  * Copyright (c) 2019 James Hastings
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/malloc.h>
21 #include <sys/systm.h>
22 
23 #include <dev/acpi/acpireg.h>
24 #include <dev/acpi/acpivar.h>
25 #include <dev/acpi/acpidev.h>
26 #include <dev/acpi/amltypes.h>
27 #include <dev/acpi/dsdt.h>
28 
29 #define APLGPIO_CONF_TXSTATE	0x00000001
30 #define APLGPIO_CONF_RXSTATE	0x00000002
31 #define APLGPIO_CONF_RXINV	0x00800000
32 #define APLGPIO_CONF_RXEV_EDGE	0x02000000
33 #define APLGPIO_CONF_RXEV_ZERO	0x04000000
34 #define APLGPIO_CONF_RXEV_MASK	0x06000000
35 
36 #define APLGPIO_IRQ_STS		0x100
37 #define APLGPIO_IRQ_EN		0x110
38 #define APLGPIO_PAD_CFG0	0x500
39 
40 struct aplgpio_intrhand {
41 	int (*ih_func)(void *);
42 	void *ih_arg;
43 };
44 
45 struct aplgpio_softc {
46 	struct device sc_dev;
47 	struct acpi_softc *sc_acpi;
48 	struct aml_node *sc_node;
49 
50 	bus_space_tag_t sc_memt;
51 	bus_space_handle_t sc_memh;
52 	void *sc_ih;
53 
54 	int sc_npins;
55 	struct aplgpio_intrhand *sc_pin_ih;
56 
57 	struct acpi_gpio sc_gpio;
58 };
59 
60 int	aplgpio_match(struct device *, void *, void *);
61 void	aplgpio_attach(struct device *, struct device *, void *);
62 
63 const struct cfattach aplgpio_ca = {
64 	sizeof(struct aplgpio_softc), aplgpio_match, aplgpio_attach
65 };
66 
67 struct cfdriver aplgpio_cd = {
68 	NULL, "aplgpio", DV_DULL
69 };
70 
71 const char *aplgpio_hids[] = {
72 	"INT3452",
73 	NULL
74 };
75 
76 int	aplgpio_read_pin(void *, int);
77 void	aplgpio_write_pin(void *, int, int);
78 void	aplgpio_intr_establish(void *, int, int, int (*)(void *), void *);
79 int	aplgpio_intr(void *);
80 
81 int
82 aplgpio_match(struct device *parent, void *match, void *aux)
83 {
84 	struct acpi_attach_args *aaa = aux;
85 	struct cfdata *cf = match;
86 
87 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
88 		return 0;
89 	return acpi_matchhids(aaa, aplgpio_hids, cf->cf_driver->cd_name);
90 }
91 
92 void
93 aplgpio_attach(struct device *parent, struct device *self, void *aux)
94 {
95 	struct aplgpio_softc *sc = (struct aplgpio_softc *)self;
96 	struct acpi_attach_args *aaa = aux;
97 	int64_t uid;
98 	int i;
99 
100 	sc->sc_acpi = (struct acpi_softc *)parent;
101 	sc->sc_node = aaa->aaa_node;
102 	printf(" %s", sc->sc_node->name);
103 
104 	if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
105 		printf(": can't find uid\n");
106 		return;
107 	}
108 
109 	printf(" uid %lld", uid);
110 
111 	switch (uid) {
112 	case 1:
113 		sc->sc_npins = 78;
114 		break;
115 	case 2:
116 		sc->sc_npins = 77;
117 		break;
118 	case 3:
119 		sc->sc_npins = 47;
120 		break;
121 	case 4:
122 		sc->sc_npins = 43;
123 		break;
124 	default:
125 		printf("\n");
126 		return;
127 	}
128 
129 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
130 	printf(" irq %d", aaa->aaa_irq[0]);
131 
132 	sc->sc_memt = aaa->aaa_bst[0];
133 	if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0],
134 	    0, &sc->sc_memh)) {
135 		printf(": can't map registers\n");
136 		return;
137 	}
138 
139 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
140 	    M_DEVBUF, M_WAITOK | M_ZERO);
141 
142 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
143 	    IPL_BIO, aplgpio_intr, sc, sc->sc_dev.dv_xname);
144 	if (sc->sc_ih == NULL) {
145 		printf(": can't establish interrupt\n");
146 		goto unmap;
147 	}
148 
149 	sc->sc_gpio.cookie = sc;
150 	sc->sc_gpio.read_pin = aplgpio_read_pin;
151 	sc->sc_gpio.write_pin = aplgpio_write_pin;
152 	sc->sc_gpio.intr_establish = aplgpio_intr_establish;
153 	sc->sc_node->gpio = &sc->sc_gpio;
154 
155 	/* Mask and clear all interrupts. */
156 	for (i = 0; i < sc->sc_npins; i++) {
157 		if (i % 32 == 0) {
158 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
159 			    APLGPIO_IRQ_EN + (i / 32) * 4, 0x00000000);
160 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
161 			    APLGPIO_IRQ_STS + (i / 32) * 4, 0xffffffff);
162 		}
163 	}
164 
165 	printf(", %d pins\n", sc->sc_npins);
166 
167 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
168 	return;
169 
170 unmap:
171 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
172 	bus_space_unmap(sc->sc_memt, sc->sc_memh, aaa->aaa_size[0]);
173 }
174 
175 int
176 aplgpio_read_pin(void *cookie, int pin)
177 {
178 	struct aplgpio_softc *sc = cookie;
179 	uint32_t reg;
180 
181 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
182 	    APLGPIO_PAD_CFG0 + pin * 8);
183 
184 	return !!(reg & APLGPIO_CONF_RXSTATE);
185 }
186 
187 void
188 aplgpio_write_pin(void *cookie, int pin, int value)
189 {
190 	struct aplgpio_softc *sc = cookie;
191 	uint32_t reg;
192 
193 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
194 	    APLGPIO_PAD_CFG0 + pin * 8);
195 	if (value)
196 		reg |= APLGPIO_CONF_TXSTATE;
197 	else
198 		reg &= ~APLGPIO_CONF_TXSTATE;
199 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
200 	    APLGPIO_PAD_CFG0 + pin * 8, reg);
201 }
202 
203 void
204 aplgpio_intr_establish(void *cookie, int pin, int flags,
205     int (*func)(void *), void *arg)
206 {
207 	struct aplgpio_softc *sc = cookie;
208 	uint32_t reg;
209 
210 	KASSERT(pin >= 0 && pin < sc->sc_npins);
211 
212 	sc->sc_pin_ih[pin].ih_func = func;
213 	sc->sc_pin_ih[pin].ih_arg = arg;
214 
215 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
216 	    APLGPIO_PAD_CFG0 + pin * 8);
217 	reg &= ~(APLGPIO_CONF_RXEV_MASK | APLGPIO_CONF_RXINV);
218 	if ((flags & LR_GPIO_MODE) == 1)
219 		reg |= APLGPIO_CONF_RXEV_EDGE;
220 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
221 		reg |= APLGPIO_CONF_RXINV;
222 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
223 		reg |= APLGPIO_CONF_RXEV_EDGE | APLGPIO_CONF_RXEV_ZERO;
224 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
225 	    APLGPIO_PAD_CFG0 + pin * 8, reg);
226 
227 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
228 	    APLGPIO_IRQ_EN + (pin / 32) * 4);
229 	reg |= (1 << (pin % 32));
230 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
231 	    APLGPIO_IRQ_EN + (pin / 32) * 4, reg);
232 }
233 
234 int
235 aplgpio_intr(void *arg)
236 {
237 	struct aplgpio_softc *sc = arg;
238 	uint32_t status, enable;
239 	int rc = 0;
240 	int pin;
241 
242 	for (pin = 0; pin < sc->sc_npins; pin++) {
243 		if (pin % 32 == 0) {
244 			status = bus_space_read_4(sc->sc_memt, sc->sc_memh,
245 			    APLGPIO_IRQ_STS + (pin / 32) * 4);
246 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
247 			    APLGPIO_IRQ_STS + (pin / 32) * 4, status);
248 			enable = bus_space_read_4(sc->sc_memt, sc->sc_memh,
249 			    APLGPIO_IRQ_EN + (pin / 32) * 4);
250 			status &= enable;
251 		}
252 		if (status & (1 << (pin % 32))) {
253 			if (sc->sc_pin_ih[pin].ih_func)
254 				sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
255 			rc = 1;
256 		}
257 	}
258 	return rc;
259 }
260