xref: /freebsd/sys/dev/p2sb/lewisburg_gpio.c (revision 5d3e7166f6a0187fa3f8831b16a06bd9955c21ff)
1 /*-
2  * Copyright (c) 2018 Stormshield
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 #include <sys/param.h>		/* defines used in kernel.h */
28 #include <sys/module.h>
29 #include <sys/systm.h>
30 #include <sys/errno.h>
31 #include <sys/kernel.h>		/* types used in module initialization */
32 #include <sys/conf.h>		/* cdevsw struct */
33 #include <sys/uio.h>		/* uio struct */
34 #include <sys/malloc.h>
35 #include <sys/bus.h>		/* structs, prototypes for pci bus stuff and DEVMETHOD macros! */
36 #include <sys/gpio.h>
37 
38 #include <machine/bus.h>
39 #include <sys/rman.h>
40 #include <machine/resource.h>
41 
42 #include <dev/gpio/gpiobusvar.h>
43 
44 #include "gpio_if.h"
45 
46 #include "lewisburg_gpiocm.h"
47 
48 #define P2SB_GROUP_GPIO_MAX_PINS 24
49 struct lbggpio_softc
50 {
51 	device_t		sc_busdev;
52 	int groupid;
53 	int pins_off;
54 	int npins;
55 	char grpname;
56 	struct gpio_pin gpio_setup[P2SB_GROUP_GPIO_MAX_PINS];
57 };
58 
59 static device_t
60 lbggpio_get_bus(device_t dev)
61 {
62 	struct lbggpio_softc *sc;
63 
64 	sc = device_get_softc(dev);
65 
66 	return (sc->sc_busdev);
67 }
68 
69 static int
70 lbggpio_pin_max(device_t dev, int *maxpin)
71 {
72 	struct lbggpio_softc *sc;
73 
74 	if (maxpin == NULL)
75 		return (EINVAL);
76 
77 	sc = device_get_softc(dev);
78 
79 	*maxpin = sc->npins - 1;
80 
81 	return (0);
82 }
83 
84 static int
85 lbggpio_pin_getname(device_t dev, uint32_t pin, char *name)
86 {
87 	struct lbggpio_softc *sc = device_get_softc(dev);
88 
89 	if (name == NULL)
90 		return (EINVAL);
91 
92 	if (pin >= sc->npins)
93 		return (EINVAL);
94 
95 	strlcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME);
96 
97 	return (0);
98 }
99 
100 static int
101 lbggpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
102 {
103 	struct lbggpio_softc *sc = device_get_softc(dev);
104 
105 	if (flags == NULL)
106 		return (EINVAL);
107 
108 	if (pin >= sc->npins)
109 		return (EINVAL);
110 
111 	*flags = sc->gpio_setup[pin].gp_flags;
112 
113 	return (0);
114 }
115 
116 static int
117 lbggpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
118 {
119 	struct lbggpio_softc *sc = device_get_softc(dev);
120 
121 	if (caps == NULL)
122 		return (EINVAL);
123 
124 	if (pin >= sc->npins)
125 		return (EINVAL);
126 
127 	*caps = sc->gpio_setup[pin].gp_caps;
128 
129 	return (0);
130 }
131 
132 static int
133 lbggpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
134 {
135 	struct lbggpio_softc *sc = device_get_softc(dev);
136 
137 	if (pin >= sc->npins)
138 		return (EINVAL);
139 
140 	/* Check for unwanted flags. */
141 	if ((flags & sc->gpio_setup[pin].gp_caps) != flags)
142 		return (EINVAL);
143 
144 	lbggpiocm_pin_setflags(device_get_parent(dev), dev, pin, flags);
145 	sc->gpio_setup[pin].gp_flags = flags;
146 
147 	return (0);
148 }
149 
150 static int
151 lbggpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
152 {
153 	struct lbggpio_softc *sc = device_get_softc(dev);
154 
155 	if (value == NULL)
156 		return (EINVAL);
157 
158 	if (pin >= sc->npins)
159 		return (EINVAL);
160 
161 	return (lbggpiocm_pin_get(device_get_parent(dev), dev, pin, value));
162 }
163 
164 static int
165 lbggpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
166 {
167 	struct lbggpio_softc *sc = device_get_softc(dev);
168 
169 	if (pin >= sc->npins)
170 		return (EINVAL);
171 
172 	return (lbggpiocm_pin_set(device_get_parent(dev), dev, pin, value));
173 }
174 
175 static int
176 lbggpio_pin_toggle(device_t dev, uint32_t pin)
177 {
178 	struct lbggpio_softc *sc = device_get_softc(dev);
179 
180 	if (pin >= sc->npins)
181 		return (EINVAL);
182 
183 	return (lbggpiocm_pin_toggle(device_get_parent(dev), dev, pin));
184 }
185 
186 static int
187 lbggpio_probe(device_t dev)
188 {
189 	struct lbggpio_softc *sc = device_get_softc(dev);
190 	/* X is a placeholder for the actual one letter group name. */
191 	static char desc[] = "LewisBurg GPIO Group X";
192 
193 	sc->npins = lbggpiocm_get_group_npins(device_get_parent(dev), dev);
194 	sc->grpname = lbggpiocm_get_group_name(device_get_parent(dev), dev);
195 	if (sc->npins <= 0)
196 		return (ENXIO);
197 
198 	desc[sizeof(desc)-2] = sc->grpname;
199 	device_set_desc_copy(dev, desc);
200 	return (BUS_PROBE_DEFAULT);
201 }
202 
203 static int
204 lbggpio_attach(device_t dev)
205 {
206 	uint32_t i;
207 	struct lbggpio_softc *sc;
208 
209 	sc = device_get_softc(dev);
210 	/* GPIO config */
211 	for (i = 0; i < sc->npins; ++i) {
212 		sc->gpio_setup[i].gp_pin = i;
213 		snprintf(sc->gpio_setup[i].gp_name,
214 		    sizeof(sc->gpio_setup[i].gp_name),
215 		    "GPIO %c%u", sc->grpname, i);
216 		sc->gpio_setup[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
217 	}
218 
219 	/* support gpio */
220 	sc->sc_busdev = gpiobus_attach_bus(dev);
221 	if (sc->sc_busdev == NULL)
222 		return (ENXIO);
223 
224 	return (0);
225 }
226 
227 static int
228 lbggpio_detach(device_t dev)
229 {
230 	struct lbggpio_softc *sc;
231 
232 	sc = device_get_softc(dev);
233 
234 	if (sc->sc_busdev)
235 		gpiobus_detach_bus(dev);
236 
237 	return (0);
238 }
239 
240 static device_method_t lbggpio_methods[] = {
241 	/* Device interface */
242 	DEVMETHOD(device_probe,		lbggpio_probe),
243 	DEVMETHOD(device_attach,	lbggpio_attach),
244 	DEVMETHOD(device_detach,	lbggpio_detach),
245 
246 	/* GPIO protocol */
247 	DEVMETHOD(gpio_get_bus,		lbggpio_get_bus),
248 	DEVMETHOD(gpio_pin_max,		lbggpio_pin_max),
249 	DEVMETHOD(gpio_pin_getcaps,	lbggpio_pin_getcaps),
250 	DEVMETHOD(gpio_pin_getflags,	lbggpio_pin_getflags),
251 	DEVMETHOD(gpio_pin_setflags,	lbggpio_pin_setflags),
252 	DEVMETHOD(gpio_pin_getname,	lbggpio_pin_getname),
253 	DEVMETHOD(gpio_pin_set,		lbggpio_pin_set),
254 	DEVMETHOD(gpio_pin_get,		lbggpio_pin_get),
255 	DEVMETHOD(gpio_pin_toggle,	lbggpio_pin_toggle),
256 
257 	DEVMETHOD_END
258 };
259 
260 static driver_t lbggpio_driver = {
261 	"gpio",
262 	lbggpio_methods,
263 	sizeof(struct lbggpio_softc)
264 };
265 
266 DRIVER_MODULE(lbggpio, lbggpiocm, lbggpio_driver, NULL, NULL);
267 MODULE_DEPEND(lbggpio, gpiobus, 1, 1, 1);
268