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