xref: /freebsd/sys/dev/gpio/gpiobus.c (revision ff0ba87247820afbdfdc1b307c803f7923d0e4d3)
1 /*-
2  * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
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/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 
37 #include <dev/gpio/gpiobusvar.h>
38 
39 #include "gpiobus_if.h"
40 
41 static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int);
42 static int gpiobus_probe(device_t);
43 static int gpiobus_attach(device_t);
44 static int gpiobus_detach(device_t);
45 static int gpiobus_suspend(device_t);
46 static int gpiobus_resume(device_t);
47 static int gpiobus_print_child(device_t, device_t);
48 static int gpiobus_child_location_str(device_t, device_t, char *, size_t);
49 static int gpiobus_child_pnpinfo_str(device_t, device_t, char *, size_t);
50 static device_t gpiobus_add_child(device_t, u_int, const char *, int);
51 static void gpiobus_hinted_child(device_t, const char *, int);
52 
53 /*
54  * GPIOBUS interface
55  */
56 static int gpiobus_acquire_bus(device_t, device_t, int);
57 static void gpiobus_release_bus(device_t, device_t);
58 static int gpiobus_pin_setflags(device_t, device_t, uint32_t, uint32_t);
59 static int gpiobus_pin_getflags(device_t, device_t, uint32_t, uint32_t*);
60 static int gpiobus_pin_getcaps(device_t, device_t, uint32_t, uint32_t*);
61 static int gpiobus_pin_set(device_t, device_t, uint32_t, unsigned int);
62 static int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*);
63 static int gpiobus_pin_toggle(device_t, device_t, uint32_t);
64 
65 void
66 gpiobus_print_pins(struct gpiobus_ivar *devi)
67 {
68 	int range_start, range_stop, need_coma;
69 	int i;
70 
71 	if (devi->npins == 0)
72 		return;
73 
74 	need_coma = 0;
75 	range_start = range_stop = devi->pins[0];
76 	for (i = 1; i < devi->npins; i++) {
77 		if (devi->pins[i] != (range_stop + 1)) {
78 			if (need_coma)
79 				printf(",");
80 			if (range_start != range_stop)
81 				printf("%d-%d", range_start, range_stop);
82 			else
83 				printf("%d", range_start);
84 
85 			range_start = range_stop = devi->pins[i];
86 			need_coma = 1;
87 		}
88 		else
89 			range_stop++;
90 	}
91 
92 	if (need_coma)
93 		printf(",");
94 	if (range_start != range_stop)
95 		printf("%d-%d", range_start, range_stop);
96 	else
97 		printf("%d", range_start);
98 }
99 
100 int
101 gpiobus_init_softc(device_t dev)
102 {
103 	struct gpiobus_softc *sc;
104 
105 	sc = GPIOBUS_SOFTC(dev);
106 	sc->sc_busdev = dev;
107 	sc->sc_dev = device_get_parent(dev);
108 
109 	if (GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins) != 0)
110 		return (ENXIO);
111 
112 	KASSERT(sc->sc_npins != 0, ("GPIO device with no pins"));
113 
114 	/* Pins = GPIO_PIN_MAX() + 1 */
115 	sc->sc_npins++;
116 
117 	sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF,
118 	    M_NOWAIT | M_ZERO);
119 	if (sc->sc_pins_mapped == NULL)
120 		return (ENOMEM);
121 
122 	/* Initialize the bus lock. */
123 	GPIOBUS_LOCK_INIT(sc);
124 
125 	return (0);
126 }
127 
128 static int
129 gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
130 {
131 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
132 	int i, npins;
133 
134 	npins = 0;
135 	for (i = 0; i < 32; i++) {
136 		if (mask & (1 << i))
137 			npins++;
138 	}
139 
140 	if (npins == 0) {
141 		device_printf(child, "empty pin mask\n");
142 		return (EINVAL);
143 	}
144 
145 	devi->npins = npins;
146 	devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF,
147 	    M_NOWAIT | M_ZERO);
148 
149 	if (!devi->pins)
150 		return (ENOMEM);
151 
152 	npins = 0;
153 	for (i = 0; i < 32; i++) {
154 
155 		if ((mask & (1 << i)) == 0)
156 			continue;
157 
158 		if (i >= sc->sc_npins) {
159 			device_printf(child,
160 			    "invalid pin %d, max: %d\n", i, sc->sc_npins - 1);
161 			free(devi->pins, M_DEVBUF);
162 			return (EINVAL);
163 		}
164 
165 		devi->pins[npins++] = i;
166 		/*
167 		 * Mark pin as mapped and give warning if it's already mapped
168 		 */
169 		if (sc->sc_pins_mapped[i]) {
170 			device_printf(child,
171 			    "warning: pin %d is already mapped\n", i);
172 			free(devi->pins, M_DEVBUF);
173 			return (EINVAL);
174 		}
175 		sc->sc_pins_mapped[i] = 1;
176 	}
177 
178 	return (0);
179 }
180 
181 static int
182 gpiobus_probe(device_t dev)
183 {
184 	device_set_desc(dev, "GPIO bus");
185 
186 	return (BUS_PROBE_GENERIC);
187 }
188 
189 static int
190 gpiobus_attach(device_t dev)
191 {
192 	int err;
193 
194 	err = gpiobus_init_softc(dev);
195 	if (err != 0)
196 		return (err);
197 
198 	/*
199 	 * Get parent's pins and mark them as unmapped
200 	 */
201 	bus_generic_probe(dev);
202 	bus_enumerate_hinted_children(dev);
203 
204 	return (bus_generic_attach(dev));
205 }
206 
207 /*
208  * Since this is not a self-enumerating bus, and since we always add
209  * children in attach, we have to always delete children here.
210  */
211 static int
212 gpiobus_detach(device_t dev)
213 {
214 	struct gpiobus_softc *sc;
215 	struct gpiobus_ivar *devi;
216 	device_t *devlist;
217 	int i, err, ndevs;
218 
219 	sc = GPIOBUS_SOFTC(dev);
220 	KASSERT(mtx_initialized(&sc->sc_mtx),
221 	    ("gpiobus mutex not initialized"));
222 	GPIOBUS_LOCK_DESTROY(sc);
223 
224 	if ((err = bus_generic_detach(dev)) != 0)
225 		return (err);
226 
227 	if ((err = device_get_children(dev, &devlist, &ndevs)) != 0)
228 		return (err);
229 	for (i = 0; i < ndevs; i++) {
230 		device_delete_child(dev, devlist[i]);
231 		devi = GPIOBUS_IVAR(devlist[i]);
232 		if (devi->pins) {
233 			free(devi->pins, M_DEVBUF);
234 			devi->pins = NULL;
235 		}
236 	}
237 	free(devlist, M_TEMP);
238 
239 	if (sc->sc_pins_mapped) {
240 		free(sc->sc_pins_mapped, M_DEVBUF);
241 		sc->sc_pins_mapped = NULL;
242 	}
243 
244 	return (0);
245 }
246 
247 static int
248 gpiobus_suspend(device_t dev)
249 {
250 
251 	return (bus_generic_suspend(dev));
252 }
253 
254 static int
255 gpiobus_resume(device_t dev)
256 {
257 
258 	return (bus_generic_resume(dev));
259 }
260 
261 static int
262 gpiobus_print_child(device_t dev, device_t child)
263 {
264 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
265 	int retval = 0;
266 
267 	retval += bus_print_child_header(dev, child);
268 	retval += printf(" at pin(s) ");
269 	gpiobus_print_pins(devi);
270 	retval += bus_print_child_footer(dev, child);
271 
272 	return (retval);
273 }
274 
275 static int
276 gpiobus_child_location_str(device_t bus, device_t child, char *buf,
277     size_t buflen)
278 {
279 
280 	snprintf(buf, buflen, "pins=?");
281 	return (0);
282 }
283 
284 static int
285 gpiobus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
286     size_t buflen)
287 {
288 
289 	*buf = '\0';
290 	return (0);
291 }
292 
293 static device_t
294 gpiobus_add_child(device_t dev, u_int order, const char *name, int unit)
295 {
296 	device_t child;
297 	struct gpiobus_ivar *devi;
298 
299 	child = device_add_child_ordered(dev, order, name, unit);
300 	if (child == NULL)
301 		return (child);
302 	devi = malloc(sizeof(struct gpiobus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
303 	if (devi == NULL) {
304 		device_delete_child(dev, child);
305 		return (0);
306 	}
307 	device_set_ivars(child, devi);
308 	return (child);
309 }
310 
311 static void
312 gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
313 {
314 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus);
315 	struct gpiobus_ivar *devi;
316 	device_t child;
317 	int pins;
318 
319 
320 	child = BUS_ADD_CHILD(bus, 0, dname, dunit);
321 	devi = GPIOBUS_IVAR(child);
322 	resource_int_value(dname, dunit, "pins", &pins);
323 	if (gpiobus_parse_pins(sc, child, pins))
324 		device_delete_child(bus, child);
325 }
326 
327 static int
328 gpiobus_acquire_bus(device_t busdev, device_t child, int how)
329 {
330 	struct gpiobus_softc *sc;
331 
332 	sc = device_get_softc(busdev);
333 	GPIOBUS_ASSERT_UNLOCKED(sc);
334 	GPIOBUS_LOCK(sc);
335 	if (sc->sc_owner != NULL) {
336 		if (how == GPIOBUS_DONTWAIT) {
337 			GPIOBUS_UNLOCK(sc);
338 			return (EWOULDBLOCK);
339 		}
340 		while (sc->sc_owner != NULL)
341 			mtx_sleep(sc, &sc->sc_mtx, 0, "gpiobuswait", 0);
342 	}
343 	sc->sc_owner = child;
344 	GPIOBUS_UNLOCK(sc);
345 
346 	return (0);
347 }
348 
349 static void
350 gpiobus_release_bus(device_t busdev, device_t child)
351 {
352 	struct gpiobus_softc *sc;
353 
354 	sc = device_get_softc(busdev);
355 	GPIOBUS_ASSERT_UNLOCKED(sc);
356 	GPIOBUS_LOCK(sc);
357 	if (sc->sc_owner == NULL)
358 		panic("gpiobus: releasing unowned bus.");
359 	if (sc->sc_owner != child)
360 		panic("gpiobus: you don't own the bus. game over.");
361 	sc->sc_owner = NULL;
362 	wakeup(sc);
363 	GPIOBUS_UNLOCK(sc);
364 }
365 
366 static int
367 gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin,
368     uint32_t flags)
369 {
370 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
371 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
372 
373 	if (pin >= devi->npins)
374 		return (EINVAL);
375 
376 	return GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags);
377 }
378 
379 static int
380 gpiobus_pin_getflags(device_t dev, device_t child, uint32_t pin,
381     uint32_t *flags)
382 {
383 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
384 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
385 
386 	if (pin >= devi->npins)
387 		return (EINVAL);
388 
389 	return GPIO_PIN_GETFLAGS(sc->sc_dev, devi->pins[pin], flags);
390 }
391 
392 static int
393 gpiobus_pin_getcaps(device_t dev, device_t child, uint32_t pin,
394     uint32_t *caps)
395 {
396 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
397 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
398 
399 	if (pin >= devi->npins)
400 		return (EINVAL);
401 
402 	return GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], caps);
403 }
404 
405 static int
406 gpiobus_pin_set(device_t dev, device_t child, uint32_t pin,
407     unsigned int value)
408 {
409 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
410 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
411 
412 	if (pin >= devi->npins)
413 		return (EINVAL);
414 
415 	return GPIO_PIN_SET(sc->sc_dev, devi->pins[pin], value);
416 }
417 
418 static int
419 gpiobus_pin_get(device_t dev, device_t child, uint32_t pin,
420     unsigned int *value)
421 {
422 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
423 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
424 
425 	if (pin >= devi->npins)
426 		return (EINVAL);
427 
428 	return GPIO_PIN_GET(sc->sc_dev, devi->pins[pin], value);
429 }
430 
431 static int
432 gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin)
433 {
434 	struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
435 	struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
436 
437 	if (pin >= devi->npins)
438 		return (EINVAL);
439 
440 	return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]);
441 }
442 
443 static device_method_t gpiobus_methods[] = {
444 	/* Device interface */
445 	DEVMETHOD(device_probe,		gpiobus_probe),
446 	DEVMETHOD(device_attach,	gpiobus_attach),
447 	DEVMETHOD(device_detach,	gpiobus_detach),
448 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
449 	DEVMETHOD(device_suspend,	gpiobus_suspend),
450 	DEVMETHOD(device_resume,	gpiobus_resume),
451 
452 	/* Bus interface */
453 	DEVMETHOD(bus_add_child,	gpiobus_add_child),
454 	DEVMETHOD(bus_print_child,	gpiobus_print_child),
455 	DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str),
456 	DEVMETHOD(bus_child_location_str, gpiobus_child_location_str),
457 	DEVMETHOD(bus_hinted_child,	gpiobus_hinted_child),
458 
459 	/* GPIO protocol */
460 	DEVMETHOD(gpiobus_acquire_bus,	gpiobus_acquire_bus),
461 	DEVMETHOD(gpiobus_release_bus,	gpiobus_release_bus),
462 	DEVMETHOD(gpiobus_pin_getflags,	gpiobus_pin_getflags),
463 	DEVMETHOD(gpiobus_pin_getcaps,	gpiobus_pin_getcaps),
464 	DEVMETHOD(gpiobus_pin_setflags,	gpiobus_pin_setflags),
465 	DEVMETHOD(gpiobus_pin_get,	gpiobus_pin_get),
466 	DEVMETHOD(gpiobus_pin_set,	gpiobus_pin_set),
467 	DEVMETHOD(gpiobus_pin_toggle,	gpiobus_pin_toggle),
468 
469 	DEVMETHOD_END
470 };
471 
472 driver_t gpiobus_driver = {
473 	"gpiobus",
474 	gpiobus_methods,
475 	sizeof(struct gpiobus_softc)
476 };
477 
478 devclass_t	gpiobus_devclass;
479 
480 DRIVER_MODULE(gpiobus, gpio, gpiobus_driver, gpiobus_devclass, 0, 0);
481 MODULE_VERSION(gpiobus, 1);
482