]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/xscale/ixp425/avila_gpio.c
arm: make some use of mallocarray(9).
[FreeBSD/FreeBSD.git] / sys / arm / xscale / ixp425 / avila_gpio.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
5  * Copyright (c) 2009, Luiz Otavio O Souza.
6  * Copyright (c) 2010, Andrew Thompson <thompsa@FreeBSD.org>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice unmodified, this list of conditions, and the following
14  *    disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*
33  * GPIO driver for Gateworks Avilia
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/rman.h>
46 #include <sys/lock.h>
47 #include <sys/mutex.h>
48 #include <sys/gpio.h>
49
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52 #include <arm/xscale/ixp425/ixp425reg.h>
53 #include <arm/xscale/ixp425/ixp425var.h>
54 #include <dev/gpio/gpiobusvar.h>
55
56 #include "gpio_if.h"
57
58 #define GPIO_SET_BITS(sc, reg, bits)    \
59         GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, (reg)) | (bits))
60
61 #define GPIO_CLEAR_BITS(sc, reg, bits)  \
62         GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, (reg)) & ~(bits))
63
64 struct avila_gpio_softc {
65         device_t                sc_dev;
66         device_t                sc_busdev;
67         bus_space_tag_t         sc_iot;
68         bus_space_handle_t      sc_gpio_ioh;
69         uint32_t                sc_valid;
70         struct gpio_pin         sc_pins[IXP4XX_GPIO_PINS];
71 };
72
73 struct avila_gpio_pin {
74         const char *name;
75         int pin;
76         int caps;
77 };
78
79 #define GPIO_PIN_IO     (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)
80 static struct avila_gpio_pin avila_gpio_pins[] = {
81         { "GPIO0", 0, GPIO_PIN_IO },
82         { "GPIO1", 1, GPIO_PIN_IO },
83         { "GPIO2", 2, GPIO_PIN_IO },
84         { "GPIO3", 3, GPIO_PIN_IO },
85         { "GPIO4", 4, GPIO_PIN_IO },
86         /*
87          * The following pins are connected to system devices and should not
88          * really be frobbed.
89          */
90 #if 0
91         { "SER_ENA", 5, GPIO_PIN_IO },
92         { "I2C_SCL", 6, GPIO_PIN_IO },
93         { "I2C_SDA", 7, GPIO_PIN_IO },
94         { "PCI_INTD", 8, GPIO_PIN_IO },
95         { "PCI_INTC", 9, GPIO_PIN_IO },
96         { "PCI_INTB", 10, GPIO_PIN_IO },
97         { "PCI_INTA", 11, GPIO_PIN_IO },
98         { "ATA_INT", 12, GPIO_PIN_IO },
99         { "PCI_RST", 13, GPIO_PIN_IO },
100         { "PCI_CLK", 14, GPIO_PIN_OUTPUT },
101         { "EX_CLK", 15, GPIO_PIN_OUTPUT },
102 #endif
103 };
104 #undef GPIO_PIN_IO
105
106 /*
107  * Helpers
108  */
109 static void avila_gpio_pin_configure(struct avila_gpio_softc *sc,
110     struct gpio_pin *pin, uint32_t flags);
111 static int  avila_gpio_pin_flags(struct avila_gpio_softc *sc, uint32_t pin);
112
113 /*
114  * Driver stuff
115  */
116 static int avila_gpio_probe(device_t dev);
117 static int avila_gpio_attach(device_t dev);
118 static int avila_gpio_detach(device_t dev);
119
120 /*
121  * GPIO interface
122  */
123 static device_t avila_gpio_get_bus(device_t);
124 static int avila_gpio_pin_max(device_t dev, int *maxpin);
125 static int avila_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
126 static int avila_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
127     *flags);
128 static int avila_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
129 static int avila_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
130 static int avila_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
131 static int avila_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
132 static int avila_gpio_pin_toggle(device_t dev, uint32_t pin);
133
134 static int
135 avila_gpio_pin_flags(struct avila_gpio_softc *sc, uint32_t pin)
136 {
137         uint32_t v;
138
139         v = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & (1 << pin);
140
141         return (v ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT);
142 }
143
144 static void
145 avila_gpio_pin_configure(struct avila_gpio_softc *sc, struct gpio_pin *pin,
146     unsigned int flags)
147 {
148         uint32_t mask;
149
150         mask = 1 << pin->gp_pin;
151
152         /*
153          * Manage input/output
154          */
155         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
156                 IXP4XX_GPIO_LOCK();
157                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
158                 if (flags & GPIO_PIN_OUTPUT) {
159                         pin->gp_flags |= GPIO_PIN_OUTPUT;
160                         GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOER, mask);
161                 }
162                 else {
163                         pin->gp_flags |= GPIO_PIN_INPUT;
164                         GPIO_SET_BITS(sc, IXP425_GPIO_GPOER, mask);
165                 }
166                 IXP4XX_GPIO_UNLOCK();
167         }
168 }
169
170 static device_t
171 avila_gpio_get_bus(device_t dev)
172 {
173         struct avila_gpio_softc *sc;
174
175         sc = device_get_softc(dev);
176
177         return (sc->sc_busdev);
178 }
179
180 static int
181 avila_gpio_pin_max(device_t dev, int *maxpin)
182 {
183
184         *maxpin = IXP4XX_GPIO_PINS - 1;
185         return (0);
186 }
187
188 static int
189 avila_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
190 {
191         struct avila_gpio_softc *sc = device_get_softc(dev);
192
193         if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin)))
194                 return (EINVAL);
195
196         *caps = sc->sc_pins[pin].gp_caps;
197         return (0);
198 }
199
200 static int
201 avila_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
202 {
203         struct avila_gpio_softc *sc = device_get_softc(dev);
204
205         if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin)))
206                 return (EINVAL);
207
208         IXP4XX_GPIO_LOCK();
209         /* refresh since we do not own all the pins */
210         sc->sc_pins[pin].gp_flags = avila_gpio_pin_flags(sc, pin);
211         *flags = sc->sc_pins[pin].gp_flags;
212         IXP4XX_GPIO_UNLOCK();
213
214         return (0);
215 }
216
217 static int
218 avila_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
219 {
220         struct avila_gpio_softc *sc = device_get_softc(dev);
221
222         if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin)))
223                 return (EINVAL);
224
225         memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME);
226         return (0);
227 }
228
229 static int
230 avila_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
231 {
232         struct avila_gpio_softc *sc = device_get_softc(dev);
233         uint32_t mask = 1 << pin;
234
235         if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask))
236                 return (EINVAL);
237
238         avila_gpio_pin_configure(sc, &sc->sc_pins[pin], flags);
239
240         return (0);
241 }
242
243 static int
244 avila_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
245 {
246         struct avila_gpio_softc *sc = device_get_softc(dev);
247         uint32_t mask = 1 << pin;
248
249         if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask))
250                 return (EINVAL);
251
252         IXP4XX_GPIO_LOCK();
253         if (value)
254                 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask);
255         else
256                 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask);
257         IXP4XX_GPIO_UNLOCK();
258
259         return (0);
260 }
261
262 static int
263 avila_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
264 {
265         struct avila_gpio_softc *sc = device_get_softc(dev);
266
267         if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin)))
268                 return (EINVAL);
269
270         IXP4XX_GPIO_LOCK();
271         *val = (GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & (1 << pin)) ? 1 : 0;
272         IXP4XX_GPIO_UNLOCK();
273
274         return (0);
275 }
276
277 static int
278 avila_gpio_pin_toggle(device_t dev, uint32_t pin)
279 {
280         struct avila_gpio_softc *sc = device_get_softc(dev);
281         uint32_t mask = 1 << pin;
282         int res;
283
284         if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask))
285                 return (EINVAL);
286
287         IXP4XX_GPIO_LOCK();
288         res = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & mask;
289         if (res)
290                 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask);
291         else
292                 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask);
293         IXP4XX_GPIO_UNLOCK();
294
295         return (0);
296 }
297
298 static int
299 avila_gpio_probe(device_t dev)
300 {
301
302         device_set_desc(dev, "Gateworks Avila GPIO driver");
303         return (0);
304 }
305
306 static int
307 avila_gpio_attach(device_t dev)
308 {
309 #define N(a)    (sizeof(a) / sizeof(a[0]))
310         struct avila_gpio_softc *sc = device_get_softc(dev);
311         struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
312         int i;
313
314         sc->sc_dev = dev;
315         sc->sc_iot = sa->sc_iot;
316         sc->sc_gpio_ioh = sa->sc_gpio_ioh;
317
318         for (i = 0; i < N(avila_gpio_pins); i++) {
319                 struct avila_gpio_pin *p = &avila_gpio_pins[i];
320
321                 strncpy(sc->sc_pins[p->pin].gp_name, p->name, GPIOMAXNAME);
322                 sc->sc_pins[p->pin].gp_pin = p->pin;
323                 sc->sc_pins[p->pin].gp_caps = p->caps;
324                 sc->sc_pins[p->pin].gp_flags = avila_gpio_pin_flags(sc, p->pin);
325                 sc->sc_valid |= 1 << p->pin;
326         }
327
328         sc->sc_busdev = gpiobus_attach_bus(dev);
329         if (sc->sc_busdev == NULL)
330                 return (ENXIO);
331
332         return (0);
333 #undef N
334 }
335
336 static int
337 avila_gpio_detach(device_t dev)
338 {
339
340         gpiobus_detach_bus(dev);
341
342         return(0);
343 }
344
345 static device_method_t gpio_avila_methods[] = {
346         DEVMETHOD(device_probe, avila_gpio_probe),
347         DEVMETHOD(device_attach, avila_gpio_attach),
348         DEVMETHOD(device_detach, avila_gpio_detach),
349
350         /* GPIO protocol */
351         DEVMETHOD(gpio_get_bus, avila_gpio_get_bus),
352         DEVMETHOD(gpio_pin_max, avila_gpio_pin_max),
353         DEVMETHOD(gpio_pin_getname, avila_gpio_pin_getname),
354         DEVMETHOD(gpio_pin_getflags, avila_gpio_pin_getflags),
355         DEVMETHOD(gpio_pin_getcaps, avila_gpio_pin_getcaps),
356         DEVMETHOD(gpio_pin_setflags, avila_gpio_pin_setflags),
357         DEVMETHOD(gpio_pin_get, avila_gpio_pin_get),
358         DEVMETHOD(gpio_pin_set, avila_gpio_pin_set),
359         DEVMETHOD(gpio_pin_toggle, avila_gpio_pin_toggle),
360         {0, 0},
361 };
362
363 static driver_t gpio_avila_driver = {
364         "gpio",
365         gpio_avila_methods,
366         sizeof(struct avila_gpio_softc),
367 };
368 static devclass_t gpio_avila_devclass;
369
370 DRIVER_MODULE(gpio_avila, ixp, gpio_avila_driver, gpio_avila_devclass, 0, 0);
371 MODULE_VERSION(gpio_avila, 1);