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/nctgpio/nctgpio.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  * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  *
   28  */
   29 
   30 /*
   31  * Nuvoton GPIO driver.
   32  *
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 
   37 #include <sys/param.h>
   38 #include <sys/kernel.h>
   39 #include <sys/systm.h>
   40 #include <sys/bus.h>
   41 #include <sys/eventhandler.h>
   42 #include <sys/lock.h>
   43 
   44 #include <sys/module.h>
   45 #include <sys/gpio.h>
   46 
   47 #include <machine/bus.h>
   48 
   49 #include <dev/gpio/gpiobusvar.h>
   50 #include <dev/superio/superio.h>
   51 
   52 #include "gpio_if.h"
   53 
   54 /* Logical Device Numbers. */
   55 #define NCT_LDN_GPIO                    0x07
   56 #define NCT_LDN_GPIO_MODE               0x0f
   57 
   58 /* Logical Device 7 */
   59 #define NCT_LD7_GPIO0_IOR               0xe0
   60 #define NCT_LD7_GPIO0_DAT               0xe1
   61 #define NCT_LD7_GPIO0_INV               0xe2
   62 #define NCT_LD7_GPIO0_DST               0xe3
   63 #define NCT_LD7_GPIO1_IOR               0xe4
   64 #define NCT_LD7_GPIO1_DAT               0xe5
   65 #define NCT_LD7_GPIO1_INV               0xe6
   66 #define NCT_LD7_GPIO1_DST               0xe7
   67 
   68 /* Logical Device F */
   69 #define NCT_LDF_GPIO0_OUTCFG            0xe0
   70 #define NCT_LDF_GPIO1_OUTCFG            0xe1
   71 
   72 /* Direct I/O port access. */
   73 #define NCT_IO_GSR                      0
   74 #define NCT_IO_IOR                      1
   75 #define NCT_IO_DAT                      2
   76 #define NCT_IO_INV                      3
   77 
   78 #define NCT_MAX_PIN                     15
   79 #define NCT_IS_VALID_PIN(_p)    ((_p) >= 0 && (_p) <= NCT_MAX_PIN)
   80 
   81 #define NCT_PIN_BIT(_p)         (1 << ((_p) & 7))
   82 
   83 #define NCT_GPIO_CAPS   (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
   84         GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
   85         GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
   86 
   87 /*
   88  * Note that the values are important.
   89  * They match actual register offsets.
   90  */
   91 typedef enum {
   92         REG_IOR = 0,
   93         REG_DAT = 1,
   94         REG_INV = 2,
   95 } reg_t;
   96 
   97 struct nct_softc {
   98         device_t                        dev;
   99         device_t                        dev_f;
  100         device_t                        busdev;
  101         struct mtx                      mtx;
  102         struct resource                 *iores;
  103         int                             iorid;
  104         int                             curgrp;
  105         struct {
  106                 /* direction, 1: pin is input */
  107                 uint8_t                 ior[2];
  108                 /* output value */
  109                 uint8_t                 out[2];
  110                 /* whether out is valid */
  111                 uint8_t                 out_known[2];
  112                 /* inversion, 1: pin is inverted */
  113                 uint8_t                 inv[2];
  114         }                               cache;
  115         struct gpio_pin                 pins[NCT_MAX_PIN + 1];
  116 };
  117 
  118 #define GPIO_LOCK_INIT(_sc)     mtx_init(&(_sc)->mtx,           \
  119                 device_get_nameunit(dev), NULL, MTX_DEF)
  120 #define GPIO_LOCK_DESTROY(_sc)          mtx_destroy(&(_sc)->mtx)
  121 #define GPIO_LOCK(_sc)          mtx_lock(&(_sc)->mtx)
  122 #define GPIO_UNLOCK(_sc)        mtx_unlock(&(_sc)->mtx)
  123 #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
  124 #define GPIO_ASSERT_UNLOCKED(_sc)       mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
  125 
  126 struct nuvoton_vendor_device_id {
  127         uint16_t                chip_id;
  128         const char *            descr;
  129 } nct_devs[] = {
  130         {
  131                 .chip_id        = 0x1061,
  132                 .descr          = "Nuvoton NCT5104D",
  133         },
  134         {
  135                 .chip_id        = 0xc452,
  136                 .descr          = "Nuvoton NCT5104D (PC-Engines APU)",
  137         },
  138         {
  139                 .chip_id        = 0xc453,
  140                 .descr          = "Nuvoton NCT5104D (PC-Engines APU3)",
  141         },
  142 };
  143 
  144 static void
  145 nct_io_set_group(struct nct_softc *sc, int group)
  146 {
  147 
  148         GPIO_ASSERT_LOCKED(sc);
  149         if (group != sc->curgrp) {
  150                 bus_write_1(sc->iores, NCT_IO_GSR, group);
  151                 sc->curgrp = group;
  152         }
  153 }
  154 
  155 static uint8_t
  156 nct_io_read(struct nct_softc *sc, int group, uint8_t reg)
  157 {
  158         nct_io_set_group(sc, group);
  159         return (bus_read_1(sc->iores, reg));
  160 }
  161 
  162 static void
  163 nct_io_write(struct nct_softc *sc, int group, uint8_t reg, uint8_t val)
  164 {
  165         nct_io_set_group(sc, group);
  166         return (bus_write_1(sc->iores, reg, val));
  167 }
  168 
  169 static uint8_t
  170 nct_get_ioreg(struct nct_softc *sc, reg_t reg, int group)
  171 {
  172         uint8_t ioreg;
  173 
  174         if (sc->iores != NULL)
  175                 ioreg = NCT_IO_IOR + reg;
  176         else if (group == 0)
  177                 ioreg = NCT_LD7_GPIO0_IOR + reg;
  178         else
  179                 ioreg = NCT_LD7_GPIO1_IOR + reg;
  180         return (ioreg);
  181 }
  182 
  183 static uint8_t
  184 nct_read_reg(struct nct_softc *sc, reg_t reg, int group)
  185 {
  186         uint8_t ioreg;
  187         uint8_t val;
  188 
  189         ioreg = nct_get_ioreg(sc, reg, group);
  190         if (sc->iores != NULL)
  191                 val = nct_io_read(sc, group, ioreg);
  192         else
  193                 val = superio_read(sc->dev, ioreg);
  194 
  195         return (val);
  196 }
  197 
  198 #define GET_BIT(v, b)   (((v) >> (b)) & 1)
  199 static bool
  200 nct_get_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num)
  201 {
  202         uint8_t bit;
  203         uint8_t group;
  204         uint8_t val;
  205 
  206         KASSERT(NCT_IS_VALID_PIN(pin_num), ("%s: invalid pin number %d",
  207             __func__, pin_num));
  208 
  209         group = pin_num >> 3;
  210         bit = pin_num & 7;
  211         val = nct_read_reg(sc, reg, group);
  212         return (GET_BIT(val, bit));
  213 }
  214 
  215 static int
  216 nct_get_pin_cache(struct nct_softc *sc, uint32_t pin_num, uint8_t *cache)
  217 {
  218         uint8_t bit;
  219         uint8_t group;
  220         uint8_t val;
  221 
  222         KASSERT(NCT_IS_VALID_PIN(pin_num), ("%s: invalid pin number %d",
  223             __func__, pin_num));
  224 
  225         group = pin_num >> 3;
  226         bit = pin_num & 7;
  227         val = cache[group];
  228         return (GET_BIT(val, bit));
  229 }
  230 
  231 static void
  232 nct_write_reg(struct nct_softc *sc, reg_t reg, int group, uint8_t val)
  233 {
  234         uint8_t ioreg;
  235 
  236         ioreg = nct_get_ioreg(sc, reg, group);
  237         if (sc->iores != NULL)
  238                 nct_io_write(sc, group, ioreg, val);
  239         else
  240                 superio_write(sc->dev, ioreg, val);
  241 }
  242 
  243 static void
  244 nct_set_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num, bool val)
  245 {
  246         uint8_t *cache;
  247         uint8_t bit;
  248         uint8_t bitval;
  249         uint8_t group;
  250         uint8_t mask;
  251 
  252         KASSERT(NCT_IS_VALID_PIN(pin_num),
  253             ("%s: invalid pin number %d", __func__, pin_num));
  254         KASSERT(reg == REG_IOR || reg == REG_INV,
  255             ("%s: unsupported register %d", __func__, reg));
  256 
  257         group = pin_num >> 3;
  258         bit = pin_num & 7;
  259         mask = (uint8_t)1 << bit;
  260         bitval = (uint8_t)val << bit;
  261 
  262         if (reg == REG_IOR)
  263                 cache = &sc->cache.ior[group];
  264         else
  265                 cache = &sc->cache.inv[group];
  266         if ((*cache & mask) == bitval)
  267                 return;
  268         *cache &= ~mask;
  269         *cache |= bitval;
  270         nct_write_reg(sc, reg, group, *cache);
  271 }
  272 
  273 /*
  274  * Set a pin to input (val is true) or output (val is false) mode.
  275  */
  276 static void
  277 nct_set_pin_input(struct nct_softc *sc, uint32_t pin_num, bool val)
  278 {
  279         nct_set_pin_reg(sc, REG_IOR, pin_num, val);
  280 }
  281 
  282 /*
  283  * Check whether a pin is configured as an input.
  284  */
  285 static bool
  286 nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
  287 {
  288         return (nct_get_pin_cache(sc, pin_num, sc->cache.ior));
  289 }
  290 
  291 /*
  292  * Set a pin to inverted (val is true) or normal (val is false) mode.
  293  */
  294 static void
  295 nct_set_pin_inverted(struct nct_softc *sc, uint32_t pin_num, bool val)
  296 {
  297         nct_set_pin_reg(sc, REG_INV, pin_num, val);
  298 }
  299 
  300 static bool
  301 nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
  302 {
  303         return (nct_get_pin_cache(sc, pin_num, sc->cache.inv));
  304 }
  305 
  306 /*
  307  * Write a value to an output pin.
  308  * NB: the hardware remembers last output value across switching from
  309  * output mode to input mode and back.
  310  * Writes to a pin in input mode are not allowed here as they cannot
  311  * have any effect and would corrupt the output value cache.
  312  */
  313 static void
  314 nct_write_pin(struct nct_softc *sc, uint32_t pin_num, bool val)
  315 {
  316         uint8_t bit;
  317         uint8_t group;
  318 
  319         KASSERT(!nct_pin_is_input(sc, pin_num), ("attempt to write input pin"));
  320         group = pin_num >> 3;
  321         bit = pin_num & 7;
  322         if (GET_BIT(sc->cache.out_known[group], bit) &&
  323             GET_BIT(sc->cache.out[group], bit) == val) {
  324                 /* The pin is already in requested state. */
  325                 return;
  326         }
  327         sc->cache.out_known[group] |= 1 << bit;
  328         if (val)
  329                 sc->cache.out[group] |= 1 << bit;
  330         else
  331                 sc->cache.out[group] &= ~(1 << bit);
  332         nct_write_reg(sc, REG_DAT, group, sc->cache.out[group]);
  333 }
  334 
  335 /*
  336  * NB: state of an input pin cannot be cached, of course.
  337  * For an output we can either take the value from the cache if it's valid
  338  * or read the state from the hadrware and cache it.
  339  */
  340 static bool
  341 nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
  342 {
  343         uint8_t bit;
  344         uint8_t group;
  345         bool val;
  346 
  347         if (nct_pin_is_input(sc, pin_num))
  348                 return (nct_get_pin_reg(sc, REG_DAT, pin_num));
  349 
  350         group = pin_num >> 3;
  351         bit = pin_num & 7;
  352         if (GET_BIT(sc->cache.out_known[group], bit))
  353                 return (GET_BIT(sc->cache.out[group], bit));
  354 
  355         val = nct_get_pin_reg(sc, REG_DAT, pin_num);
  356         sc->cache.out_known[group] |= 1 << bit;
  357         if (val)
  358                 sc->cache.out[group] |= 1 << bit;
  359         else
  360                 sc->cache.out[group] &= ~(1 << bit);
  361         return (val);
  362 }
  363 
  364 static uint8_t
  365 nct_outcfg_addr(uint32_t pin_num)
  366 {
  367         KASSERT(NCT_IS_VALID_PIN(pin_num), ("%s: invalid pin number %d",
  368             __func__, pin_num));
  369         if ((pin_num >> 3) == 0)
  370                 return (NCT_LDF_GPIO0_OUTCFG);
  371         else
  372                 return (NCT_LDF_GPIO1_OUTCFG);
  373 }
  374 
  375 /*
  376  * NB: PP/OD can be configured only via configuration registers.
  377  * Also, the registers are in a different logical device.
  378  * So, this is a special case.  No caching too.
  379  */
  380 static void
  381 nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
  382 {
  383         uint8_t reg;
  384         uint8_t outcfg;
  385 
  386         reg = nct_outcfg_addr(pin_num);
  387         outcfg = superio_read(sc->dev_f, reg);
  388         outcfg |= NCT_PIN_BIT(pin_num);
  389         superio_write(sc->dev_f, reg, outcfg);
  390 }
  391 
  392 static void
  393 nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
  394 {
  395         uint8_t reg;
  396         uint8_t outcfg;
  397 
  398         reg = nct_outcfg_addr(pin_num);
  399         outcfg = superio_read(sc->dev_f, reg);
  400         outcfg &= ~NCT_PIN_BIT(pin_num);
  401         superio_write(sc->dev_f, reg, outcfg);
  402 }
  403 
  404 static bool
  405 nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
  406 {
  407         uint8_t reg;
  408         uint8_t outcfg;
  409 
  410         reg = nct_outcfg_addr(pin_num);
  411         outcfg = superio_read(sc->dev_f, reg);
  412         return (outcfg & NCT_PIN_BIT(pin_num));
  413 }
  414 
  415 static int
  416 nct_probe(device_t dev)
  417 {
  418         int j;
  419         uint16_t chipid;
  420 
  421         if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON)
  422                 return (ENXIO);
  423         if (superio_get_type(dev) != SUPERIO_DEV_GPIO)
  424                 return (ENXIO);
  425 
  426         /*
  427          * There are several GPIO devices, we attach only to one of them
  428          * and use the rest without attaching.
  429          */
  430         if (superio_get_ldn(dev) != NCT_LDN_GPIO)
  431                 return (ENXIO);
  432 
  433         chipid = superio_devid(dev);
  434         for (j = 0; j < nitems(nct_devs); j++) {
  435                 if (chipid == nct_devs[j].chip_id) {
  436                         device_set_desc(dev, "Nuvoton GPIO controller");
  437                         return (BUS_PROBE_DEFAULT);
  438                 }
  439         }
  440         return (ENXIO);
  441 }
  442 
  443 static int
  444 nct_attach(device_t dev)
  445 {
  446         struct nct_softc *sc;
  447         device_t dev_8;
  448         uint16_t iobase;
  449         int err;
  450         int i;
  451 
  452         sc = device_get_softc(dev);
  453         sc->dev = dev;
  454         sc->dev_f = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_GPIO,
  455             NCT_LDN_GPIO_MODE);
  456         if (sc->dev_f == NULL) {
  457                 device_printf(dev, "failed to find LDN F\n");
  458                 return (ENXIO);
  459         }
  460 
  461         /*
  462          * As strange as it may seem, I/O port base is configured in the
  463          * Logical Device 8 which is primarily used for WDT, but also plays
  464          * a role in GPIO configuration.
  465          */
  466         iobase = 0;
  467         dev_8 = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_WDT, 8);
  468         if (dev_8 != NULL)
  469                 iobase = superio_get_iobase(dev_8);
  470         if (iobase != 0 && iobase != 0xffff) {
  471                 sc->curgrp = -1;
  472                 sc->iorid = 0;
  473                 err = bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid,
  474                     iobase, 7);
  475                 if (err == 0) {
  476                         sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
  477                             &sc->iorid, RF_ACTIVE);
  478                         if (sc->iores == NULL) {
  479                                 device_printf(dev, "can't map i/o space, "
  480                                     "iobase=0x%04x\n", iobase);
  481                         }
  482                 } else {
  483                         device_printf(dev,
  484                             "failed to set io port resource at 0x%x\n", iobase);
  485                 }
  486         }
  487 
  488         /* Enable gpio0 and gpio1. */
  489         superio_dev_enable(dev, 0x03);
  490 
  491         GPIO_LOCK_INIT(sc);
  492         GPIO_LOCK(sc);
  493 
  494         sc->cache.inv[0] = nct_read_reg(sc, REG_INV, 0);
  495         sc->cache.inv[1] = nct_read_reg(sc, REG_INV, 1);
  496         sc->cache.ior[0] = nct_read_reg(sc, REG_IOR, 0);
  497         sc->cache.ior[1] = nct_read_reg(sc, REG_IOR, 1);
  498 
  499         /*
  500          * Caching input values is meaningless as an input can be changed at any
  501          * time by an external agent.  But outputs are controlled by this
  502          * driver, so it can cache their state.  Also, the hardware remembers
  503          * the output state of a pin when the pin is switched to input mode and
  504          * then back to output mode.  So, the cache stays valid.
  505          * The only problem is with pins that are in input mode at the attach
  506          * time.  For them the output state is not known until it is set by the
  507          * driver for the first time.
  508          * 'out' and 'out_known' bits form a tri-state output cache:
  509          * |-----+-----------+---------|
  510          * | out | out_known | cache   |
  511          * |-----+-----------+---------|
  512          * |   X |         0 | invalid |
  513          * |   0 |         1 |       0 |
  514          * |   1 |         1 |       1 |
  515          * |-----+-----------+---------|
  516          */
  517         sc->cache.out[0] = nct_read_reg(sc, REG_DAT, 0);
  518         sc->cache.out[1] = nct_read_reg(sc, REG_DAT, 1);
  519         sc->cache.out_known[0] = ~sc->cache.ior[0];
  520         sc->cache.out_known[1] = ~sc->cache.ior[1];
  521 
  522         for (i = 0; i <= NCT_MAX_PIN; i++) {
  523                 struct gpio_pin *pin;
  524 
  525                 pin = &sc->pins[i];
  526                 pin->gp_pin = i;
  527                 pin->gp_caps = NCT_GPIO_CAPS;
  528                 pin->gp_flags = 0;
  529 
  530                 snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02o", i);
  531                 pin->gp_name[GPIOMAXNAME - 1] = '\0';
  532 
  533                 if (nct_pin_is_input(sc, i))
  534                         pin->gp_flags |= GPIO_PIN_INPUT;
  535                 else
  536                         pin->gp_flags |= GPIO_PIN_OUTPUT;
  537 
  538                 if (nct_pin_is_opendrain(sc, i))
  539                         pin->gp_flags |= GPIO_PIN_OPENDRAIN;
  540                 else
  541                         pin->gp_flags |= GPIO_PIN_PUSHPULL;
  542 
  543                 if (nct_pin_is_inverted(sc, i))
  544                         pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
  545         }
  546         GPIO_UNLOCK(sc);
  547 
  548         sc->busdev = gpiobus_attach_bus(dev);
  549         if (sc->busdev == NULL) {
  550                 GPIO_LOCK_DESTROY(sc);
  551                 return (ENXIO);
  552         }
  553 
  554         return (0);
  555 }
  556 
  557 static int
  558 nct_detach(device_t dev)
  559 {
  560         struct nct_softc *sc;
  561 
  562         sc = device_get_softc(dev);
  563         gpiobus_detach_bus(dev);
  564 
  565         if (sc->iores != NULL)
  566                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores);
  567         GPIO_ASSERT_UNLOCKED(sc);
  568         GPIO_LOCK_DESTROY(sc);
  569 
  570         return (0);
  571 }
  572 
  573 static device_t
  574 nct_gpio_get_bus(device_t dev)
  575 {
  576         struct nct_softc *sc;
  577 
  578         sc = device_get_softc(dev);
  579 
  580         return (sc->busdev);
  581 }
  582 
  583 static int
  584 nct_gpio_pin_max(device_t dev, int *npins)
  585 {
  586         *npins = NCT_MAX_PIN;
  587 
  588         return (0);
  589 }
  590 
  591 static int
  592 nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
  593 {
  594         struct nct_softc *sc;
  595 
  596         if (!NCT_IS_VALID_PIN(pin_num))
  597                 return (EINVAL);
  598 
  599         sc = device_get_softc(dev);
  600         GPIO_LOCK(sc);
  601         if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
  602                 GPIO_UNLOCK(sc);
  603                 return (EINVAL);
  604         }
  605         nct_write_pin(sc, pin_num, pin_value);
  606         GPIO_UNLOCK(sc);
  607 
  608         return (0);
  609 }
  610 
  611 static int
  612 nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
  613 {
  614         struct nct_softc *sc;
  615 
  616         if (!NCT_IS_VALID_PIN(pin_num))
  617                 return (EINVAL);
  618 
  619         sc = device_get_softc(dev);
  620         GPIO_ASSERT_UNLOCKED(sc);
  621         GPIO_LOCK(sc);
  622         *pin_value = nct_read_pin(sc, pin_num);
  623         GPIO_UNLOCK(sc);
  624 
  625         return (0);
  626 }
  627 
  628 static int
  629 nct_gpio_pin_toggle(device_t dev, uint32_t pin_num)
  630 {
  631         struct nct_softc *sc;
  632 
  633         if (!NCT_IS_VALID_PIN(pin_num))
  634                 return (EINVAL);
  635 
  636         sc = device_get_softc(dev);
  637         GPIO_ASSERT_UNLOCKED(sc);
  638         GPIO_LOCK(sc);
  639         if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
  640                 GPIO_UNLOCK(sc);
  641                 return (EINVAL);
  642         }
  643         if (nct_read_pin(sc, pin_num))
  644                 nct_write_pin(sc, pin_num, 0);
  645         else
  646                 nct_write_pin(sc, pin_num, 1);
  647 
  648         GPIO_UNLOCK(sc);
  649 
  650         return (0);
  651 }
  652 
  653 static int
  654 nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
  655 {
  656         struct nct_softc *sc;
  657 
  658         if (!NCT_IS_VALID_PIN(pin_num))
  659                 return (EINVAL);
  660 
  661         sc = device_get_softc(dev);
  662         GPIO_ASSERT_UNLOCKED(sc);
  663         GPIO_LOCK(sc);
  664         *caps = sc->pins[pin_num].gp_caps;
  665         GPIO_UNLOCK(sc);
  666 
  667         return (0);
  668 }
  669 
  670 static int
  671 nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
  672 {
  673         struct nct_softc *sc;
  674 
  675         if (!NCT_IS_VALID_PIN(pin_num))
  676                 return (EINVAL);
  677 
  678         sc = device_get_softc(dev);
  679         GPIO_ASSERT_UNLOCKED(sc);
  680         GPIO_LOCK(sc);
  681         *flags = sc->pins[pin_num].gp_flags;
  682         GPIO_UNLOCK(sc);
  683 
  684         return (0);
  685 }
  686 
  687 static int
  688 nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
  689 {
  690         struct nct_softc *sc;
  691 
  692         if (!NCT_IS_VALID_PIN(pin_num))
  693                 return (EINVAL);
  694 
  695         sc = device_get_softc(dev);
  696         GPIO_ASSERT_UNLOCKED(sc);
  697         GPIO_LOCK(sc);
  698         memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
  699         GPIO_UNLOCK(sc);
  700 
  701         return (0);
  702 }
  703 
  704 static int
  705 nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
  706 {
  707         struct nct_softc *sc;
  708         struct gpio_pin *pin;
  709 
  710         if (!NCT_IS_VALID_PIN(pin_num))
  711                 return (EINVAL);
  712 
  713         sc = device_get_softc(dev);
  714         pin = &sc->pins[pin_num];
  715         if ((flags & pin->gp_caps) != flags)
  716                 return (EINVAL);
  717 
  718         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
  719                 (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
  720                         return (EINVAL);
  721         }
  722         if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
  723                 (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
  724                         return (EINVAL);
  725         }
  726         if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) ==
  727                 (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
  728                         return (EINVAL);
  729         }
  730 
  731         GPIO_ASSERT_UNLOCKED(sc);
  732         GPIO_LOCK(sc);
  733         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != 0) {
  734                 nct_set_pin_input(sc, pin_num, (flags & GPIO_PIN_INPUT) != 0);
  735                 pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
  736                 pin->gp_flags |= flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
  737         }
  738         if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) != 0) {
  739                 nct_set_pin_inverted(sc, pin_num,
  740                     (flags & GPIO_PIN_INVIN) != 0);
  741                 pin->gp_flags &= ~(GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
  742                 pin->gp_flags |= flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
  743         }
  744         if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) != 0) {
  745                 if (flags & GPIO_PIN_OPENDRAIN)
  746                         nct_set_pin_opendrain(sc, pin_num);
  747                 else
  748                         nct_set_pin_pushpull(sc, pin_num);
  749                 pin->gp_flags &= ~(GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL);
  750                 pin->gp_flags |=
  751                     flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL);
  752         }
  753         GPIO_UNLOCK(sc);
  754 
  755         return (0);
  756 }
  757 
  758 static device_method_t nct_methods[] = {
  759         /* Device interface */
  760         DEVMETHOD(device_probe,         nct_probe),
  761         DEVMETHOD(device_attach,        nct_attach),
  762         DEVMETHOD(device_detach,        nct_detach),
  763 
  764         /* GPIO */
  765         DEVMETHOD(gpio_get_bus,         nct_gpio_get_bus),
  766         DEVMETHOD(gpio_pin_max,         nct_gpio_pin_max),
  767         DEVMETHOD(gpio_pin_get,         nct_gpio_pin_get),
  768         DEVMETHOD(gpio_pin_set,         nct_gpio_pin_set),
  769         DEVMETHOD(gpio_pin_toggle,      nct_gpio_pin_toggle),
  770         DEVMETHOD(gpio_pin_getname,     nct_gpio_pin_getname),
  771         DEVMETHOD(gpio_pin_getcaps,     nct_gpio_pin_getcaps),
  772         DEVMETHOD(gpio_pin_getflags,    nct_gpio_pin_getflags),
  773         DEVMETHOD(gpio_pin_setflags,    nct_gpio_pin_setflags),
  774 
  775         DEVMETHOD_END
  776 };
  777 
  778 static driver_t nct_driver = {
  779         "gpio",
  780         nct_methods,
  781         sizeof(struct nct_softc)
  782 };
  783 
  784 DRIVER_MODULE(nctgpio, superio, nct_driver, NULL, NULL);
  785 MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);
  786 MODULE_DEPEND(nctgpio, superio, 1, 1, 1);
  787 MODULE_VERSION(nctgpio, 1);
  788 

Cache object: 286c56c9c08d37fb85484bff33566bfb


[ 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.