xref: /openbsd-src/sys/dev/fdt/plgpio.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
1*9fdf0c62Smpi /*	$OpenBSD: plgpio.c,v 1.3 2021/10/24 17:52:26 mpi Exp $	*/
2290c6ee5Skettenis /*
3290c6ee5Skettenis  * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
4290c6ee5Skettenis  *
5290c6ee5Skettenis  * Permission to use, copy, modify, and distribute this software for any
6290c6ee5Skettenis  * purpose with or without fee is hereby granted, provided that the above
7290c6ee5Skettenis  * copyright notice and this permission notice appear in all copies.
8290c6ee5Skettenis  *
9290c6ee5Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10290c6ee5Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11290c6ee5Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12290c6ee5Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13290c6ee5Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14290c6ee5Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15290c6ee5Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16290c6ee5Skettenis  */
17290c6ee5Skettenis 
18290c6ee5Skettenis #include <sys/param.h>
19290c6ee5Skettenis #include <sys/systm.h>
20290c6ee5Skettenis #include <sys/device.h>
21290c6ee5Skettenis 
22290c6ee5Skettenis #include <machine/intr.h>
23290c6ee5Skettenis #include <machine/bus.h>
24290c6ee5Skettenis #include <machine/fdt.h>
25290c6ee5Skettenis 
26290c6ee5Skettenis #include <dev/ofw/openfirm.h>
27290c6ee5Skettenis #include <dev/ofw/ofw_gpio.h>
28290c6ee5Skettenis #include <dev/ofw/fdt.h>
29290c6ee5Skettenis 
30290c6ee5Skettenis /* Registers. */
31290c6ee5Skettenis #define GPIODATA(pin)		((1 << pin) << 2)
32290c6ee5Skettenis #define GPIODIR			0x400
33290c6ee5Skettenis 
34290c6ee5Skettenis #define HREAD1(sc, reg)							\
35290c6ee5Skettenis 	(bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg)))
36290c6ee5Skettenis #define HWRITE1(sc, reg, val)						\
37290c6ee5Skettenis 	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
38290c6ee5Skettenis #define HSET1(sc, reg, bits)						\
39290c6ee5Skettenis 	HWRITE1((sc), (reg), HREAD1((sc), (reg)) | (bits))
40290c6ee5Skettenis #define HCLR1(sc, reg, bits)						\
41290c6ee5Skettenis 	HWRITE1((sc), (reg), HREAD1((sc), (reg)) & ~(bits))
42290c6ee5Skettenis 
43290c6ee5Skettenis struct plgpio_softc {
44290c6ee5Skettenis 	struct device		sc_dev;
45290c6ee5Skettenis 	bus_space_tag_t		sc_iot;
46290c6ee5Skettenis 	bus_space_handle_t	sc_ioh;
47290c6ee5Skettenis 
48290c6ee5Skettenis 	struct gpio_controller	sc_gc;
49290c6ee5Skettenis };
50290c6ee5Skettenis 
51290c6ee5Skettenis int plgpio_match(struct device *, void *, void *);
52290c6ee5Skettenis void plgpio_attach(struct device *, struct device *, void *);
53290c6ee5Skettenis 
54*9fdf0c62Smpi const struct cfattach	plgpio_ca = {
55290c6ee5Skettenis 	sizeof (struct plgpio_softc), plgpio_match, plgpio_attach
56290c6ee5Skettenis };
57290c6ee5Skettenis 
58290c6ee5Skettenis struct cfdriver plgpio_cd = {
59290c6ee5Skettenis 	NULL, "plgpio", DV_DULL
60290c6ee5Skettenis };
61290c6ee5Skettenis 
62290c6ee5Skettenis void	plgpio_config_pin(void *, uint32_t *, int);
63290c6ee5Skettenis int	plgpio_get_pin(void *, uint32_t *);
64290c6ee5Skettenis void	plgpio_set_pin(void *, uint32_t *, int);
65290c6ee5Skettenis 
66290c6ee5Skettenis int
plgpio_match(struct device * parent,void * match,void * aux)67290c6ee5Skettenis plgpio_match(struct device *parent, void *match, void *aux)
68290c6ee5Skettenis {
69290c6ee5Skettenis 	struct fdt_attach_args *faa = aux;
70290c6ee5Skettenis 
71290c6ee5Skettenis 	return OF_is_compatible(faa->fa_node, "arm,pl061");
72290c6ee5Skettenis }
73290c6ee5Skettenis 
74290c6ee5Skettenis void
plgpio_attach(struct device * parent,struct device * self,void * aux)75290c6ee5Skettenis plgpio_attach(struct device *parent, struct device *self, void *aux)
76290c6ee5Skettenis {
77290c6ee5Skettenis 	struct plgpio_softc *sc = (struct plgpio_softc *)self;
78290c6ee5Skettenis 	struct fdt_attach_args *faa = aux;
79290c6ee5Skettenis 
80290c6ee5Skettenis 	if (faa->fa_nreg < 1) {
81290c6ee5Skettenis 		printf(": no registers\n");
82290c6ee5Skettenis 		return;
83290c6ee5Skettenis 	}
84290c6ee5Skettenis 
85290c6ee5Skettenis 	sc->sc_iot = faa->fa_iot;
86290c6ee5Skettenis 
87290c6ee5Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
88290c6ee5Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
89290c6ee5Skettenis 		printf(": can't map registers\n");
90290c6ee5Skettenis 		return;
91290c6ee5Skettenis 	}
92290c6ee5Skettenis 
93290c6ee5Skettenis 	sc->sc_gc.gc_node = faa->fa_node;
94290c6ee5Skettenis 	sc->sc_gc.gc_cookie = sc;
95290c6ee5Skettenis 	sc->sc_gc.gc_config_pin = plgpio_config_pin;
96290c6ee5Skettenis 	sc->sc_gc.gc_get_pin = plgpio_get_pin;
97290c6ee5Skettenis 	sc->sc_gc.gc_set_pin = plgpio_set_pin;
98290c6ee5Skettenis 	gpio_controller_register(&sc->sc_gc);
99290c6ee5Skettenis 
100290c6ee5Skettenis 	printf("\n");
101290c6ee5Skettenis }
102290c6ee5Skettenis 
103290c6ee5Skettenis void
plgpio_config_pin(void * cookie,uint32_t * cells,int config)104290c6ee5Skettenis plgpio_config_pin(void *cookie, uint32_t *cells, int config)
105290c6ee5Skettenis {
106290c6ee5Skettenis 	struct plgpio_softc *sc = cookie;
107290c6ee5Skettenis 	uint32_t pin = cells[0];
108290c6ee5Skettenis 
10967a9c868Sjsg 	if (pin >= 8)
110290c6ee5Skettenis 		return;
111290c6ee5Skettenis 
112290c6ee5Skettenis 	if (config & GPIO_CONFIG_OUTPUT)
113290c6ee5Skettenis 		HSET1(sc, GPIODIR, (1 << pin));
114290c6ee5Skettenis 	else
115290c6ee5Skettenis 		HCLR1(sc, GPIODIR, (1 << pin));
116290c6ee5Skettenis }
117290c6ee5Skettenis 
118290c6ee5Skettenis int
plgpio_get_pin(void * cookie,uint32_t * cells)119290c6ee5Skettenis plgpio_get_pin(void *cookie, uint32_t *cells)
120290c6ee5Skettenis {
121290c6ee5Skettenis 	struct plgpio_softc *sc = cookie;
122290c6ee5Skettenis 	uint32_t pin = cells[0];
123290c6ee5Skettenis 	uint32_t flags = cells[1];
124290c6ee5Skettenis 	uint32_t reg;
125290c6ee5Skettenis 	int val;
126290c6ee5Skettenis 
12767a9c868Sjsg 	if (pin >= 8)
128290c6ee5Skettenis 		return 0;
129290c6ee5Skettenis 
130290c6ee5Skettenis 	reg = HREAD1(sc, GPIODATA(pin));
131290c6ee5Skettenis 	val = !!reg;
132290c6ee5Skettenis 	if (flags & GPIO_ACTIVE_LOW)
133290c6ee5Skettenis 		val = !val;
134290c6ee5Skettenis 	return val;
135290c6ee5Skettenis }
136290c6ee5Skettenis 
137290c6ee5Skettenis void
plgpio_set_pin(void * cookie,uint32_t * cells,int val)138290c6ee5Skettenis plgpio_set_pin(void *cookie, uint32_t *cells, int val)
139290c6ee5Skettenis {
140290c6ee5Skettenis 	struct plgpio_softc *sc = cookie;
141290c6ee5Skettenis 	uint32_t pin = cells[0];
142290c6ee5Skettenis 	uint32_t flags = cells[1];
143290c6ee5Skettenis 
14467a9c868Sjsg 	if (pin >= 8)
145290c6ee5Skettenis 		return;
146290c6ee5Skettenis 
147290c6ee5Skettenis 	if (flags & GPIO_ACTIVE_LOW)
148290c6ee5Skettenis 		val = !val;
149290c6ee5Skettenis 	if (val)
150290c6ee5Skettenis 		HWRITE1(sc, GPIODATA(pin), (1 << pin));
151290c6ee5Skettenis 	else
152290c6ee5Skettenis 		HWRITE1(sc, GPIODATA(pin), 0);
153290c6ee5Skettenis }
154