xref: /freebsd/sys/arm/mv/a37x0_gpio.c (revision 83129c0b650734f4ca6c6f9c214aa3110d2f129d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018-2019, Rubicon Communications, LLC (Netgate)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 
36 #include <sys/gpio.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/rman.h>
40 
41 #include <machine/bus.h>
42 #include <machine/resource.h>
43 
44 #include <dev/gpio/gpiobusvar.h>
45 #include <dev/ofw/ofw_bus.h>
46 #include <dev/ofw/ofw_bus_subr.h>
47 
48 #include "gpio_if.h"
49 
50 static struct resource_spec a37x0_gpio_res_spec[] = {
51 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },	/* Pinctl / GPIO */
52 	{ SYS_RES_MEMORY, 1, RF_ACTIVE },	/* Interrupts control */
53 	{ -1, 0, 0 }
54 };
55 
56 struct a37x0_gpio_softc {
57 	bus_space_tag_t		sc_bst;
58 	bus_space_handle_t	sc_bsh;
59 	device_t		sc_busdev;
60 	int			sc_type;
61 	uint32_t		sc_max_pins;
62 	uint32_t		sc_npins;
63 	struct resource		*sc_mem_res[nitems(a37x0_gpio_res_spec) - 1];
64 };
65 
66 /* Memory regions. */
67 #define	A37X0_GPIO			0
68 #define	A37X0_INTR			1
69 
70 /* North Bridge / South Bridge. */
71 #define	A37X0_NB_GPIO			1
72 #define	A37X0_SB_GPIO			2
73 
74 #define	A37X0_GPIO_WRITE(_sc, _off, _val)		\
75     bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off), (_val))
76 #define	A37X0_GPIO_READ(_sc, _off)			\
77     bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off))
78 
79 #define	A37X0_GPIO_BIT(_p)		(1U << ((_p) % 32))
80 #define	A37X0_GPIO_OUT_EN(_p)		(0x0 + ((_p) / 32) * 4)
81 #define	A37X0_GPIO_LATCH(_p)		(0x8 + ((_p) / 32) * 4)
82 #define	A37X0_GPIO_INPUT(_p)		(0x10 + ((_p) / 32) * 4)
83 #define	A37X0_GPIO_OUTPUT(_p)		(0x18 + ((_p) / 32) * 4)
84 #define	A37X0_GPIO_SEL			0x30
85 
86 
87 static struct ofw_compat_data compat_data[] = {
88 	{ "marvell,armada3710-nb-pinctrl",	A37X0_NB_GPIO },
89 	{ "marvell,armada3710-sb-pinctrl",	A37X0_SB_GPIO },
90 	{ NULL, 0 }
91 };
92 
93 static phandle_t
94 a37x0_gpio_get_node(device_t bus, device_t dev)
95 {
96 
97 	return (ofw_bus_get_node(bus));
98 }
99 
100 static device_t
101 a37x0_gpio_get_bus(device_t dev)
102 {
103 	struct a37x0_gpio_softc *sc;
104 
105 	sc = device_get_softc(dev);
106 
107 	return (sc->sc_busdev);
108 }
109 
110 static int
111 a37x0_gpio_pin_max(device_t dev, int *maxpin)
112 {
113 	struct a37x0_gpio_softc *sc;
114 
115 	sc = device_get_softc(dev);
116 	*maxpin = sc->sc_npins - 1;
117 
118 	return (0);
119 }
120 
121 static int
122 a37x0_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
123 {
124 	struct a37x0_gpio_softc *sc;
125 
126 	sc = device_get_softc(dev);
127 	if (pin >= sc->sc_npins)
128 		return (EINVAL);
129 	snprintf(name, GPIOMAXNAME, "pin %d", pin);
130 
131 	return (0);
132 }
133 
134 static int
135 a37x0_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
136 {
137 	struct a37x0_gpio_softc *sc;
138 
139 	sc = device_get_softc(dev);
140 	if (pin >= sc->sc_npins)
141 		return (EINVAL);
142 	*caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
143 
144 	return (0);
145 }
146 
147 static int
148 a37x0_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
149 {
150 	struct a37x0_gpio_softc *sc;
151 	uint32_t reg;
152 
153 	sc = device_get_softc(dev);
154 	if (pin >= sc->sc_npins)
155 		return (EINVAL);
156 	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
157 	if ((reg & A37X0_GPIO_BIT(pin)) != 0)
158 		*flags = GPIO_PIN_OUTPUT;
159 	else
160 		*flags = GPIO_PIN_INPUT;
161 
162 	return (0);
163 }
164 
165 static int
166 a37x0_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
167 {
168 	struct a37x0_gpio_softc *sc;
169 	uint32_t reg;
170 
171 	sc = device_get_softc(dev);
172 	if (pin >= sc->sc_npins)
173 		return (EINVAL);
174 
175 	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
176 	if (flags & GPIO_PIN_OUTPUT)
177 		reg |= A37X0_GPIO_BIT(pin);
178 	else
179 		reg &= ~A37X0_GPIO_BIT(pin);
180 	A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUT_EN(pin), reg);
181 
182 	return (0);
183 }
184 
185 static int
186 a37x0_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
187 {
188 	struct a37x0_gpio_softc *sc;
189 	uint32_t reg;
190 
191 	sc = device_get_softc(dev);
192 	if (pin >= sc->sc_npins)
193 		return (EINVAL);
194 
195 	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
196 	if ((reg & A37X0_GPIO_BIT(pin)) != 0)
197 		reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin));
198 	else
199 		reg = A37X0_GPIO_READ(sc, A37X0_GPIO_INPUT(pin));
200 	*val = ((reg & A37X0_GPIO_BIT(pin)) != 0) ? 1 : 0;
201 
202 	return (0);
203 }
204 
205 static int
206 a37x0_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
207 {
208 	struct a37x0_gpio_softc *sc;
209 	uint32_t reg;
210 
211 	sc = device_get_softc(dev);
212 	if (pin >= sc->sc_npins)
213 		return (EINVAL);
214 
215 	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin));
216 	if (val != 0)
217 		reg |= A37X0_GPIO_BIT(pin);
218 	else
219 		reg &= ~A37X0_GPIO_BIT(pin);
220 	A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUTPUT(pin), reg);
221 
222 	return (0);
223 }
224 
225 static int
226 a37x0_gpio_pin_toggle(device_t dev, uint32_t pin)
227 {
228 	struct a37x0_gpio_softc *sc;
229 	uint32_t reg;
230 
231 	sc = device_get_softc(dev);
232 	if (pin >= sc->sc_npins)
233 		return (EINVAL);
234 
235 	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
236 	if ((reg & A37X0_GPIO_BIT(pin)) == 0)
237 		return (EINVAL);
238 	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin));
239 	reg ^= A37X0_GPIO_BIT(pin);
240 	A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUTPUT(pin), reg);
241 
242 	return (0);
243 }
244 
245 static int
246 a37x0_gpio_probe(device_t dev)
247 {
248 	const char *desc;
249 	struct a37x0_gpio_softc *sc;
250 
251 	if (!OF_hasprop(ofw_bus_get_node(dev), "gpio-controller"))
252 		return (ENXIO);
253 
254 	sc = device_get_softc(dev);
255 	sc->sc_type = ofw_bus_search_compatible(
256 	    device_get_parent(dev), compat_data)->ocd_data;
257 	switch (sc->sc_type) {
258 	case A37X0_NB_GPIO:
259 		sc->sc_max_pins = 36;
260 		desc = "Armada 37x0 North Bridge GPIO Controller";
261 		break;
262 	case A37X0_SB_GPIO:
263 		sc->sc_max_pins = 30;
264 		desc = "Armada 37x0 South Bridge GPIO Controller";
265 		break;
266 	default:
267 		return (ENXIO);
268 	}
269 	device_set_desc(dev, desc);
270 
271 	return (BUS_PROBE_DEFAULT);
272 }
273 
274 static int
275 a37x0_gpio_attach(device_t dev)
276 {
277 	int err, ncells;
278 	pcell_t *ranges;
279 	struct a37x0_gpio_softc *sc;
280 
281 	sc = device_get_softc(dev);
282 
283 	/* Read and verify the "gpio-ranges" property. */
284 	ncells = OF_getencprop_alloc(ofw_bus_get_node(dev), "gpio-ranges",
285 	    (void **)&ranges);
286 	if (ncells == -1)
287 		return (ENXIO);
288 	if (ncells != sizeof(*ranges) * 4 || ranges[1] != 0 || ranges[2] != 0) {
289 		OF_prop_free(ranges);
290 		return (ENXIO);
291 	}
292 	sc->sc_npins = ranges[3];
293 	OF_prop_free(ranges);
294 
295 	/* Check the number of pins in the DTS vs HW capabilities. */
296 	if (sc->sc_npins > sc->sc_max_pins)
297 		return (ENXIO);
298 
299 	err = bus_alloc_resources(dev, a37x0_gpio_res_spec, sc->sc_mem_res);
300 	if (err != 0) {
301 		device_printf(dev, "cannot allocate memory window\n");
302 		return (ENXIO);
303 	}
304 	sc->sc_bst = rman_get_bustag(sc->sc_mem_res[A37X0_GPIO]);
305 	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res[A37X0_GPIO]);
306 
307 	sc->sc_busdev = gpiobus_attach_bus(dev);
308 	if (sc->sc_busdev == NULL)
309 		return (ENXIO);
310 
311 	return (0);
312 }
313 
314 static int
315 a37x0_gpio_detach(device_t dev)
316 {
317 
318 	return (EBUSY);
319 }
320 
321 static device_method_t a37x0_gpio_methods[] = {
322 	/* Device interface */
323 	DEVMETHOD(device_probe,		a37x0_gpio_probe),
324 	DEVMETHOD(device_attach,	a37x0_gpio_attach),
325 	DEVMETHOD(device_detach,	a37x0_gpio_detach),
326 
327 	/* GPIO interface */
328 	DEVMETHOD(gpio_get_bus,		a37x0_gpio_get_bus),
329 	DEVMETHOD(gpio_pin_max,		a37x0_gpio_pin_max),
330 	DEVMETHOD(gpio_pin_getname,	a37x0_gpio_pin_getname),
331 	DEVMETHOD(gpio_pin_getcaps,	a37x0_gpio_pin_getcaps),
332 	DEVMETHOD(gpio_pin_getflags,	a37x0_gpio_pin_getflags),
333 	DEVMETHOD(gpio_pin_setflags,	a37x0_gpio_pin_setflags),
334 	DEVMETHOD(gpio_pin_get,		a37x0_gpio_pin_get),
335 	DEVMETHOD(gpio_pin_set,		a37x0_gpio_pin_set),
336 	DEVMETHOD(gpio_pin_toggle,	a37x0_gpio_pin_toggle),
337 
338 	/* ofw_bus interface */
339 	DEVMETHOD(ofw_bus_get_node,	a37x0_gpio_get_node),
340 
341 	DEVMETHOD_END
342 };
343 
344 static devclass_t a37x0_gpio_devclass;
345 static driver_t a37x0_gpio_driver = {
346 	"gpio",
347 	a37x0_gpio_methods,
348 	sizeof(struct a37x0_gpio_softc),
349 };
350 
351 EARLY_DRIVER_MODULE(a37x0_gpio, simple_mfd, a37x0_gpio_driver,
352     a37x0_gpio_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);
353