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