xref: /freebsd/sys/dev/p2sb/lewisburg_gpio.c (revision 3706af423ff257540dfe88bcb91fb0ab54e60946)
1*3706af42SArnaud Ysmal /*-
2*3706af42SArnaud Ysmal  * Copyright (c) 2018 Stormshield
3*3706af42SArnaud Ysmal  * All rights reserved.
4*3706af42SArnaud Ysmal  *
5*3706af42SArnaud Ysmal  * Redistribution and use in source and binary forms, with or without
6*3706af42SArnaud Ysmal  * modification, are permitted provided that the following conditions
7*3706af42SArnaud Ysmal  * are met:
8*3706af42SArnaud Ysmal  * 1. Redistributions of source code must retain the above copyright
9*3706af42SArnaud Ysmal  *    notice, this list of conditions and the following disclaimer.
10*3706af42SArnaud Ysmal  * 2. Redistributions in binary form must reproduce the above copyright
11*3706af42SArnaud Ysmal  *    notice, this list of conditions and the following disclaimer in the
12*3706af42SArnaud Ysmal  *    documentation and/or other materials provided with the distribution.
13*3706af42SArnaud Ysmal  *
14*3706af42SArnaud Ysmal  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*3706af42SArnaud Ysmal  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*3706af42SArnaud Ysmal  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*3706af42SArnaud Ysmal  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*3706af42SArnaud Ysmal  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*3706af42SArnaud Ysmal  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*3706af42SArnaud Ysmal  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*3706af42SArnaud Ysmal  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*3706af42SArnaud Ysmal  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*3706af42SArnaud Ysmal  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*3706af42SArnaud Ysmal  * SUCH DAMAGE.
25*3706af42SArnaud Ysmal  */
26*3706af42SArnaud Ysmal 
27*3706af42SArnaud Ysmal #include <sys/param.h>		/* defines used in kernel.h */
28*3706af42SArnaud Ysmal #include <sys/module.h>
29*3706af42SArnaud Ysmal #include <sys/systm.h>
30*3706af42SArnaud Ysmal #include <sys/errno.h>
31*3706af42SArnaud Ysmal #include <sys/kernel.h>		/* types used in module initialization */
32*3706af42SArnaud Ysmal #include <sys/conf.h>		/* cdevsw struct */
33*3706af42SArnaud Ysmal #include <sys/uio.h>		/* uio struct */
34*3706af42SArnaud Ysmal #include <sys/malloc.h>
35*3706af42SArnaud Ysmal #include <sys/bus.h>		/* structs, prototypes for pci bus stuff and DEVMETHOD macros! */
36*3706af42SArnaud Ysmal #include <sys/gpio.h>
37*3706af42SArnaud Ysmal 
38*3706af42SArnaud Ysmal #include <machine/bus.h>
39*3706af42SArnaud Ysmal #include <sys/rman.h>
40*3706af42SArnaud Ysmal #include <machine/resource.h>
41*3706af42SArnaud Ysmal 
42*3706af42SArnaud Ysmal #include <dev/gpio/gpiobusvar.h>
43*3706af42SArnaud Ysmal 
44*3706af42SArnaud Ysmal #include "gpio_if.h"
45*3706af42SArnaud Ysmal 
46*3706af42SArnaud Ysmal #include "lewisburg_gpiocm.h"
47*3706af42SArnaud Ysmal 
48*3706af42SArnaud Ysmal #define P2SB_GROUP_GPIO_MAX_PINS 24
49*3706af42SArnaud Ysmal struct lbggpio_softc
50*3706af42SArnaud Ysmal {
51*3706af42SArnaud Ysmal 	device_t		sc_busdev;
52*3706af42SArnaud Ysmal 	int groupid;
53*3706af42SArnaud Ysmal 	int pins_off;
54*3706af42SArnaud Ysmal 	int npins;
55*3706af42SArnaud Ysmal 	char grpname;
56*3706af42SArnaud Ysmal 	struct gpio_pin gpio_setup[P2SB_GROUP_GPIO_MAX_PINS];
57*3706af42SArnaud Ysmal };
58*3706af42SArnaud Ysmal 
59*3706af42SArnaud Ysmal static device_t
60*3706af42SArnaud Ysmal lbggpio_get_bus(device_t dev)
61*3706af42SArnaud Ysmal {
62*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
63*3706af42SArnaud Ysmal 
64*3706af42SArnaud Ysmal 	sc = device_get_softc(dev);
65*3706af42SArnaud Ysmal 
66*3706af42SArnaud Ysmal 	return (sc->sc_busdev);
67*3706af42SArnaud Ysmal }
68*3706af42SArnaud Ysmal 
69*3706af42SArnaud Ysmal static int
70*3706af42SArnaud Ysmal lbggpio_pin_max(device_t dev, int *maxpin)
71*3706af42SArnaud Ysmal {
72*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
73*3706af42SArnaud Ysmal 
74*3706af42SArnaud Ysmal 	if (maxpin == NULL)
75*3706af42SArnaud Ysmal 		return (EINVAL);
76*3706af42SArnaud Ysmal 
77*3706af42SArnaud Ysmal 	sc = device_get_softc(dev);
78*3706af42SArnaud Ysmal 
79*3706af42SArnaud Ysmal 	*maxpin = sc->npins - 1;
80*3706af42SArnaud Ysmal 
81*3706af42SArnaud Ysmal 	return (0);
82*3706af42SArnaud Ysmal }
83*3706af42SArnaud Ysmal 
84*3706af42SArnaud Ysmal static int
85*3706af42SArnaud Ysmal lbggpio_pin_getname(device_t dev, uint32_t pin, char *name)
86*3706af42SArnaud Ysmal {
87*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
88*3706af42SArnaud Ysmal 
89*3706af42SArnaud Ysmal 	if (name == NULL)
90*3706af42SArnaud Ysmal 		return (EINVAL);
91*3706af42SArnaud Ysmal 
92*3706af42SArnaud Ysmal 	if (pin >= sc->npins)
93*3706af42SArnaud Ysmal 		return (EINVAL);
94*3706af42SArnaud Ysmal 
95*3706af42SArnaud Ysmal 	strlcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME);
96*3706af42SArnaud Ysmal 
97*3706af42SArnaud Ysmal 	return (0);
98*3706af42SArnaud Ysmal }
99*3706af42SArnaud Ysmal 
100*3706af42SArnaud Ysmal static int
101*3706af42SArnaud Ysmal lbggpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
102*3706af42SArnaud Ysmal {
103*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
104*3706af42SArnaud Ysmal 
105*3706af42SArnaud Ysmal 	if (flags == NULL)
106*3706af42SArnaud Ysmal 		return (EINVAL);
107*3706af42SArnaud Ysmal 
108*3706af42SArnaud Ysmal 	if (pin >= sc->npins)
109*3706af42SArnaud Ysmal 		return (EINVAL);
110*3706af42SArnaud Ysmal 
111*3706af42SArnaud Ysmal 	*flags = sc->gpio_setup[pin].gp_flags;
112*3706af42SArnaud Ysmal 
113*3706af42SArnaud Ysmal 	return (0);
114*3706af42SArnaud Ysmal }
115*3706af42SArnaud Ysmal 
116*3706af42SArnaud Ysmal static int
117*3706af42SArnaud Ysmal lbggpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
118*3706af42SArnaud Ysmal {
119*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
120*3706af42SArnaud Ysmal 
121*3706af42SArnaud Ysmal 	if (caps == NULL)
122*3706af42SArnaud Ysmal 		return (EINVAL);
123*3706af42SArnaud Ysmal 
124*3706af42SArnaud Ysmal 	if (pin >= sc->npins)
125*3706af42SArnaud Ysmal 		return (EINVAL);
126*3706af42SArnaud Ysmal 
127*3706af42SArnaud Ysmal 	*caps = sc->gpio_setup[pin].gp_caps;
128*3706af42SArnaud Ysmal 
129*3706af42SArnaud Ysmal 	return (0);
130*3706af42SArnaud Ysmal }
131*3706af42SArnaud Ysmal 
132*3706af42SArnaud Ysmal static int
133*3706af42SArnaud Ysmal lbggpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
134*3706af42SArnaud Ysmal {
135*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
136*3706af42SArnaud Ysmal 
137*3706af42SArnaud Ysmal 	if (pin >= sc->npins)
138*3706af42SArnaud Ysmal 		return (EINVAL);
139*3706af42SArnaud Ysmal 
140*3706af42SArnaud Ysmal 	/* Check for unwanted flags. */
141*3706af42SArnaud Ysmal 	if ((flags & sc->gpio_setup[pin].gp_caps) != flags)
142*3706af42SArnaud Ysmal 		return (EINVAL);
143*3706af42SArnaud Ysmal 
144*3706af42SArnaud Ysmal 	lbggpiocm_pin_setflags(device_get_parent(dev), dev, pin, flags);
145*3706af42SArnaud Ysmal 	sc->gpio_setup[pin].gp_flags = flags;
146*3706af42SArnaud Ysmal 
147*3706af42SArnaud Ysmal 	return (0);
148*3706af42SArnaud Ysmal }
149*3706af42SArnaud Ysmal 
150*3706af42SArnaud Ysmal static int
151*3706af42SArnaud Ysmal lbggpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
152*3706af42SArnaud Ysmal {
153*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
154*3706af42SArnaud Ysmal 
155*3706af42SArnaud Ysmal 	if (value == NULL)
156*3706af42SArnaud Ysmal 		return (EINVAL);
157*3706af42SArnaud Ysmal 
158*3706af42SArnaud Ysmal 	if (pin >= sc->npins)
159*3706af42SArnaud Ysmal 		return (EINVAL);
160*3706af42SArnaud Ysmal 
161*3706af42SArnaud Ysmal 	return (lbggpiocm_pin_get(device_get_parent(dev), dev, pin, value));
162*3706af42SArnaud Ysmal }
163*3706af42SArnaud Ysmal 
164*3706af42SArnaud Ysmal static int
165*3706af42SArnaud Ysmal lbggpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
166*3706af42SArnaud Ysmal {
167*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
168*3706af42SArnaud Ysmal 
169*3706af42SArnaud Ysmal 	if (pin >= sc->npins)
170*3706af42SArnaud Ysmal 		return (EINVAL);
171*3706af42SArnaud Ysmal 
172*3706af42SArnaud Ysmal 	return (lbggpiocm_pin_set(device_get_parent(dev), dev, pin, value));
173*3706af42SArnaud Ysmal }
174*3706af42SArnaud Ysmal 
175*3706af42SArnaud Ysmal static int
176*3706af42SArnaud Ysmal lbggpio_pin_toggle(device_t dev, uint32_t pin)
177*3706af42SArnaud Ysmal {
178*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
179*3706af42SArnaud Ysmal 
180*3706af42SArnaud Ysmal 	if (pin >= sc->npins)
181*3706af42SArnaud Ysmal 		return (EINVAL);
182*3706af42SArnaud Ysmal 
183*3706af42SArnaud Ysmal 	return (lbggpiocm_pin_toggle(device_get_parent(dev), dev, pin));
184*3706af42SArnaud Ysmal }
185*3706af42SArnaud Ysmal 
186*3706af42SArnaud Ysmal static int
187*3706af42SArnaud Ysmal lbggpio_probe(device_t dev)
188*3706af42SArnaud Ysmal {
189*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
190*3706af42SArnaud Ysmal 	/* X is a placeholder for the actual one letter group name. */
191*3706af42SArnaud Ysmal 	static char desc[] = "LewisBurg GPIO Group X";
192*3706af42SArnaud Ysmal 
193*3706af42SArnaud Ysmal 	sc->npins = lbggpiocm_get_group_npins(device_get_parent(dev), dev);
194*3706af42SArnaud Ysmal 	sc->grpname = lbggpiocm_get_group_name(device_get_parent(dev), dev);
195*3706af42SArnaud Ysmal 	if (sc->npins <= 0)
196*3706af42SArnaud Ysmal 		return (ENXIO);
197*3706af42SArnaud Ysmal 
198*3706af42SArnaud Ysmal 	desc[sizeof(desc)-2] = sc->grpname;
199*3706af42SArnaud Ysmal 	device_set_desc_copy(dev, desc);
200*3706af42SArnaud Ysmal 	return (BUS_PROBE_DEFAULT);
201*3706af42SArnaud Ysmal }
202*3706af42SArnaud Ysmal 
203*3706af42SArnaud Ysmal static int
204*3706af42SArnaud Ysmal lbggpio_attach(device_t dev)
205*3706af42SArnaud Ysmal {
206*3706af42SArnaud Ysmal 	uint32_t i;
207*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
208*3706af42SArnaud Ysmal 
209*3706af42SArnaud Ysmal 	sc = device_get_softc(dev);
210*3706af42SArnaud Ysmal 	/* GPIO config */
211*3706af42SArnaud Ysmal 	for (i = 0; i < sc->npins; ++i) {
212*3706af42SArnaud Ysmal 		sc->gpio_setup[i].gp_pin = i;
213*3706af42SArnaud Ysmal 		snprintf(sc->gpio_setup[i].gp_name,
214*3706af42SArnaud Ysmal 		    sizeof(sc->gpio_setup[i].gp_name),
215*3706af42SArnaud Ysmal 		    "GPIO %c%u", sc->grpname, i);
216*3706af42SArnaud Ysmal 		sc->gpio_setup[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
217*3706af42SArnaud Ysmal 	}
218*3706af42SArnaud Ysmal 
219*3706af42SArnaud Ysmal 	/* support gpio */
220*3706af42SArnaud Ysmal 	sc->sc_busdev = gpiobus_attach_bus(dev);
221*3706af42SArnaud Ysmal 	if (sc->sc_busdev == NULL)
222*3706af42SArnaud Ysmal 		return (ENXIO);
223*3706af42SArnaud Ysmal 
224*3706af42SArnaud Ysmal 	return (0);
225*3706af42SArnaud Ysmal }
226*3706af42SArnaud Ysmal 
227*3706af42SArnaud Ysmal static int
228*3706af42SArnaud Ysmal lbggpio_detach(device_t dev)
229*3706af42SArnaud Ysmal {
230*3706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
231*3706af42SArnaud Ysmal 
232*3706af42SArnaud Ysmal 	sc = device_get_softc(dev);
233*3706af42SArnaud Ysmal 
234*3706af42SArnaud Ysmal 	if (sc->sc_busdev)
235*3706af42SArnaud Ysmal 		gpiobus_detach_bus(dev);
236*3706af42SArnaud Ysmal 
237*3706af42SArnaud Ysmal 	return (0);
238*3706af42SArnaud Ysmal }
239*3706af42SArnaud Ysmal 
240*3706af42SArnaud Ysmal static device_method_t lbggpio_methods[] = {
241*3706af42SArnaud Ysmal 	/* Device interface */
242*3706af42SArnaud Ysmal 	DEVMETHOD(device_probe,		lbggpio_probe),
243*3706af42SArnaud Ysmal 	DEVMETHOD(device_attach,	lbggpio_attach),
244*3706af42SArnaud Ysmal 	DEVMETHOD(device_detach,	lbggpio_detach),
245*3706af42SArnaud Ysmal 
246*3706af42SArnaud Ysmal 	/* GPIO protocol */
247*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_get_bus,		lbggpio_get_bus),
248*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_max,		lbggpio_pin_max),
249*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_getcaps,	lbggpio_pin_getcaps),
250*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_getflags,	lbggpio_pin_getflags),
251*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_setflags,	lbggpio_pin_setflags),
252*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_getname,	lbggpio_pin_getname),
253*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_set,		lbggpio_pin_set),
254*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_get,		lbggpio_pin_get),
255*3706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_toggle,	lbggpio_pin_toggle),
256*3706af42SArnaud Ysmal 
257*3706af42SArnaud Ysmal 	DEVMETHOD_END
258*3706af42SArnaud Ysmal };
259*3706af42SArnaud Ysmal 
260*3706af42SArnaud Ysmal static driver_t lbggpio_driver = {
261*3706af42SArnaud Ysmal 	"gpio",
262*3706af42SArnaud Ysmal 	lbggpio_methods,
263*3706af42SArnaud Ysmal 	sizeof(struct lbggpio_softc)
264*3706af42SArnaud Ysmal };
265*3706af42SArnaud Ysmal 
266*3706af42SArnaud Ysmal static devclass_t lbggpio_devclass;
267*3706af42SArnaud Ysmal 
268*3706af42SArnaud Ysmal DRIVER_MODULE(lbggpio, lbggpiocm, lbggpio_driver, lbggpio_devclass, NULL, NULL);
269*3706af42SArnaud Ysmal MODULE_DEPEND(lbggpio, gpiobus, 1, 1, 1);
270