1/*-
2 * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
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
27/*
28 * Vybrid Family General-Purpose Input/Output (GPIO)
29 * Chapter 7, Vybrid Reference Manual, Rev. 5, 07/2013
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: releng/11.0/sys/arm/freescale/vybrid/vf_gpio.c 281085 2015-04-04 21:34:26Z andrew $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/bus.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <sys/malloc.h>
41#include <sys/rman.h>
42#include <sys/timeet.h>
43#include <sys/timetc.h>
44#include <sys/watchdog.h>
45#include <sys/mutex.h>
46#include <sys/gpio.h>
47
48#include <dev/fdt/fdt_common.h>
49#include <dev/gpio/gpiobusvar.h>
50#include <dev/ofw/openfirm.h>
51#include <dev/ofw/ofw_bus.h>
52#include <dev/ofw/ofw_bus_subr.h>
53
54#include <machine/bus.h>
55#include <machine/cpu.h>
56#include <machine/intr.h>
57
58#include "gpio_if.h"
59
60#include <arm/freescale/vybrid/vf_common.h>
61#include <arm/freescale/vybrid/vf_port.h>
62
63#define	GPIO_PDOR(n)	(0x00 + 0x40 * (n >> 5))
64#define	GPIO_PSOR(n)	(0x04 + 0x40 * (n >> 5))
65#define	GPIO_PCOR(n)	(0x08 + 0x40 * (n >> 5))
66#define	GPIO_PTOR(n)	(0x0C + 0x40 * (n >> 5))
67#define	GPIO_PDIR(n)	(0x10 + 0x40 * (n >> 5))
68
69#define	GPIO_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
70#define	GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_mtx)
71
72#define	DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
73
74/*
75 * GPIO interface
76 */
77static device_t vf_gpio_get_bus(device_t);
78static int vf_gpio_pin_max(device_t, int *);
79static int vf_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
80static int vf_gpio_pin_getname(device_t, uint32_t, char *);
81static int vf_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
82static int vf_gpio_pin_setflags(device_t, uint32_t, uint32_t);
83static int vf_gpio_pin_set(device_t, uint32_t, unsigned int);
84static int vf_gpio_pin_get(device_t, uint32_t, unsigned int *);
85static int vf_gpio_pin_toggle(device_t, uint32_t pin);
86
87struct vf_gpio_softc {
88	struct resource		*res[1];
89	bus_space_tag_t		bst;
90	bus_space_handle_t	bsh;
91
92	device_t		sc_busdev;
93	struct mtx		sc_mtx;
94	int			gpio_npins;
95	struct gpio_pin		gpio_pins[NGPIO];
96};
97
98struct vf_gpio_softc *gpio_sc;
99
100static struct resource_spec vf_gpio_spec[] = {
101	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
102	{ -1, 0 }
103};
104
105static int
106vf_gpio_probe(device_t dev)
107{
108
109	if (!ofw_bus_status_okay(dev))
110		return (ENXIO);
111
112	if (!ofw_bus_is_compatible(dev, "fsl,mvf600-gpio"))
113		return (ENXIO);
114
115	device_set_desc(dev, "Vybrid Family GPIO Unit");
116	return (BUS_PROBE_DEFAULT);
117}
118
119static int
120vf_gpio_attach(device_t dev)
121{
122	struct vf_gpio_softc *sc;
123	int i;
124
125	sc = device_get_softc(dev);
126	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
127
128	if (bus_alloc_resources(dev, vf_gpio_spec, sc->res)) {
129		device_printf(dev, "could not allocate resources\n");
130		mtx_destroy(&sc->sc_mtx);
131		return (ENXIO);
132	}
133
134	/* Memory interface */
135	sc->bst = rman_get_bustag(sc->res[0]);
136	sc->bsh = rman_get_bushandle(sc->res[0]);
137
138	gpio_sc = sc;
139
140	sc->gpio_npins = NGPIO;
141
142	for (i = 0; i < sc->gpio_npins; i++) {
143		sc->gpio_pins[i].gp_pin = i;
144		sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
145		sc->gpio_pins[i].gp_flags =
146		    (READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ?
147		    GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;
148		snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
149		    "vf_gpio%d.%d", device_get_unit(dev), i);
150	}
151
152	sc->sc_busdev = gpiobus_attach_bus(dev);
153	if (sc->sc_busdev == NULL) {
154		bus_release_resources(dev, vf_gpio_spec, sc->res);
155		mtx_destroy(&sc->sc_mtx);
156		return (ENXIO);
157	}
158
159	return (0);
160}
161
162static device_t
163vf_gpio_get_bus(device_t dev)
164{
165	struct vf_gpio_softc *sc;
166
167	sc = device_get_softc(dev);
168
169	return (sc->sc_busdev);
170}
171
172static int
173vf_gpio_pin_max(device_t dev, int *maxpin)
174{
175
176	*maxpin = NGPIO - 1;
177	return (0);
178}
179
180static int
181vf_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
182{
183	struct vf_gpio_softc *sc;
184	int i;
185
186	sc = device_get_softc(dev);
187	for (i = 0; i < sc->gpio_npins; i++) {
188		if (sc->gpio_pins[i].gp_pin == pin)
189			break;
190	}
191
192	if (i >= sc->gpio_npins)
193		return (EINVAL);
194
195	GPIO_LOCK(sc);
196	memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
197	GPIO_UNLOCK(sc);
198
199	return (0);
200}
201
202static int
203vf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
204{
205	struct vf_gpio_softc *sc;
206	int i;
207
208	sc = device_get_softc(dev);
209	for (i = 0; i < sc->gpio_npins; i++) {
210		if (sc->gpio_pins[i].gp_pin == pin)
211			break;
212	}
213
214	if (i >= sc->gpio_npins)
215		return (EINVAL);
216
217	GPIO_LOCK(sc);
218	*caps = sc->gpio_pins[i].gp_caps;
219	GPIO_UNLOCK(sc);
220
221	return (0);
222}
223
224static int
225vf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
226{
227	struct vf_gpio_softc *sc;
228	int i;
229
230	sc = device_get_softc(dev);
231	for (i = 0; i < sc->gpio_npins; i++) {
232		if (sc->gpio_pins[i].gp_pin == pin)
233			break;
234	}
235
236	if (i >= sc->gpio_npins)
237		return (EINVAL);
238
239	GPIO_LOCK(sc);
240	*flags = sc->gpio_pins[i].gp_flags;
241	GPIO_UNLOCK(sc);
242
243	return (0);
244}
245
246static int
247vf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
248{
249	struct vf_gpio_softc *sc;
250	int i;
251
252	sc = device_get_softc(dev);
253	for (i = 0; i < sc->gpio_npins; i++) {
254		if (sc->gpio_pins[i].gp_pin == pin)
255			break;
256	}
257
258	if (i >= sc->gpio_npins)
259		return (EINVAL);
260
261	GPIO_LOCK(sc);
262	*val = (READ4(sc, GPIO_PDIR(i)) & (1 << (i % 32))) ? 1 : 0;
263	GPIO_UNLOCK(sc);
264
265	return (0);
266}
267
268static int
269vf_gpio_pin_toggle(device_t dev, uint32_t pin)
270{
271	struct vf_gpio_softc *sc;
272	int i;
273
274	sc = device_get_softc(dev);
275	for (i = 0; i < sc->gpio_npins; i++) {
276		if (sc->gpio_pins[i].gp_pin == pin)
277			break;
278	}
279
280	if (i >= sc->gpio_npins)
281		return (EINVAL);
282
283	GPIO_LOCK(sc);
284	WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32)));
285	GPIO_UNLOCK(sc);
286
287	return (0);
288}
289
290
291static void
292vf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin,
293    unsigned int flags)
294{
295
296	GPIO_LOCK(sc);
297
298	/*
299	 * Manage input/output
300	 */
301	if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
302		pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
303		if (flags & GPIO_PIN_OUTPUT) {
304			pin->gp_flags |= GPIO_PIN_OUTPUT;
305
306		} else {
307			pin->gp_flags |= GPIO_PIN_INPUT;
308			WRITE4(sc, GPIO_PCOR(pin->gp_pin),
309			    (1 << (pin->gp_pin % 32)));
310		}
311	}
312
313	GPIO_UNLOCK(sc);
314}
315
316
317static int
318vf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
319{
320	struct vf_gpio_softc *sc;
321	int i;
322
323	sc = device_get_softc(dev);
324	for (i = 0; i < sc->gpio_npins; i++) {
325		if (sc->gpio_pins[i].gp_pin == pin)
326			break;
327	}
328
329	if (i >= sc->gpio_npins)
330		return (EINVAL);
331
332	vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
333
334	return (0);
335}
336
337static int
338vf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
339{
340	struct vf_gpio_softc *sc;
341	int i;
342
343	sc = device_get_softc(dev);
344	for (i = 0; i < sc->gpio_npins; i++) {
345		if (sc->gpio_pins[i].gp_pin == pin)
346			break;
347	}
348
349	if (i >= sc->gpio_npins)
350		return (EINVAL);
351
352	GPIO_LOCK(sc);
353	if (value)
354		WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32)));
355	else
356		WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32)));
357	GPIO_UNLOCK(sc);
358
359	return (0);
360}
361
362static device_method_t vf_gpio_methods[] = {
363	DEVMETHOD(device_probe,		vf_gpio_probe),
364	DEVMETHOD(device_attach,	vf_gpio_attach),
365
366	/* GPIO protocol */
367	DEVMETHOD(gpio_get_bus,		vf_gpio_get_bus),
368	DEVMETHOD(gpio_pin_max,		vf_gpio_pin_max),
369	DEVMETHOD(gpio_pin_getname,	vf_gpio_pin_getname),
370	DEVMETHOD(gpio_pin_getcaps,	vf_gpio_pin_getcaps),
371	DEVMETHOD(gpio_pin_getflags,	vf_gpio_pin_getflags),
372	DEVMETHOD(gpio_pin_get,		vf_gpio_pin_get),
373	DEVMETHOD(gpio_pin_toggle,	vf_gpio_pin_toggle),
374	DEVMETHOD(gpio_pin_setflags,	vf_gpio_pin_setflags),
375	DEVMETHOD(gpio_pin_set,		vf_gpio_pin_set),
376	{ 0, 0 }
377};
378
379static driver_t vf_gpio_driver = {
380	"gpio",
381	vf_gpio_methods,
382	sizeof(struct vf_gpio_softc),
383};
384
385static devclass_t vf_gpio_devclass;
386
387DRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, vf_gpio_devclass, 0, 0);
388