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