1/*-
2 * Copyright (c) 2015 Rubicon Communications, LLC (Netgate)
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#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: stable/11/sys/dev/rccgpio/rccgpio.c 311205 2017-01-04 00:25:22Z loos $");
28
29/*
30 * GPIO driver for the ADI Engineering RCC-VE and RCC-DFF/DFFv2.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/bus.h>
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
43#include <dev/gpio/gpiobusvar.h>
44#include <isa/isavar.h>
45
46#include "gpio_if.h"
47
48#define	RCC_GPIO_BASE		0x500
49#define	RCC_GPIO_USE_SEL	0x00
50#define	RCC_GPIO_IO_SEL		0x04
51#define	RCC_GPIO_GP_LVL		0x08
52
53struct rcc_gpio_pin {
54	uint32_t		pin;
55	const char		*name;
56	uint32_t		caps;
57};
58
59static struct rcc_gpio_pin rcc_pins[] = {
60	{ .pin = (1 << 11), .name = "reset switch", .caps = GPIO_PIN_INPUT },
61	{ .pin = (1 << 15), .name = "red LED", .caps = GPIO_PIN_OUTPUT },
62	{ .pin = (1 << 17), .name = "green LED", .caps = GPIO_PIN_OUTPUT },
63#if 0
64	{ .pin = (1 << 16), .name = "HD1 LED", .caps = GPIO_PIN_OUTPUT },
65	{ .pin = (1 << 18), .name = "HD2 LED", .caps = GPIO_PIN_OUTPUT },
66#endif
67};
68
69struct rcc_gpio_softc {
70	device_t		sc_dev;
71	device_t		sc_busdev;
72	struct mtx		sc_mtx;
73	struct resource		*sc_io_res;
74	bus_space_tag_t		sc_bst;
75	bus_space_handle_t	sc_bsh;
76	uint32_t		sc_output;
77	int			sc_io_rid;
78	int			sc_gpio_npins;
79};
80
81#define	RCC_GPIO_LOCK(_sc)	mtx_lock(&(_sc)->sc_mtx)
82#define	RCC_GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_mtx)
83#define	RCC_WRITE(_sc, _off, _val)				\
84	bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, _off, _val)
85#define	RCC_READ(_sc, _off)					\
86	bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, _off)
87
88static void
89rcc_gpio_modify_bits(struct rcc_gpio_softc *sc, uint32_t reg, uint32_t mask,
90	uint32_t writebits)
91{
92	uint32_t value;
93
94	RCC_GPIO_LOCK(sc);
95	value = RCC_READ(sc, reg);
96	value &= ~mask;
97	value |= writebits;
98	RCC_WRITE(sc, reg, value);
99	RCC_GPIO_UNLOCK(sc);
100}
101
102static device_t
103rcc_gpio_get_bus(device_t dev)
104{
105	struct rcc_gpio_softc *sc;
106
107	sc = device_get_softc(dev);
108
109	return (sc->sc_busdev);
110}
111
112static int
113rcc_gpio_pin_max(device_t dev, int *maxpin)
114{
115	struct rcc_gpio_softc *sc;
116
117	sc = device_get_softc(dev);
118	*maxpin = sc->sc_gpio_npins - 1;
119
120	return (0);
121}
122
123static int
124rcc_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
125{
126	struct rcc_gpio_softc *sc;
127
128	sc = device_get_softc(dev);
129	if (pin >= sc->sc_gpio_npins)
130		return (EINVAL);
131
132	*caps = rcc_pins[pin].caps;
133
134	return (0);
135}
136
137static int
138rcc_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
139{
140	struct rcc_gpio_softc *sc;
141
142	sc = device_get_softc(dev);
143	if (pin >= sc->sc_gpio_npins)
144		return (EINVAL);
145
146	/* Flags cannot be changed. */
147	*flags = rcc_pins[pin].caps;
148
149	return (0);
150}
151
152static int
153rcc_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
154{
155	struct rcc_gpio_softc *sc;
156
157	sc = device_get_softc(dev);
158	if (pin >= sc->sc_gpio_npins)
159		return (EINVAL);
160
161	memcpy(name, rcc_pins[pin].name, GPIOMAXNAME);
162
163	return (0);
164}
165
166static int
167rcc_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
168{
169	struct rcc_gpio_softc *sc;
170
171	sc = device_get_softc(dev);
172	if (pin >= sc->sc_gpio_npins)
173		return (EINVAL);
174
175	/* Flags cannot be changed - risk of short-circuit!!! */
176
177	return (0);
178}
179
180static int
181rcc_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
182{
183	struct rcc_gpio_softc *sc;
184
185	sc = device_get_softc(dev);
186	if (pin >= sc->sc_gpio_npins)
187		return (EINVAL);
188
189	if ((rcc_pins[pin].caps & GPIO_PIN_OUTPUT) == 0)
190		return (EINVAL);
191
192	RCC_GPIO_LOCK(sc);
193	if (value)
194		sc->sc_output |= (1 << rcc_pins[pin].pin);
195	else
196		sc->sc_output &= ~(1 << rcc_pins[pin].pin);
197	RCC_WRITE(sc, RCC_GPIO_GP_LVL, sc->sc_output);
198	RCC_GPIO_UNLOCK(sc);
199
200	return (0);
201}
202
203static int
204rcc_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
205{
206	struct rcc_gpio_softc *sc;
207	uint32_t value;
208
209	sc = device_get_softc(dev);
210	if (pin >= sc->sc_gpio_npins)
211		return (EINVAL);
212
213	RCC_GPIO_LOCK(sc);
214	if (rcc_pins[pin].caps & GPIO_PIN_INPUT)
215		value = RCC_READ(sc, RCC_GPIO_GP_LVL);
216	else
217		value = sc->sc_output;
218	RCC_GPIO_UNLOCK(sc);
219	*val = (value & (1 << rcc_pins[pin].pin)) ? 1 : 0;
220
221	return (0);
222}
223
224static int
225rcc_gpio_pin_toggle(device_t dev, uint32_t pin)
226{
227	struct rcc_gpio_softc *sc;
228
229	sc = device_get_softc(dev);
230	if (pin >= sc->sc_gpio_npins)
231		return (EINVAL);
232
233	if ((rcc_pins[pin].caps & GPIO_PIN_OUTPUT) == 0)
234		return (EINVAL);
235
236	RCC_GPIO_LOCK(sc);
237	if ((sc->sc_output & (1 << rcc_pins[pin].pin)) == 0)
238		sc->sc_output |= (1 << rcc_pins[pin].pin);
239	else
240		sc->sc_output &= ~(1 << rcc_pins[pin].pin);
241	RCC_WRITE(sc, RCC_GPIO_GP_LVL, sc->sc_output);
242	RCC_GPIO_UNLOCK(sc);
243
244	return (0);
245}
246
247static int
248rcc_gpio_probe(device_t dev)
249{
250	char *prod;
251	int port;
252
253	/*
254	 * We don't know of any PnP ID's for this GPIO controller.
255	 */
256	if (isa_get_logicalid(dev) != 0)
257		return (ENXIO);
258
259	/*
260	 * We have to have an IO port hint that is valid.
261	 */
262	port = isa_get_port(dev);
263	if (port != RCC_GPIO_BASE)
264		return (ENXIO);
265
266	prod = kern_getenv("smbios.system.product");
267	if (prod == NULL ||
268	    (strcmp(prod, "RCC-VE") != 0 && strcmp(prod, "RCC-DFF") != 0))
269		return (ENXIO);
270
271	device_set_desc(dev, "RCC-VE/DFF GPIO controller");
272
273	return (BUS_PROBE_DEFAULT);
274}
275
276static int
277rcc_gpio_attach(device_t dev)
278{
279	int i;
280	struct rcc_gpio_softc *sc;
281
282	sc = device_get_softc(dev);
283 	sc->sc_dev = dev;
284
285	/* Allocate IO resources. */
286	sc->sc_io_rid = 0;
287	sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
288	    &sc->sc_io_rid, RF_ACTIVE);
289	if (sc->sc_io_res == NULL) {
290		device_printf(dev, "cannot allocate memory window\n");
291		return (ENXIO);
292	}
293	sc->sc_bst = rman_get_bustag(sc->sc_io_res);
294	sc->sc_bsh = rman_get_bushandle(sc->sc_io_res);
295	mtx_init(&sc->sc_mtx, "rcc-gpio", "gpio", MTX_DEF);
296
297	/* Initialize the pins. */
298	sc->sc_gpio_npins = nitems(rcc_pins);
299	for (i = 0; i < sc->sc_gpio_npins; i++) {
300		/* Enable it for GPIO. */
301		rcc_gpio_modify_bits(sc, RCC_GPIO_USE_SEL, 0, rcc_pins[i].pin);
302		/* Set the pin as input or output. */
303		if (rcc_pins[i].caps & GPIO_PIN_OUTPUT)
304			rcc_gpio_modify_bits(sc, RCC_GPIO_IO_SEL,
305			    rcc_pins[i].pin, 0);
306		else
307			rcc_gpio_modify_bits(sc, RCC_GPIO_IO_SEL,
308			    0, rcc_pins[i].pin);
309	}
310	RCC_WRITE(sc, RCC_GPIO_GP_LVL, sc->sc_output);
311
312	/* Attach the gpiobus. */
313	sc->sc_busdev = gpiobus_attach_bus(dev);
314	if (sc->sc_busdev == NULL) {
315		bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_io_rid,
316		    sc->sc_io_res);
317		mtx_destroy(&sc->sc_mtx);
318		return (ENXIO);
319	}
320
321	return (0);
322}
323
324static int
325rcc_gpio_detach(device_t dev)
326{
327	int i;
328	struct rcc_gpio_softc *sc;
329
330	sc = device_get_softc(dev);
331	gpiobus_detach_bus(dev);
332
333	/* Disable the GPIO function. */
334	for (i = 0; i < sc->sc_gpio_npins; i++)
335		rcc_gpio_modify_bits(sc, RCC_GPIO_USE_SEL, rcc_pins[i].pin, 0);
336
337	if (sc->sc_io_res != NULL)
338		bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_io_rid,
339		    sc->sc_io_res);
340	mtx_destroy(&sc->sc_mtx);
341
342	return (0);
343}
344
345static device_method_t rcc_gpio_methods[] = {
346	/* Device interface */
347	DEVMETHOD(device_probe,		rcc_gpio_probe),
348	DEVMETHOD(device_attach,	rcc_gpio_attach),
349	DEVMETHOD(device_detach,	rcc_gpio_detach),
350
351	/* GPIO protocol */
352	DEVMETHOD(gpio_get_bus,		rcc_gpio_get_bus),
353	DEVMETHOD(gpio_pin_max,		rcc_gpio_pin_max),
354	DEVMETHOD(gpio_pin_getname,	rcc_gpio_pin_getname),
355	DEVMETHOD(gpio_pin_getflags,	rcc_gpio_pin_getflags),
356	DEVMETHOD(gpio_pin_getcaps,	rcc_gpio_pin_getcaps),
357	DEVMETHOD(gpio_pin_setflags,	rcc_gpio_pin_setflags),
358	DEVMETHOD(gpio_pin_get,		rcc_gpio_pin_get),
359	DEVMETHOD(gpio_pin_set,		rcc_gpio_pin_set),
360	DEVMETHOD(gpio_pin_toggle,	rcc_gpio_pin_toggle),
361
362	DEVMETHOD_END
363};
364
365static devclass_t rcc_gpio_devclass;
366
367static driver_t rcc_gpio_driver = {
368	"gpio",
369	rcc_gpio_methods,
370	sizeof(struct rcc_gpio_softc),
371};
372
373DRIVER_MODULE(rcc_gpio, isa, rcc_gpio_driver, rcc_gpio_devclass, 0, 0);
374MODULE_DEPEND(rcc_gpio, gpiobus, 1, 1, 1);
375