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/iicbus/gpio/tca64xx.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) 2020 Alstom Group.
    5  * Copyright (c) 2020 Semihalf.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * Driver for TI TCA64XX I2C GPIO expander module.
   31  *
   32  * This driver only supports basic functionality
   33  * (interrupt handling and polarity inversion were omitted).
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/param.h>
   40 #include <sys/bus.h>
   41 #include <sys/gpio.h>
   42 #include <sys/kernel.h>
   43 #include <sys/module.h>
   44 #include <sys/proc.h>
   45 #include <sys/systm.h>
   46 #include <sys/sysctl.h>
   47 
   48 #include <machine/bus.h>
   49 
   50 #include <dev/ofw/openfirm.h>
   51 #include <dev/ofw/ofw_bus.h>
   52 #include <dev/ofw/ofw_bus_subr.h>
   53 
   54 #include <dev/iicbus/iicbus.h>
   55 #include <dev/iicbus/iiconf.h>
   56 
   57 #include <dev/gpio/gpiobusvar.h>
   58 
   59 #include "gpio_if.h"
   60 
   61 /* Base addresses of registers. LSB omitted. */
   62 
   63 #define TCA64XX_PINS_PER_REG            8
   64 
   65 #define TCA64XX_BIT_FROM_PIN(pin)       (pin % TCA64XX_PINS_PER_REG)
   66 #define TCA64XX_REG_ADDR(pin, baseaddr) (baseaddr | (pin / \
   67                                         TCA64XX_PINS_PER_REG))
   68 #define TCA64XX_PIN_CAPS                (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT \
   69                                         | GPIO_PIN_PUSHPULL | GPIO_PIN_INVIN)
   70 
   71 #define TCA6416_IN_PORT_REG             0x0
   72 #define TCA6416_OUT_PORT_REG            0x2
   73 #define TCA6416_POLARITY_INV_REG        0x4
   74 #define TCA6416_CONF_REG                0x6
   75 #define TCA6416_NUM_PINS                16
   76 
   77 #define TCA6408_IN_PORT_REG             0x0
   78 #define TCA6408_OUT_PORT_REG            0x1
   79 #define TCA6408_POLARITY_INV_REG        0x2
   80 #define TCA6408_CONF_REG                0x3
   81 #define TCA6408_NUM_PINS                8
   82 
   83 #ifdef DEBUG
   84 #define dbg_dev_printf(dev, fmt, args...)       \
   85         device_printf(dev, fmt, ##args)
   86 #else
   87 #define dbg_dev_printf(dev, fmt, args...)
   88 #endif
   89 
   90 enum chip_type{
   91         TCA6416_TYPE = 1,
   92         TCA6408_TYPE
   93 };
   94 
   95 struct tca64xx_softc {
   96         device_t        dev;
   97         device_t        busdev;
   98         enum chip_type  chip;
   99         struct mtx      mtx;
  100         uint32_t        addr;
  101         uint8_t         num_pins;
  102         uint8_t         in_port_reg;
  103         uint8_t         out_port_reg;
  104         uint8_t         polarity_inv_reg;
  105         uint8_t         conf_reg;
  106         uint8_t         pin_caps;
  107 };
  108 
  109 static int tca64xx_read(device_t, uint8_t, uint8_t *);
  110 static int tca64xx_write(device_t, uint8_t, uint8_t);
  111 static int tca64xx_probe(device_t);
  112 static int tca64xx_attach(device_t);
  113 static int tca64xx_detach(device_t);
  114 static device_t tca64xx_get_bus(device_t);
  115 static int tca64xx_pin_max(device_t, int *);
  116 static int tca64xx_pin_getcaps(device_t, uint32_t, uint32_t *);
  117 static int tca64xx_pin_getflags(device_t, uint32_t, uint32_t *);
  118 static int tca64xx_pin_setflags(device_t, uint32_t, uint32_t);
  119 static int tca64xx_pin_getname(device_t, uint32_t, char *);
  120 static int tca64xx_pin_get(device_t, uint32_t, unsigned int *);
  121 static int tca64xx_pin_set(device_t, uint32_t, unsigned int);
  122 static int tca64xx_pin_toggle(device_t, uint32_t);
  123 #ifdef DEBUG
  124 static void tca6408_regdump_setup(device_t dev);
  125 static void tca6416_regdump_setup(device_t dev);
  126 static int tca64xx_regdump_sysctl(SYSCTL_HANDLER_ARGS);
  127 #endif
  128 
  129 static device_method_t tca64xx_methods[] = {
  130         DEVMETHOD(device_probe,         tca64xx_probe),
  131         DEVMETHOD(device_attach,        tca64xx_attach),
  132         DEVMETHOD(device_detach,        tca64xx_detach),
  133 
  134         /* GPIO methods */
  135         DEVMETHOD(gpio_get_bus,         tca64xx_get_bus),
  136         DEVMETHOD(gpio_pin_max,         tca64xx_pin_max),
  137         DEVMETHOD(gpio_pin_getcaps,     tca64xx_pin_getcaps),
  138         DEVMETHOD(gpio_pin_getflags,    tca64xx_pin_getflags),
  139         DEVMETHOD(gpio_pin_setflags,    tca64xx_pin_setflags),
  140         DEVMETHOD(gpio_pin_getname,     tca64xx_pin_getname),
  141         DEVMETHOD(gpio_pin_get,         tca64xx_pin_get),
  142         DEVMETHOD(gpio_pin_set,         tca64xx_pin_set),
  143         DEVMETHOD(gpio_pin_toggle,      tca64xx_pin_toggle),
  144 
  145         DEVMETHOD_END
  146 };
  147 
  148 static driver_t tca64xx_driver = {
  149         "gpio",
  150         tca64xx_methods,
  151         sizeof(struct tca64xx_softc)
  152 };
  153 
  154 DRIVER_MODULE(tca64xx, iicbus, tca64xx_driver, 0, 0);
  155 MODULE_VERSION(tca64xx, 1);
  156 
  157 static struct ofw_compat_data compat_data[] = {
  158         {"nxp,pca9555", TCA6416_TYPE},
  159         {"ti,tca6408",  TCA6408_TYPE},
  160         {"ti,tca6416",  TCA6416_TYPE},
  161         {"ti,tca9539",  TCA6416_TYPE},
  162         {0,0}
  163 };
  164 
  165 static int
  166 tca64xx_read(device_t dev, uint8_t reg, uint8_t *data)
  167 {
  168         struct iic_msg msgs[2];
  169         struct tca64xx_softc *sc;
  170         int error;
  171 
  172         sc = device_get_softc(dev);
  173         if (data == NULL)
  174                 return (EINVAL);
  175 
  176         msgs[0].slave = sc->addr;
  177         msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
  178         msgs[0].len = 1;
  179         msgs[0].buf = &reg;
  180 
  181         msgs[1].slave = sc->addr;
  182         msgs[1].flags = IIC_M_RD;
  183         msgs[1].len = 1;
  184         msgs[1].buf = data;
  185 
  186         error = iicbus_transfer_excl(dev, msgs, 2, IIC_WAIT);
  187         return (iic2errno(error));
  188 }
  189 
  190 static int
  191 tca64xx_write(device_t dev, uint8_t reg, uint8_t val)
  192 {
  193         struct iic_msg msg;
  194         struct tca64xx_softc *sc;
  195         int error;
  196         uint8_t buffer[2] = {reg, val};
  197 
  198         sc = device_get_softc(dev);
  199 
  200         msg.slave = sc->addr;
  201         msg.flags = IIC_M_WR;
  202         msg.len = 2;
  203         msg.buf = buffer;
  204 
  205         error = iicbus_transfer_excl(dev, &msg, 1, IIC_WAIT);
  206         return (iic2errno(error));
  207 }
  208 
  209 static int
  210 tca64xx_probe(device_t dev)
  211 {
  212         const struct ofw_compat_data *compat_ptr;
  213 
  214         if (!ofw_bus_status_okay(dev))
  215                 return (ENXIO);
  216 
  217         compat_ptr = ofw_bus_search_compatible(dev, compat_data);
  218 
  219         switch (compat_ptr->ocd_data) {
  220         case TCA6416_TYPE:
  221                 device_set_desc(dev, "TCA6416 I/O expander");
  222                 break;
  223         case TCA6408_TYPE:
  224                 device_set_desc(dev, "TCA6408 I/O expander");
  225                 break;
  226         default:
  227                 return (ENXIO);
  228         }
  229 
  230         return (BUS_PROBE_DEFAULT);
  231 }
  232 
  233 static int
  234 tca64xx_attach(device_t dev)
  235 {
  236         struct tca64xx_softc *sc;
  237         const struct ofw_compat_data *compat_ptr;
  238 
  239         sc = device_get_softc(dev);
  240         compat_ptr = ofw_bus_search_compatible(dev, compat_data);
  241 
  242         switch (compat_ptr->ocd_data) {
  243         case TCA6416_TYPE:
  244                 sc->in_port_reg = TCA6416_IN_PORT_REG;
  245                 sc->out_port_reg = TCA6416_OUT_PORT_REG;
  246                 sc->polarity_inv_reg = TCA6416_POLARITY_INV_REG;
  247                 sc->conf_reg = TCA6416_CONF_REG;
  248                 sc->num_pins = TCA6416_NUM_PINS;
  249                 break;
  250         case TCA6408_TYPE:
  251                 sc->in_port_reg = TCA6408_IN_PORT_REG;
  252                 sc->out_port_reg = TCA6408_OUT_PORT_REG;
  253                 sc->polarity_inv_reg = TCA6408_POLARITY_INV_REG;
  254                 sc->conf_reg = TCA6408_CONF_REG;
  255                 sc->num_pins = TCA6408_NUM_PINS;
  256                 break;
  257         default:
  258                 __assert_unreachable();
  259         }
  260 
  261         sc->pin_caps = TCA64XX_PIN_CAPS;
  262         sc->chip = compat_ptr->ocd_data;
  263         sc->dev = dev;
  264         sc->addr = iicbus_get_addr(dev);
  265 
  266         mtx_init(&sc->mtx, "tca64xx gpio", "gpio", MTX_DEF);
  267         sc->busdev = gpiobus_attach_bus(dev);
  268         if (sc->busdev == NULL) {
  269                 device_printf(dev, "Could not create busdev child\n");
  270                 return (ENXIO);
  271         }
  272 
  273         OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
  274 
  275 #ifdef DEBUG
  276         switch (sc->chip) {
  277         case TCA6416_TYPE:
  278                 tca6416_regdump_setup(dev);
  279                 break;
  280         case TCA6408_TYPE:
  281                 tca6408_regdump_setup(dev);
  282                 break;
  283         default:
  284                 __assert_unreachable();
  285         }
  286 #endif
  287 
  288         return (0);
  289 }
  290 
  291 static int
  292 tca64xx_detach(device_t dev)
  293 {
  294         struct tca64xx_softc *sc;
  295 
  296         sc = device_get_softc(dev);
  297 
  298         if (sc->busdev != NULL)
  299                 gpiobus_detach_bus(sc->busdev);
  300 
  301         mtx_destroy(&sc->mtx);
  302 
  303         return (0);
  304 }
  305 
  306 static device_t
  307 tca64xx_get_bus(device_t dev)
  308 {
  309         struct tca64xx_softc *sc;
  310 
  311         sc = device_get_softc(dev);
  312 
  313         return (sc->busdev);
  314 }
  315 
  316 static int
  317 tca64xx_pin_max(device_t dev __unused, int *maxpin)
  318 {
  319         struct tca64xx_softc *sc;
  320 
  321         sc = device_get_softc(dev);
  322 
  323         if (maxpin == NULL)
  324                 return (EINVAL);
  325 
  326         *maxpin = sc->num_pins-1;
  327 
  328         return (0);
  329 }
  330 
  331 static int
  332 tca64xx_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  333 {
  334         struct tca64xx_softc *sc;
  335 
  336         sc = device_get_softc(dev);
  337 
  338         if (pin >= sc->num_pins || caps == NULL)
  339                 return (EINVAL);
  340         *caps = sc->pin_caps;
  341 
  342         return (0);
  343 }
  344 
  345 static int
  346 tca64xx_pin_getflags(device_t dev, uint32_t pin, uint32_t *pflags)
  347 {
  348         int error;
  349         uint8_t bit, val, addr;
  350         struct tca64xx_softc *sc;
  351 
  352         sc = device_get_softc(dev);
  353 
  354         bit = TCA64XX_BIT_FROM_PIN(pin);
  355 
  356         if (pin >= sc->num_pins || pflags == NULL)
  357                 return (EINVAL);
  358 
  359         addr = TCA64XX_REG_ADDR(pin, sc->conf_reg);
  360         error = tca64xx_read(dev, addr, &val);
  361         if (error != 0)
  362                 return (error);
  363 
  364         *pflags = (val & (1 << bit)) ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT;
  365 
  366         addr = TCA64XX_REG_ADDR(pin, sc->polarity_inv_reg);
  367         error = tca64xx_read(dev, addr, &val);
  368         if (error != 0)
  369                 return (error);
  370 
  371         if (val & (1 << bit))
  372                 *pflags |= GPIO_PIN_INVIN;
  373 
  374         return (0);
  375 }
  376 
  377 static int
  378 tca64xx_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  379 {
  380         uint8_t bit, val, addr, pins, inv_val;
  381         int error;
  382         struct tca64xx_softc *sc;
  383 
  384         sc = device_get_softc(dev);
  385 
  386         pins = sc->num_pins;
  387         bit = TCA64XX_BIT_FROM_PIN(pin);
  388 
  389         if (pin >= pins)
  390                 return (EINVAL);
  391         mtx_lock(&sc->mtx);
  392 
  393         addr = TCA64XX_REG_ADDR(pin, sc->conf_reg);
  394         error = tca64xx_read(dev, addr, &val);
  395         if (error != 0)
  396                 goto fail;
  397 
  398         addr = TCA64XX_REG_ADDR(pin, sc->polarity_inv_reg);
  399         error = tca64xx_read(dev, addr, &inv_val);
  400         if (error != 0)
  401                 goto fail;
  402 
  403         if (flags & GPIO_PIN_INPUT)
  404                 val |= (1 << bit);
  405         else if (flags & GPIO_PIN_OUTPUT)
  406                 val &= ~(1 << bit);
  407 
  408         if (flags & GPIO_PIN_INVIN)
  409                 inv_val |= (1 << bit);
  410         else
  411                 inv_val &= ~(1 << bit);
  412 
  413         addr = TCA64XX_REG_ADDR(pin, sc->conf_reg);
  414         error = tca64xx_write(dev, addr, val);
  415         if (error != 0)
  416                 goto fail;
  417 
  418         addr = TCA64XX_REG_ADDR(pin, sc->polarity_inv_reg);
  419         error = tca64xx_write(dev, addr, inv_val);
  420 
  421 fail:
  422         mtx_unlock(&sc->mtx);
  423         return (error);
  424 }
  425 
  426 static int
  427 tca64xx_pin_getname(device_t dev, uint32_t pin, char *name)
  428 {
  429         struct tca64xx_softc *sc;
  430 
  431         sc = device_get_softc(dev);
  432 
  433         if (pin >= sc->num_pins || name == NULL)
  434                 return (EINVAL);
  435 
  436         snprintf(name, GPIOMAXNAME, "gpio_P%d%d", pin / TCA64XX_PINS_PER_REG,
  437             pin % TCA64XX_PINS_PER_REG);
  438 
  439         return (0);
  440 }
  441 
  442 static int
  443 tca64xx_pin_get(device_t dev, uint32_t pin, unsigned int *pval)
  444 {
  445         uint8_t bit, addr, pins, reg_pvalue;
  446         int error;
  447         struct tca64xx_softc *sc;
  448 
  449         sc = device_get_softc(dev);
  450 
  451         pins = sc->num_pins;
  452         addr = TCA64XX_REG_ADDR(pin, sc->in_port_reg);
  453         bit = TCA64XX_BIT_FROM_PIN(pin);
  454 
  455         if (pin >= pins || pval == NULL)
  456                 return (EINVAL);
  457 
  458         dbg_dev_printf(dev, "Reading pin %u pvalue.", pin);
  459 
  460         error = tca64xx_read(dev, addr, &reg_pvalue);
  461         if (error != 0)
  462                 return (error);
  463         *pval = reg_pvalue & (1 << bit) ? 1 : 0;
  464 
  465         return (0);
  466 }
  467 
  468 static int
  469 tca64xx_pin_set(device_t dev, uint32_t pin, unsigned int val)
  470 {
  471         uint8_t bit, addr, pins, value;
  472         int error;
  473         struct tca64xx_softc *sc;
  474 
  475         sc = device_get_softc(dev);
  476 
  477         pins = sc->num_pins;
  478         addr = TCA64XX_REG_ADDR(pin, sc->out_port_reg);
  479         bit = TCA64XX_BIT_FROM_PIN(pin);
  480 
  481         if (pin >= pins)
  482                 return (EINVAL);
  483 
  484         dbg_dev_printf(dev, "Setting pin: %u to %u\n", pin, val);
  485 
  486         mtx_lock(&sc->mtx);
  487 
  488         error = tca64xx_read(dev, addr, &value);
  489         if (error != 0) {
  490                 mtx_unlock(&sc->mtx);
  491                 dbg_dev_printf(dev, "Failed to read from register.\n");
  492                 return (error);
  493         }
  494 
  495         if (val != 0)
  496                 value |= (1 << bit);
  497         else
  498                 value &= ~(1 << bit);
  499 
  500         error = tca64xx_write(dev, addr, value);
  501         if (error != 0) {
  502                 mtx_unlock(&sc->mtx);
  503                 dbg_dev_printf(dev, "Could not write to register.\n");
  504                 return (error);
  505         }
  506 
  507         mtx_unlock(&sc->mtx);
  508 
  509         return (0);
  510 }
  511 
  512 static int
  513 tca64xx_pin_toggle(device_t dev, uint32_t pin)
  514 {
  515         int error;
  516         uint8_t bit, addr, pins, value;
  517         struct tca64xx_softc *sc;
  518 
  519         sc = device_get_softc(dev);
  520 
  521         pins = sc->num_pins;
  522         addr = TCA64XX_REG_ADDR(pin, sc->out_port_reg);
  523         bit = TCA64XX_BIT_FROM_PIN(pin);
  524 
  525         if (pin >= pins)
  526                 return (EINVAL);
  527 
  528         dbg_dev_printf(dev, "Toggling pin: %d\n", pin);
  529 
  530         mtx_lock(&sc->mtx);
  531 
  532         error = tca64xx_read(dev, addr, &value);
  533         if (error != 0) {
  534                 mtx_unlock(&sc->mtx);
  535                 dbg_dev_printf(dev, "Cannot read from register.\n");
  536                 return (error);
  537         }
  538 
  539         value ^= (1 << bit);
  540 
  541         error = tca64xx_write(dev, addr, value);
  542         if (error != 0) {
  543                 mtx_unlock(&sc->mtx);
  544                 dbg_dev_printf(dev, "Cannot write to register.\n");
  545                 return (error);
  546         }
  547 
  548         mtx_unlock(&sc->mtx);
  549 
  550         return (0);
  551 }
  552 
  553 #ifdef DEBUG
  554 static void
  555 tca6416_regdump_setup(device_t dev)
  556 {
  557         struct sysctl_ctx_list *ctx;
  558         struct sysctl_oid *node;
  559 
  560         ctx = device_get_sysctl_ctx(dev);
  561         node = device_get_sysctl_tree(dev);
  562 
  563         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "in_reg_1",
  564             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  565             TCA6416_IN_PORT_REG, tca64xx_regdump_sysctl, "A", "Input port 1");
  566         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "in_reg_2",
  567             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  568             TCA6416_IN_PORT_REG | 1, tca64xx_regdump_sysctl, "A",
  569             "Input port 2");
  570         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "out_reg_1",
  571             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  572             TCA6416_OUT_PORT_REG, tca64xx_regdump_sysctl, "A",
  573             "Output port 1");
  574         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "out_reg_2",
  575             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  576             TCA6416_OUT_PORT_REG | 1, tca64xx_regdump_sysctl, "A",
  577             "Output port 2");
  578         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "pol_inv_1",
  579             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  580             TCA6416_POLARITY_INV_REG, tca64xx_regdump_sysctl, "A",
  581             "Polarity inv 1");
  582         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "pol_inv_2",
  583             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  584             TCA6416_POLARITY_INV_REG | 1, tca64xx_regdump_sysctl, "A",
  585             "Polarity inv 2");
  586         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "conf_reg_1",
  587             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  588             TCA6416_CONF_REG, tca64xx_regdump_sysctl, "A", "Configuration 1");
  589         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "conf_reg_2",
  590             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  591             TCA6416_CONF_REG | 1, tca64xx_regdump_sysctl, "A",
  592             "Configuration 2");
  593 }
  594 
  595 static void
  596 tca6408_regdump_setup(device_t dev)
  597 {
  598         struct sysctl_ctx_list *ctx;
  599         struct sysctl_oid *node;
  600 
  601         ctx = device_get_sysctl_ctx(dev);
  602         node = device_get_sysctl_tree(dev);
  603 
  604         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "in_reg_1",
  605             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  606             TCA6408_IN_PORT_REG, tca64xx_regdump_sysctl, "A", "Input port 1");
  607         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "out_reg_1",
  608             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  609             TCA6408_OUT_PORT_REG, tca64xx_regdump_sysctl, "A",
  610             "Output port 1");
  611         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "pol_inv_1",
  612             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  613             TCA6408_POLARITY_INV_REG, tca64xx_regdump_sysctl,
  614             "A", "Polarity inv 1");
  615         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(node), OID_AUTO, "conf_reg_1",
  616             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  617             TCA6408_CONF_REG, tca64xx_regdump_sysctl, "A", "Configuration 1");
  618 }
  619 
  620 static int
  621 tca64xx_regdump_sysctl(SYSCTL_HANDLER_ARGS)
  622 {
  623         device_t dev;
  624         char buf[5];
  625         int len, error;
  626         uint8_t reg, regval;
  627 
  628         dev = (device_t)arg1;
  629         reg = (uint8_t)arg2;
  630 
  631         error = tca64xx_read(dev, reg, &regval);
  632         if (error != 0) {
  633                 return (error);
  634         }
  635 
  636         len = snprintf(buf, 5, "0x%02x", regval);
  637 
  638         error = sysctl_handle_string(oidp, buf, len, req);
  639 
  640         return (error);
  641 }
  642 #endif

Cache object: eef112cdc5999160993eceb511c7808b


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