Path: blob/main/sys/arm/broadcom/bcm2835/bcm2835_gpio.c
39566 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2012 Oleksandr Tymoshenko <[email protected]>4* Copyright (c) 2012-2015 Luiz Otavio O Souza <[email protected]>5* All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*28*/29#include <sys/cdefs.h>30#include "opt_platform.h"3132#include <sys/param.h>33#include <sys/systm.h>34#include <sys/bus.h>35#include <sys/gpio.h>36#include <sys/interrupt.h>37#include <sys/kernel.h>38#include <sys/lock.h>39#include <sys/module.h>40#include <sys/mutex.h>41#include <sys/proc.h>42#include <sys/rman.h>43#include <sys/sysctl.h>4445#include <machine/bus.h>46#include <machine/intr.h>4748#include <dev/fdt/fdt_pinctrl.h>49#include <dev/gpio/gpiobusvar.h>50#include <dev/ofw/ofw_bus.h>5152#include "gpio_if.h"5354#include "pic_if.h"5556#ifdef DEBUG57#define dprintf(fmt, args...) do { printf("%s(): ", __func__); \58printf(fmt,##args); } while (0)59#else60#define dprintf(fmt, args...)61#endif6263#define BCM_GPIO_IRQS 464#define BCM_GPIO_PINS_PER_BANK 3265#define BCM2835_GPIO_PINS 5466#define BCM2711_GPIO_PINS 5867#define BCM_GPIO_PINS BCM2711_GPIO_PINS6869#define BCM_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \70GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_INTR_LEVEL_LOW | \71GPIO_INTR_LEVEL_HIGH | GPIO_INTR_EDGE_RISING | \72GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH)7374#define BCM2835_FSEL_GPIO_IN 075#define BCM2835_FSEL_GPIO_OUT 176#define BCM2835_FSEL_ALT5 277#define BCM2835_FSEL_ALT4 378#define BCM2835_FSEL_ALT0 479#define BCM2835_FSEL_ALT1 580#define BCM2835_FSEL_ALT2 681#define BCM2835_FSEL_ALT3 78283#define BCM2835_PUD_OFF 084#define BCM2835_PUD_DOWN 185#define BCM2835_PUD_UP 28687#define BCM2711_PUD_OFF 088#define BCM2711_PUD_DOWN 289#define BCM2711_PUD_UP 19091static struct resource_spec bcm_gpio_res_spec[] = {92{ SYS_RES_MEMORY, 0, RF_ACTIVE },93{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* bank 0 interrupt */94{ SYS_RES_IRQ, 1, RF_ACTIVE }, /* bank 1 interrupt */95{ -1, 0, 0 }96};9798struct bcm_gpio_sysctl {99struct bcm_gpio_softc *sc;100uint32_t pin;101};102103struct bcm_gpio_irqsrc {104struct intr_irqsrc bgi_isrc;105uint32_t bgi_irq;106uint32_t bgi_mode;107uint32_t bgi_mask;108};109110struct bcm_gpio_softc {111device_t sc_dev;112device_t sc_busdev;113struct mtx sc_mtx;114struct resource * sc_res[BCM_GPIO_IRQS + 1];115bus_space_tag_t sc_bst;116bus_space_handle_t sc_bsh;117void * sc_intrhand[BCM_GPIO_IRQS];118bool sc_is2711;119u_int sc_maxpins;120int sc_gpio_npins;121int sc_ro_npins;122int sc_ro_pins[BCM_GPIO_PINS];123struct gpio_pin sc_gpio_pins[BCM_GPIO_PINS];124struct bcm_gpio_sysctl sc_sysctl[BCM_GPIO_PINS];125struct bcm_gpio_irqsrc sc_isrcs[BCM_GPIO_PINS];126};127128enum bcm_gpio_pud {129BCM_GPIO_NONE,130BCM_GPIO_PULLDOWN,131BCM_GPIO_PULLUP,132};133134#define BCM_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx)135#define BCM_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx)136#define BCM_GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)137#define BCM_GPIO_WRITE(_sc, _off, _val) \138bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, _off, _val)139#define BCM_GPIO_READ(_sc, _off) \140bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, _off)141#define BCM_GPIO_CLEAR_BITS(_sc, _off, _bits) \142BCM_GPIO_WRITE(_sc, _off, BCM_GPIO_READ(_sc, _off) & ~(_bits))143#define BCM_GPIO_SET_BITS(_sc, _off, _bits) \144BCM_GPIO_WRITE(_sc, _off, BCM_GPIO_READ(_sc, _off) | _bits)145#define BCM_GPIO_BANK(a) (a / BCM_GPIO_PINS_PER_BANK)146#define BCM_GPIO_MASK(a) (1U << (a % BCM_GPIO_PINS_PER_BANK))147148#define BCM_GPIO_GPFSEL(_bank) (0x00 + _bank * 4) /* Function Select */149#define BCM_GPIO_GPSET(_bank) (0x1c + _bank * 4) /* Pin Out Set */150#define BCM_GPIO_GPCLR(_bank) (0x28 + _bank * 4) /* Pin Out Clear */151#define BCM_GPIO_GPLEV(_bank) (0x34 + _bank * 4) /* Pin Level */152#define BCM_GPIO_GPEDS(_bank) (0x40 + _bank * 4) /* Event Status */153#define BCM_GPIO_GPREN(_bank) (0x4c + _bank * 4) /* Rising Edge irq */154#define BCM_GPIO_GPFEN(_bank) (0x58 + _bank * 4) /* Falling Edge irq */155#define BCM_GPIO_GPHEN(_bank) (0x64 + _bank * 4) /* High Level irq */156#define BCM_GPIO_GPLEN(_bank) (0x70 + _bank * 4) /* Low Level irq */157#define BCM_GPIO_GPAREN(_bank) (0x7c + _bank * 4) /* Async Rising Edge */158#define BCM_GPIO_GPAFEN(_bank) (0x88 + _bank * 4) /* Async Falling Egde */159#define BCM2835_GPIO_GPPUD(_bank) (0x94) /* Pin Pull up/down */160#define BCM2835_GPIO_GPPUDCLK(_bank) (0x98 + _bank * 4) /* Pin Pull up clock */161162#define BCM2711_GPIO_GPPUD(x) (0x0e4 + (x) * sizeof(uint32_t)) /* Pin Pull up/down */163#define BCM2711_GPIO_MASK (0x3)164#define BCM2711_GPIO_SHIFT(n) (((n) % 16) * 2)165#define BCM2711_GPIO_REGID(n) ((n) / 16)166167static struct ofw_compat_data compat_data[] = {168{"broadcom,bcm2835-gpio", 1},169{"brcm,bcm2835-gpio", 1},170{"brcm,bcm2711-gpio", 1},171{NULL, 0}172};173174static struct bcm_gpio_softc *bcm_gpio_sc = NULL;175176static int bcm_gpio_intr_bank0(void *arg);177static int bcm_gpio_intr_bank1(void *arg);178static int bcm_gpio_pic_attach(struct bcm_gpio_softc *sc);179static int bcm_gpio_pic_detach(struct bcm_gpio_softc *sc);180181static int182bcm_gpio_pin_is_ro(struct bcm_gpio_softc *sc, int pin)183{184int i;185186for (i = 0; i < sc->sc_ro_npins; i++)187if (pin == sc->sc_ro_pins[i])188return (1);189return (0);190}191192static uint32_t193bcm_gpio_get_function(struct bcm_gpio_softc *sc, uint32_t pin)194{195uint32_t bank, func, offset;196197/* Five banks, 10 pins per bank, 3 bits per pin. */198bank = pin / 10;199offset = (pin - bank * 10) * 3;200201BCM_GPIO_LOCK(sc);202func = (BCM_GPIO_READ(sc, BCM_GPIO_GPFSEL(bank)) >> offset) & 7;203BCM_GPIO_UNLOCK(sc);204205return (func);206}207208static void209bcm_gpio_func_str(uint32_t nfunc, char *buf, int bufsize)210{211212switch (nfunc) {213case BCM2835_FSEL_GPIO_IN:214strncpy(buf, "input", bufsize);215break;216case BCM2835_FSEL_GPIO_OUT:217strncpy(buf, "output", bufsize);218break;219case BCM2835_FSEL_ALT0:220strncpy(buf, "alt0", bufsize);221break;222case BCM2835_FSEL_ALT1:223strncpy(buf, "alt1", bufsize);224break;225case BCM2835_FSEL_ALT2:226strncpy(buf, "alt2", bufsize);227break;228case BCM2835_FSEL_ALT3:229strncpy(buf, "alt3", bufsize);230break;231case BCM2835_FSEL_ALT4:232strncpy(buf, "alt4", bufsize);233break;234case BCM2835_FSEL_ALT5:235strncpy(buf, "alt5", bufsize);236break;237default:238strncpy(buf, "invalid", bufsize);239}240}241242static int243bcm_gpio_str_func(char *func, uint32_t *nfunc)244{245246if (strcasecmp(func, "input") == 0)247*nfunc = BCM2835_FSEL_GPIO_IN;248else if (strcasecmp(func, "output") == 0)249*nfunc = BCM2835_FSEL_GPIO_OUT;250else if (strcasecmp(func, "alt0") == 0)251*nfunc = BCM2835_FSEL_ALT0;252else if (strcasecmp(func, "alt1") == 0)253*nfunc = BCM2835_FSEL_ALT1;254else if (strcasecmp(func, "alt2") == 0)255*nfunc = BCM2835_FSEL_ALT2;256else if (strcasecmp(func, "alt3") == 0)257*nfunc = BCM2835_FSEL_ALT3;258else if (strcasecmp(func, "alt4") == 0)259*nfunc = BCM2835_FSEL_ALT4;260else if (strcasecmp(func, "alt5") == 0)261*nfunc = BCM2835_FSEL_ALT5;262else263return (-1);264265return (0);266}267268static uint32_t269bcm_gpio_func_flag(uint32_t nfunc)270{271272switch (nfunc) {273case BCM2835_FSEL_GPIO_IN:274return (GPIO_PIN_INPUT);275case BCM2835_FSEL_GPIO_OUT:276return (GPIO_PIN_OUTPUT);277}278return (0);279}280281static void282bcm_gpio_set_function(struct bcm_gpio_softc *sc, uint32_t pin, uint32_t f)283{284uint32_t bank, data, offset;285286/* Must be called with lock held. */287BCM_GPIO_LOCK_ASSERT(sc);288289/* Five banks, 10 pins per bank, 3 bits per pin. */290bank = pin / 10;291offset = (pin - bank * 10) * 3;292293data = BCM_GPIO_READ(sc, BCM_GPIO_GPFSEL(bank));294data &= ~(7 << offset);295data |= (f << offset);296BCM_GPIO_WRITE(sc, BCM_GPIO_GPFSEL(bank), data);297}298299static void300bcm_gpio_set_pud(struct bcm_gpio_softc *sc, uint32_t pin, uint32_t state)301{302/* Must be called with lock held. */303BCM_GPIO_LOCK_ASSERT(sc);304305if (sc->sc_is2711) { /* BCM2711 */306u_int regid = BCM2711_GPIO_REGID(pin);307u_int shift = BCM2711_GPIO_SHIFT(pin);308uint32_t reg;309310switch (state) {311case BCM2835_PUD_OFF:312state = BCM2711_PUD_OFF;313break;314case BCM2835_PUD_DOWN:315state = BCM2711_PUD_DOWN;316break;317case BCM2835_PUD_UP:318state = BCM2711_PUD_UP;319break;320}321322reg = BCM_GPIO_READ(sc, BCM2711_GPIO_GPPUD(regid));323reg &= ~(BCM2711_GPIO_MASK << shift);324reg |= (state << shift);325BCM_GPIO_WRITE(sc, BCM2711_GPIO_GPPUD(regid), reg);326} else { /* BCM2835 */327uint32_t bank;328329bank = BCM_GPIO_BANK(pin);330BCM_GPIO_WRITE(sc, BCM2835_GPIO_GPPUD(0), state);331BCM_GPIO_WRITE(sc, BCM2835_GPIO_GPPUDCLK(bank), BCM_GPIO_MASK(pin));332BCM_GPIO_WRITE(sc, BCM2835_GPIO_GPPUD(0), 0);333BCM_GPIO_WRITE(sc, BCM2835_GPIO_GPPUDCLK(bank), 0);334}335}336337static void338bcm_gpio_set_alternate(device_t dev, uint32_t pin, uint32_t nfunc)339{340struct bcm_gpio_softc *sc;341int i;342343sc = device_get_softc(dev);344BCM_GPIO_LOCK(sc);345346/* Set the pin function. */347bcm_gpio_set_function(sc, pin, nfunc);348349/* Update the pin flags. */350for (i = 0; i < sc->sc_gpio_npins; i++) {351if (sc->sc_gpio_pins[i].gp_pin == pin)352break;353}354if (i < sc->sc_gpio_npins)355sc->sc_gpio_pins[i].gp_flags = bcm_gpio_func_flag(nfunc);356357BCM_GPIO_UNLOCK(sc);358}359360static void361bcm_gpio_pin_configure(struct bcm_gpio_softc *sc, struct gpio_pin *pin,362unsigned int flags)363{364365BCM_GPIO_LOCK(sc);366367/*368* Manage input/output.369*/370if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {371pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);372if (flags & GPIO_PIN_OUTPUT) {373pin->gp_flags |= GPIO_PIN_OUTPUT;374bcm_gpio_set_function(sc, pin->gp_pin,375BCM2835_FSEL_GPIO_OUT);376} else {377pin->gp_flags |= GPIO_PIN_INPUT;378bcm_gpio_set_function(sc, pin->gp_pin,379BCM2835_FSEL_GPIO_IN);380}381}382383/* Manage Pull-up/pull-down. */384pin->gp_flags &= ~(GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN);385if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) {386if (flags & GPIO_PIN_PULLUP) {387pin->gp_flags |= GPIO_PIN_PULLUP;388bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_PULLUP);389} else {390pin->gp_flags |= GPIO_PIN_PULLDOWN;391bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_PULLDOWN);392}393} else394bcm_gpio_set_pud(sc, pin->gp_pin, BCM_GPIO_NONE);395396BCM_GPIO_UNLOCK(sc);397}398399static device_t400bcm_gpio_get_bus(device_t dev)401{402struct bcm_gpio_softc *sc;403404sc = device_get_softc(dev);405406return (sc->sc_busdev);407}408409static int410bcm_gpio_pin_max(device_t dev, int *maxpin)411{412struct bcm_gpio_softc *sc;413414sc = device_get_softc(dev);415*maxpin = sc->sc_maxpins - 1;416return (0);417}418419static int420bcm_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)421{422struct bcm_gpio_softc *sc = device_get_softc(dev);423int i;424425for (i = 0; i < sc->sc_gpio_npins; i++) {426if (sc->sc_gpio_pins[i].gp_pin == pin)427break;428}429430if (i >= sc->sc_gpio_npins)431return (EINVAL);432433BCM_GPIO_LOCK(sc);434*caps = sc->sc_gpio_pins[i].gp_caps;435BCM_GPIO_UNLOCK(sc);436437return (0);438}439440static int441bcm_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)442{443struct bcm_gpio_softc *sc = device_get_softc(dev);444int i;445446for (i = 0; i < sc->sc_gpio_npins; i++) {447if (sc->sc_gpio_pins[i].gp_pin == pin)448break;449}450451if (i >= sc->sc_gpio_npins)452return (EINVAL);453454BCM_GPIO_LOCK(sc);455*flags = sc->sc_gpio_pins[i].gp_flags;456BCM_GPIO_UNLOCK(sc);457458return (0);459}460461static int462bcm_gpio_pin_getname(device_t dev, uint32_t pin, char *name)463{464struct bcm_gpio_softc *sc = device_get_softc(dev);465int i;466467for (i = 0; i < sc->sc_gpio_npins; i++) {468if (sc->sc_gpio_pins[i].gp_pin == pin)469break;470}471472if (i >= sc->sc_gpio_npins)473return (EINVAL);474475BCM_GPIO_LOCK(sc);476memcpy(name, sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME);477BCM_GPIO_UNLOCK(sc);478479return (0);480}481482static int483bcm_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)484{485struct bcm_gpio_softc *sc = device_get_softc(dev);486int i;487488for (i = 0; i < sc->sc_gpio_npins; i++) {489if (sc->sc_gpio_pins[i].gp_pin == pin)490break;491}492493if (i >= sc->sc_gpio_npins)494return (EINVAL);495496/* We never touch on read-only/reserved pins. */497if (bcm_gpio_pin_is_ro(sc, pin))498return (EINVAL);499500bcm_gpio_pin_configure(sc, &sc->sc_gpio_pins[i], flags);501502return (0);503}504505static int506bcm_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)507{508struct bcm_gpio_softc *sc = device_get_softc(dev);509uint32_t bank, reg;510int i;511512for (i = 0; i < sc->sc_gpio_npins; i++) {513if (sc->sc_gpio_pins[i].gp_pin == pin)514break;515}516if (i >= sc->sc_gpio_npins)517return (EINVAL);518/* We never write to read-only/reserved pins. */519if (bcm_gpio_pin_is_ro(sc, pin))520return (EINVAL);521BCM_GPIO_LOCK(sc);522bank = BCM_GPIO_BANK(pin);523if (value)524reg = BCM_GPIO_GPSET(bank);525else526reg = BCM_GPIO_GPCLR(bank);527BCM_GPIO_WRITE(sc, reg, BCM_GPIO_MASK(pin));528BCM_GPIO_UNLOCK(sc);529530return (0);531}532533static int534bcm_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)535{536struct bcm_gpio_softc *sc = device_get_softc(dev);537uint32_t bank, reg_data;538int i;539540for (i = 0; i < sc->sc_gpio_npins; i++) {541if (sc->sc_gpio_pins[i].gp_pin == pin)542break;543}544if (i >= sc->sc_gpio_npins)545return (EINVAL);546bank = BCM_GPIO_BANK(pin);547BCM_GPIO_LOCK(sc);548reg_data = BCM_GPIO_READ(sc, BCM_GPIO_GPLEV(bank));549BCM_GPIO_UNLOCK(sc);550*val = (reg_data & BCM_GPIO_MASK(pin)) ? 1 : 0;551552return (0);553}554555static int556bcm_gpio_pin_toggle(device_t dev, uint32_t pin)557{558struct bcm_gpio_softc *sc = device_get_softc(dev);559uint32_t bank, data, reg;560int i;561562for (i = 0; i < sc->sc_gpio_npins; i++) {563if (sc->sc_gpio_pins[i].gp_pin == pin)564break;565}566if (i >= sc->sc_gpio_npins)567return (EINVAL);568/* We never write to read-only/reserved pins. */569if (bcm_gpio_pin_is_ro(sc, pin))570return (EINVAL);571BCM_GPIO_LOCK(sc);572bank = BCM_GPIO_BANK(pin);573data = BCM_GPIO_READ(sc, BCM_GPIO_GPLEV(bank));574if (data & BCM_GPIO_MASK(pin))575reg = BCM_GPIO_GPCLR(bank);576else577reg = BCM_GPIO_GPSET(bank);578BCM_GPIO_WRITE(sc, reg, BCM_GPIO_MASK(pin));579BCM_GPIO_UNLOCK(sc);580581return (0);582}583584static int585bcm_gpio_func_proc(SYSCTL_HANDLER_ARGS)586{587char buf[16];588struct bcm_gpio_softc *sc;589struct bcm_gpio_sysctl *sc_sysctl;590uint32_t nfunc;591int error;592593sc_sysctl = arg1;594sc = sc_sysctl->sc;595596/* Get the current pin function. */597nfunc = bcm_gpio_get_function(sc, sc_sysctl->pin);598bcm_gpio_func_str(nfunc, buf, sizeof(buf));599600error = sysctl_handle_string(oidp, buf, sizeof(buf), req);601if (error != 0 || req->newptr == NULL)602return (error);603/* Ignore changes on read-only pins. */604if (bcm_gpio_pin_is_ro(sc, sc_sysctl->pin))605return (0);606/* Parse the user supplied string and check for a valid pin function. */607if (bcm_gpio_str_func(buf, &nfunc) != 0)608return (EINVAL);609610/* Update the pin alternate function. */611bcm_gpio_set_alternate(sc->sc_dev, sc_sysctl->pin, nfunc);612613return (0);614}615616static void617bcm_gpio_sysctl_init(struct bcm_gpio_softc *sc)618{619char pinbuf[3];620struct bcm_gpio_sysctl *sc_sysctl;621struct sysctl_ctx_list *ctx;622struct sysctl_oid *tree_node, *pin_node, *pinN_node;623struct sysctl_oid_list *tree, *pin_tree, *pinN_tree;624int i;625626/*627* Add per-pin sysctl tree/handlers.628*/629ctx = device_get_sysctl_ctx(sc->sc_dev);630tree_node = device_get_sysctl_tree(sc->sc_dev);631tree = SYSCTL_CHILDREN(tree_node);632pin_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "pin",633CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "GPIO Pins");634pin_tree = SYSCTL_CHILDREN(pin_node);635636for (i = 0; i < sc->sc_gpio_npins; i++) {637snprintf(pinbuf, sizeof(pinbuf), "%d", i);638pinN_node = SYSCTL_ADD_NODE(ctx, pin_tree, OID_AUTO, pinbuf,639CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "GPIO Pin");640pinN_tree = SYSCTL_CHILDREN(pinN_node);641642sc->sc_sysctl[i].sc = sc;643sc_sysctl = &sc->sc_sysctl[i];644sc_sysctl->sc = sc;645sc_sysctl->pin = sc->sc_gpio_pins[i].gp_pin;646SYSCTL_ADD_PROC(ctx, pinN_tree, OID_AUTO, "function",647CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, sc_sysctl,648sizeof(struct bcm_gpio_sysctl), bcm_gpio_func_proc,649"A", "Pin Function");650}651}652653static int654bcm_gpio_get_ro_pins(struct bcm_gpio_softc *sc, phandle_t node,655const char *propname, const char *label)656{657int i, need_comma, npins, range_start, range_stop;658pcell_t *pins;659660/* Get the property data. */661npins = OF_getencprop_alloc_multi(node, propname, sizeof(*pins),662(void **)&pins);663if (npins < 0)664return (-1);665if (npins == 0) {666OF_prop_free(pins);667return (0);668}669for (i = 0; i < npins; i++)670sc->sc_ro_pins[i + sc->sc_ro_npins] = pins[i];671sc->sc_ro_npins += npins;672need_comma = 0;673device_printf(sc->sc_dev, "%s pins: ", label);674range_start = range_stop = pins[0];675for (i = 1; i < npins; i++) {676if (pins[i] != range_stop + 1) {677if (need_comma)678printf(",");679if (range_start != range_stop)680printf("%d-%d", range_start, range_stop);681else682printf("%d", range_start);683range_start = range_stop = pins[i];684need_comma = 1;685} else686range_stop++;687}688if (need_comma)689printf(",");690if (range_start != range_stop)691printf("%d-%d.\n", range_start, range_stop);692else693printf("%d.\n", range_start);694OF_prop_free(pins);695696return (0);697}698699static int700bcm_gpio_get_reserved_pins(struct bcm_gpio_softc *sc)701{702char *name;703phandle_t gpio, node, reserved;704ssize_t len;705706/* Get read-only pins if they're provided */707gpio = ofw_bus_get_node(sc->sc_dev);708if (bcm_gpio_get_ro_pins(sc, gpio, "broadcom,read-only",709"read-only") != 0)710return (0);711/* Traverse the GPIO subnodes to find the reserved pins node. */712reserved = 0;713node = OF_child(gpio);714while ((node != 0) && (reserved == 0)) {715len = OF_getprop_alloc(node, "name", (void **)&name);716if (len == -1)717return (-1);718if (strcmp(name, "reserved") == 0)719reserved = node;720OF_prop_free(name);721node = OF_peer(node);722}723if (reserved == 0)724return (-1);725/* Get the reserved pins. */726if (bcm_gpio_get_ro_pins(sc, reserved, "broadcom,pins",727"reserved") != 0)728return (-1);729730return (0);731}732733static int734bcm_gpio_probe(device_t dev)735{736737if (!ofw_bus_status_okay(dev))738return (ENXIO);739740if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)741return (ENXIO);742743device_set_desc(dev, "BCM2708/2835 GPIO controller");744return (BUS_PROBE_DEFAULT);745}746747static int748bcm_gpio_intr_attach(device_t dev)749{750struct bcm_gpio_softc *sc;751752/*753* Only first two interrupt lines are used. Third line is754* mirrored second line and forth line is common for all banks.755*/756sc = device_get_softc(dev);757if (sc->sc_res[1] == NULL || sc->sc_res[2] == NULL)758return (-1);759760if (bcm_gpio_pic_attach(sc) != 0) {761device_printf(dev, "unable to attach PIC\n");762return (-1);763}764if (bus_setup_intr(dev, sc->sc_res[1], INTR_TYPE_MISC | INTR_MPSAFE,765bcm_gpio_intr_bank0, NULL, sc, &sc->sc_intrhand[0]) != 0)766return (-1);767if (bus_setup_intr(dev, sc->sc_res[2], INTR_TYPE_MISC | INTR_MPSAFE,768bcm_gpio_intr_bank1, NULL, sc, &sc->sc_intrhand[1]) != 0)769return (-1);770771return (0);772}773774static void775bcm_gpio_intr_detach(device_t dev)776{777struct bcm_gpio_softc *sc;778779sc = device_get_softc(dev);780if (sc->sc_intrhand[0] != NULL)781bus_teardown_intr(dev, sc->sc_res[1], sc->sc_intrhand[0]);782if (sc->sc_intrhand[1] != NULL)783bus_teardown_intr(dev, sc->sc_res[2], sc->sc_intrhand[1]);784785bcm_gpio_pic_detach(sc);786}787788static int789bcm_gpio_attach(device_t dev)790{791int i, j;792phandle_t gpio;793struct bcm_gpio_softc *sc;794uint32_t func;795796if (bcm_gpio_sc != NULL)797return (ENXIO);798799bcm_gpio_sc = sc = device_get_softc(dev);800sc->sc_dev = dev;801mtx_init(&sc->sc_mtx, "bcm gpio", "gpio", MTX_SPIN);802if (bus_alloc_resources(dev, bcm_gpio_res_spec, sc->sc_res) != 0) {803device_printf(dev, "cannot allocate resources\n");804goto fail;805}806sc->sc_bst = rman_get_bustag(sc->sc_res[0]);807sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);808/* Find our node. */809gpio = ofw_bus_get_node(sc->sc_dev);810if (!OF_hasprop(gpio, "gpio-controller"))811/* Node is not a GPIO controller. */812goto fail;813/* Guess I'm BCM2711 or not. */814sc->sc_is2711 = ofw_bus_node_is_compatible(gpio, "brcm,bcm2711-gpio");815sc->sc_maxpins = sc->sc_is2711 ? BCM2711_GPIO_PINS : BCM2835_GPIO_PINS;816/* Setup the GPIO interrupt handler. */817if (bcm_gpio_intr_attach(dev)) {818device_printf(dev, "unable to setup the gpio irq handler\n");819goto fail;820}821/*822* Find the read-only pins. These are pins we never touch or bad823* things could happen.824*/825if (bcm_gpio_get_reserved_pins(sc) == -1)826goto fail;827/* Initialize the software controlled pins. */828for (i = 0, j = 0; j < sc->sc_maxpins; j++) {829snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,830"pin %d", j);831func = bcm_gpio_get_function(sc, j);832sc->sc_gpio_pins[i].gp_pin = j;833sc->sc_gpio_pins[i].gp_caps = BCM_GPIO_DEFAULT_CAPS;834sc->sc_gpio_pins[i].gp_flags = bcm_gpio_func_flag(func);835i++;836}837sc->sc_gpio_npins = i;838bcm_gpio_sysctl_init(sc);839840fdt_pinctrl_register(dev, "brcm,pins");841fdt_pinctrl_configure_tree(dev);842sc->sc_busdev = gpiobus_add_bus(dev);843if (sc->sc_busdev == NULL)844goto fail;845846bus_attach_children(dev);847return (0);848849fail:850bcm_gpio_intr_detach(dev);851bus_release_resources(dev, bcm_gpio_res_spec, sc->sc_res);852mtx_destroy(&sc->sc_mtx);853854return (ENXIO);855}856857static int858bcm_gpio_detach(device_t dev)859{860861return (EBUSY);862}863864static inline void865bcm_gpio_modify(struct bcm_gpio_softc *sc, uint32_t reg, uint32_t mask,866bool set_bits)867{868869if (set_bits)870BCM_GPIO_SET_BITS(sc, reg, mask);871else872BCM_GPIO_CLEAR_BITS(sc, reg, mask);873}874875static inline void876bcm_gpio_isrc_eoi(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi)877{878uint32_t bank;879880/* Write 1 to clear. */881bank = BCM_GPIO_BANK(bgi->bgi_irq);882BCM_GPIO_WRITE(sc, BCM_GPIO_GPEDS(bank), bgi->bgi_mask);883}884885static inline bool886bcm_gpio_isrc_is_level(struct bcm_gpio_irqsrc *bgi)887{888889return (bgi->bgi_mode == GPIO_INTR_LEVEL_LOW ||890bgi->bgi_mode == GPIO_INTR_LEVEL_HIGH);891}892893static inline void894bcm_gpio_isrc_mask(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi)895{896uint32_t bank;897898bank = BCM_GPIO_BANK(bgi->bgi_irq);899BCM_GPIO_LOCK(sc);900switch (bgi->bgi_mode) {901case GPIO_INTR_LEVEL_LOW:902BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask);903break;904case GPIO_INTR_LEVEL_HIGH:905BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask);906break;907case GPIO_INTR_EDGE_RISING:908BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask);909break;910case GPIO_INTR_EDGE_FALLING:911BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask);912break;913case GPIO_INTR_EDGE_BOTH:914BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask);915BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask);916break;917}918BCM_GPIO_UNLOCK(sc);919}920921static inline void922bcm_gpio_isrc_unmask(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi)923{924uint32_t bank;925926bank = BCM_GPIO_BANK(bgi->bgi_irq);927BCM_GPIO_LOCK(sc);928switch (bgi->bgi_mode) {929case GPIO_INTR_LEVEL_LOW:930BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask);931break;932case GPIO_INTR_LEVEL_HIGH:933BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask);934break;935case GPIO_INTR_EDGE_RISING:936BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask);937break;938case GPIO_INTR_EDGE_FALLING:939BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask);940break;941case GPIO_INTR_EDGE_BOTH:942BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask);943BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask);944break;945}946BCM_GPIO_UNLOCK(sc);947}948949static int950bcm_gpio_intr_internal(struct bcm_gpio_softc *sc, uint32_t bank)951{952u_int irq;953struct bcm_gpio_irqsrc *bgi;954uint32_t reg;955956/* Do not care of spurious interrupt on GPIO. */957reg = BCM_GPIO_READ(sc, BCM_GPIO_GPEDS(bank));958while (reg != 0) {959irq = BCM_GPIO_PINS_PER_BANK * bank + ffs(reg) - 1;960bgi = sc->sc_isrcs + irq;961if (!bcm_gpio_isrc_is_level(bgi))962bcm_gpio_isrc_eoi(sc, bgi);963if (intr_isrc_dispatch(&bgi->bgi_isrc,964curthread->td_intr_frame) != 0) {965bcm_gpio_isrc_mask(sc, bgi);966if (bcm_gpio_isrc_is_level(bgi))967bcm_gpio_isrc_eoi(sc, bgi);968device_printf(sc->sc_dev, "Stray irq %u disabled\n",969irq);970}971reg &= ~bgi->bgi_mask;972}973return (FILTER_HANDLED);974}975976static int977bcm_gpio_intr_bank0(void *arg)978{979980return (bcm_gpio_intr_internal(arg, 0));981}982983static int984bcm_gpio_intr_bank1(void *arg)985{986987return (bcm_gpio_intr_internal(arg, 1));988}989990static int991bcm_gpio_pic_attach(struct bcm_gpio_softc *sc)992{993int error;994uint32_t irq;995const char *name;996997name = device_get_nameunit(sc->sc_dev);998for (irq = 0; irq < sc->sc_maxpins; irq++) {999sc->sc_isrcs[irq].bgi_irq = irq;1000sc->sc_isrcs[irq].bgi_mask = BCM_GPIO_MASK(irq);1001sc->sc_isrcs[irq].bgi_mode = GPIO_INTR_CONFORM;10021003error = intr_isrc_register(&sc->sc_isrcs[irq].bgi_isrc,1004sc->sc_dev, 0, "%s,%u", name, irq);1005if (error != 0)1006return (error); /* XXX deregister ISRCs */1007}1008if (intr_pic_register(sc->sc_dev,1009OF_xref_from_node(ofw_bus_get_node(sc->sc_dev))) == NULL)1010return (ENXIO);10111012return (0);1013}10141015static int1016bcm_gpio_pic_detach(struct bcm_gpio_softc *sc)1017{10181019/*1020* There has not been established any procedure yet1021* how to detach PIC from living system correctly.1022*/1023device_printf(sc->sc_dev, "%s: not implemented yet\n", __func__);1024return (EBUSY);1025}10261027static void1028bcm_gpio_pic_config_intr(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi,1029uint32_t mode)1030{1031uint32_t bank;10321033bank = BCM_GPIO_BANK(bgi->bgi_irq);1034BCM_GPIO_LOCK(sc);1035bcm_gpio_modify(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask,1036mode == GPIO_INTR_EDGE_RISING || mode == GPIO_INTR_EDGE_BOTH);1037bcm_gpio_modify(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask,1038mode == GPIO_INTR_EDGE_FALLING || mode == GPIO_INTR_EDGE_BOTH);1039bcm_gpio_modify(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask,1040mode == GPIO_INTR_LEVEL_HIGH);1041bcm_gpio_modify(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask,1042mode == GPIO_INTR_LEVEL_LOW);1043bgi->bgi_mode = mode;1044BCM_GPIO_UNLOCK(sc);1045}10461047static void1048bcm_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)1049{1050struct bcm_gpio_softc *sc = device_get_softc(dev);1051struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc;10521053bcm_gpio_isrc_mask(sc, bgi);1054}10551056static void1057bcm_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)1058{1059struct bcm_gpio_softc *sc = device_get_softc(dev);1060struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc;10611062arm_irq_memory_barrier(bgi->bgi_irq);1063bcm_gpio_isrc_unmask(sc, bgi);1064}10651066static int1067bcm_gpio_pic_map_fdt(struct bcm_gpio_softc *sc, struct intr_map_data_fdt *daf,1068u_int *irqp, uint32_t *modep)1069{1070u_int irq;1071uint32_t mode;10721073/*1074* The first cell is the interrupt number.1075* The second cell is used to specify flags:1076* bits[3:0] trigger type and level flags:1077* 1 = low-to-high edge triggered.1078* 2 = high-to-low edge triggered.1079* 4 = active high level-sensitive.1080* 8 = active low level-sensitive.1081*/1082if (daf->ncells != 2)1083return (EINVAL);10841085irq = daf->cells[0];1086if (irq >= sc->sc_maxpins || bcm_gpio_pin_is_ro(sc, irq))1087return (EINVAL);10881089/* Only reasonable modes are supported. */1090if (daf->cells[1] == 1)1091mode = GPIO_INTR_EDGE_RISING;1092else if (daf->cells[1] == 2)1093mode = GPIO_INTR_EDGE_FALLING;1094else if (daf->cells[1] == 3)1095mode = GPIO_INTR_EDGE_BOTH;1096else if (daf->cells[1] == 4)1097mode = GPIO_INTR_LEVEL_HIGH;1098else if (daf->cells[1] == 8)1099mode = GPIO_INTR_LEVEL_LOW;1100else1101return (EINVAL);11021103*irqp = irq;1104if (modep != NULL)1105*modep = mode;1106return (0);1107}11081109static int1110bcm_gpio_pic_map_gpio(struct bcm_gpio_softc *sc, struct intr_map_data_gpio *dag,1111u_int *irqp, uint32_t *modep)1112{1113u_int irq;1114uint32_t mode;11151116irq = dag->gpio_pin_num;1117if (irq >= sc->sc_maxpins || bcm_gpio_pin_is_ro(sc, irq))1118return (EINVAL);11191120mode = dag->gpio_intr_mode;1121if (mode != GPIO_INTR_LEVEL_LOW && mode != GPIO_INTR_LEVEL_HIGH &&1122mode != GPIO_INTR_EDGE_RISING && mode != GPIO_INTR_EDGE_FALLING &&1123mode != GPIO_INTR_EDGE_BOTH)1124return (EINVAL);11251126*irqp = irq;1127if (modep != NULL)1128*modep = mode;1129return (0);1130}11311132static int1133bcm_gpio_pic_map(struct bcm_gpio_softc *sc, struct intr_map_data *data,1134u_int *irqp, uint32_t *modep)1135{11361137switch (data->type) {1138case INTR_MAP_DATA_FDT:1139return (bcm_gpio_pic_map_fdt(sc,1140(struct intr_map_data_fdt *)data, irqp, modep));1141case INTR_MAP_DATA_GPIO:1142return (bcm_gpio_pic_map_gpio(sc,1143(struct intr_map_data_gpio *)data, irqp, modep));1144default:1145return (ENOTSUP);1146}1147}11481149static int1150bcm_gpio_pic_map_intr(device_t dev, struct intr_map_data *data,1151struct intr_irqsrc **isrcp)1152{1153int error;1154u_int irq;1155struct bcm_gpio_softc *sc = device_get_softc(dev);11561157error = bcm_gpio_pic_map(sc, data, &irq, NULL);1158if (error == 0)1159*isrcp = &sc->sc_isrcs[irq].bgi_isrc;1160return (error);1161}11621163static void1164bcm_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)1165{1166struct bcm_gpio_softc *sc = device_get_softc(dev);1167struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc;11681169if (bcm_gpio_isrc_is_level(bgi))1170bcm_gpio_isrc_eoi(sc, bgi);1171}11721173static void1174bcm_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)1175{11761177bcm_gpio_pic_enable_intr(dev, isrc);1178}11791180static void1181bcm_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)1182{1183struct bcm_gpio_softc *sc = device_get_softc(dev);1184struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc;11851186bcm_gpio_isrc_mask(sc, bgi);1187if (bcm_gpio_isrc_is_level(bgi))1188bcm_gpio_isrc_eoi(sc, bgi);1189}11901191static int1192bcm_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,1193struct resource *res, struct intr_map_data *data)1194{1195u_int irq;1196uint32_t mode;1197struct bcm_gpio_softc *sc;1198struct bcm_gpio_irqsrc *bgi;11991200if (data == NULL)1201return (ENOTSUP);12021203sc = device_get_softc(dev);1204bgi = (struct bcm_gpio_irqsrc *)isrc;12051206/* Get and check config for an interrupt. */1207if (bcm_gpio_pic_map(sc, data, &irq, &mode) != 0 || bgi->bgi_irq != irq)1208return (EINVAL);12091210/*1211* If this is a setup for another handler,1212* only check that its configuration match.1213*/1214if (isrc->isrc_handlers != 0)1215return (bgi->bgi_mode == mode ? 0 : EINVAL);12161217bcm_gpio_pic_config_intr(sc, bgi, mode);1218return (0);1219}12201221static int1222bcm_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,1223struct resource *res, struct intr_map_data *data)1224{1225struct bcm_gpio_softc *sc = device_get_softc(dev);1226struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc;12271228if (isrc->isrc_handlers == 0)1229bcm_gpio_pic_config_intr(sc, bgi, GPIO_INTR_CONFORM);1230return (0);1231}12321233static phandle_t1234bcm_gpio_get_node(device_t bus, device_t dev)1235{12361237/* We only have one child, the GPIO bus, which needs our own node. */1238return (ofw_bus_get_node(bus));1239}12401241static int1242bcm_gpio_configure_pins(device_t dev, phandle_t cfgxref)1243{1244phandle_t cfgnode;1245int i, pintuples, pulltuples;1246uint32_t pin;1247uint32_t *pins;1248uint32_t *pulls;1249uint32_t function;12501251cfgnode = OF_node_from_xref(cfgxref);12521253pins = NULL;1254pintuples = OF_getencprop_alloc_multi(cfgnode, "brcm,pins",1255sizeof(*pins), (void **)&pins);12561257char name[32];1258OF_getprop(cfgnode, "name", &name, sizeof(name));12591260if (pintuples < 0)1261return (ENOENT);12621263if (pintuples == 0)1264return (0); /* Empty property is not an error. */12651266if (OF_getencprop(cfgnode, "brcm,function", &function,1267sizeof(function)) <= 0) {1268OF_prop_free(pins);1269return (EINVAL);1270}12711272pulls = NULL;1273pulltuples = OF_getencprop_alloc_multi(cfgnode, "brcm,pull",1274sizeof(*pulls), (void **)&pulls);12751276if ((pulls != NULL) && (pulltuples != pintuples)) {1277OF_prop_free(pins);1278OF_prop_free(pulls);1279return (EINVAL);1280}12811282for (i = 0; i < pintuples; i++) {1283pin = pins[i];1284bcm_gpio_set_alternate(dev, pin, function);1285if (bootverbose)1286device_printf(dev, "set pin %d to func %d", pin, function);1287if (pulls) {1288if (bootverbose)1289printf(", pull %d", pulls[i]);1290switch (pulls[i]) {1291/* Convert to gpio(4) flags */1292case BCM2835_PUD_OFF:1293bcm_gpio_pin_setflags(dev, pin, 0);1294break;1295case BCM2835_PUD_UP:1296bcm_gpio_pin_setflags(dev, pin, GPIO_PIN_PULLUP);1297break;1298case BCM2835_PUD_DOWN:1299bcm_gpio_pin_setflags(dev, pin, GPIO_PIN_PULLDOWN);1300break;1301default:1302printf("%s: invalid pull value for pin %d: %d\n",1303name, pin, pulls[i]);1304}1305}1306if (bootverbose)1307printf("\n");1308}13091310OF_prop_free(pins);1311if (pulls)1312OF_prop_free(pulls);13131314return (0);1315}13161317static device_method_t bcm_gpio_methods[] = {1318/* Device interface */1319DEVMETHOD(device_probe, bcm_gpio_probe),1320DEVMETHOD(device_attach, bcm_gpio_attach),1321DEVMETHOD(device_detach, bcm_gpio_detach),13221323/* Bus interface */1324DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),1325DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),13261327/* GPIO protocol */1328DEVMETHOD(gpio_get_bus, bcm_gpio_get_bus),1329DEVMETHOD(gpio_pin_max, bcm_gpio_pin_max),1330DEVMETHOD(gpio_pin_getname, bcm_gpio_pin_getname),1331DEVMETHOD(gpio_pin_getflags, bcm_gpio_pin_getflags),1332DEVMETHOD(gpio_pin_getcaps, bcm_gpio_pin_getcaps),1333DEVMETHOD(gpio_pin_setflags, bcm_gpio_pin_setflags),1334DEVMETHOD(gpio_pin_get, bcm_gpio_pin_get),1335DEVMETHOD(gpio_pin_set, bcm_gpio_pin_set),1336DEVMETHOD(gpio_pin_toggle, bcm_gpio_pin_toggle),13371338/* Interrupt controller interface */1339DEVMETHOD(pic_disable_intr, bcm_gpio_pic_disable_intr),1340DEVMETHOD(pic_enable_intr, bcm_gpio_pic_enable_intr),1341DEVMETHOD(pic_map_intr, bcm_gpio_pic_map_intr),1342DEVMETHOD(pic_post_filter, bcm_gpio_pic_post_filter),1343DEVMETHOD(pic_post_ithread, bcm_gpio_pic_post_ithread),1344DEVMETHOD(pic_pre_ithread, bcm_gpio_pic_pre_ithread),1345DEVMETHOD(pic_setup_intr, bcm_gpio_pic_setup_intr),1346DEVMETHOD(pic_teardown_intr, bcm_gpio_pic_teardown_intr),13471348/* ofw_bus interface */1349DEVMETHOD(ofw_bus_get_node, bcm_gpio_get_node),13501351/* fdt_pinctrl interface */1352DEVMETHOD(fdt_pinctrl_configure, bcm_gpio_configure_pins),13531354DEVMETHOD_END1355};13561357static driver_t bcm_gpio_driver = {1358"gpio",1359bcm_gpio_methods,1360sizeof(struct bcm_gpio_softc),1361};13621363EARLY_DRIVER_MODULE(bcm_gpio, simplebus, bcm_gpio_driver, 0, 0,1364BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);136513661367