1 /* $OpenBSD: mvgpio.c,v 1.3 2021/10/24 17:52:26 mpi Exp $ */
2 /*
3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21
22 #include <machine/intr.h>
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_gpio.h>
28 #include <dev/ofw/ofw_misc.h>
29 #include <dev/ofw/fdt.h>
30
31 /* Registers. */
32 #define GPIO_DOUT 0x0000
33 #define GPIO_DOUTEN 0x0004
34 #define GPIO_DINACTLOW 0x000c
35 #define GPIO_DIN 0x0010
36
37 #define HREAD4(sc, reg) \
38 (regmap_read_4((sc)->sc_rm, (sc)->sc_offset + (reg)))
39 #define HWRITE4(sc, reg, val) \
40 regmap_write_4((sc)->sc_rm, (sc)->sc_offset + (reg), (val))
41 #define HSET4(sc, reg, bits) \
42 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
43 #define HCLR4(sc, reg, bits) \
44 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
45
46 struct mvgpio_softc {
47 struct device sc_dev;
48 struct regmap *sc_rm;
49 bus_size_t sc_offset;
50
51 struct gpio_controller sc_gc;
52 };
53
54 int mvgpio_match(struct device *, void *, void *);
55 void mvgpio_attach(struct device *, struct device *, void *);
56
57 const struct cfattach mvgpio_ca = {
58 sizeof (struct mvgpio_softc), mvgpio_match, mvgpio_attach
59 };
60
61 struct cfdriver mvgpio_cd = {
62 NULL, "mvgpio", DV_DULL
63 };
64
65 void mvgpio_config_pin(void *, uint32_t *, int);
66 int mvgpio_get_pin(void *, uint32_t *);
67 void mvgpio_set_pin(void *, uint32_t *, int);
68
69 int
mvgpio_match(struct device * parent,void * match,void * aux)70 mvgpio_match(struct device *parent, void *match, void *aux)
71 {
72 struct fdt_attach_args *faa = aux;
73
74 return OF_is_compatible(faa->fa_node, "marvell,armada-8k-gpio");
75 }
76
77 void
mvgpio_attach(struct device * parent,struct device * self,void * aux)78 mvgpio_attach(struct device *parent, struct device *self, void *aux)
79 {
80 struct mvgpio_softc *sc = (struct mvgpio_softc *)self;
81 struct fdt_attach_args *faa = aux;
82
83 sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
84 if (sc->sc_rm == NULL) {
85 printf(": no registers\n");
86 return;
87 }
88 sc->sc_offset = OF_getpropint(faa->fa_node, "offset", 0);
89
90 sc->sc_gc.gc_node = faa->fa_node;
91 sc->sc_gc.gc_cookie = sc;
92 sc->sc_gc.gc_config_pin = mvgpio_config_pin;
93 sc->sc_gc.gc_get_pin = mvgpio_get_pin;
94 sc->sc_gc.gc_set_pin = mvgpio_set_pin;
95 gpio_controller_register(&sc->sc_gc);
96
97 printf("\n");
98 }
99
100 void
mvgpio_config_pin(void * cookie,uint32_t * cells,int config)101 mvgpio_config_pin(void *cookie, uint32_t *cells, int config)
102 {
103 struct mvgpio_softc *sc = cookie;
104 uint32_t pin = cells[0];
105
106 if (pin >= 32)
107 return;
108
109 if (config & GPIO_CONFIG_OUTPUT)
110 HCLR4(sc, GPIO_DOUTEN, (1 << pin));
111 else
112 HSET4(sc, GPIO_DOUTEN, (1 << pin));
113 }
114
115 int
mvgpio_get_pin(void * cookie,uint32_t * cells)116 mvgpio_get_pin(void *cookie, uint32_t *cells)
117 {
118 struct mvgpio_softc *sc = cookie;
119 uint32_t pin = cells[0];
120 uint32_t flags = cells[1];
121 uint32_t reg;
122 int val;
123
124 if (pin >= 32)
125 return 0;
126
127 reg = HREAD4(sc, GPIO_DIN);
128 reg ^= HREAD4(sc, GPIO_DINACTLOW);
129 reg &= (1 << pin);
130 val = (reg >> pin) & 1;
131 if (flags & GPIO_ACTIVE_LOW)
132 val = !val;
133 return val;
134 }
135
136 void
mvgpio_set_pin(void * cookie,uint32_t * cells,int val)137 mvgpio_set_pin(void *cookie, uint32_t *cells, int val)
138 {
139 struct mvgpio_softc *sc = cookie;
140 uint32_t pin = cells[0];
141 uint32_t flags = cells[1];
142
143 if (pin >= 32)
144 return;
145
146 if (flags & GPIO_ACTIVE_LOW)
147 val = !val;
148 if (val)
149 HSET4(sc, GPIO_DOUT, (1 << pin));
150 else
151 HCLR4(sc, GPIO_DOUT, (1 << pin));
152 }
153