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