xref: /openbsd-src/sys/dev/fdt/mvpinctrl.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /* $OpenBSD: mvpinctrl.c,v 1.6 2019/04/30 20:06:32 patrick Exp $ */
2 /*
3  * Copyright (c) 2013,2016 Patrick Wildt <patrick@blueri.se>
4  * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org>
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/systm.h>
21 #include <sys/device.h>
22 #include <sys/malloc.h>
23 
24 #include <machine/intr.h>
25 #include <machine/bus.h>
26 #include <machine/fdt.h>
27 
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/ofw_gpio.h>
30 #include <dev/ofw/ofw_misc.h>
31 #include <dev/ofw/ofw_pinctrl.h>
32 #include <dev/ofw/fdt.h>
33 
34 /* Armada 3700 Registers */
35 #define GPIO_DIRECTION		0x00
36 #define GPIO_INPUT		0x10
37 #define GPIO_OUTPUT		0x18
38 
39 #define HREAD4(sc, reg)							\
40 	(regmap_read_4((sc)->sc_rm, (reg)))
41 #define HWRITE4(sc, reg, val)						\
42 	regmap_write_4((sc)->sc_rm, (reg), (val))
43 #define HSET4(sc, reg, bits)						\
44 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
45 #define HCLR4(sc, reg, bits)						\
46 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
47 
48 struct mvpinctrl_pin {
49 	char *pin;
50 	char *function;
51 	int value;
52 	int pid;
53 };
54 
55 struct mvpinctrl_softc {
56 	struct device		 sc_dev;
57 	bus_space_tag_t		 sc_iot;
58 	bus_space_handle_t	 sc_ioh;
59 	struct regmap		*sc_rm;
60 	struct mvpinctrl_pin	*sc_pins;
61 	int			 sc_npins;
62 	struct gpio_controller	 sc_gc;
63 };
64 
65 int	mvpinctrl_match(struct device *, void *, void *);
66 void	mvpinctrl_attach(struct device *, struct device *, void *);
67 int	mvpinctrl_pinctrl(uint32_t, void *);
68 
69 void	mvpinctrl_config_pin(void *, uint32_t *, int);
70 int	mvpinctrl_get_pin(void *, uint32_t *);
71 void	mvpinctrl_set_pin(void *, uint32_t *, int);
72 
73 struct cfattach mvpinctrl_ca = {
74 	sizeof (struct mvpinctrl_softc), mvpinctrl_match, mvpinctrl_attach
75 };
76 
77 struct cfdriver mvpinctrl_cd = {
78 	NULL, "mvpinctrl", DV_DULL
79 };
80 
81 #define STR_HELPER(x) #x
82 #define STR(x) STR_HELPER(x)
83 #define MPP(id, func, val) { STR(mpp ## id), func, val, id }
84 
85 #include "mvpinctrl_pins.h"
86 
87 struct mvpinctrl_pins {
88 	const char *compat;
89 	struct mvpinctrl_pin *pins;
90 	int npins;
91 };
92 
93 struct mvpinctrl_pins mvpinctrl_pins[] = {
94 	{
95 		"marvell,mv88f6810-pinctrl",
96 		armada_38x_pins, nitems(armada_38x_pins)
97 	},
98 	{
99 		"marvell,mv88f6820-pinctrl",
100 		armada_38x_pins, nitems(armada_38x_pins)
101 	},
102 	{
103 		"marvell,mv88f6828-pinctrl",
104 		armada_38x_pins, nitems(armada_38x_pins)
105 	},
106 	{
107 		"marvell,ap806-pinctrl",
108 		armada_ap806_pins, nitems(armada_ap806_pins)
109 	},
110 	{
111 		"marvell,cp110-pinctrl",
112 		armada_cp110_pins, nitems(armada_cp110_pins)
113 	},
114 	{
115 		"marvell,armada-7k-pinctrl",
116 		armada_cp110_pins, nitems(armada_cp110_pins)
117 	},
118 	{
119 		"marvell,armada-8k-cpm-pinctrl",
120 		armada_cp110_pins, nitems(armada_cp110_pins)
121 	},
122 	{
123 		"marvell,armada-8k-cps-pinctrl",
124 		armada_cp110_pins, nitems(armada_cp110_pins)
125 	},
126 };
127 
128 int
129 mvpinctrl_match(struct device *parent, void *match, void *aux)
130 {
131 	struct fdt_attach_args *faa = aux;
132 	int i;
133 
134 	for (i = 0; i < nitems(mvpinctrl_pins); i++) {
135 		if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat))
136 			return 10;
137 	}
138 
139 	if (OF_is_compatible(faa->fa_node, "marvell,armada3710-sb-pinctrl"))
140 		return 10;
141 
142 	return 0;
143 }
144 
145 void
146 mvpinctrl_attach(struct device *parent, struct device *self, void *aux)
147 {
148 	struct mvpinctrl_softc *sc = (struct mvpinctrl_softc *)self;
149 	struct fdt_attach_args *faa = aux;
150 	int i, node;
151 
152 	if (faa->fa_nreg > 0) {
153 		sc->sc_iot = faa->fa_iot;
154 		if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
155 		    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
156 			printf(": can't map registers\n");
157 			return;
158 		}
159 
160 		regmap_register(faa->fa_node, sc->sc_iot, sc->sc_ioh,
161 		    faa->fa_reg[0].size);
162 		sc->sc_rm = regmap_bynode(faa->fa_node);
163 	} else {
164 		/* No registers; use regmap provided by parent. */
165 		sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node));
166 	}
167 
168 	if (sc->sc_rm == NULL) {
169 		printf(": no registers\n");
170 		return;
171 	}
172 
173 	printf("\n");
174 
175 	if (OF_is_compatible(faa->fa_node, "marvell,armada3710-sb-pinctrl")) {
176 		for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) {
177 			if (OF_getproplen(node, "gpio-controller") == 0)
178 				break;
179 		}
180 		KASSERT(node != 0);
181 		sc->sc_gc.gc_node = node;
182 		sc->sc_gc.gc_cookie = sc;
183 		sc->sc_gc.gc_config_pin = mvpinctrl_config_pin;
184 		sc->sc_gc.gc_get_pin = mvpinctrl_get_pin;
185 		sc->sc_gc.gc_set_pin = mvpinctrl_set_pin;
186 		gpio_controller_register(&sc->sc_gc);
187 		return;
188 	}
189 
190 	for (i = 0; i < nitems(mvpinctrl_pins); i++) {
191 		if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat)) {
192 			sc->sc_pins = mvpinctrl_pins[i].pins;
193 			sc->sc_npins = mvpinctrl_pins[i].npins;
194 			break;
195 		}
196 	}
197 
198 	KASSERT(sc->sc_pins);
199 	pinctrl_register(faa->fa_node, mvpinctrl_pinctrl, sc);
200 }
201 
202 int
203 mvpinctrl_pinctrl(uint32_t phandle, void *cookie)
204 {
205 	struct mvpinctrl_softc *sc = cookie;
206 	char *pins, *pin, *func;
207 	int i, flen, plen, node;
208 
209 	node = OF_getnodebyphandle(phandle);
210 	if (node == 0)
211 		return -1;
212 
213 	flen = OF_getproplen(node, "marvell,function");
214 	if (flen <= 0)
215 		return -1;
216 
217 	func = malloc(flen, M_TEMP, M_WAITOK);
218 	OF_getprop(node, "marvell,function", func, flen);
219 
220 	plen = OF_getproplen(node, "marvell,pins");
221 	if (plen <= 0)
222 		return -1;
223 
224 	pin = pins = malloc(plen, M_TEMP, M_WAITOK);
225 	OF_getprop(node, "marvell,pins", pins, plen);
226 
227 	while (plen > 0) {
228 		for (i = 0; i < sc->sc_npins; i++) {
229 			uint32_t off, shift;
230 
231 			if (strcmp(sc->sc_pins[i].pin, pin))
232 				continue;
233 			if (strcmp(sc->sc_pins[i].function, func))
234 				continue;
235 
236 			off = (sc->sc_pins[i].pid / 8) * sizeof(uint32_t);
237 			shift = (sc->sc_pins[i].pid % 8) * 4;
238 
239 			HWRITE4(sc, off, (HREAD4(sc, off) & ~(0xf << shift)) |
240 			    (sc->sc_pins[i].value << shift));
241 			break;
242 		}
243 
244 		if (i == sc->sc_npins)
245 			printf("%s: unsupported pin %s function %s\n",
246 			    sc->sc_dev.dv_xname, pin, func);
247 
248 		plen -= strlen(pin) + 1;
249 		pin += strlen(pin) + 1;
250 	}
251 
252 	free(func, M_TEMP, flen);
253 	free(pins, M_TEMP, plen);
254 	return 0;
255 }
256 
257 void
258 mvpinctrl_config_pin(void *cookie, uint32_t *cells, int config)
259 {
260 	struct mvpinctrl_softc *sc = cookie;
261 	uint32_t pin = cells[0];
262 
263 	if (pin > 32)
264 		return;
265 
266 	if (config & GPIO_CONFIG_OUTPUT)
267 		HSET4(sc, GPIO_DIRECTION, (1 << pin));
268 	else
269 		HCLR4(sc, GPIO_DIRECTION, (1 << pin));
270 }
271 
272 int
273 mvpinctrl_get_pin(void *cookie, uint32_t *cells)
274 {
275 	struct mvpinctrl_softc *sc = cookie;
276 	uint32_t pin = cells[0];
277 	uint32_t flags = cells[1];
278 	uint32_t reg;
279 	int val;
280 
281 	if (pin > 32)
282 		return 0;
283 
284 	reg = HREAD4(sc, GPIO_INPUT);
285 	reg &= (1 << pin);
286 	val = (reg >> pin) & 1;
287 	if (flags & GPIO_ACTIVE_LOW)
288 		val = !val;
289 	return val;
290 }
291 
292 void
293 mvpinctrl_set_pin(void *cookie, uint32_t *cells, int val)
294 {
295 	struct mvpinctrl_softc *sc = cookie;
296 	uint32_t pin = cells[0];
297 	uint32_t flags = cells[1];
298 
299 	if (pin > 32)
300 		return;
301 
302 	if (flags & GPIO_ACTIVE_LOW)
303 		val = !val;
304 	if (val)
305 		HSET4(sc, GPIO_OUTPUT, (1 << pin));
306 	else
307 		HCLR4(sc, GPIO_OUTPUT, (1 << pin));
308 }
309