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/ads111x.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
    3  *
    4  * Copyright (c) 2019 Ian Lepore.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * Driver for Texas Instruments ADS101x and ADS111x family i2c ADC chips.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include "opt_platform.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/endian.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/module.h>
   43 #include <sys/sx.h>
   44 #include <sys/sysctl.h>
   45 
   46 #ifdef FDT
   47 #include <dev/ofw/ofw_bus.h>
   48 #include <dev/ofw/ofw_bus_subr.h>
   49 #endif
   50 
   51 #include <dev/iicbus/iiconf.h>
   52 #include <dev/iicbus/iicbus.h>
   53 
   54 #include "iicbus_if.h"
   55 
   56 /*
   57  * Chip registers, bit definitions, shifting and masking values.
   58  */
   59 #define ADS111x_CONV                    0       /* Reg 0: Latest sample (ro) */
   60 
   61 #define ADS111x_CONF                    1       /* Reg 1: Config (rw) */
   62 #define   ADS111x_CONF_OS_SHIFT         15      /* Operational state */
   63 #define   ADS111x_CONF_MUX_SHIFT        12      /* Input mux setting */
   64 #define   ADS111x_CONF_GAIN_SHIFT        9      /* Programmable gain amp */
   65 #define   ADS111x_CONF_MODE_SHIFT        8      /* Operational mode */
   66 #define   ADS111x_CONF_RATE_SHIFT        5      /* Sample rate */
   67 #define   ADS111x_CONF_COMP_DISABLE      3      /* Comparator disable */
   68 
   69 #define ADS111x_LOTHRESH                2       /* Compare lo threshold (rw) */
   70 
   71 #define ADS111x_HITHRESH                3       /* Compare hi threshold (rw) */
   72 
   73 /*
   74  * On config write, the operational-state bit starts a measurement, on read it
   75  * indicates when the measurement process is complete/idle.
   76  */
   77 #define   ADS111x_CONF_MEASURE          (1u << ADS111x_CONF_OS_SHIFT)
   78 #define   ADS111x_CONF_IDLE             (1u << ADS111x_CONF_OS_SHIFT)
   79 
   80 /*
   81  * The default values for config items that are not per-channel.  Mostly, this
   82  * turns off the comparator on chips that have that feature, because this driver
   83  * doesn't support it directly.  However, the user is allowed to enable the
   84  * comparator and we'll leave it alone if they do.  That allows them connect the
   85  * alert pin to something and use the feature without any help from this driver.
   86  */
   87 #define ADS111x_CONF_DEFAULT    \
   88     ((1 << ADS111x_CONF_MODE_SHIFT) | ADS111x_CONF_COMP_DISABLE)
   89 #define ADS111x_CONF_USERMASK   0x001f
   90 
   91 /*
   92  * Per-channel defaults.  The chip only has one control register, and we load
   93  * per-channel values into it every time we make a measurement on that channel.
   94  * These are the default values for the control register from the datasheet, for
   95  * values we maintain on a per-channel basis.
   96  */
   97 #define DEFAULT_GAINIDX         2
   98 #define DEFAULT_RATEIDX         4
   99 
  100 /*
  101  * Full-scale ranges for each available amplifier setting, in microvolts.  The
  102  * ADS1x13 chips are fixed-range, the other chips contain a programmable gain
  103  * amplifier, and the full scale range is based on the amplifier setting.
  104  */
  105 static const u_int fixedranges[8] = {
  106         2048000, 2048000, 2048000, 2048000, 2048000, 2048000, 2048000, 2048000,
  107 };
  108 static const u_int gainranges[8] = {
  109         6144000, 4096000, 2048000, 1024000,  512000,  256000,  256000,  256000,
  110 };
  111 
  112 /* The highest value for the ADS101x chip is 0x7ff0, for ADS111x it's 0x7fff. */
  113 #define ADS101x_RANGEDIV        ((1 << 15) - 15)
  114 #define ADS111x_RANGEDIV        ((1 << 15) - 1)
  115 
  116 /* Samples per second; varies based on chip type. */
  117 static const u_int rates101x[8] = {128, 250, 490, 920, 1600, 2400, 3300, 3300};
  118 static const u_int rates111x[8] = {  8,  16,  32,  64,  128,  250,  475,  860};
  119 
  120 struct ads111x_channel {
  121         u_int gainidx;          /* Amplifier (full-scale range) config index */
  122         u_int rateidx;          /* Samples per second config index */
  123         bool  configured;       /* Channel has been configured */
  124 };
  125 
  126 #define ADS111x_MAX_CHANNELS    8
  127 
  128 struct ads111x_chipinfo {
  129         const char      *name;
  130         const u_int     *rangetab;
  131         const u_int     *ratetab;
  132         u_int           numchan;
  133         int             rangediv;
  134 };
  135 
  136 static struct ads111x_chipinfo ads111x_chip_infos[] = {
  137         { "ADS1013", fixedranges, rates101x, 1, ADS101x_RANGEDIV },
  138         { "ADS1014", gainranges,  rates101x, 1, ADS101x_RANGEDIV },
  139         { "ADS1015", gainranges,  rates101x, 8, ADS101x_RANGEDIV },
  140         { "ADS1113", fixedranges, rates111x, 1, ADS111x_RANGEDIV },
  141         { "ADS1114", gainranges,  rates111x, 1, ADS111x_RANGEDIV },
  142         { "ADS1115", gainranges,  rates111x, 8, ADS111x_RANGEDIV },
  143 };
  144 
  145 #ifdef FDT
  146 static struct ofw_compat_data compat_data[] = {
  147         {"ti,ads1013",   (uintptr_t)&ads111x_chip_infos[0]},
  148         {"ti,ads1014",   (uintptr_t)&ads111x_chip_infos[1]},
  149         {"ti,ads1015",   (uintptr_t)&ads111x_chip_infos[2]},
  150         {"ti,ads1113",   (uintptr_t)&ads111x_chip_infos[3]},
  151         {"ti,ads1114",   (uintptr_t)&ads111x_chip_infos[4]},
  152         {"ti,ads1115",   (uintptr_t)&ads111x_chip_infos[5]},
  153         {NULL,           (uintptr_t)NULL},
  154 };
  155 IICBUS_FDT_PNP_INFO(compat_data);
  156 #endif
  157 
  158 struct ads111x_softc {
  159         device_t        dev;
  160         struct sx       lock;
  161         int             addr;
  162         int             cfgword;
  163         const struct ads111x_chipinfo
  164                         *chipinfo;
  165         struct ads111x_channel
  166                         channels[ADS111x_MAX_CHANNELS];
  167 };
  168 
  169 static int
  170 ads111x_write_2(struct ads111x_softc *sc, int reg, int val) 
  171 {
  172         uint8_t data[3];
  173         struct iic_msg msgs[1];
  174         uint8_t slaveaddr;
  175 
  176         slaveaddr = iicbus_get_addr(sc->dev);
  177 
  178         data[0] = reg;
  179         be16enc(&data[1], val);
  180 
  181         msgs[0].slave = slaveaddr;
  182         msgs[0].flags = IIC_M_WR;
  183         msgs[0].len   = sizeof(data);
  184         msgs[0].buf   = data;
  185 
  186         return (iicbus_transfer_excl(sc->dev, msgs, nitems(msgs), IIC_WAIT));
  187 }
  188 
  189 static int
  190 ads111x_read_2(struct ads111x_softc *sc, int reg, int *val) 
  191 {
  192         int err;
  193         uint8_t data[2];
  194 
  195         err = iic2errno(iicdev_readfrom(sc->dev, reg, data, 2, IIC_WAIT));
  196         if (err == 0)
  197                 *val = (int16_t)be16dec(data);
  198 
  199         return (err);
  200 }
  201 
  202 static int
  203 ads111x_sample_voltage(struct ads111x_softc *sc, int channum, int *voltage) 
  204 {
  205         struct ads111x_channel *chan;
  206         int err, cfgword, convword, rate, retries, waitns;
  207         int64_t fsrange;
  208 
  209         chan = &sc->channels[channum];
  210 
  211         /* Ask the chip to do a one-shot measurement of the given channel. */
  212         cfgword = sc->cfgword |
  213             (1 << ADS111x_CONF_OS_SHIFT) |
  214             (channum << ADS111x_CONF_MUX_SHIFT) |
  215             (chan->gainidx << ADS111x_CONF_GAIN_SHIFT) |
  216             (chan->rateidx << ADS111x_CONF_RATE_SHIFT);
  217         if ((err = ads111x_write_2(sc, ADS111x_CONF, cfgword)) != 0)
  218                 return (err);
  219 
  220         /*
  221          * Calculate how long it will take to make the measurement at the
  222          * current sampling rate (round up).  The measurement averaging time
  223          * ranges from 300us to 125ms, so we yield the cpu while waiting.
  224          */
  225         rate = sc->chipinfo->ratetab[chan->rateidx];
  226         waitns = (1000000000 + rate - 1) / rate;
  227         err = pause_sbt("ads111x", nstosbt(waitns), 0, C_PREL(2));
  228         if (err != 0 && err != EWOULDBLOCK)
  229                 return (err);
  230 
  231         /*
  232          * In theory the measurement should be available now; we waited long
  233          * enough.  However, the chip times its averaging intervals using an
  234          * internal 1 MHz oscillator which likely isn't running at the same rate
  235          * as the system clock, so we have to double-check that the measurement
  236          * is complete before reading the result.  If it's not ready yet, yield
  237          * the cpu again for 5% of the time we originally calculated.
  238          *
  239          * Unlike most i2c slaves, this device does not auto-increment the
  240          * register number on reads, so we can't read both status and
  241          * measurement in one operation.
  242          */
  243         for (retries = 5; ; --retries) {
  244                 if (retries == 0)
  245                         return (EWOULDBLOCK);
  246                 if ((err = ads111x_read_2(sc, ADS111x_CONF, &cfgword)) != 0)
  247                         return (err);
  248                 if (cfgword & ADS111x_CONF_IDLE)
  249                         break;
  250                 pause_sbt("ads111x", nstosbt(waitns / 20), 0, C_PREL(2));
  251         }
  252 
  253         /* Retrieve the sample and convert it to microvolts. */
  254         if ((err = ads111x_read_2(sc, ADS111x_CONV, &convword)) != 0)
  255                 return (err);
  256         fsrange = sc->chipinfo->rangetab[chan->gainidx];
  257         *voltage = (int)((convword * fsrange ) / sc->chipinfo->rangediv);
  258 
  259         return (err);
  260 }
  261 
  262 static int
  263 ads111x_sysctl_gainidx(SYSCTL_HANDLER_ARGS)
  264 {
  265         struct ads111x_softc *sc;
  266         int chan, err, gainidx;
  267 
  268         sc = arg1;
  269         chan = arg2;
  270 
  271         gainidx = sc->channels[chan].gainidx;
  272         err = sysctl_handle_int(oidp, &gainidx, 0, req);
  273         if (err != 0 || req->newptr == NULL)
  274                 return (err);
  275         if (gainidx < 0 || gainidx > 7)
  276                 return (EINVAL);
  277         sx_xlock(&sc->lock);
  278         sc->channels[chan].gainidx = gainidx;
  279         sx_xunlock(&sc->lock);
  280 
  281         return (err);
  282 }
  283 
  284 static int
  285 ads111x_sysctl_rateidx(SYSCTL_HANDLER_ARGS)
  286 {
  287         struct ads111x_softc *sc;
  288         int chan, err, rateidx;
  289 
  290         sc = arg1;
  291         chan = arg2;
  292 
  293         rateidx = sc->channels[chan].rateidx;
  294         err = sysctl_handle_int(oidp, &rateidx, 0, req);
  295         if (err != 0 || req->newptr == NULL)
  296                 return (err);
  297         if (rateidx < 0 || rateidx > 7)
  298                 return (EINVAL);
  299         sx_xlock(&sc->lock);
  300         sc->channels[chan].rateidx = rateidx;
  301         sx_xunlock(&sc->lock);
  302 
  303         return (err);
  304 }
  305 
  306 static int
  307 ads111x_sysctl_voltage(SYSCTL_HANDLER_ARGS)
  308 {
  309         struct ads111x_softc *sc;
  310         int chan, err, voltage;
  311 
  312         sc = arg1;
  313         chan = arg2;
  314 
  315         if (req->oldptr != NULL) {
  316                 sx_xlock(&sc->lock);
  317                 err = ads111x_sample_voltage(sc, chan, &voltage);
  318                 sx_xunlock(&sc->lock);
  319                 if (err != 0) {
  320                         device_printf(sc->dev,
  321                             "conversion read failed, error %d\n", err);
  322                         return (err);
  323                 }
  324         }
  325         err = sysctl_handle_int(oidp, &voltage, 0, req);
  326         return (err);
  327 }
  328 
  329 static int
  330 ads111x_sysctl_config(SYSCTL_HANDLER_ARGS)
  331 {
  332         struct ads111x_softc *sc;
  333         int config, err;
  334 
  335         sc = arg1;
  336         config = sc->cfgword & ADS111x_CONF_USERMASK;
  337         err = sysctl_handle_int(oidp, &config, 0, req);
  338         if (err != 0 || req->newptr == NULL)
  339                 return (err);
  340         sx_xlock(&sc->lock);
  341         sc->cfgword = config & ADS111x_CONF_USERMASK;
  342         err = ads111x_write_2(sc, ADS111x_CONF, sc->cfgword);
  343         sx_xunlock(&sc->lock);
  344 
  345         return (err);
  346 }
  347 static int
  348 ads111x_sysctl_lothresh(SYSCTL_HANDLER_ARGS)
  349 {
  350         struct ads111x_softc *sc;
  351         int thresh, err;
  352 
  353         sc = arg1;
  354         if ((err = ads111x_read_2(sc, ADS111x_LOTHRESH, &thresh)) != 0)
  355                 return (err);
  356         err = sysctl_handle_int(oidp, &thresh, 0, req);
  357         if (err != 0 || req->newptr == NULL)
  358                 return (err);
  359         sx_xlock(&sc->lock);
  360         err = ads111x_write_2(sc, ADS111x_CONF, thresh);
  361         sx_xunlock(&sc->lock);
  362 
  363         return (err);
  364 }
  365 
  366 static int
  367 ads111x_sysctl_hithresh(SYSCTL_HANDLER_ARGS)
  368 {
  369         struct ads111x_softc *sc;
  370         int thresh, err;
  371 
  372         sc = arg1;
  373         if ((err = ads111x_read_2(sc, ADS111x_HITHRESH, &thresh)) != 0)
  374                 return (err);
  375         err = sysctl_handle_int(oidp, &thresh, 0, req);
  376         if (err != 0 || req->newptr == NULL)
  377                 return (err);
  378         sx_xlock(&sc->lock);
  379         err = ads111x_write_2(sc, ADS111x_CONF, thresh);
  380         sx_xunlock(&sc->lock);
  381 
  382         return (err);
  383 }
  384 
  385 static void
  386 ads111x_setup_channel(struct ads111x_softc *sc, int chan, int gainidx, int rateidx)
  387 {
  388         struct ads111x_channel *c;
  389         struct sysctl_ctx_list *ctx;
  390         struct sysctl_oid *chantree, *devtree;
  391         char chanstr[4];
  392 
  393         c = &sc->channels[chan];
  394         c->gainidx = gainidx;
  395         c->rateidx = rateidx;
  396 
  397         /*
  398          *  If setting up the channel for the first time, create channel's
  399          *  sysctl entries.  We might have already configured the channel if
  400          *  config data for it exists in both FDT and hints.
  401          */
  402 
  403         if (c->configured)
  404                 return;
  405 
  406         ctx = device_get_sysctl_ctx(sc->dev);
  407         devtree = device_get_sysctl_tree(sc->dev);
  408         snprintf(chanstr, sizeof(chanstr), "%d", chan);
  409         chantree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(devtree), OID_AUTO,
  410             chanstr, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "channel data");
  411         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(chantree), OID_AUTO,
  412             "gain_index", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT,
  413             sc, chan, ads111x_sysctl_gainidx, "I",
  414             "programmable gain amp setting, 0-7");
  415         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(chantree), OID_AUTO,
  416             "rate_index", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT,
  417             sc, chan, ads111x_sysctl_rateidx, "I", "sample rate setting, 0-7");
  418         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(chantree), OID_AUTO,
  419             "voltage",
  420             CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT, sc,
  421             chan, ads111x_sysctl_voltage, "I", "sampled voltage in microvolts");
  422 
  423         c->configured = true;
  424 }
  425 
  426 static void
  427 ads111x_add_channels(struct ads111x_softc *sc)
  428 {
  429         const char *name;
  430         uint32_t chan, gainidx, num_added, rateidx, unit;
  431         bool found;
  432 
  433 #ifdef FDT
  434         phandle_t child, node;
  435 
  436         /* Configure any channels that have FDT data. */
  437         num_added = 0;
  438         node = ofw_bus_get_node(sc->dev);
  439         for (child = OF_child(node); child != 0; child = OF_peer(child)) {
  440                 if (OF_getencprop(child, "reg", &chan, sizeof(chan)) == -1)
  441                         continue;
  442                 if (chan >= ADS111x_MAX_CHANNELS)
  443                         continue;
  444                 gainidx = DEFAULT_GAINIDX;
  445                 rateidx = DEFAULT_RATEIDX;
  446                 OF_getencprop(child, "ti,gain", &gainidx, sizeof(gainidx));
  447                 OF_getencprop(child, "ti,datarate", &rateidx, sizeof(rateidx));
  448                 ads111x_setup_channel(sc, chan, gainidx, rateidx);
  449                 ++num_added;
  450         }
  451 #else
  452         num_added = 0;
  453 #endif
  454 
  455         /* Configure any channels that have hint data. */
  456         name = device_get_name(sc->dev);
  457         unit = device_get_unit(sc->dev);
  458         for (chan = 0; chan < sc->chipinfo->numchan; ++chan) {
  459                 char resname[16];
  460                 found = false;
  461                 gainidx = DEFAULT_GAINIDX;
  462                 rateidx = DEFAULT_RATEIDX;
  463                 snprintf(resname, sizeof(resname), "%d.gain_index", chan);
  464                 if (resource_int_value(name, unit, resname, &gainidx) == 0)
  465                         found = true;
  466                 snprintf(resname, sizeof(resname), "%d.rate_index", chan);
  467                 if (resource_int_value(name, unit, resname, &rateidx) == 0)
  468                         found = true;
  469                 if (found) {
  470                         ads111x_setup_channel(sc, chan, gainidx, rateidx);
  471                         ++num_added;
  472                 }
  473         }
  474 
  475         /* If any channels were configured via FDT or hints, we're done. */
  476         if (num_added > 0)
  477                 return;
  478 
  479         /*
  480          * No channel config; add all possible channels using default values,
  481          * and let the user configure the ones they want on the fly via sysctl.
  482          */
  483         for (chan = 0; chan < sc->chipinfo->numchan; ++chan) {
  484                 gainidx = DEFAULT_GAINIDX;
  485                 rateidx = DEFAULT_RATEIDX;
  486                 ads111x_setup_channel(sc, chan, gainidx, rateidx);
  487         }
  488 }
  489 
  490 static const struct ads111x_chipinfo *
  491 ads111x_find_chipinfo(device_t dev)
  492 {
  493         const struct ads111x_chipinfo *info;
  494         const char *chiptype;
  495         int i;
  496 
  497 #ifdef FDT
  498         if (ofw_bus_status_okay(dev)) {
  499                 info = (struct ads111x_chipinfo*)
  500                     ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  501                 if (info != NULL)
  502                         return (info);
  503         }
  504 #endif
  505 
  506         /* For hinted devices, we must be told the chip type. */
  507         chiptype = NULL;
  508         resource_string_value(device_get_name(dev), device_get_unit(dev),
  509             "type", &chiptype);
  510         if (chiptype != NULL) {
  511                 for (i = 0; i < nitems(ads111x_chip_infos); ++i) {
  512                         info = &ads111x_chip_infos[i];
  513                         if (strcasecmp(chiptype, info->name) == 0)
  514                                 return (info);
  515                 }
  516         }
  517         return (NULL);
  518 }
  519 
  520 static int
  521 ads111x_probe(device_t dev)
  522 {
  523         const struct ads111x_chipinfo *info;
  524 
  525         info = ads111x_find_chipinfo(dev);
  526         if (info != NULL) {
  527                 device_set_desc(dev, info->name);
  528 #ifdef FDT
  529                 return (BUS_PROBE_DEFAULT);
  530 #else
  531                 return (BUS_PROBE_NOWILDCARD);
  532 #endif
  533         }
  534 
  535         return (ENXIO);
  536 }
  537 
  538 static int
  539 ads111x_attach(device_t dev)
  540 {
  541         struct ads111x_softc *sc;
  542         struct sysctl_ctx_list *ctx;
  543         struct sysctl_oid *tree;
  544         int err;
  545 
  546         sc = device_get_softc(dev);
  547         sc->dev = dev;
  548         sc->addr = iicbus_get_addr(dev);
  549         sc->cfgword = ADS111x_CONF_DEFAULT;
  550 
  551         sc->chipinfo = ads111x_find_chipinfo(sc->dev);
  552         if (sc->chipinfo == NULL) {
  553                 device_printf(dev,
  554                     "cannot get chipinfo (but it worked during probe)");
  555                 return (ENXIO);
  556         }
  557 
  558         /* Set the default chip config. */
  559         if ((err = ads111x_write_2(sc, ADS111x_CONF, sc->cfgword)) != 0) {
  560                 device_printf(dev, "cannot write chip config register\n");
  561                 return (err);
  562         }
  563 
  564         /* Add the sysctl handler to set the chip configuration register.  */
  565         ctx = device_get_sysctl_ctx(dev);
  566         tree = device_get_sysctl_tree(dev);
  567         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  568             "config", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, sc, 0,
  569             ads111x_sysctl_config, "I", "configuration register word");
  570         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  571             "lo_thresh", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, sc, 0,
  572             ads111x_sysctl_lothresh, "I", "comparator low threshold");
  573         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
  574             "hi_thresh", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, sc, 0,
  575             ads111x_sysctl_hithresh, "I", "comparator high threshold");
  576 
  577         /* Set up channels based on metadata or default config. */
  578         ads111x_add_channels(sc);
  579 
  580         sx_init(&sc->lock, "ads111x");
  581 
  582         return (0);
  583 }
  584 
  585 static int
  586 ads111x_detach(device_t dev)
  587 {
  588         struct ads111x_softc *sc;
  589 
  590         sc = device_get_softc(dev);
  591 
  592         sx_destroy(&sc->lock);
  593         return (0);
  594 }
  595 
  596 static device_method_t ads111x_methods[] = {
  597         DEVMETHOD(device_probe,         ads111x_probe),
  598         DEVMETHOD(device_attach,        ads111x_attach),
  599         DEVMETHOD(device_detach,        ads111x_detach),
  600 
  601         DEVMETHOD_END,
  602 };
  603 
  604 static driver_t ads111x_driver = {
  605         "ads111x",
  606         ads111x_methods,
  607         sizeof(struct ads111x_softc),
  608 };
  609 
  610 DRIVER_MODULE(ads111x, iicbus, ads111x_driver, NULL, NULL);
  611 MODULE_VERSION(ads111x, 1);
  612 MODULE_DEPEND(ads111x, iicbus, 1, 1, 1);

Cache object: 48b515aec5f60c46a3ec15945999724c


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