]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/mpc85xx/qoriq_gpio.c
sysctl(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sys / powerpc / mpc85xx / qoriq_gpio.c
1 /*-
2  * Copyright (c) 2015 Justin Hibbits
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/mutex.h>
39 #include <sys/rman.h>
40 #include <sys/gpio.h>
41
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44 #include <machine/stdarg.h>
45
46 #include <dev/gpio/gpiobusvar.h>
47 #include <dev/ofw/ofw_bus.h>
48 #include <dev/ofw/ofw_bus_subr.h>
49
50 #include "gpio_if.h"
51
52 #define MAXPIN          (31)
53
54 #define VALID_PIN(u)    ((u) >= 0 && (u) <= MAXPIN)
55
56 #define GPIO_LOCK(sc)                   mtx_lock(&(sc)->sc_mtx)
57 #define GPIO_UNLOCK(sc)         mtx_unlock(&(sc)->sc_mtx)
58 #define GPIO_LOCK_INIT(sc) \
59         mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
60             "gpio", MTX_DEF)
61 #define GPIO_LOCK_DESTROY(_sc)  mtx_destroy(&_sc->sc_mtx);
62
63 #define GPIO_GPDIR      0x0
64 #define GPIO_GPODR      0x4
65 #define GPIO_GPDAT      0x8
66 #define GPIO_GPIER      0xc
67 #define GPIO_GPIMR      0x10
68 #define GPIO_GPICR      0x14
69
70 struct qoriq_gpio_softc {
71         device_t        dev;
72         device_t        busdev;
73         struct mtx      sc_mtx;
74         struct resource *sc_mem;        /* Memory resource */
75 };
76
77 static device_t
78 qoriq_gpio_get_bus(device_t dev)
79 {
80         struct qoriq_gpio_softc *sc;
81
82         sc = device_get_softc(dev);
83
84         return (sc->busdev);
85 }
86
87 static int
88 qoriq_gpio_pin_max(device_t dev, int *maxpin)
89 {
90
91         *maxpin = MAXPIN;
92         return (0);
93 }
94
95 /* Get a specific pin's capabilities. */
96 static int
97 qoriq_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
98 {
99
100         if (!VALID_PIN(pin))
101                 return (EINVAL);
102
103         *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN);
104
105         return (0);
106 }
107
108 /* Get a specific pin's name. */
109 static int
110 qoriq_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
111 {
112
113         if (!VALID_PIN(pin))
114                 return (EINVAL);
115
116         snprintf(name, GPIOMAXNAME, "qoriq_gpio%d.%d",
117             device_get_unit(dev), pin);
118         name[GPIOMAXNAME-1] = '\0';
119
120         return (0);
121 }
122
123 /* Set flags for the pin. */
124 static int
125 qoriq_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
126 {
127         struct qoriq_gpio_softc *sc = device_get_softc(dev);
128         uint32_t reg;
129
130         if (!VALID_PIN(pin))
131                 return (EINVAL);
132
133         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
134             (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
135                 return (EINVAL);
136
137         GPIO_LOCK(sc);
138         if (flags & GPIO_PIN_INPUT) {
139                 reg = bus_read_4(sc->sc_mem, GPIO_GPDIR);
140                 reg &= ~(1 << (31 - pin));
141                 bus_write_4(sc->sc_mem, GPIO_GPDIR, reg);
142         }
143         else if (flags & GPIO_PIN_OUTPUT) {
144                 reg = bus_read_4(sc->sc_mem, GPIO_GPDIR);
145                 reg |= (1 << (31 - pin));
146                 bus_write_4(sc->sc_mem, GPIO_GPDIR, reg);
147                 reg = bus_read_4(sc->sc_mem, GPIO_GPODR);
148                 if (flags & GPIO_PIN_OPENDRAIN)
149                         reg |= (1 << (31 - pin));
150                 else
151                         reg &= ~(1 << (31 - pin));
152                 bus_write_4(sc->sc_mem, GPIO_GPODR, reg);
153         }
154         GPIO_UNLOCK(sc);
155         return (0);
156 }
157
158 /* Set a specific output pin's value. */
159 static int
160 qoriq_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
161 {
162         struct qoriq_gpio_softc *sc = device_get_softc(dev);
163         uint32_t outvals;
164         uint8_t pinbit;
165
166         if (!VALID_PIN(pin) || value > 1)
167                 return (EINVAL);
168
169         GPIO_LOCK(sc);
170         pinbit = 31 - pin;
171
172         outvals = bus_read_4(sc->sc_mem, GPIO_GPDAT);
173         outvals &= ~(1 << pinbit);
174         outvals |= (value << pinbit);
175         bus_write_4(sc->sc_mem, GPIO_GPDAT, outvals);
176
177         GPIO_UNLOCK(sc);
178
179         return (0);
180 }
181
182 /* Get a specific pin's input value. */
183 static int
184 qoriq_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
185 {
186         struct qoriq_gpio_softc *sc = device_get_softc(dev);
187
188         if (!VALID_PIN(pin))
189                 return (EINVAL);
190
191         *value = (bus_read_4(sc->sc_mem, GPIO_GPDAT) >> (31 - pin)) & 1;
192
193         return (0);
194 }
195
196 /* Toggle a pin's output value. */
197 static int
198 qoriq_gpio_pin_toggle(device_t dev, uint32_t pin)
199 {
200         struct qoriq_gpio_softc *sc = device_get_softc(dev);
201         uint32_t val;
202
203         if (!VALID_PIN(pin))
204                 return (EINVAL);
205
206         GPIO_LOCK(sc);
207
208         val = bus_read_4(sc->sc_mem, GPIO_GPDAT);
209         val ^= (1 << (31 - pin));
210         bus_write_4(sc->sc_mem, GPIO_GPDAT, val);
211
212         GPIO_UNLOCK(sc);
213
214         return (0);
215 }
216
217 static struct ofw_compat_data gpio_matches[] = {
218     {"fsl,qoriq-gpio", 1},
219     {"fsl,pq3-gpio", 1},
220     {"fsl,mpc8572-gpio", 1},
221     {0, 0}
222 };
223
224 static int
225 qoriq_gpio_probe(device_t dev)
226 {
227
228         if (ofw_bus_search_compatible(dev, gpio_matches)->ocd_data == 0)
229                 return (ENXIO);
230
231         device_set_desc(dev, "Freescale QorIQ GPIO driver");
232
233         return (0);
234 }
235
236 static int qoriq_gpio_detach(device_t dev);
237
238 static int
239 qoriq_gpio_attach(device_t dev)
240 {
241         struct qoriq_gpio_softc *sc = device_get_softc(dev);
242         int rid;
243
244         sc->dev = dev;
245
246         GPIO_LOCK_INIT(sc);
247
248         /* Allocate memory. */
249         rid = 0;
250         sc->sc_mem = bus_alloc_resource_any(dev,
251                      SYS_RES_MEMORY, &rid, RF_ACTIVE);
252         if (sc->sc_mem == NULL) {
253                 device_printf(dev, "Can't allocate memory for device output port");
254                 qoriq_gpio_detach(dev);
255                 return (ENOMEM);
256         }
257
258         sc->busdev = gpiobus_attach_bus(dev);
259         if (sc->busdev == NULL) {
260                 qoriq_gpio_detach(dev);
261                 return (ENOMEM);
262         }
263
264         OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
265
266         return (0);
267 }
268
269 static int
270 qoriq_gpio_detach(device_t dev)
271 {
272         struct qoriq_gpio_softc *sc = device_get_softc(dev);
273
274         gpiobus_detach_bus(dev);
275
276         if (sc->sc_mem != NULL) {
277                 /* Release output port resource. */
278                 bus_release_resource(dev, SYS_RES_MEMORY,
279                                      rman_get_rid(sc->sc_mem), sc->sc_mem);
280         }
281
282         GPIO_LOCK_DESTROY(sc);
283
284         return (0);
285 }
286
287 static device_method_t qoriq_gpio_methods[] = {
288         /* device_if */
289         DEVMETHOD(device_probe,         qoriq_gpio_probe),
290         DEVMETHOD(device_attach,        qoriq_gpio_attach),
291         DEVMETHOD(device_detach,        qoriq_gpio_detach),
292
293         /* GPIO protocol */
294         DEVMETHOD(gpio_get_bus,         qoriq_gpio_get_bus),
295         DEVMETHOD(gpio_pin_max,         qoriq_gpio_pin_max),
296         DEVMETHOD(gpio_pin_getname,     qoriq_gpio_pin_getname),
297         DEVMETHOD(gpio_pin_getcaps,     qoriq_gpio_pin_getcaps),
298         DEVMETHOD(gpio_pin_get,         qoriq_gpio_pin_get),
299         DEVMETHOD(gpio_pin_set,         qoriq_gpio_pin_set),
300         DEVMETHOD(gpio_pin_setflags,    qoriq_gpio_pin_setflags),
301         DEVMETHOD(gpio_pin_toggle,      qoriq_gpio_pin_toggle),
302
303         DEVMETHOD_END
304 };
305
306 static driver_t qoriq_gpio_driver = {
307         "gpio",
308         qoriq_gpio_methods,
309         sizeof(struct qoriq_gpio_softc),
310 };
311 static devclass_t qoriq_gpio_devclass;
312
313 EARLY_DRIVER_MODULE(qoriq_gpio, simplebus, qoriq_gpio_driver,
314     qoriq_gpio_devclass, NULL, NULL,
315     BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);