]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/mv/a37x0_gpio.c
Upgrade to Bzip2 version 1.0.7.
[FreeBSD/FreeBSD.git] / sys / arm / mv / a37x0_gpio.c
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);