Deleted Added
full compact
ofw_gpiobus.c (265191) ofw_gpiobus.c (265289)
1/*-
2 * Copyright (c) 2009, Nathan Whitehorn <nwhitehorn@FreeBSD.org>
3 * Copyright (c) 2013, Luiz Otavio O Souza <loos@FreeBSD.org>
4 * Copyright (c) 2013 The FreeBSD Foundation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
12 * disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2009, Nathan Whitehorn <nwhitehorn@FreeBSD.org>
3 * Copyright (c) 2013, Luiz Otavio O Souza <loos@FreeBSD.org>
4 * Copyright (c) 2013 The FreeBSD Foundation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
12 * disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/gpio/ofw_gpiobus.c 265191 2014-05-01 14:09:47Z loos $");
30__FBSDID("$FreeBSD: head/sys/dev/gpio/ofw_gpiobus.c 265289 2014-05-03 20:33:00Z loos $");
31
32#include <sys/param.h>
31
32#include <sys/param.h>
33#include <sys/systm.h>
33#include <sys/bus.h>
34#include <sys/bus.h>
34#include <sys/gpio.h>
35#include <sys/kernel.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
36#include <sys/module.h>
37#include <sys/module.h>
37#include <sys/systm.h>
38
39#include <dev/gpio/gpiobusvar.h>
40#include <dev/ofw/ofw_bus.h>
38
39#include <dev/gpio/gpiobusvar.h>
40#include <dev/ofw/ofw_bus.h>
41#include <dev/ofw/openfirm.h>
42
43#include "gpio_if.h"
41
42#include "gpio_if.h"
44#include "gpiobus_if.h"
45
46static int ofw_gpiobus_parse_gpios(struct gpiobus_softc *,
47 struct gpiobus_ivar *, phandle_t);
48static struct ofw_gpiobus_devinfo *ofw_gpiobus_setup_devinfo(device_t,
49 phandle_t);
50static void ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *);
51
52device_t
53ofw_gpiobus_add_fdt_child(device_t bus, phandle_t child)
54{
55 struct ofw_gpiobus_devinfo *dinfo;
56 device_t childdev;
57
58 /*
59 * Set up the GPIO child and OFW bus layer devinfo and add it to bus.
60 */
61 dinfo = ofw_gpiobus_setup_devinfo(bus, child);
62 if (dinfo == NULL)
63 return (NULL);
64 childdev = device_add_child(bus, NULL, -1);
65 if (childdev == NULL) {
66 device_printf(bus, "could not add child: %s\n",
67 dinfo->opd_obdinfo.obd_name);
68 ofw_gpiobus_destroy_devinfo(dinfo);
69 return (NULL);
70 }
71 device_set_ivars(childdev, dinfo);
72
73 return (childdev);
74}
75
76static int
77ofw_gpiobus_alloc_ivars(struct gpiobus_ivar *dinfo)
78{
79
80 /* Allocate pins and flags memory. */
81 dinfo->pins = malloc(sizeof(uint32_t) * dinfo->npins, M_DEVBUF,
82 M_NOWAIT | M_ZERO);
83 if (dinfo->pins == NULL)
84 return (ENOMEM);
85 dinfo->flags = malloc(sizeof(uint32_t) * dinfo->npins, M_DEVBUF,
86 M_NOWAIT | M_ZERO);
87 if (dinfo->flags == NULL) {
88 free(dinfo->pins, M_DEVBUF);
89 return (ENOMEM);
90 }
91
92 return (0);
93}
94
95static void
96ofw_gpiobus_free_ivars(struct gpiobus_ivar *dinfo)
97{
98
99 free(dinfo->flags, M_DEVBUF);
100 free(dinfo->pins, M_DEVBUF);
101}
102
103static int
104ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
105 phandle_t child)
106{
107 int cells, i, j, len;
108 pcell_t *gpios;
109 phandle_t gpio;
110
111 /* Retrieve the gpios property. */
112 if ((len = OF_getproplen(child, "gpios")) < 0)
113 return (EINVAL);
114 gpios = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
115 if (gpios == NULL)
116 return (ENOMEM);
117 if (OF_getencprop(child, "gpios", gpios, len) < 0) {
118 free(gpios, M_DEVBUF);
119 return (EINVAL);
120 }
121
122 /*
123 * The gpio-specifier is controller independent, but the first pcell
124 * has the reference to the GPIO controller phandler.
125 * One the first pass we count the number of encoded gpio-specifiers.
126 */
127 i = 0;
128 len /= sizeof(pcell_t);
129 while (i < len) {
130 /* Allow NULL specifiers. */
131 if (gpios[i] == 0) {
132 dinfo->npins++;
133 i++;
134 continue;
135 }
136 gpio = OF_xref_phandle(gpios[i]);
137 /* Verify if we're attaching to the correct GPIO controller. */
138 if (!OF_hasprop(gpio, "gpio-controller") ||
139 gpio != ofw_bus_get_node(sc->sc_dev)) {
140 free(gpios, M_DEVBUF);
141 return (EINVAL);
142 }
143 /* Read gpio-cells property for this GPIO controller. */
144 if (OF_getencprop(gpio, "#gpio-cells", &cells,
145 sizeof(cells)) < 0) {
146 free(gpios, M_DEVBUF);
147 return (EINVAL);
148 }
149 dinfo->npins++;
150 i += cells + 1;
151 }
152
153 if (dinfo->npins == 0) {
154 free(gpios, M_DEVBUF);
155 return (EINVAL);
156 }
157
158 /* Allocate the child resources. */
159 if (ofw_gpiobus_alloc_ivars(dinfo) != 0) {
160 free(gpios, M_DEVBUF);
161 return (ENOMEM);
162 }
163
164 /* Decode the gpio specifier on the second pass. */
165 i = 0;
166 j = 0;
167 while (i < len) {
168 /* Allow NULL specifiers. */
169 if (gpios[i] == 0) {
170 i++;
171 j++;
172 continue;
173 }
174
175 gpio = OF_xref_phandle(gpios[i]);
176 /* Read gpio-cells property for this GPIO controller. */
177 if (OF_getencprop(gpio, "#gpio-cells", &cells,
178 sizeof(cells)) < 0) {
179 ofw_gpiobus_free_ivars(dinfo);
180 free(gpios, M_DEVBUF);
181 return (EINVAL);
182 }
183
184 /* Get the GPIO pin number and flags. */
185 if (ofw_bus_map_gpios(sc->sc_dev, child, gpio, cells,
186 &gpios[i + 1], &dinfo->pins[j], &dinfo->flags[j]) != 0) {
187 ofw_gpiobus_free_ivars(dinfo);
188 free(gpios, M_DEVBUF);
189 return (EINVAL);
190 }
191
192 /* Consistency check. */
193 if (dinfo->pins[j] > sc->sc_npins) {
194 device_printf(sc->sc_busdev,
195 "invalid pin %d, max: %d\n",
196 dinfo->pins[j], sc->sc_npins - 1);
197 ofw_gpiobus_free_ivars(dinfo);
198 free(gpios, M_DEVBUF);
199 return (EINVAL);
200 }
201
202 /*
203 * Mark pin as mapped and give warning if it's already mapped.
204 */
205 if (sc->sc_pins_mapped[dinfo->pins[j]]) {
206 device_printf(sc->sc_busdev,
207 "warning: pin %d is already mapped\n",
208 dinfo->pins[j]);
209 ofw_gpiobus_free_ivars(dinfo);
210 free(gpios, M_DEVBUF);
211 return (EINVAL);
212 }
213 sc->sc_pins_mapped[dinfo->pins[j]] = 1;
214
215 i += cells + 1;
216 j++;
217 }
218
219 free(gpios, M_DEVBUF);
220
221 return (0);
222}
223
224static struct ofw_gpiobus_devinfo *
225ofw_gpiobus_setup_devinfo(device_t dev, phandle_t node)
226{
227 struct gpiobus_softc *sc;
228 struct ofw_gpiobus_devinfo *dinfo;
229
230 sc = device_get_softc(dev);
231 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
232 if (dinfo == NULL)
233 return (NULL);
234 if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0) {
235 free(dinfo, M_DEVBUF);
236 return (NULL);
237 }
238
239 /* Parse the gpios property for the child. */
240 if (ofw_gpiobus_parse_gpios(sc, &dinfo->opd_dinfo, node) != 0) {
241 ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
242 free(dinfo, M_DEVBUF);
243 return (NULL);
244 }
245
246 return (dinfo);
247}
248
249static void
250ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *dinfo)
251{
252
253 ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
254 free(dinfo, M_DEVBUF);
255}
256
257static int
258ofw_gpiobus_probe(device_t dev)
259{
260
261 if (ofw_bus_get_node(dev) == -1)
262 return (ENXIO);
263 device_set_desc(dev, "OFW GPIO bus");
264
265 return (0);
266}
267
268static int
269ofw_gpiobus_attach(device_t dev)
270{
271 struct gpiobus_softc *sc;
272 phandle_t child;
273
274 sc = GPIOBUS_SOFTC(dev);
275 sc->sc_busdev = dev;
276 sc->sc_dev = device_get_parent(dev);
277
278 /* Read the pin max. value */
279 if (GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins) != 0)
280 return (ENXIO);
281
282 KASSERT(sc->sc_npins != 0, ("GPIO device with no pins"));
283
284 /*
285 * Increase to get number of pins.
286 */
287 sc->sc_npins++;
288
289 sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF,
290 M_NOWAIT | M_ZERO);
291
292 if (!sc->sc_pins_mapped)
293 return (ENOMEM);
294
295 /* Init the bus lock. */
296 GPIOBUS_LOCK_INIT(sc);
297
298 bus_generic_probe(dev);
299 bus_enumerate_hinted_children(dev);
300
301 /*
302 * Attach the children represented in the device tree.
303 */
304 for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
305 child = OF_peer(child))
306 if (ofw_gpiobus_add_fdt_child(dev, child) == NULL)
307 continue;
308
309 return (bus_generic_attach(dev));
310}
311
312static device_t
313ofw_gpiobus_add_child(device_t dev, u_int order, const char *name, int unit)
314{
315 device_t child;
316 struct ofw_gpiobus_devinfo *devi;
317
318 child = device_add_child_ordered(dev, order, name, unit);
319 if (child == NULL)
320 return (child);
321 devi = malloc(sizeof(struct ofw_gpiobus_devinfo), M_DEVBUF,
322 M_NOWAIT | M_ZERO);
323 if (devi == NULL) {
324 device_delete_child(dev, child);
325 return (0);
326 }
327
328 /*
329 * NULL all the OFW-related parts of the ivars for non-OFW
330 * children.
331 */
332 devi->opd_obdinfo.obd_node = -1;
333 devi->opd_obdinfo.obd_name = NULL;
334 devi->opd_obdinfo.obd_compat = NULL;
335 devi->opd_obdinfo.obd_type = NULL;
336 devi->opd_obdinfo.obd_model = NULL;
337
338 device_set_ivars(child, devi);
339
340 return (child);
341}
342
343static int
344ofw_gpiobus_print_child(device_t dev, device_t child)
345{
346 struct ofw_gpiobus_devinfo *devi;
347 int retval = 0;
348
349 devi = device_get_ivars(child);
350 retval += bus_print_child_header(dev, child);
351 retval += printf(" at pin(s) ");
352 gpiobus_print_pins(&devi->opd_dinfo);
353 retval += bus_print_child_footer(dev, child);
354
355 return (retval);
356}
357
358static const struct ofw_bus_devinfo *
359ofw_gpiobus_get_devinfo(device_t bus, device_t dev)
360{
361 struct ofw_gpiobus_devinfo *dinfo;
362
363 dinfo = device_get_ivars(dev);
364
365 return (&dinfo->opd_obdinfo);
366}
367
368static device_method_t ofw_gpiobus_methods[] = {
369 /* Device interface */
370 DEVMETHOD(device_probe, ofw_gpiobus_probe),
371 DEVMETHOD(device_attach, ofw_gpiobus_attach),
372
373 /* Bus interface */
374 DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
375 DEVMETHOD(bus_print_child, ofw_gpiobus_print_child),
376 DEVMETHOD(bus_add_child, ofw_gpiobus_add_child),
377
378 /* ofw_bus interface */
379 DEVMETHOD(ofw_bus_get_devinfo, ofw_gpiobus_get_devinfo),
380 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
381 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
382 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
383 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
384 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
385
386 DEVMETHOD_END
387};
388
389static devclass_t ofwgpiobus_devclass;
390
391DEFINE_CLASS_1(gpiobus, ofw_gpiobus_driver, ofw_gpiobus_methods,
392 sizeof(struct gpiobus_softc), gpiobus_driver);
393DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0);
394MODULE_VERSION(ofw_gpiobus, 1);
395MODULE_DEPEND(ofw_gpiobus, gpiobus, 1, 1, 1);
43
44static int ofw_gpiobus_parse_gpios(struct gpiobus_softc *,
45 struct gpiobus_ivar *, phandle_t);
46static struct ofw_gpiobus_devinfo *ofw_gpiobus_setup_devinfo(device_t,
47 phandle_t);
48static void ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *);
49
50device_t
51ofw_gpiobus_add_fdt_child(device_t bus, phandle_t child)
52{
53 struct ofw_gpiobus_devinfo *dinfo;
54 device_t childdev;
55
56 /*
57 * Set up the GPIO child and OFW bus layer devinfo and add it to bus.
58 */
59 dinfo = ofw_gpiobus_setup_devinfo(bus, child);
60 if (dinfo == NULL)
61 return (NULL);
62 childdev = device_add_child(bus, NULL, -1);
63 if (childdev == NULL) {
64 device_printf(bus, "could not add child: %s\n",
65 dinfo->opd_obdinfo.obd_name);
66 ofw_gpiobus_destroy_devinfo(dinfo);
67 return (NULL);
68 }
69 device_set_ivars(childdev, dinfo);
70
71 return (childdev);
72}
73
74static int
75ofw_gpiobus_alloc_ivars(struct gpiobus_ivar *dinfo)
76{
77
78 /* Allocate pins and flags memory. */
79 dinfo->pins = malloc(sizeof(uint32_t) * dinfo->npins, M_DEVBUF,
80 M_NOWAIT | M_ZERO);
81 if (dinfo->pins == NULL)
82 return (ENOMEM);
83 dinfo->flags = malloc(sizeof(uint32_t) * dinfo->npins, M_DEVBUF,
84 M_NOWAIT | M_ZERO);
85 if (dinfo->flags == NULL) {
86 free(dinfo->pins, M_DEVBUF);
87 return (ENOMEM);
88 }
89
90 return (0);
91}
92
93static void
94ofw_gpiobus_free_ivars(struct gpiobus_ivar *dinfo)
95{
96
97 free(dinfo->flags, M_DEVBUF);
98 free(dinfo->pins, M_DEVBUF);
99}
100
101static int
102ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
103 phandle_t child)
104{
105 int cells, i, j, len;
106 pcell_t *gpios;
107 phandle_t gpio;
108
109 /* Retrieve the gpios property. */
110 if ((len = OF_getproplen(child, "gpios")) < 0)
111 return (EINVAL);
112 gpios = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
113 if (gpios == NULL)
114 return (ENOMEM);
115 if (OF_getencprop(child, "gpios", gpios, len) < 0) {
116 free(gpios, M_DEVBUF);
117 return (EINVAL);
118 }
119
120 /*
121 * The gpio-specifier is controller independent, but the first pcell
122 * has the reference to the GPIO controller phandler.
123 * One the first pass we count the number of encoded gpio-specifiers.
124 */
125 i = 0;
126 len /= sizeof(pcell_t);
127 while (i < len) {
128 /* Allow NULL specifiers. */
129 if (gpios[i] == 0) {
130 dinfo->npins++;
131 i++;
132 continue;
133 }
134 gpio = OF_xref_phandle(gpios[i]);
135 /* Verify if we're attaching to the correct GPIO controller. */
136 if (!OF_hasprop(gpio, "gpio-controller") ||
137 gpio != ofw_bus_get_node(sc->sc_dev)) {
138 free(gpios, M_DEVBUF);
139 return (EINVAL);
140 }
141 /* Read gpio-cells property for this GPIO controller. */
142 if (OF_getencprop(gpio, "#gpio-cells", &cells,
143 sizeof(cells)) < 0) {
144 free(gpios, M_DEVBUF);
145 return (EINVAL);
146 }
147 dinfo->npins++;
148 i += cells + 1;
149 }
150
151 if (dinfo->npins == 0) {
152 free(gpios, M_DEVBUF);
153 return (EINVAL);
154 }
155
156 /* Allocate the child resources. */
157 if (ofw_gpiobus_alloc_ivars(dinfo) != 0) {
158 free(gpios, M_DEVBUF);
159 return (ENOMEM);
160 }
161
162 /* Decode the gpio specifier on the second pass. */
163 i = 0;
164 j = 0;
165 while (i < len) {
166 /* Allow NULL specifiers. */
167 if (gpios[i] == 0) {
168 i++;
169 j++;
170 continue;
171 }
172
173 gpio = OF_xref_phandle(gpios[i]);
174 /* Read gpio-cells property for this GPIO controller. */
175 if (OF_getencprop(gpio, "#gpio-cells", &cells,
176 sizeof(cells)) < 0) {
177 ofw_gpiobus_free_ivars(dinfo);
178 free(gpios, M_DEVBUF);
179 return (EINVAL);
180 }
181
182 /* Get the GPIO pin number and flags. */
183 if (ofw_bus_map_gpios(sc->sc_dev, child, gpio, cells,
184 &gpios[i + 1], &dinfo->pins[j], &dinfo->flags[j]) != 0) {
185 ofw_gpiobus_free_ivars(dinfo);
186 free(gpios, M_DEVBUF);
187 return (EINVAL);
188 }
189
190 /* Consistency check. */
191 if (dinfo->pins[j] > sc->sc_npins) {
192 device_printf(sc->sc_busdev,
193 "invalid pin %d, max: %d\n",
194 dinfo->pins[j], sc->sc_npins - 1);
195 ofw_gpiobus_free_ivars(dinfo);
196 free(gpios, M_DEVBUF);
197 return (EINVAL);
198 }
199
200 /*
201 * Mark pin as mapped and give warning if it's already mapped.
202 */
203 if (sc->sc_pins_mapped[dinfo->pins[j]]) {
204 device_printf(sc->sc_busdev,
205 "warning: pin %d is already mapped\n",
206 dinfo->pins[j]);
207 ofw_gpiobus_free_ivars(dinfo);
208 free(gpios, M_DEVBUF);
209 return (EINVAL);
210 }
211 sc->sc_pins_mapped[dinfo->pins[j]] = 1;
212
213 i += cells + 1;
214 j++;
215 }
216
217 free(gpios, M_DEVBUF);
218
219 return (0);
220}
221
222static struct ofw_gpiobus_devinfo *
223ofw_gpiobus_setup_devinfo(device_t dev, phandle_t node)
224{
225 struct gpiobus_softc *sc;
226 struct ofw_gpiobus_devinfo *dinfo;
227
228 sc = device_get_softc(dev);
229 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
230 if (dinfo == NULL)
231 return (NULL);
232 if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0) {
233 free(dinfo, M_DEVBUF);
234 return (NULL);
235 }
236
237 /* Parse the gpios property for the child. */
238 if (ofw_gpiobus_parse_gpios(sc, &dinfo->opd_dinfo, node) != 0) {
239 ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
240 free(dinfo, M_DEVBUF);
241 return (NULL);
242 }
243
244 return (dinfo);
245}
246
247static void
248ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *dinfo)
249{
250
251 ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
252 free(dinfo, M_DEVBUF);
253}
254
255static int
256ofw_gpiobus_probe(device_t dev)
257{
258
259 if (ofw_bus_get_node(dev) == -1)
260 return (ENXIO);
261 device_set_desc(dev, "OFW GPIO bus");
262
263 return (0);
264}
265
266static int
267ofw_gpiobus_attach(device_t dev)
268{
269 struct gpiobus_softc *sc;
270 phandle_t child;
271
272 sc = GPIOBUS_SOFTC(dev);
273 sc->sc_busdev = dev;
274 sc->sc_dev = device_get_parent(dev);
275
276 /* Read the pin max. value */
277 if (GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins) != 0)
278 return (ENXIO);
279
280 KASSERT(sc->sc_npins != 0, ("GPIO device with no pins"));
281
282 /*
283 * Increase to get number of pins.
284 */
285 sc->sc_npins++;
286
287 sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF,
288 M_NOWAIT | M_ZERO);
289
290 if (!sc->sc_pins_mapped)
291 return (ENOMEM);
292
293 /* Init the bus lock. */
294 GPIOBUS_LOCK_INIT(sc);
295
296 bus_generic_probe(dev);
297 bus_enumerate_hinted_children(dev);
298
299 /*
300 * Attach the children represented in the device tree.
301 */
302 for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
303 child = OF_peer(child))
304 if (ofw_gpiobus_add_fdt_child(dev, child) == NULL)
305 continue;
306
307 return (bus_generic_attach(dev));
308}
309
310static device_t
311ofw_gpiobus_add_child(device_t dev, u_int order, const char *name, int unit)
312{
313 device_t child;
314 struct ofw_gpiobus_devinfo *devi;
315
316 child = device_add_child_ordered(dev, order, name, unit);
317 if (child == NULL)
318 return (child);
319 devi = malloc(sizeof(struct ofw_gpiobus_devinfo), M_DEVBUF,
320 M_NOWAIT | M_ZERO);
321 if (devi == NULL) {
322 device_delete_child(dev, child);
323 return (0);
324 }
325
326 /*
327 * NULL all the OFW-related parts of the ivars for non-OFW
328 * children.
329 */
330 devi->opd_obdinfo.obd_node = -1;
331 devi->opd_obdinfo.obd_name = NULL;
332 devi->opd_obdinfo.obd_compat = NULL;
333 devi->opd_obdinfo.obd_type = NULL;
334 devi->opd_obdinfo.obd_model = NULL;
335
336 device_set_ivars(child, devi);
337
338 return (child);
339}
340
341static int
342ofw_gpiobus_print_child(device_t dev, device_t child)
343{
344 struct ofw_gpiobus_devinfo *devi;
345 int retval = 0;
346
347 devi = device_get_ivars(child);
348 retval += bus_print_child_header(dev, child);
349 retval += printf(" at pin(s) ");
350 gpiobus_print_pins(&devi->opd_dinfo);
351 retval += bus_print_child_footer(dev, child);
352
353 return (retval);
354}
355
356static const struct ofw_bus_devinfo *
357ofw_gpiobus_get_devinfo(device_t bus, device_t dev)
358{
359 struct ofw_gpiobus_devinfo *dinfo;
360
361 dinfo = device_get_ivars(dev);
362
363 return (&dinfo->opd_obdinfo);
364}
365
366static device_method_t ofw_gpiobus_methods[] = {
367 /* Device interface */
368 DEVMETHOD(device_probe, ofw_gpiobus_probe),
369 DEVMETHOD(device_attach, ofw_gpiobus_attach),
370
371 /* Bus interface */
372 DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
373 DEVMETHOD(bus_print_child, ofw_gpiobus_print_child),
374 DEVMETHOD(bus_add_child, ofw_gpiobus_add_child),
375
376 /* ofw_bus interface */
377 DEVMETHOD(ofw_bus_get_devinfo, ofw_gpiobus_get_devinfo),
378 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
379 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
380 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
381 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
382 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
383
384 DEVMETHOD_END
385};
386
387static devclass_t ofwgpiobus_devclass;
388
389DEFINE_CLASS_1(gpiobus, ofw_gpiobus_driver, ofw_gpiobus_methods,
390 sizeof(struct gpiobus_softc), gpiobus_driver);
391DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0);
392MODULE_VERSION(ofw_gpiobus, 1);
393MODULE_DEPEND(ofw_gpiobus, gpiobus, 1, 1, 1);