]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/arm/broadcom/bcm2835/bcm2835_gpio.c
MFC r257199, r257200, r257217:
[FreeBSD/stable/10.git] / sys / arm / broadcom / bcm2835 / bcm2835_gpio.c
1 /*-
2  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
3  * Copyright (c) 2012 Luiz Otavio O Souza.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/rman.h>
38 #include <sys/lock.h>
39 #include <sys/mutex.h>
40 #include <sys/gpio.h>
41 #include <sys/sysctl.h>
42
43 #include <machine/bus.h>
44 #include <machine/cpu.h>
45 #include <machine/cpufunc.h>
46 #include <machine/resource.h>
47 #include <machine/fdt.h>
48 #include <machine/intr.h>
49
50 #include <dev/fdt/fdt_common.h>
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
53
54 #include <arm/broadcom/bcm2835/bcm2835_gpio.h>
55
56 #include "gpio_if.h"
57
58 #undef  DEBUG
59
60 #ifdef DEBUG
61 #define dprintf(fmt, args...) do { printf("%s(): ", __func__);   \
62     printf(fmt,##args); } while (0)
63 #else
64 #define dprintf(fmt, args...)
65 #endif
66
67 #define BCM_GPIO_PINS           54
68 #define BCM_GPIO_DEFAULT_CAPS   (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |     \
69     GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)
70
71 struct bcm_gpio_sysctl {
72         struct bcm_gpio_softc   *sc;
73         uint32_t                pin;
74 };
75
76 struct bcm_gpio_softc {
77         device_t                sc_dev;
78         struct mtx              sc_mtx;
79         struct resource *       sc_mem_res;
80         struct resource *       sc_irq_res;
81         bus_space_tag_t         sc_bst;
82         bus_space_handle_t      sc_bsh;
83         void *                  sc_intrhand;
84         int                     sc_gpio_npins;
85         int                     sc_ro_npins;
86         int                     sc_ro_pins[BCM_GPIO_PINS];
87         struct gpio_pin         sc_gpio_pins[BCM_GPIO_PINS];
88         struct bcm_gpio_sysctl  sc_sysctl[BCM_GPIO_PINS];
89 };
90
91 enum bcm_gpio_pud {
92         BCM_GPIO_NONE,
93         BCM_GPIO_PULLDOWN,
94         BCM_GPIO_PULLUP,
95 };
96
97 #define BCM_GPIO_LOCK(_sc)      mtx_lock(&_sc->sc_mtx)
98 #define BCM_GPIO_UNLOCK(_sc)    mtx_unlock(&_sc->sc_mtx)
99 #define BCM_GPIO_LOCK_ASSERT(_sc)       mtx_assert(&_sc->sc_mtx, MA_OWNED)
100
101 #define BCM_GPIO_GPFSEL(_bank)  0x00 + _bank * 4
102 #define BCM_GPIO_GPSET(_bank)   0x1c + _bank * 4
103 #define BCM_GPIO_GPCLR(_bank)   0x28 + _bank * 4
104 #define BCM_GPIO_GPLEV(_bank)   0x34 + _bank * 4
105 #define BCM_GPIO_GPPUD(_bank)   0x94
106 #define BCM_GPIO_GPPUDCLK(_bank)        0x98 + _bank * 4
107
108 #define BCM_GPIO_WRITE(_sc, _off, _val)         \
109     bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
110 #define BCM_GPIO_READ(_sc, _off)                \
111     bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off)
112
113 static int
114 bcm_gpio_pin_is_ro(struct bcm_gpio_softc *sc, int pin)
115 {
116         int i;
117
118         for (i = 0; i < sc->sc_ro_npins; i++)
119                 if (pin == sc->sc_ro_pins[i])
120                         return (1);
121         return (0);
122 }
123
124 static uint32_t
125 bcm_gpio_get_function(struct bcm_gpio_softc *sc, uint32_t pin)
126 {
127         uint32_t bank, func, offset;
128
129         /* Five banks, 10 pins per bank, 3 bits per pin. */
130         bank = pin / 10;
131         offset = (pin - bank * 10) * 3;
132
133         BCM_GPIO_LOCK(sc);
134         func = (BCM_GPIO_READ(sc, BCM_GPIO_GPFSEL(bank)) >> offset) & 7;
135         BCM_GPIO_UNLOCK(sc);
136
137         return (func);
138 }
139
140 static void
141 bcm_gpio_func_str(uint32_t nfunc, char *buf, int bufsize)
142 {
143
144         switch (nfunc) {
145         case BCM_GPIO_INPUT:
146                 strncpy(buf, "input", bufsize);
147                 break;
148         case BCM_GPIO_OUTPUT:
149                 strncpy(buf, "output", bufsize);
150                 break;
151         case BCM_GPIO_ALT0:
152                 strncpy(buf, "alt0", bufsize);
153                 break;
154         case BCM_GPIO_ALT1:
155                 strncpy(buf, "alt1", bufsize);
156                 break;
157         case BCM_GPIO_ALT2:
158                 strncpy(buf, "alt2", bufsize);
159                 break;
160         case BCM_GPIO_ALT3:
161                 strncpy(buf, "alt3", bufsize);
162                 break;
163         case BCM_GPIO_ALT4:
164                 strncpy(buf, "alt4", bufsize);
165                 break;
166         case BCM_GPIO_ALT5:
167                 strncpy(buf, "alt5", bufsize);
168                 break;
169         default:
170                 strncpy(buf, "invalid", bufsize);
171         }
172 }
173
174 static int
175 bcm_gpio_str_func(char *func, uint32_t *nfunc)
176 {
177
178         if (strcasecmp(func, "input") == 0)
179                 *nfunc = BCM_GPIO_INPUT;
180         else if (strcasecmp(func, "output") == 0)
181                 *nfunc = BCM_GPIO_OUTPUT;
182         else if (strcasecmp(func, "alt0") == 0)
183                 *nfunc = BCM_GPIO_ALT0;
184         else if (strcasecmp(func, "alt1") == 0)
185                 *nfunc = BCM_GPIO_ALT1;
186         else if (strcasecmp(func, "alt2") == 0)
187                 *nfunc = BCM_GPIO_ALT2;
188         else if (strcasecmp(func, "alt3") == 0)
189                 *nfunc = BCM_GPIO_ALT3;
190         else if (strcasecmp(func, "alt4") == 0)
191                 *nfunc = BCM_GPIO_ALT4;
192         else if (strcasecmp(func, "alt5") == 0)
193                 *nfunc = BCM_GPIO_ALT5;
194         else
195                 return (-1);
196
197         return (0);
198 }
199
200 static uint32_t
201 bcm_gpio_func_flag(uint32_t nfunc)
202 {
203
204         switch (nfunc) {
205         case BCM_GPIO_INPUT:
206                 return (GPIO_PIN_INPUT);
207         case BCM_GPIO_OUTPUT:
208                 return (GPIO_PIN_OUTPUT);
209         }
210         return (0);
211 }
212
213 static void
214 bcm_gpio_set_function(struct bcm_gpio_softc *sc, uint32_t pin, uint32_t f)
215 {
216         uint32_t bank, data, offset;
217
218         /* Must be called with lock held. */
219         BCM_GPIO_LOCK_ASSERT(sc);
220
221         /* Five banks, 10 pins per bank, 3 bits per pin. */
222         bank = pin / 10;
223         offset = (pin - bank * 10) * 3;
224
225         data = BCM_GPIO_READ(sc, BCM_GPIO_GPFSEL(bank));
226         data &= ~(7 << offset);
227         data |= (f << offset);
228         BCM_GPIO_WRITE(sc, BCM_GPIO_GPFSEL(bank), data);
229 }
230
231 static void
232 bcm_gpio_set_pud(struct bcm_gpio_softc *sc, uint32_t pin, uint32_t state)
233 {
234         uint32_t bank, offset;
235
236         /* Must be called with lock held. */
237         BCM_GPIO_LOCK_ASSERT(sc);
238
239         bank = pin / 32;
240         offset = pin - 32 * bank;
241
242         BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUD(0), state);
243         DELAY(10);
244         BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUDCLK(bank), (1 << offset));
245         DELAY(10);
246         BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUD(0), 0);
247         BCM_GPIO_WRITE(sc, BCM_GPIO_GPPUDCLK(bank), 0);
248 }
249
250 void
251 bcm_gpio_set_alternate(device_t dev, uint32_t pin, uint32_t nfunc)
252 {
253         struct bcm_gpio_softc *sc;
254         int i;
255
256         sc = device_get_softc(dev);
257         BCM_GPIO_LOCK(sc);
258
259         /* Disable pull-up or pull-down on pin. */
260         bcm_gpio_set_pud(sc, pin, BCM_GPIO_NONE);
261
262         /* And now set the pin function. */
263         bcm_gpio_set_function(sc, pin, nfunc);
264
265         /* Update the pin flags. */
266         for (i = 0; i < sc->sc_gpio_npins; i++) {
267                 if (sc->sc_gpio_pins[i].gp_pin == pin)
268                         break;
269         }
270         if (i < sc->sc_gpio_npins)
271                 sc->sc_gpio_pins[i].gp_flags = bcm_gpio_func_flag(nfunc);
272
273         BCM_GPIO_UNLOCK(sc);
274 }
275
276 static void
277 bcm_gpio_pin_configure(struct bcm_gpio_softc *sc, struct gpio_pin *pin,
278     unsigned int flags)
279 {
280
281         BCM_GPIO_LOCK(sc);
282
283         /*
284          * Manage input/output.
285          */
286         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
287                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
288                 if (flags & GPIO_PIN_OUTPUT) {
289                         pin->gp_flags |= GPIO_PIN_OUTPUT;
290                         bcm_gpio_set_function(sc, pin->gp_pin,
291                             BCM_GPIO_OUTPUT);
292                 } else {
293                         pin->gp_flags |= GPIO_PIN_INPUT;
294                         bcm_gpio_set_function(sc, pin->gp_pin,
295                             BCM_GPIO_INPUT);
296                 }
297         }
298
299         /* Manage Pull-up/pull-down. */
300         pin->gp_flags &= ~(GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN);
301         if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) {
302                 if (flags & GPIO_PIN_PULLUP) {
303                         pin->gp_flags |= GPIO_PIN_PULLUP;
304                         bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_PULLUP);
305                 } else {
306                         pin->gp_flags |= GPIO_PIN_PULLDOWN;
307                         bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_PULLDOWN);
308                 }
309         } else 
310                 bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_NONE);
311
312         BCM_GPIO_UNLOCK(sc);
313 }
314
315 static int
316 bcm_gpio_pin_max(device_t dev, int *maxpin)
317 {
318
319         *maxpin = BCM_GPIO_PINS - 1;
320         return (0);
321 }
322
323 static int
324 bcm_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
325 {
326         struct bcm_gpio_softc *sc = device_get_softc(dev);
327         int i;
328
329         for (i = 0; i < sc->sc_gpio_npins; i++) {
330                 if (sc->sc_gpio_pins[i].gp_pin == pin)
331                         break;
332         }
333
334         if (i >= sc->sc_gpio_npins)
335                 return (EINVAL);
336
337         BCM_GPIO_LOCK(sc);
338         *caps = sc->sc_gpio_pins[i].gp_caps;
339         BCM_GPIO_UNLOCK(sc);
340
341         return (0);
342 }
343
344 static int
345 bcm_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
346 {
347         struct bcm_gpio_softc *sc = device_get_softc(dev);
348         int i;
349
350         for (i = 0; i < sc->sc_gpio_npins; i++) {
351                 if (sc->sc_gpio_pins[i].gp_pin == pin)
352                         break;
353         }
354
355         if (i >= sc->sc_gpio_npins)
356                 return (EINVAL);
357
358         BCM_GPIO_LOCK(sc);
359         *flags = sc->sc_gpio_pins[i].gp_flags;
360         BCM_GPIO_UNLOCK(sc);
361
362         return (0);
363 }
364
365 static int
366 bcm_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
367 {
368         struct bcm_gpio_softc *sc = device_get_softc(dev);
369         int i;
370
371         for (i = 0; i < sc->sc_gpio_npins; i++) {
372                 if (sc->sc_gpio_pins[i].gp_pin == pin)
373                         break;
374         }
375
376         if (i >= sc->sc_gpio_npins)
377                 return (EINVAL);
378
379         BCM_GPIO_LOCK(sc);
380         memcpy(name, sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME);
381         BCM_GPIO_UNLOCK(sc);
382
383         return (0);
384 }
385
386 static int
387 bcm_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
388 {
389         struct bcm_gpio_softc *sc = device_get_softc(dev);
390         int i;
391
392         for (i = 0; i < sc->sc_gpio_npins; i++) {
393                 if (sc->sc_gpio_pins[i].gp_pin == pin)
394                         break;
395         }
396
397         if (i >= sc->sc_gpio_npins)
398                 return (EINVAL);
399
400         /* We never touch on read-only/reserved pins. */
401         if (bcm_gpio_pin_is_ro(sc, pin))
402                 return (EINVAL);
403
404         /* Check for unwanted flags. */
405         if ((flags & sc->sc_gpio_pins[i].gp_caps) != flags)
406                 return (EINVAL);
407
408         /* Can't mix input/output together. */
409         if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
410             (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
411                 return (EINVAL);
412
413         /* Can't mix pull-up/pull-down together. */
414         if ((flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) ==
415             (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN))
416                 return (EINVAL);
417
418         bcm_gpio_pin_configure(sc, &sc->sc_gpio_pins[i], flags);
419
420         return (0);
421 }
422
423 static int
424 bcm_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
425 {
426         struct bcm_gpio_softc *sc = device_get_softc(dev);
427         uint32_t bank, offset;
428         int i;
429
430         for (i = 0; i < sc->sc_gpio_npins; i++) {
431                 if (sc->sc_gpio_pins[i].gp_pin == pin)
432                         break;
433         }
434
435         if (i >= sc->sc_gpio_npins)
436                 return (EINVAL);
437
438         /* We never write to read-only/reserved pins. */
439         if (bcm_gpio_pin_is_ro(sc, pin))
440                 return (EINVAL);
441
442         bank = pin / 32;
443         offset = pin - 32 * bank;
444
445         BCM_GPIO_LOCK(sc);
446         if (value)
447                 BCM_GPIO_WRITE(sc, BCM_GPIO_GPSET(bank), (1 << offset));
448         else
449                 BCM_GPIO_WRITE(sc, BCM_GPIO_GPCLR(bank), (1 << offset));
450         BCM_GPIO_UNLOCK(sc);
451
452         return (0);
453 }
454
455 static int
456 bcm_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
457 {
458         struct bcm_gpio_softc *sc = device_get_softc(dev);
459         uint32_t bank, offset, reg_data;
460         int i;
461
462         for (i = 0; i < sc->sc_gpio_npins; i++) {
463                 if (sc->sc_gpio_pins[i].gp_pin == pin)
464                         break;
465         }
466
467         if (i >= sc->sc_gpio_npins)
468                 return (EINVAL);
469
470         bank = pin / 32;
471         offset = pin - 32 * bank;
472
473         BCM_GPIO_LOCK(sc);
474         reg_data = BCM_GPIO_READ(sc, BCM_GPIO_GPLEV(bank));
475         BCM_GPIO_UNLOCK(sc);
476         *val = (reg_data & (1 << offset)) ? 1 : 0;
477
478         return (0);
479 }
480
481 static int
482 bcm_gpio_pin_toggle(device_t dev, uint32_t pin)
483 {
484         struct bcm_gpio_softc *sc = device_get_softc(dev);
485         uint32_t bank, data, offset;
486         int i;
487
488         for (i = 0; i < sc->sc_gpio_npins; i++) {
489                 if (sc->sc_gpio_pins[i].gp_pin == pin)
490                         break;
491         }
492
493         if (i >= sc->sc_gpio_npins)
494                 return (EINVAL);
495
496         /* We never write to read-only/reserved pins. */
497         if (bcm_gpio_pin_is_ro(sc, pin))
498                 return (EINVAL);
499
500         bank = pin / 32;
501         offset = pin - 32 * bank;
502
503         BCM_GPIO_LOCK(sc);
504         data = BCM_GPIO_READ(sc, BCM_GPIO_GPLEV(bank));
505         if (data & (1 << offset))
506                 BCM_GPIO_WRITE(sc, BCM_GPIO_GPCLR(bank), (1 << offset));
507         else
508                 BCM_GPIO_WRITE(sc, BCM_GPIO_GPSET(bank), (1 << offset));
509         BCM_GPIO_UNLOCK(sc);
510
511         return (0);
512 }
513
514 static int
515 bcm_gpio_get_ro_pins(struct bcm_gpio_softc *sc)
516 {
517         int i, len;
518         pcell_t pins[BCM_GPIO_PINS];
519         phandle_t gpio;
520
521         /* Find the gpio node to start. */
522         gpio = ofw_bus_get_node(sc->sc_dev);
523
524         len = OF_getproplen(gpio, "broadcom,read-only");
525         if (len < 0 || len > sizeof(pins))
526                 return (-1);
527
528         if (OF_getprop(gpio, "broadcom,read-only", &pins, len) < 0)
529                 return (-1);
530
531         sc->sc_ro_npins = len / sizeof(pcell_t);
532
533         device_printf(sc->sc_dev, "read-only pins: ");
534         for (i = 0; i < sc->sc_ro_npins; i++) {
535                 sc->sc_ro_pins[i] = fdt32_to_cpu(pins[i]);
536                 if (i > 0)
537                         printf(",");
538                 printf("%d", sc->sc_ro_pins[i]);
539         }
540         if (i > 0)
541                 printf(".");
542         printf("\n");
543
544         return (0);
545 }
546
547 static int
548 bcm_gpio_func_proc(SYSCTL_HANDLER_ARGS)
549 {
550         char buf[16];
551         struct bcm_gpio_softc *sc;
552         struct bcm_gpio_sysctl *sc_sysctl;
553         uint32_t nfunc;
554         int error;
555
556         sc_sysctl = arg1;
557         sc = sc_sysctl->sc;
558
559         /* Get the current pin function. */
560         nfunc = bcm_gpio_get_function(sc, sc_sysctl->pin);
561         bcm_gpio_func_str(nfunc, buf, sizeof(buf));
562
563         error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
564         if (error != 0 || req->newptr == NULL)
565                 return (error);
566
567         /* Parse the user supplied string and check for a valid pin function. */
568         if (bcm_gpio_str_func(buf, &nfunc) != 0)
569                 return (EINVAL);
570
571         /* Update the pin alternate function. */
572         bcm_gpio_set_alternate(sc->sc_dev, sc_sysctl->pin, nfunc);
573
574         return (0);
575 }
576
577 static void
578 bcm_gpio_sysctl_init(struct bcm_gpio_softc *sc)
579 {
580         char pinbuf[3];
581         struct bcm_gpio_sysctl *sc_sysctl;
582         struct sysctl_ctx_list *ctx;
583         struct sysctl_oid *tree_node, *pin_node, *pinN_node;
584         struct sysctl_oid_list *tree, *pin_tree, *pinN_tree;
585         int i;
586
587         /*
588          * Add per-pin sysctl tree/handlers.
589          */
590         ctx = device_get_sysctl_ctx(sc->sc_dev);
591         tree_node = device_get_sysctl_tree(sc->sc_dev);
592         tree = SYSCTL_CHILDREN(tree_node);
593         pin_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "pin",
594             CTLFLAG_RW, NULL, "GPIO Pins");
595         pin_tree = SYSCTL_CHILDREN(pin_node);
596
597         for (i = 0; i < sc->sc_gpio_npins; i++) {
598
599                 snprintf(pinbuf, sizeof(pinbuf), "%d", i);
600                 pinN_node = SYSCTL_ADD_NODE(ctx, pin_tree, OID_AUTO, pinbuf,
601                     CTLFLAG_RD, NULL, "GPIO Pin");
602                 pinN_tree = SYSCTL_CHILDREN(pinN_node);
603
604                 sc->sc_sysctl[i].sc = sc;
605                 sc_sysctl = &sc->sc_sysctl[i];
606                 sc_sysctl->sc = sc;
607                 sc_sysctl->pin = sc->sc_gpio_pins[i].gp_pin;
608                 SYSCTL_ADD_PROC(ctx, pinN_tree, OID_AUTO, "function",
609                     CTLFLAG_RW | CTLTYPE_STRING, sc_sysctl,
610                     sizeof(struct bcm_gpio_sysctl), bcm_gpio_func_proc,
611                     "A", "Pin Function");
612         }
613 }
614
615 static int
616 bcm_gpio_get_reserved_pins(struct bcm_gpio_softc *sc)
617 {
618         int i, j, len, npins;
619         pcell_t pins[BCM_GPIO_PINS];
620         phandle_t gpio, node, reserved;
621         char name[32];
622
623         /* Get read-only pins. */
624         if (bcm_gpio_get_ro_pins(sc) != 0)
625                 return (-1);
626
627         /* Find the gpio/reserved pins node to start. */
628         gpio = ofw_bus_get_node(sc->sc_dev);
629         node = OF_child(gpio);
630         
631         /*
632          * Find reserved node
633          */
634         reserved = 0;
635         while ((node != 0) && (reserved == 0)) {
636                 len = OF_getprop(node, "name", name,
637                     sizeof(name) - 1);
638                 name[len] = 0;
639                 if (strcmp(name, "reserved") == 0)
640                         reserved = node;
641                 node = OF_peer(node);
642         }
643
644         if (reserved == 0)
645                 return (-1);
646
647         /* Get the reserved pins. */
648         len = OF_getproplen(reserved, "broadcom,pins");
649         if (len < 0 || len > sizeof(pins))
650                 return (-1);
651
652         if (OF_getprop(reserved, "broadcom,pins", &pins, len) < 0)
653                 return (-1);
654
655         npins = len / sizeof(pcell_t);
656
657         j = 0;
658         device_printf(sc->sc_dev, "reserved pins: ");
659         for (i = 0; i < npins; i++) {
660                 if (i > 0)
661                         printf(",");
662                 printf("%d", fdt32_to_cpu(pins[i]));
663                 /* Some pins maybe already on the list of read-only pins. */
664                 if (bcm_gpio_pin_is_ro(sc, fdt32_to_cpu(pins[i])))
665                         continue;
666                 sc->sc_ro_pins[j++ + sc->sc_ro_npins] = fdt32_to_cpu(pins[i]);
667         }
668         sc->sc_ro_npins += j;
669         if (i > 0)
670                 printf(".");
671         printf("\n");
672
673         return (0);
674 }
675
676 static int
677 bcm_gpio_probe(device_t dev)
678 {
679         if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-gpio"))
680                 return (ENXIO);
681
682         device_set_desc(dev, "BCM2708/2835 GPIO controller");
683         return (BUS_PROBE_DEFAULT);
684 }
685
686 static int
687 bcm_gpio_attach(device_t dev)
688 {
689         struct bcm_gpio_softc *sc = device_get_softc(dev);
690         uint32_t func;
691         int i, j, rid;
692         phandle_t gpio;
693
694         sc->sc_dev = dev;
695
696         mtx_init(&sc->sc_mtx, "bcm gpio", "gpio", MTX_DEF);
697
698         rid = 0;
699         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
700             RF_ACTIVE);
701         if (!sc->sc_mem_res) {
702                 device_printf(dev, "cannot allocate memory window\n");
703                 return (ENXIO);
704         }
705
706         sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
707         sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
708
709         rid = 0;
710         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
711             RF_ACTIVE);
712         if (!sc->sc_irq_res) {
713                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
714                 device_printf(dev, "cannot allocate interrupt\n");
715                 return (ENXIO);
716         }
717
718         /* Find our node. */
719         gpio = ofw_bus_get_node(sc->sc_dev);
720
721         if (!OF_hasprop(gpio, "gpio-controller"))
722                 /* Node is not a GPIO controller. */
723                 goto fail;
724
725         /*
726          * Find the read-only pins.  These are pins we never touch or bad
727          * things could happen.
728          */
729         if (bcm_gpio_get_reserved_pins(sc) == -1)
730                 goto fail;
731
732         /* Initialize the software controlled pins. */
733         for (i = 0, j = 0; j < BCM_GPIO_PINS; j++) {
734                 if (bcm_gpio_pin_is_ro(sc, j))
735                         continue;
736                 snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,
737                     "pin %d", j);
738                 func = bcm_gpio_get_function(sc, j);
739                 sc->sc_gpio_pins[i].gp_pin = j;
740                 sc->sc_gpio_pins[i].gp_caps = BCM_GPIO_DEFAULT_CAPS;
741                 sc->sc_gpio_pins[i].gp_flags = bcm_gpio_func_flag(func);
742                 i++;
743         }
744         sc->sc_gpio_npins = i;
745
746         bcm_gpio_sysctl_init(sc);
747
748         device_add_child(dev, "gpioc", device_get_unit(dev));
749         device_add_child(dev, "gpiobus", device_get_unit(dev));
750         return (bus_generic_attach(dev));
751
752 fail:
753         if (sc->sc_irq_res)
754                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
755         if (sc->sc_mem_res)
756                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
757         return (ENXIO);
758 }
759
760 static int
761 bcm_gpio_detach(device_t dev)
762 {
763
764         return (EBUSY);
765 }
766
767 static device_method_t bcm_gpio_methods[] = {
768         /* Device interface */
769         DEVMETHOD(device_probe,         bcm_gpio_probe),
770         DEVMETHOD(device_attach,        bcm_gpio_attach),
771         DEVMETHOD(device_detach,        bcm_gpio_detach),
772
773         /* GPIO protocol */
774         DEVMETHOD(gpio_pin_max,         bcm_gpio_pin_max),
775         DEVMETHOD(gpio_pin_getname,     bcm_gpio_pin_getname),
776         DEVMETHOD(gpio_pin_getflags,    bcm_gpio_pin_getflags),
777         DEVMETHOD(gpio_pin_getcaps,     bcm_gpio_pin_getcaps),
778         DEVMETHOD(gpio_pin_setflags,    bcm_gpio_pin_setflags),
779         DEVMETHOD(gpio_pin_get,         bcm_gpio_pin_get),
780         DEVMETHOD(gpio_pin_set,         bcm_gpio_pin_set),
781         DEVMETHOD(gpio_pin_toggle,      bcm_gpio_pin_toggle),
782
783         DEVMETHOD_END
784 };
785
786 static devclass_t bcm_gpio_devclass;
787
788 static driver_t bcm_gpio_driver = {
789         "gpio",
790         bcm_gpio_methods,
791         sizeof(struct bcm_gpio_softc),
792 };
793
794 DRIVER_MODULE(bcm_gpio, simplebus, bcm_gpio_driver, bcm_gpio_devclass, 0, 0);