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