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