The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/bhnd/cores/chipc/chipc_gpio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2017 The FreeBSD Foundation
    5  *
    6  * This software was developed by Landon Fuller under sponsorship from
    7  * the FreeBSD Foundation.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *     notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  *
   30  * $FreeBSD$
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/kernel.h>
   38 #include <sys/bus.h>
   39 #include <sys/gpio.h>
   40 #include <sys/limits.h>
   41 #include <sys/module.h>
   42 
   43 #include <machine/_inttypes.h>
   44 #include <machine/bus.h>
   45 #include <sys/rman.h>
   46 #include <machine/resource.h>
   47 
   48 #include <dev/bhnd/bhnd.h>
   49 #include <dev/gpio/gpiobusvar.h>
   50 
   51 #include "gpio_if.h"
   52 
   53 #include "bhnd_nvram_map.h"
   54 
   55 #include "chipcreg.h"
   56 #include "chipc_gpiovar.h"
   57 
   58 /*
   59  * ChipCommon GPIO driver
   60  */
   61 
   62 static int                      chipc_gpio_check_flags(
   63                                     struct chipc_gpio_softc *sc,
   64                                     uint32_t pin_num, uint32_t flags,
   65                                     chipc_gpio_pin_mode *mode);
   66 static int                      chipc_gpio_pin_update(
   67                                     struct chipc_gpio_softc *sc,
   68                                     struct chipc_gpio_update *update,
   69                                     uint32_t pin_num, uint32_t flags);
   70 static int                      chipc_gpio_commit_update(
   71                                     struct chipc_gpio_softc *sc,
   72                                     struct chipc_gpio_update *update);
   73 static chipc_gpio_pin_mode      chipc_gpio_pin_get_mode(
   74                                     struct chipc_gpio_softc *sc,
   75                                     uint32_t pin_num);
   76 
   77 /* Debugging flags */
   78 static u_long chipc_gpio_debug = 0;
   79 TUNABLE_ULONG("hw.bhnd_chipc.gpio_debug", &chipc_gpio_debug);
   80 
   81 enum {
   82         /** Allow userspace GPIO access on bridged network (e.g. wi-fi)
   83           * adapters */
   84         CC_GPIO_DEBUG_ADAPTER_GPIOC = 1 << 0,
   85 };
   86 
   87 #define CC_GPIO_DEBUG(_type)    (CC_GPIO_DEBUG_ ## _type & chipc_gpio_debug)
   88 
   89 static struct bhnd_device_quirk chipc_gpio_quirks[];
   90 
   91 /* Supported parent core device identifiers */
   92 static const struct bhnd_device chipc_gpio_devices[] = {
   93         BHND_DEVICE(BCM, CC, "Broadcom ChipCommon GPIO", chipc_gpio_quirks),
   94         BHND_DEVICE_END
   95 };
   96 
   97 /* Device quirks table */
   98 static struct bhnd_device_quirk chipc_gpio_quirks[] = {
   99         BHND_CORE_QUIRK (HWREV_LTE(10), CC_GPIO_QUIRK_NO_EVENTS),
  100         BHND_CORE_QUIRK (HWREV_LTE(15), CC_GPIO_QUIRK_NO_DCTIMER),
  101         BHND_CORE_QUIRK (HWREV_LTE(19), CC_GPIO_QUIRK_NO_PULLUPDOWN),
  102 
  103         BHND_DEVICE_QUIRK_END
  104 };
  105 
  106 static int
  107 chipc_gpio_probe(device_t dev)
  108 {
  109         const struct bhnd_device        *id;
  110         device_t                         chipc;
  111 
  112         /* Look for compatible chipc parent */
  113         chipc = device_get_parent(dev);
  114         id = bhnd_device_lookup(chipc, chipc_gpio_devices,
  115             sizeof(chipc_gpio_devices[0]));
  116         if (id == NULL)
  117                 return (ENXIO);
  118 
  119         device_set_desc(dev, id->desc);
  120         return (BUS_PROBE_NOWILDCARD);
  121 }
  122 
  123 static int
  124 chipc_gpio_attach(device_t dev)
  125 {
  126         struct chipc_gpio_softc *sc;
  127         device_t                 chipc;
  128         int                      error;
  129 
  130         chipc = device_get_parent(dev);
  131 
  132         sc = device_get_softc(dev);
  133         sc->dev = dev;
  134         sc->quirks = bhnd_device_quirks(chipc, chipc_gpio_devices,
  135             sizeof(chipc_gpio_devices[0]));
  136 
  137         /* If this is a bridged wi-fi adapter, we don't want to support
  138          * userspace requests via gpioc(4) */
  139         if (bhnd_get_attach_type(chipc) == BHND_ATTACH_ADAPTER) {
  140                 if (!CC_GPIO_DEBUG(ADAPTER_GPIOC))
  141                         sc->quirks |= CC_GPIO_QUIRK_NO_GPIOC;
  142         }
  143 
  144         CC_GPIO_LOCK_INIT(sc);
  145 
  146         sc->mem_rid = 0;
  147         sc->mem_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
  148             RF_ACTIVE|RF_SHAREABLE);
  149         if (sc->mem_res == NULL) {
  150                 device_printf(dev, "failed to allocate chipcommon registers\n");
  151                 error = ENXIO;
  152                 goto failed;
  153         }
  154 
  155         /*
  156          * If hardware 'pulsate' support is available, set the timer duty-cycle
  157          * to either the NVRAM 'leddc' value if available, or the default duty
  158          * cycle.
  159          */
  160         if (!CC_GPIO_QUIRK(sc, NO_DCTIMER)) {
  161                 uint32_t dctimerval;
  162 
  163                 error = bhnd_nvram_getvar_uint32(chipc, BHND_NVAR_LEDDC,
  164                     &dctimerval);
  165                 if (error == ENOENT) {
  166                         /* Fall back on default duty cycle */
  167                         dctimerval = CHIPC_GPIOTIMERVAL_DEFAULT;
  168                 } else if (error) {
  169                         device_printf(dev, "error reading %s from NVRAM: %d\n",
  170                             BHND_NVAR_LEDDC, error);
  171                         goto failed;
  172                 }
  173 
  174                 CC_GPIO_WR4(sc, CHIPC_GPIOTIMERVAL, dctimerval);
  175         }
  176 
  177         /* Attach gpioc/gpiobus */
  178         if (CC_GPIO_QUIRK(sc, NO_GPIOC)) {
  179                 sc->gpiobus = NULL;
  180         } else {
  181                 if ((sc->gpiobus = gpiobus_attach_bus(dev)) == NULL) {
  182                         device_printf(dev, "failed to attach gpiobus\n");
  183                         error = ENXIO;
  184                         goto failed;
  185                 }
  186         }
  187 
  188         /* Register as the bus GPIO provider */
  189         if ((error = bhnd_register_provider(dev, BHND_SERVICE_GPIO))) {
  190                 device_printf(dev, "failed to register gpio with bus: %d\n",
  191                     error);
  192                 goto failed;
  193         }
  194 
  195         return (0);
  196 
  197 failed:
  198         device_delete_children(dev);
  199 
  200         if (sc->mem_res != NULL) {
  201                 bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
  202                     sc->mem_res);
  203         }
  204 
  205         CC_GPIO_LOCK_DESTROY(sc);
  206 
  207         return (error);
  208 }
  209 
  210 static int
  211 chipc_gpio_detach(device_t dev)
  212 {
  213         struct chipc_gpio_softc *sc;
  214         int                      error;
  215 
  216         sc = device_get_softc(dev);
  217 
  218         if ((error = bus_generic_detach(dev)))
  219                 return (error);
  220 
  221         if ((error = bhnd_deregister_provider(dev, BHND_SERVICE_ANY)))
  222                 return (error);
  223 
  224         bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res);
  225         CC_GPIO_LOCK_DESTROY(sc);
  226 
  227         return (0);
  228 }
  229 
  230 static device_t
  231 chipc_gpio_get_bus(device_t dev)
  232 {
  233         struct chipc_gpio_softc *sc = device_get_softc(dev);
  234 
  235         return (sc->gpiobus);
  236 }
  237 
  238 static int
  239 chipc_gpio_pin_max(device_t dev, int *maxpin)
  240 {
  241         *maxpin = CC_GPIO_NPINS-1;
  242         return (0);
  243 }
  244 
  245 static int
  246 chipc_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
  247 {
  248         struct chipc_gpio_softc *sc;
  249         bool                     pin_high;
  250         int                      error;
  251 
  252         sc = device_get_softc(dev);
  253         error = 0;
  254 
  255         if (!CC_GPIO_VALID_PIN(pin_num))
  256                 return (EINVAL);
  257 
  258         switch (pin_value) {
  259         case GPIO_PIN_HIGH:
  260                 pin_high = true;
  261                 break;
  262         case GPIO_PIN_LOW:
  263                 pin_high = false;
  264                 break;
  265         default:
  266                 return (EINVAL);
  267         }
  268 
  269         CC_GPIO_LOCK(sc);
  270 
  271         switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
  272         case CC_GPIO_PIN_INPUT:
  273         case CC_GPIO_PIN_TRISTATE:
  274                 error = ENODEV;
  275                 break;
  276 
  277         case CC_GPIO_PIN_OUTPUT:
  278                 CC_GPIO_WRFLAG(sc, pin_num, GPIOOUT, pin_high);
  279                 break;
  280         }
  281 
  282         CC_GPIO_UNLOCK(sc);
  283 
  284         return (error);
  285 }
  286 
  287 static int
  288 chipc_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
  289 {
  290         struct chipc_gpio_softc *sc;
  291         bool                     pin_high;
  292 
  293         if (!CC_GPIO_VALID_PIN(pin_num))
  294                 return (EINVAL);
  295 
  296         sc = device_get_softc(dev);
  297         pin_high = false;
  298 
  299         CC_GPIO_LOCK(sc);
  300 
  301         switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
  302         case CC_GPIO_PIN_INPUT:
  303                 pin_high = CC_GPIO_RDFLAG(sc, pin_num, GPIOIN);
  304                 break;
  305 
  306         case CC_GPIO_PIN_OUTPUT:
  307                 pin_high = CC_GPIO_RDFLAG(sc, pin_num, GPIOOUT);
  308                 break;
  309 
  310         case CC_GPIO_PIN_TRISTATE:
  311                 pin_high = false;
  312                 break;
  313         }
  314 
  315         CC_GPIO_UNLOCK(sc);
  316 
  317         *pin_value = pin_high ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
  318 
  319         return (0);
  320 }
  321 
  322 static int
  323 chipc_gpio_pin_toggle(device_t dev, uint32_t pin_num)
  324 {
  325         struct chipc_gpio_softc *sc;
  326         bool                     pin_high;
  327         int                      error;
  328 
  329         if (!CC_GPIO_VALID_PIN(pin_num))
  330                 return (EINVAL);
  331 
  332         sc = device_get_softc(dev);
  333         error = 0;
  334 
  335         CC_GPIO_LOCK(sc);
  336 
  337         switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
  338         case CC_GPIO_PIN_INPUT:
  339         case CC_GPIO_PIN_TRISTATE:
  340                 error = ENODEV;
  341                 break;
  342 
  343         case CC_GPIO_PIN_OUTPUT:
  344                 pin_high = CC_GPIO_RDFLAG(sc, pin_num, GPIOOUT);
  345                 CC_GPIO_WRFLAG(sc, pin_num, GPIOOUT, !pin_high);
  346                 break;
  347         }
  348 
  349         CC_GPIO_UNLOCK(sc);
  350 
  351         return (error);
  352 }
  353 
  354 static int
  355 chipc_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
  356 {
  357         struct chipc_gpio_softc *sc = device_get_softc(dev);
  358 
  359         if (!CC_GPIO_VALID_PIN(pin_num))
  360                 return (EINVAL);
  361 
  362         *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
  363 
  364         if (!CC_GPIO_QUIRK(sc, NO_PULLUPDOWN))
  365                 *caps |= (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
  366 
  367         if (!CC_GPIO_QUIRK(sc, NO_DCTIMER))
  368                 *caps |= GPIO_PIN_PULSATE;
  369 
  370         return (0);
  371 }
  372 
  373 static int
  374 chipc_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
  375 {
  376         struct chipc_gpio_softc *sc = device_get_softc(dev);
  377 
  378         if (!CC_GPIO_VALID_PIN(pin_num))
  379                 return (EINVAL);
  380 
  381         CC_GPIO_LOCK(sc);
  382 
  383         switch (chipc_gpio_pin_get_mode(sc, pin_num)) {
  384         case CC_GPIO_PIN_INPUT:
  385                 *flags = GPIO_PIN_INPUT;
  386 
  387                 if (!CC_GPIO_QUIRK(sc, NO_PULLUPDOWN)) {
  388                         if (CC_GPIO_RDFLAG(sc, pin_num, GPIOPU)) {
  389                                 *flags |= GPIO_PIN_PULLUP;
  390                         } else if (CC_GPIO_RDFLAG(sc, pin_num, GPIOPD)) {
  391                                 *flags |= GPIO_PIN_PULLDOWN;
  392                         }
  393                 }
  394                 break;
  395 
  396         case CC_GPIO_PIN_OUTPUT:
  397                 *flags = GPIO_PIN_OUTPUT;
  398 
  399                 if (!CC_GPIO_QUIRK(sc, NO_DCTIMER)) {
  400                         if (CC_GPIO_RDFLAG(sc, pin_num, GPIOTIMEROUTMASK))
  401                                 *flags |= GPIO_PIN_PULSATE;
  402                 }
  403 
  404                 break;
  405 
  406         case CC_GPIO_PIN_TRISTATE:
  407                 *flags = GPIO_PIN_TRISTATE|GPIO_PIN_OUTPUT;
  408                 break;
  409         }
  410 
  411         CC_GPIO_UNLOCK(sc);
  412 
  413         return (0);
  414 }
  415 
  416 static int
  417 chipc_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
  418 {
  419         int ret;
  420 
  421         if (!CC_GPIO_VALID_PIN(pin_num))
  422                 return (EINVAL);
  423 
  424         ret = snprintf(name, GPIOMAXNAME, "bhnd_gpio%02" PRIu32, pin_num);
  425 
  426         if (ret < 0)
  427                 return (ENXIO);
  428 
  429         if (ret >= GPIOMAXNAME)
  430                 return (ENOMEM);
  431 
  432         return (0);
  433 }
  434 
  435 static int
  436 chipc_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
  437 {
  438         struct chipc_gpio_softc         *sc;
  439         struct chipc_gpio_update         upd;
  440         int                              error;
  441 
  442         sc = device_get_softc(dev);
  443 
  444         if (!CC_GPIO_VALID_PIN(pin_num))
  445                 return (EINVAL);
  446 
  447         /* Produce an update descriptor */
  448         memset(&upd, 0, sizeof(upd));
  449         if ((error = chipc_gpio_pin_update(sc, &upd, pin_num, flags)))
  450                 return (error);
  451 
  452         /* Commit the update */
  453         CC_GPIO_LOCK(sc);
  454         error = chipc_gpio_commit_update(sc, &upd);
  455         CC_GPIO_UNLOCK(sc);
  456 
  457         return (error);
  458 }
  459 
  460 static int
  461 chipc_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
  462     uint32_t change_pins, uint32_t *orig_pins)
  463 {
  464         struct chipc_gpio_softc         *sc;
  465         struct chipc_gpio_update         upd;
  466         uint32_t                         out, outen, ctrl;
  467         uint32_t                         num_pins;
  468         int                              error;
  469 
  470         sc = device_get_softc(dev);
  471 
  472         if (first_pin >= CC_GPIO_NPINS)
  473                 return (EINVAL);
  474 
  475         /* Determine the actual number of referenced pins */
  476         if (clear_pins == 0 && change_pins == 0) {
  477                 num_pins = CC_GPIO_NPINS - first_pin;
  478         } else {
  479                 int num_clear_pins, num_change_pins;
  480 
  481                 num_clear_pins = flsl((u_long)clear_pins);
  482                 num_change_pins = flsl((u_long)change_pins);
  483                 num_pins = MAX(num_clear_pins, num_change_pins);
  484         }
  485 
  486         /* Validate the full pin range */
  487         if (!CC_GPIO_VALID_PINS(first_pin, num_pins))
  488                 return (EINVAL);
  489 
  490         /* Produce an update descriptor for all pins, relative to the current
  491          * pin state */
  492         CC_GPIO_LOCK(sc);
  493         memset(&upd, 0, sizeof(upd));
  494 
  495         out = CC_GPIO_RD4(sc, CHIPC_GPIOOUT);
  496         outen = CC_GPIO_RD4(sc, CHIPC_GPIOOUTEN);
  497         ctrl = CC_GPIO_RD4(sc, CHIPC_GPIOCTRL);
  498 
  499         for (uint32_t i = 0; i < num_pins; i++) {
  500                 uint32_t        pin;
  501                 bool            pin_high;
  502 
  503                 pin = first_pin + i;
  504 
  505                 /* The pin must be configured for output */
  506                 if ((outen & (1 << pin)) == 0) {
  507                         CC_GPIO_UNLOCK(sc);
  508                         return (EINVAL);
  509                 }
  510 
  511                 /* The pin must not tristated */
  512                 if ((ctrl & (1 << pin)) != 0) {
  513                         CC_GPIO_UNLOCK(sc);
  514                         return (EINVAL);
  515                 }
  516 
  517                 /* Fetch current state */
  518                 if (out & (1 << pin)) {
  519                         pin_high = true;
  520                 } else {
  521                         pin_high = false;
  522                 }
  523 
  524                 /* Apply clear/toggle request */
  525                 if (clear_pins & (1 << pin))
  526                         pin_high = false;
  527 
  528                 if (change_pins & (1 << pin))
  529                         pin_high = !pin_high;
  530 
  531                 /* Add to our update descriptor */
  532                 CC_GPIO_UPDATE(&upd, pin, out, pin_high);
  533         }
  534 
  535         /* Commit the update */
  536         error = chipc_gpio_commit_update(sc, &upd);
  537         CC_GPIO_UNLOCK(sc);
  538 
  539         return (error);
  540 }
  541 
  542 static int
  543 chipc_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
  544     uint32_t *pin_flags)
  545 {
  546         struct chipc_gpio_softc         *sc;
  547         struct chipc_gpio_update         upd;
  548         int                              error;
  549 
  550         sc = device_get_softc(dev);
  551 
  552         if (!CC_GPIO_VALID_PINS(first_pin, num_pins))
  553                 return (EINVAL);
  554 
  555         /* Produce an update descriptor */
  556         memset(&upd, 0, sizeof(upd));
  557         for (uint32_t i = 0; i < num_pins; i++) {
  558                 uint32_t pin, flags;
  559 
  560                 pin = first_pin + i;
  561                 flags = pin_flags[i];
  562 
  563                 /* As per the gpio_config_32 API documentation, any pins for
  564                  * which neither GPIO_PIN_OUTPUT or GPIO_PIN_INPUT are set
  565                  * should be ignored and left unmodified */
  566                 if ((flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) == 0)
  567                         continue;
  568 
  569                 if ((error = chipc_gpio_pin_update(sc, &upd, pin, flags)))
  570                         return (error);
  571         }
  572 
  573         /* Commit the update */
  574         CC_GPIO_LOCK(sc);
  575         error = chipc_gpio_commit_update(sc, &upd);
  576         CC_GPIO_UNLOCK(sc);
  577 
  578         return (error);
  579 }
  580 
  581 /**
  582  * Commit a single @p reg register update.
  583  */
  584 static void
  585 chipc_gpio_commit_reg(struct chipc_gpio_softc *sc, bus_size_t offset,
  586     struct chipc_gpio_reg *reg)
  587 {
  588         uint32_t value;
  589 
  590         CC_GPIO_LOCK_ASSERT(sc, MA_OWNED);
  591 
  592         if (reg->mask == 0)
  593                 return;
  594 
  595         value = bhnd_bus_read_4(sc->mem_res, offset);
  596         value &= ~reg->mask;
  597         value |= reg->value;
  598 
  599         bhnd_bus_write_4(sc->mem_res, offset, value);
  600 }
  601 
  602 /**
  603  * Commit the set of GPIO register updates described by @p update.
  604  */
  605 static int
  606 chipc_gpio_commit_update(struct chipc_gpio_softc *sc,
  607     struct chipc_gpio_update *update)
  608 {
  609         CC_GPIO_LOCK_ASSERT(sc, MA_OWNED);
  610 
  611         /* Commit pulldown/pullup before potentially disabling an output pin */
  612         chipc_gpio_commit_reg(sc, CHIPC_GPIOPD, &update->pulldown);
  613         chipc_gpio_commit_reg(sc, CHIPC_GPIOPU, &update->pullup);
  614 
  615         /* Commit output settings before potentially enabling an output pin */
  616         chipc_gpio_commit_reg(sc, CHIPC_GPIOTIMEROUTMASK,
  617             &update->timeroutmask);
  618         chipc_gpio_commit_reg(sc, CHIPC_GPIOOUT, &update->out);
  619 
  620         /* Commit input/output/tristate modes */
  621         chipc_gpio_commit_reg(sc, CHIPC_GPIOOUTEN, &update->outen);
  622         chipc_gpio_commit_reg(sc, CHIPC_GPIOCTRL, &update->ctrl);
  623 
  624         return (0);
  625 }
  626 
  627 /**
  628  * Apply the changes described by @p flags for @p pin_num to the given @p update
  629  * descriptor.
  630  */
  631 static int
  632 chipc_gpio_pin_update(struct chipc_gpio_softc *sc,
  633     struct chipc_gpio_update *update, uint32_t pin_num, uint32_t flags)
  634 {
  635         chipc_gpio_pin_mode     mode;
  636         int                     error;
  637 
  638         if (!CC_GPIO_VALID_PIN(pin_num))
  639                 return (EINVAL);
  640 
  641         /* Verify flag compatibility and determine the pin mode */
  642         if ((error = chipc_gpio_check_flags(sc, pin_num, flags, &mode)))
  643                 return (error);
  644 
  645         /* Apply the mode-specific changes */
  646         switch (mode) {
  647         case CC_GPIO_PIN_INPUT:
  648                 CC_GPIO_UPDATE(update, pin_num, pullup, false);
  649                 CC_GPIO_UPDATE(update, pin_num, pulldown, false);
  650                 CC_GPIO_UPDATE(update, pin_num, out, false);
  651                 CC_GPIO_UPDATE(update, pin_num, outen, false);
  652                 CC_GPIO_UPDATE(update, pin_num, timeroutmask, false);
  653                 CC_GPIO_UPDATE(update, pin_num, ctrl, false);
  654 
  655                 if (flags & GPIO_PIN_PULLUP) {
  656                         CC_GPIO_UPDATE(update, pin_num, pullup, true);
  657                 } else if (flags & GPIO_PIN_PULLDOWN) {
  658                         CC_GPIO_UPDATE(update, pin_num, pulldown, true);
  659                 }
  660 
  661                 return (0);
  662 
  663         case CC_GPIO_PIN_OUTPUT:
  664                 CC_GPIO_UPDATE(update, pin_num, pullup, false);
  665                 CC_GPIO_UPDATE(update, pin_num, pulldown, false);
  666                 CC_GPIO_UPDATE(update, pin_num, outen, true);
  667                 CC_GPIO_UPDATE(update, pin_num, timeroutmask, false);
  668                 CC_GPIO_UPDATE(update, pin_num, ctrl, false);
  669 
  670                 if (flags & GPIO_PIN_PRESET_HIGH) {
  671                         CC_GPIO_UPDATE(update, pin_num, out, true);
  672                 } else if (flags & GPIO_PIN_PRESET_LOW) {
  673                         CC_GPIO_UPDATE(update, pin_num, out, false);
  674                 }
  675 
  676                 if (flags & GPIO_PIN_PULSATE)
  677                         CC_GPIO_UPDATE(update, pin_num, timeroutmask, true);
  678 
  679                 return (0);
  680 
  681         case CC_GPIO_PIN_TRISTATE:
  682                 CC_GPIO_UPDATE(update, pin_num, pullup, false);
  683                 CC_GPIO_UPDATE(update, pin_num, pulldown, false);
  684                 CC_GPIO_UPDATE(update, pin_num, out, false);
  685                 CC_GPIO_UPDATE(update, pin_num, outen, false);
  686                 CC_GPIO_UPDATE(update, pin_num, timeroutmask, false);
  687                 CC_GPIO_UPDATE(update, pin_num, ctrl, true);
  688 
  689                 if (flags & GPIO_PIN_OUTPUT)
  690                         CC_GPIO_UPDATE(update, pin_num, outen, true);
  691 
  692                 return (0);
  693         }
  694 
  695         device_printf(sc->dev, "unknown pin mode %d\n", mode);
  696         return (EINVAL);
  697 }
  698 
  699 /**
  700  * Verify that @p flags are valid for use with @p pin_num, and on success,
  701  * return the pin mode described by @p flags in @p mode.
  702  * 
  703  * @param       sc      GPIO driver instance state.
  704  * @param       pin_num The pin number to configure.
  705  * @param       flags   The pin flags to be validated.
  706  * @param[out]  mode    On success, will be populated with the GPIO pin mode
  707  *                      defined by @p flags.
  708  * 
  709  * @retval 0            success
  710  * @retval EINVAL       if @p flags are invalid.
  711  */
  712 static int
  713 chipc_gpio_check_flags(struct chipc_gpio_softc *sc, uint32_t pin_num,
  714     uint32_t flags, chipc_gpio_pin_mode *mode)
  715 {
  716         uint32_t mode_flag, input_flag, output_flag;
  717 
  718         CC_GPIO_ASSERT_VALID_PIN(sc, pin_num);
  719 
  720         mode_flag = flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT |
  721             GPIO_PIN_TRISTATE);
  722         output_flag = flags & (GPIO_PIN_PRESET_HIGH | GPIO_PIN_PRESET_LOW
  723             | GPIO_PIN_PULSATE);
  724         input_flag = flags & (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
  725 
  726         switch (mode_flag) {
  727         case GPIO_PIN_OUTPUT:
  728                 /* No input flag(s) should be set */
  729                 if (input_flag != 0)
  730                         return (EINVAL);
  731 
  732                 /* Validate our output flag(s) */
  733                 switch (output_flag) {
  734                 case GPIO_PIN_PRESET_HIGH:
  735                 case GPIO_PIN_PRESET_LOW:
  736                 case (GPIO_PIN_PRESET_HIGH|GPIO_PIN_PULSATE):
  737                 case (GPIO_PIN_PRESET_LOW|GPIO_PIN_PULSATE):
  738                 case 0:
  739                         /* Check for unhandled flags */
  740                         if ((flags & ~(mode_flag | output_flag)) != 0)
  741                                 return (EINVAL);
  742 
  743                         *mode = CC_GPIO_PIN_OUTPUT;
  744                         return (0);
  745 
  746                 default:
  747                         /* Incompatible output flags */
  748                         return (EINVAL);
  749                 }
  750 
  751         case GPIO_PIN_INPUT:
  752                 /* No output flag(s) should be set */
  753                 if (output_flag != 0)
  754                         return (EINVAL);
  755 
  756                 /* Validate our input flag(s) */
  757                 switch (input_flag) {
  758                 case GPIO_PIN_PULLUP:
  759                 case GPIO_PIN_PULLDOWN:
  760                 case 0:
  761                         /* Check for unhandled flags */
  762                         if ((flags & ~(mode_flag | input_flag)) != 0)
  763                                 return (EINVAL);
  764 
  765                         *mode = CC_GPIO_PIN_INPUT;
  766                         return (0);
  767 
  768                 default:
  769                         /* Incompatible input flags */
  770                         return (EINVAL);
  771                 }
  772 
  773                 break;
  774 
  775         case (GPIO_PIN_TRISTATE|GPIO_PIN_OUTPUT):
  776         case GPIO_PIN_TRISTATE:
  777                 /* No input or output flag(s) should be set */
  778                 if (input_flag != 0 || output_flag != 0)
  779                         return (EINVAL);
  780 
  781                 /* Check for unhandled flags */
  782                 if ((flags & ~mode_flag) != 0)
  783                         return (EINVAL);
  784 
  785                 *mode = CC_GPIO_PIN_TRISTATE;
  786                 return (0);
  787 
  788         default:
  789                 /* Incompatible mode flags */
  790                 return (EINVAL);
  791         }
  792 }
  793 
  794 /**
  795  * Return the current pin mode for @p pin_num.
  796  * 
  797  * @param sc            GPIO driver instance state.
  798  * @param pin_num       The pin number to query.
  799  */
  800 static chipc_gpio_pin_mode
  801 chipc_gpio_pin_get_mode(struct chipc_gpio_softc *sc, uint32_t pin_num)
  802 {
  803         CC_GPIO_LOCK_ASSERT(sc, MA_OWNED);
  804         CC_GPIO_ASSERT_VALID_PIN(sc, pin_num);
  805 
  806         if (CC_GPIO_RDFLAG(sc, pin_num, GPIOCTRL)) {
  807                 return (CC_GPIO_PIN_TRISTATE);
  808         } else if (CC_GPIO_RDFLAG(sc, pin_num, GPIOOUTEN)) {
  809                 return (CC_GPIO_PIN_OUTPUT);
  810         } else {
  811                 return (CC_GPIO_PIN_INPUT);
  812         }
  813 }
  814 
  815 static device_method_t chipc_gpio_methods[] = {
  816         /* Device interface */
  817         DEVMETHOD(device_probe,         chipc_gpio_probe),
  818         DEVMETHOD(device_attach,        chipc_gpio_attach),
  819         DEVMETHOD(device_detach,        chipc_gpio_detach),
  820 
  821         /* GPIO interface */
  822         DEVMETHOD(gpio_get_bus,         chipc_gpio_get_bus),
  823         DEVMETHOD(gpio_pin_max,         chipc_gpio_pin_max),
  824         DEVMETHOD(gpio_pin_getname,     chipc_gpio_pin_getname),
  825         DEVMETHOD(gpio_pin_getflags,    chipc_gpio_pin_getflags),
  826         DEVMETHOD(gpio_pin_getcaps,     chipc_gpio_pin_getcaps),
  827         DEVMETHOD(gpio_pin_setflags,    chipc_gpio_pin_setflags),
  828         DEVMETHOD(gpio_pin_get,         chipc_gpio_pin_get),
  829         DEVMETHOD(gpio_pin_set,         chipc_gpio_pin_set),
  830         DEVMETHOD(gpio_pin_toggle,      chipc_gpio_pin_toggle),
  831         DEVMETHOD(gpio_pin_access_32,   chipc_gpio_pin_access_32),
  832         DEVMETHOD(gpio_pin_config_32,   chipc_gpio_pin_config_32),
  833 
  834         DEVMETHOD_END
  835 };
  836 
  837 DEFINE_CLASS_0(gpio, chipc_gpio_driver, chipc_gpio_methods, sizeof(struct chipc_gpio_softc));
  838 EARLY_DRIVER_MODULE(chipc_gpio, bhnd_chipc, chipc_gpio_driver, NULL, NULL,
  839     BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
  840 
  841 MODULE_DEPEND(chipc_gpio, bhnd, 1, 1, 1);
  842 MODULE_DEPEND(chipc_gpio, gpiobus, 1, 1, 1);
  843 MODULE_VERSION(chipc_gpio, 1);

Cache object: f200282c831c3b83ca74a4378ac684c5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.