Annotation of src/sys/dev/i2c/si70xx.c, Revision 1.6.4.1
1.6.4.1 ! thorpej 1: /* $NetBSD: si70xx.c,v 1.7 2021/06/15 04:39:49 mlelstv Exp $ */
1.1 christos 2:
3: /*
4: * Copyright (c) 2017 Brad Spencer <brad@anduin.eldar.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/cdefs.h>
1.6.4.1 ! thorpej 20: __KERNEL_RCSID(0, "$NetBSD: si70xx.c,v 1.7 2021/06/15 04:39:49 mlelstv Exp $");
1.1 christos 21:
22: /*
23: Driver for the Silicon Labs SI7013/SI7020/SI7021
24: */
25:
26: #include <sys/param.h>
27: #include <sys/systm.h>
28: #include <sys/kernel.h>
29: #include <sys/device.h>
30: #include <sys/module.h>
31: #include <sys/sysctl.h>
32: #include <sys/mutex.h>
33:
34: #include <dev/sysmon/sysmonvar.h>
35: #include <dev/i2c/i2cvar.h>
36: #include <dev/i2c/si70xxreg.h>
37: #include <dev/i2c/si70xxvar.h>
38:
39:
40: static uint8_t si70xx_crc(uint8_t *, size_t);
41: static int si70xx_poke(i2c_tag_t, i2c_addr_t, bool);
42: static int si70xx_match(device_t, cfdata_t, void *);
43: static void si70xx_attach(device_t, device_t, void *);
44: static int si70xx_detach(device_t, int);
45: static void si70xx_refresh(struct sysmon_envsys *, envsys_data_t *);
46: static int si70xx_update_status(struct si70xx_sc *);
47: static int si70xx_set_heateron(struct si70xx_sc *);
48: static int si70xx_set_resolution(struct si70xx_sc *, size_t);
49: static int si70xx_set_heatervalue(struct si70xx_sc *, size_t);
50: static int si70xx_verify_sysctl(SYSCTLFN_ARGS);
51: static int si70xx_verify_sysctl_resolution(SYSCTLFN_ARGS);
52: static int si70xx_verify_sysctl_heateron(SYSCTLFN_ARGS);
53: static int si70xx_verify_sysctl_heatervalue(SYSCTLFN_ARGS);
54:
55: #define SI70XX_DEBUG
56: #ifdef SI70XX_DEBUG
57: #define DPRINTF(s, l, x) \
58: do { \
59: if (l <= s->sc_si70xxdebug) \
60: printf x; \
61: } while (/*CONSTCOND*/0)
62: #else
63: #define DPRINTF(s, l, x)
64: #endif
65:
66: CFATTACH_DECL_NEW(si70xxtemp, sizeof(struct si70xx_sc),
67: si70xx_match, si70xx_attach, si70xx_detach, NULL);
68:
69: static struct si70xx_sensor si70xx_sensors[] = {
70: {
71: .desc = "humidity",
72: .type = ENVSYS_SRELHUMIDITY,
73: },
74: {
75: .desc = "temperature",
76: .type = ENVSYS_STEMP,
77: }
78: };
79:
80: static struct si70xx_resolution si70xx_resolutions[] = {
81: {
82: .text = "12bit/14bit",
83: .num = 0x00,
84: },
85: {
86: .text = "8bit/12bit",
87: .num = 0x01,
88: },
89: {
90: .text = "10bit/13bit",
91: .num = 0x80,
92: },
93: {
94: .text = "11bit/11bit",
95: .num = 0x81,
96: }
97: };
98:
99: static const char si70xx_resolution_names[] =
100: "12bit/14bit, 8bit/12bit, 10bit/13bit, 11bit/11bit";
101:
102: static const int si70xx_heatervalues[] = {
103: 0xdeadbeef, 0x00, 0x01, 0x02, 0x04, 0x08, 0x0f
104: };
105:
106: int
107: si70xx_verify_sysctl(SYSCTLFN_ARGS)
108: {
109: int error, t;
110: struct sysctlnode node;
111:
112: node = *rnode;
113: t = *(int *)rnode->sysctl_data;
114: node.sysctl_data = &t;
115: error = sysctl_lookup(SYSCTLFN_CALL(&node));
116: if (error || newp == NULL)
117: return error;
118:
119: if (t < 0)
120: return EINVAL;
121:
122: *(int *)rnode->sysctl_data = t;
123:
124: return 0;
125: }
126:
127: int
128: si70xx_verify_sysctl_resolution(SYSCTLFN_ARGS)
129: {
130: char buf[SI70XX_RES_NAME];
131: struct si70xx_sc *sc;
132: struct sysctlnode node;
133: int error = 0;
134: size_t i;
135:
136: node = *rnode;
137: sc = node.sysctl_data;
138: (void) memcpy(buf, sc->sc_resolution, SI70XX_RES_NAME);
139: node.sysctl_data = buf;
140: error = sysctl_lookup(SYSCTLFN_CALL(&node));
141: if (error || newp == NULL)
142: return error;
143:
144: for (i = 0; i < __arraycount(si70xx_resolutions); i++) {
145: if (memcmp(node.sysctl_data, si70xx_resolutions[i].text,
146: SI70XX_RES_NAME) == 0)
147: break;
148: }
149:
150: if (i == __arraycount(si70xx_resolutions))
151: return EINVAL;
152: (void) memcpy(sc->sc_resolution, node.sysctl_data, SI70XX_RES_NAME);
153:
154: error = si70xx_set_resolution(sc, i);
155:
156: return error;
157: }
158:
159: int
160: si70xx_verify_sysctl_heateron(SYSCTLFN_ARGS)
161: {
162: int error;
163: bool t;
164: struct si70xx_sc *sc;
165: struct sysctlnode node;
166:
167: node = *rnode;
168: sc = node.sysctl_data;
169: t = sc->sc_heateron;
170: node.sysctl_data = &t;
171: error = sysctl_lookup(SYSCTLFN_CALL(&node));
172: if (error || newp == NULL)
173: return error;
174:
175: sc->sc_heateron = t;
176: error = si70xx_set_heateron(sc);
177:
178: return error;
179: }
180:
181: int
182: si70xx_verify_sysctl_heatervalue(SYSCTLFN_ARGS)
183: {
184: int error = 0, t;
185: struct si70xx_sc *sc;
186: struct sysctlnode node;
187:
188: node = *rnode;
189: sc = node.sysctl_data;
190: t = sc->sc_heaterval;
191: node.sysctl_data = &t;
192: error = sysctl_lookup(SYSCTLFN_CALL(&node));
193: if (error || newp == NULL)
194: return (error);
195:
196: if (t < 1 || t >= __arraycount(si70xx_heatervalues))
197: return (EINVAL);
198:
199: sc->sc_heaterval = t;
200: error = si70xx_set_heatervalue(sc, t);
201:
202: return error;
203: }
204:
1.3 christos 205: static uint8_t
206: si70xx_dir(uint8_t cmd, size_t len)
1.1 christos 207: {
1.3 christos 208: switch (cmd) {
1.1 christos 209: case SI70XX_READ_USER_REG_1:
210: case SI70XX_READ_HEATER_REG:
211: case SI70XX_READ_ID_PT1A:
212: case SI70XX_READ_ID_PT1B:
213: case SI70XX_READ_ID_PT2A:
214: case SI70XX_READ_ID_PT2B:
215: case SI70XX_READ_FW_VERA:
216: case SI70XX_READ_FW_VERB:
1.3 christos 217: return I2C_OP_READ_WITH_STOP;
1.1 christos 218: case SI70XX_WRITE_USER_REG_1:
219: case SI70XX_WRITE_HEATER_REG:
220: case SI70XX_RESET:
1.3 christos 221: return I2C_OP_WRITE_WITH_STOP;
1.1 christos 222: case SI70XX_MEASURE_RH_NOHOLD:
223: case SI70XX_MEASURE_TEMP_NOHOLD:
1.3 christos 224: return len == 0 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP;
1.1 christos 225: default:
1.3 christos 226: panic("%s: bad command %#x\n", __func__, cmd);
227: return 0;
1.1 christos 228: }
1.3 christos 229: }
230:
231: static int
232: si70xx_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t *cmd,
233: uint8_t clen, uint8_t *buf, size_t blen)
234: {
235: uint8_t dir;
236: if (clen == 0)
237: dir = blen == 0 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP;
238: else
239: dir = si70xx_dir(cmd[0], blen);
240:
241: if (dir == I2C_OP_READ || dir == I2C_OP_READ_WITH_STOP)
242: memset(buf, 0, blen);
1.1 christos 243:
244: return iic_exec(tag, dir, addr, cmd, clen, buf, blen, 0);
245: }
246:
247: static int
248: si70xx_cmd0(struct si70xx_sc *sc, uint8_t *buf, size_t blen)
249: {
250: return si70xx_cmd(sc->sc_tag, sc->sc_addr, NULL, 0, buf, blen);
251: }
252:
253: static int
254: si70xx_cmd1(struct si70xx_sc *sc, uint8_t cmd, uint8_t *buf, size_t blen)
255: {
256: return si70xx_cmd(sc->sc_tag, sc->sc_addr, &cmd, 1, buf, blen);
257: }
258:
259: static int
260: si70xx_cmd2(struct si70xx_sc *sc, uint8_t cmd1, uint8_t cmd2, uint8_t *buf,
261: size_t blen)
262: {
263: uint8_t cmd[] = { cmd1, cmd2 };
264: return si70xx_cmd(sc->sc_tag, sc->sc_addr, cmd, __arraycount(cmd),
265: buf, blen);
266: }
267:
268: static int
269: si70xx_set_heateron(struct si70xx_sc * sc)
270: {
271: int error;
272: uint8_t userregister;
273:
274: error = iic_acquire_bus(sc->sc_tag, 0);
275: if (error) {
276: DPRINTF(sc, 2, ("%s:%s: Failed to acquire bus: %d\n",
277: device_xname(sc->sc_dev), __func__, error));
278: return error;
279: }
280:
281: error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
282: if (error) {
283: DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
284: device_xname(sc->sc_dev), error));
285: goto out;
286: }
287:
288: DPRINTF(sc, 2, ("%s:%s: reg 1 values before: %#x\n",
289: device_xname(sc->sc_dev), __func__, userregister));
290: if (sc->sc_heateron) {
291: userregister |= SI70XX_HTRE_MASK;
292: } else {
293: userregister &= ~SI70XX_HTRE_MASK;
294: }
295: DPRINTF(sc, 2, ("%s:%s: user reg 1 values after: %#x\n",
296: device_xname(sc->sc_dev), __func__, userregister));
297:
298: error = si70xx_cmd1(sc, SI70XX_WRITE_USER_REG_1, &userregister, 1);
299: if (error) {
300: DPRINTF(sc, 2, ("%s: Failed to write user register 1: %d\n",
301: device_xname(sc->sc_dev), error));
302: }
303: out:
304: iic_release_bus(sc->sc_tag, 0);
305: return error;
306: }
307:
308: static int
309: si70xx_set_resolution(struct si70xx_sc * sc, size_t index)
310: {
311: int error;
312: uint8_t userregister;
313:
314: error = iic_acquire_bus(sc->sc_tag, 0);
315: if (error) {
316: DPRINTF(sc, 2, ("%s: Failed to acquire bus: %d\n",
317: device_xname(sc->sc_dev), error));
318: return error;
319: }
320:
321: error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
322: if (error) {
323: DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
324: device_xname(sc->sc_dev), error));
325: goto out;
326: }
327:
328: DPRINTF(sc, 2, ("%s:%s: reg 1 values before: %#x\n",
329: device_xname(sc->sc_dev), __func__, userregister));
330: userregister &= (~SI70XX_RESOLUTION_MASK);
331: userregister |= si70xx_resolutions[index].num;
332: DPRINTF(sc, 2, ("%s:%s: reg 1 values after: %#x\n",
333: device_xname(sc->sc_dev), __func__, userregister));
334:
335: error = si70xx_cmd1(sc, SI70XX_WRITE_USER_REG_1, &userregister, 1);
336: if (error) {
337: DPRINTF(sc, 2, ("%s: Failed to write user register 1: %d\n",
338: device_xname(sc->sc_dev), error));
339: }
340: out:
341: iic_release_bus(sc->sc_tag, 0);
342: return error;
343: }
344:
345: static int
346: si70xx_set_heatervalue(struct si70xx_sc * sc, size_t index)
347: {
348: int error;
349: uint8_t heaterregister;
350:
351: error = iic_acquire_bus(sc->sc_tag, 0);
352: if (error) {
353: DPRINTF(sc, 2, ("%s: Failed to acquire bus: %d\n",
354: device_xname(sc->sc_dev), error));
355: return error;
356: }
357: error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
358: if (error) {
359: DPRINTF(sc, 2, ("%s: Failed to read heater register: %d\n",
360: device_xname(sc->sc_dev), error));
361: goto out;
362: }
363:
364: DPRINTF(sc, 2, ("%s:%s: heater values before: %#x\n",
365: device_xname(sc->sc_dev), __func__, heaterregister));
366: heaterregister &= ~SI70XX_HEATER_MASK;
367: heaterregister |= si70xx_heatervalues[index];
368: DPRINTF(sc, 2, ("%s:%s: heater values after: %#x\n",
369: device_xname(sc->sc_dev), __func__, heaterregister));
370:
1.3 christos 371: error = si70xx_cmd1(sc, SI70XX_WRITE_HEATER_REG, &heaterregister, 1);
1.1 christos 372: if (error) {
373: DPRINTF(sc, 2, ("%s: Failed to write heater register: %d\n",
374: device_xname(sc->sc_dev), error));
375: }
376: out:
377: iic_release_bus(sc->sc_tag, 0);
378: return error;
379: }
380:
381: static int
382: si70xx_update_heater(struct si70xx_sc *sc)
383: {
384: size_t i;
385: int error;
386: uint8_t heaterregister;
387:
388: error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
389: if (error) {
390: DPRINTF(sc, 2, ("%s: Failed to read heater register: %d\n",
391: device_xname(sc->sc_dev), error));
392: return error;
393: }
394:
395: DPRINTF(sc, 2, ("%s: read heater reg values: %02x\n",
396: device_xname(sc->sc_dev), heaterregister));
397:
398: uint8_t heat = heaterregister & SI70XX_HEATER_MASK;
399: for (i = 0; i < __arraycount(si70xx_heatervalues); i++) {
400: if (si70xx_heatervalues[i] == heat)
401: break;
402: }
403: sc->sc_heaterval = i != __arraycount(si70xx_heatervalues) ? i : 0;
404: return 0;
405: }
406:
407: static int
408: si70xx_update_user(struct si70xx_sc *sc)
409: {
410: size_t i;
411: int error;
412: uint8_t userregister;
413:
414: error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
415: if (error) {
416: DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
417: device_xname(sc->sc_dev), error));
418: return error;
419: }
420: DPRINTF(sc, 2, ("%s: read user reg 1 values: %#x\n",
421: device_xname(sc->sc_dev), userregister));
422:
423: uint8_t res = userregister & SI70XX_RESOLUTION_MASK;
424: for (i = 0; i < __arraycount(si70xx_resolutions); i++) {
425: if (si70xx_resolutions[i].num == res)
426: break;
427: }
428:
429: if (i != __arraycount(si70xx_resolutions)) {
430: memcpy(sc->sc_resolution, si70xx_resolutions[i].text,
431: SI70XX_RES_NAME);
432: } else {
433: snprintf(sc->sc_resolution, SI70XX_RES_NAME, "%02x", res);
434: }
435:
436: sc->sc_vddok = (userregister & SI70XX_VDDS_MASK) == 0;
437: sc->sc_heaterval = userregister & SI70XX_HTRE_MASK;
438: return 0;
439: }
440:
441: static int
442: si70xx_update_status(struct si70xx_sc *sc)
443: {
444: int error1 = si70xx_update_user(sc);
445: int error2 = si70xx_update_heater(sc);
446: return error1 ? error1 : error2;
447: }
448:
449: static uint8_t
450: si70xx_crc(uint8_t * data, size_t size)
451: {
452: uint8_t crc = 0;
453:
454: for (size_t i = 0; i < size; i++) {
455: crc ^= data[i];
456: for (size_t j = 8; j > 0; j--) {
457: if (crc & 0x80)
458: crc = (crc << 1) ^ 0x131;
459: else
460: crc <<= 1;
461: }
462: }
463: return crc;
464: }
465:
466: static int
467: si70xx_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
468: {
469: uint8_t reg = SI70XX_READ_USER_REG_1;
470: uint8_t buf;
471: int error;
472:
473: error = si70xx_cmd(tag, addr, ®, 1, &buf, 1);
474: if (matchdebug) {
475: printf("poke X 1: %d\n", error);
476: }
477: return error;
478: }
479:
480: static int
481: si70xx_sysctl_init(struct si70xx_sc *sc)
482: {
483: int error;
484: const struct sysctlnode *cnode;
485: int sysctlroot_num;
486:
487: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
488: 0, CTLTYPE_NODE, device_xname(sc->sc_dev),
489: SYSCTL_DESCR("si70xx controls"), NULL, 0, NULL, 0, CTL_HW,
490: CTL_CREATE, CTL_EOL)) != 0)
491: return error;
492:
493: sysctlroot_num = cnode->sysctl_num;
494:
495: #ifdef SI70XX_DEBUG
496: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
497: CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
498: SYSCTL_DESCR("Debug level"), si70xx_verify_sysctl, 0,
499: &sc->sc_si70xxdebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
500: CTL_EOL)) != 0)
501: return error;
502:
503: #endif
504:
505: #ifdef HAVE_I2C_EXECV
506: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
507: CTLFLAG_READWRITE, CTLTYPE_INT, "clockstretch",
508: SYSCTL_DESCR("Clockstretch value"), si70xx_verify_sysctl, 0,
509: &sc->sc_clockstretch, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
510: CTL_EOL)) != 0)
511: return error;
512: #endif
513:
514:
515: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
516: CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
517: SYSCTL_DESCR("The number of times to attempt to read the values"),
518: si70xx_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW,
519: sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
520: return error;
521:
522:
523: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
524: CTLFLAG_READONLY, CTLTYPE_STRING, "resolutions",
525: SYSCTL_DESCR("Valid resolutions"), 0, 0,
526: __UNCONST(si70xx_resolution_names),
527: sizeof(si70xx_resolution_names) + 1,
528: CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
529: return error;
530:
531: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
532: CTLFLAG_READWRITE, CTLTYPE_STRING, "resolution",
533: SYSCTL_DESCR("Resolution of RH and Temp"),
534: si70xx_verify_sysctl_resolution, 0, (void *) sc,
535: SI70XX_RES_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
536: return error;
537:
538: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
539: CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc",
540: SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc,
541: 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
542: return error;
543:
544: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
545: CTLFLAG_READONLY, CTLTYPE_BOOL, "vddok",
546: SYSCTL_DESCR("Vdd at least 1.9v"), NULL, 0, &sc->sc_vddok, 0,
547: CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
548: return error;
549:
550: if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
551: CTLFLAG_READWRITE, CTLTYPE_BOOL, "heateron",
552: SYSCTL_DESCR("Heater on"), si70xx_verify_sysctl_heateron, 0,
553: (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
554: return error;
555:
556: return sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
557: CTLFLAG_READWRITE, CTLTYPE_INT, "heaterstrength",
558: SYSCTL_DESCR("Heater strength 1 to 6"),
559: si70xx_verify_sysctl_heatervalue, 0, (void *)sc, 0, CTL_HW,
560: sysctlroot_num, CTL_CREATE, CTL_EOL);
561: }
562:
563: static int
564: si70xx_match(device_t parent, cfdata_t match, void *aux)
565: {
1.4 thorpej 566: struct i2c_attach_args *ia = aux;
567: int error, match_result;
1.1 christos 568: const bool matchdebug = false;
569:
1.4 thorpej 570: if (iic_use_direct_match(ia, match, NULL, &match_result))
571: return match_result;
1.1 christos 572:
1.4 thorpej 573: /* indirect config - check for configured address */
574: if (ia->ia_addr != SI70XX_TYPICAL_ADDR)
575: return 0;
1.1 christos 576:
577: /*
578: * Check to see if something is really at this i2c address. This will
579: * keep phantom devices from appearing
580: */
581: if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
582: if (matchdebug)
583: printf("in match acquire bus failed\n");
584: return 0;
585: }
586:
587: error = si70xx_poke(ia->ia_tag, ia->ia_addr, matchdebug);
588: iic_release_bus(ia->ia_tag, 0);
589:
1.4 thorpej 590: return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
1.1 christos 591: }
592:
593: static void
594: si70xx_attach(device_t parent, device_t self, void *aux)
595: {
596: struct si70xx_sc *sc;
597: struct i2c_attach_args *ia;
598: int error, i;
599: int ecount = 0;
600: uint8_t buf[8];
601: uint8_t testcrcpt1[4];
602: uint8_t testcrcpt2[4];
603: uint8_t crc1 = 0, crc2 = 0;
604: uint8_t readcrc1 = 0, readcrc2 = 0;
605: uint8_t fwversion, model;
606:
607: ia = aux;
608: sc = device_private(self);
609:
610: sc->sc_dev = self;
611: sc->sc_tag = ia->ia_tag;
612: sc->sc_addr = ia->ia_addr;
613: sc->sc_si70xxdebug = 0;
614: #ifdef HAVE_I2C_EXECV
615: sc->sc_clockstretch = 2048;
616: #endif
1.3 christos 617: sc->sc_readattempts = 25;
1.1 christos 618: sc->sc_ignorecrc = false;
619: sc->sc_sme = NULL;
620:
621: aprint_normal("\n");
622:
623: mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
624: sc->sc_numsensors = __arraycount(si70xx_sensors);
625:
626: if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
627: aprint_error_dev(self,
628: "Unable to create sysmon structure\n");
629: sc->sc_sme = NULL;
630: return;
631: }
632: if ((error = si70xx_sysctl_init(sc)) != 0) {
633: aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
634: goto out;
635: }
636:
637: error = iic_acquire_bus(sc->sc_tag, 0);
638: if (error) {
639: aprint_error_dev(self, "Could not acquire iic bus: %d\n",
640: error);
641: goto out;
642: }
643: error = si70xx_cmd1(sc, SI70XX_RESET, NULL, 0);
644: if (error != 0)
645: aprint_error_dev(self, "Reset failed: %d\n", error);
646:
647: delay(15000); /* 15 ms max */
648:
649: error = si70xx_cmd2(sc, SI70XX_READ_ID_PT1A, SI70XX_READ_ID_PT1B,
650: buf, 8);
651: if (error) {
652: aprint_error_dev(self, "Failed to read first part of ID: %d\n",
653: error);
654: ecount++;
655: }
656: testcrcpt1[0] = buf[0];
657: testcrcpt1[1] = buf[2];
658: testcrcpt1[2] = buf[4];
659: testcrcpt1[3] = buf[6];
660: readcrc1 = buf[7];
661: crc1 = si70xx_crc(testcrcpt1, 4);
662:
663: DPRINTF(sc, 2, ("%s: read 1 values: %02x%02x%02x%02x%02x%02x%02x%02x "
664: "- %02x\n", device_xname(sc->sc_dev), buf[0], buf[1],
665: buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
666: crc1));
667:
668: error = si70xx_cmd2(sc, SI70XX_READ_ID_PT2A, SI70XX_READ_ID_PT2B,
669: buf, 8);
670: if (error != 0) {
671: aprint_error_dev(self, "Failed to read second part of ID: %d\n",
672: error);
673: ecount++;
674: }
675: model = testcrcpt2[0] = buf[0];
676: testcrcpt2[1] = buf[1];
677: testcrcpt2[2] = buf[3];
678: testcrcpt2[3] = buf[4];
679: readcrc2 = buf[5];
680: crc2 = si70xx_crc(testcrcpt2, 4);
681:
682: DPRINTF(sc, 2, ("%s: read 2 values: %02x%02x%02x%02x%02x%02x - %02x\n",
683: device_xname(sc->sc_dev), buf[0], buf[1], buf[2],
684: buf[3], buf[4], buf[5], crc2));
685:
686: error = si70xx_cmd2(sc, SI70XX_READ_FW_VERA, SI70XX_READ_FW_VERB,
687: buf, 8);
688:
689: if (error) {
690: aprint_error_dev(self, "Failed to read firware version: %d\n",
691: error);
692: ecount++;
693: }
694: fwversion = buf[0];
695: DPRINTF(sc, 2, ("%s: read fw values: %#x\n", device_xname(sc->sc_dev),
696: fwversion));
697:
698: error = si70xx_update_status(sc);
699: iic_release_bus(sc->sc_tag, 0);
700: if (error != 0) {
701: aprint_error_dev(self, "Failed to update status: %x\n", error);
702: aprint_error_dev(self, "Unable to setup device\n");
703: goto out;
704: }
705:
706: for (i = 0; i < sc->sc_numsensors; i++) {
707: strlcpy(sc->sc_sensors[i].desc, si70xx_sensors[i].desc,
708: sizeof(sc->sc_sensors[i].desc));
709:
710: sc->sc_sensors[i].units = si70xx_sensors[i].type;
711: sc->sc_sensors[i].state = ENVSYS_SINVALID;
712:
713: DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
714: sc->sc_sensors[i].desc));
715:
716: error = sysmon_envsys_sensor_attach(sc->sc_sme,
717: &sc->sc_sensors[i]);
718: if (error) {
719: aprint_error_dev(self,
720: "Unable to attach sensor %d: %d\n", i, error);
1.6 jdc 721: sc->sc_sme = NULL;
1.1 christos 722: goto out;
723: }
724: }
725:
726: sc->sc_sme->sme_name = device_xname(sc->sc_dev);
727: sc->sc_sme->sme_cookie = sc;
728: sc->sc_sme->sme_refresh = si70xx_refresh;
729:
730: DPRINTF(sc, 2, ("si70xx_attach: registering with envsys\n"));
731:
732: if (sysmon_envsys_register(sc->sc_sme)) {
733: aprint_error_dev(self,
734: "unable to register with sysmon\n");
735: sysmon_envsys_destroy(sc->sc_sme);
736: sc->sc_sme = NULL;
737: return;
738: }
739: if (ecount != 0) {
740: aprint_normal_dev(self, "Could not read model, "
741: "probably an HTU21D\n");
742: return;
743: }
744:
745: char modelstr[64];
746: switch (model) {
747: case 0:
748: case 0xff:
749: snprintf(modelstr, sizeof(modelstr), "Engineering Sample");
1.5 mrg 750: break;
1.1 christos 751: case 13:
752: case 20:
753: case 21:
754: snprintf(modelstr, sizeof(modelstr), "SI70%d", model);
755: break;
756: default:
757: snprintf(modelstr, sizeof(modelstr), "Unknown SI70%d", model);
758: break;
759: }
760:
761: const char *fwversionstr;
762: switch (fwversion) {
763: case 0xff:
764: fwversionstr = "1.0";
765: break;
766: case 0x20:
767: fwversionstr = "2.0";
768: break;
769: default:
770: fwversionstr = "unknown";
771: break;
772: }
773:
774: aprint_normal_dev(self, "Silicon Labs Model: %s, "
775: "Firmware version: %s, "
776: "Serial number: %02x%02x%02x%02x%02x%02x%02x%02x%s",
777: modelstr, fwversionstr, testcrcpt1[0], testcrcpt1[1],
778: testcrcpt1[2], testcrcpt1[3], testcrcpt2[0], testcrcpt2[1],
779: testcrcpt2[2], testcrcpt2[3],
780: (crc1 == readcrc1 && crc2 == readcrc2) ? "\n" : " (bad crc)\n");
781: return;
782: out:
783: sysmon_envsys_destroy(sc->sc_sme);
784: sc->sc_sme = NULL;
785: }
786:
787: static int
788: si70xx_exec(struct si70xx_sc *sc, uint8_t cmd, envsys_data_t *edata)
789: {
790: int error;
791: int xdelay;
792: const char *name;
793: int64_t mul, offs;
794: uint8_t buf[3];
795:
796: switch (cmd) {
797: case SI70XX_MEASURE_RH_NOHOLD:
798: /*
799: * The published conversion for RH is: %RH =
800: * ((125 * RHCODE) / 65536) - 6
801: *
802: * The sysmon infrastructure for RH wants %RH *
803: * 10^6 The result will fit in 32 bits, but
804: * the intermediate values will not.
805: */
806: mul = 125000000;
807: offs = -6000000;
808: /*
809: * Conversion times for %RH in ms
810: *
811: * Typical Max
812: * 12-bit 10.0 12.0
813: * 11-bit 5.8 7.0
814: * 10-bit 3.7 4.5
815: * 8-bit 2.6 3.1
816: *
817: * A call to read %RH will also read temperature. The
818: * conversion time will be the amount of time above
819: * plus the amount of time for temperature below
820: */
821: xdelay = 10500;
822: name = "RH";
823: break;
824: case SI70XX_MEASURE_TEMP_NOHOLD:
825: /*
826: * The published conversion for temp is:
827: * degree C = ((175.72 * TEMPCODE) / 65536) -
828: * 46.85
829: *
830: * The sysmon infrastructure for temp wants
831: * microkelvin. This is simple, as degree C
832: * converts directly with K with simple
833: * addition. The result will fit in 32 bits,
834: * but the intermediate values will not.
835: */
836: mul = 175720000;
837: offs = 226300000;
838: /*
839: * Conversion times for temperature in ms
840: *
841: * Typical Max
842: * 14-bit 7.0 10.8
843: * 13-bit 4.0 6.2
844: * 12-bit 2.4 3.8
845: * 11-bit 1.5 2.4
846: */
847: xdelay = 4750;
848: name = "TEMP";
849: break;
850: default:
851: return EINVAL;
852: }
853:
854: #if HAVE_I2C_EXECV
855: memset(buf, 0, sizeof(buf));
856: error = iic_execv(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
857: &cmd, 1, buf, sizeof(buf), 0, I2C_ATTR_CLOCKSTRETCH,
858: sc->sc_clockstretch, I2C_ATTR_EOL);
859: #else
860: /*
861: * The lower level driver must support the ability to
862: * do a zero length read, otherwise this breaks
863: */
864: error = si70xx_cmd1(sc, cmd, buf, 0);
865: if (error) {
866: DPRINTF(sc, 2, ("%s: Failed to read NO HOLD %s %d %d\n",
867: device_xname(sc->sc_dev), name, 1, error));
868: return error;
869: }
870:
871: /*
872: * It will probably be at least this long... we would
873: * not have to do this sort of thing if clock
874: * stretching worked. Even this is a problem for the
875: * RPI without a patch to remove a [apparently] not
876: * needed KASSERT()
877: */
878: delay(xdelay);
879:
880: for (int aint = 0; aint < sc->sc_readattempts; aint++) {
881: error = si70xx_cmd0(sc, buf, sizeof(buf));
882: if (error == 0)
883: break;
884: DPRINTF(sc, 2, ("%s: Failed to read NO HOLD RH"
885: " %d %d\n", device_xname(sc->sc_dev), 2, error));
1.3 christos 886: delay(1000);
1.1 christos 887: }
888: #endif
889:
890: DPRINTF(sc, 2, ("%s: %s values: %02x%02x%02x - %02x\n",
891: device_xname(sc->sc_dev), name, buf[0], buf[1], buf[2],
892: si70xx_crc(buf, 2)));
893:
894: uint8_t crc;
895: if (sc->sc_ignorecrc) {
896: crc = buf[2];
897: } else {
898: crc = si70xx_crc(buf, 2);
899: }
900:
901: if (crc != buf[2]) {
902: DPRINTF(sc, 2, ("%s: Bad CRC for %s: %#x and %#x\n",
903: device_xname(sc->sc_dev), name, crc, buf[2]));
904: return EINVAL;
905: }
906:
907: uint16_t val16 = (buf[0] << 8) | buf[1];
908: uint64_t val64 = ((mul * val16) >> 16) + offs;
909: DPRINTF(sc, 2, ("%s: %s calculated values: %x %#jx\n",
910: device_xname(sc->sc_dev), name, val16, (uintmax_t)val64));
911: edata->value_cur = (uint32_t) val64;
912: edata->state = ENVSYS_SVALID;
913: return 0;
914: }
915:
916: static void
917: si70xx_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
918: {
919: struct si70xx_sc *sc;
920: int error;
921:
922: sc = sme->sme_cookie;
923: edata->state = ENVSYS_SINVALID;
924:
925: mutex_enter(&sc->sc_mutex);
926: error = iic_acquire_bus(sc->sc_tag, 0);
927: if (error) {
928: DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
929: device_xname(sc->sc_dev), error));
930: goto out;
931: }
932: error = si70xx_update_status(sc);
933: if (error) {
934: DPRINTF(sc, 2, ("%s: Failed to update status in refresh %d\n",
935: device_xname(sc->sc_dev), error));
936: goto out1;
937: }
938: switch (edata->sensor) {
939: case SI70XX_HUMIDITY_SENSOR:
1.3 christos 940: error = si70xx_exec(sc, SI70XX_MEASURE_RH_NOHOLD, edata);
1.1 christos 941: break;
942:
943: case SI70XX_TEMP_SENSOR:
1.3 christos 944: error = si70xx_exec(sc, SI70XX_MEASURE_TEMP_NOHOLD, edata);
1.1 christos 945: break;
946: default:
947: error = EINVAL;
948: break;
949: }
950:
951: if (error) {
952: DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
953: device_xname(sc->sc_dev), error));
954: }
955: out1:
956: iic_release_bus(sc->sc_tag, 0);
957: out:
958: mutex_exit(&sc->sc_mutex);
959: }
960:
961: static int
962: si70xx_detach(device_t self, int flags)
963: {
964: struct si70xx_sc *sc;
965:
966: sc = device_private(self);
967:
968: mutex_enter(&sc->sc_mutex);
969:
970: /* Remove the sensors */
1.6.4.1 ! thorpej 971: if (sc->sc_sme != NULL)
1.1 christos 972: sysmon_envsys_unregister(sc->sc_sme);
973: mutex_exit(&sc->sc_mutex);
974:
975: /* Remove the sysctl tree */
976: sysctl_teardown(&sc->sc_si70xxlog);
977:
978: /* Remove the mutex */
979: mutex_destroy(&sc->sc_mutex);
980:
981: return 0;
982: }
983:
984: MODULE(MODULE_CLASS_DRIVER, si70xxtemp, "i2cexec,sysmon_envsys");
985:
986: #ifdef _MODULE
987: #include "ioconf.c"
988: #endif
989:
990: static int
991: si70xxtemp_modcmd(modcmd_t cmd, void *opaque)
992: {
993:
994: switch (cmd) {
995: case MODULE_CMD_INIT:
996: #ifdef _MODULE
997: return config_init_component(cfdriver_ioconf_si70xxtemp,
998: cfattach_ioconf_si70xxtemp, cfdata_ioconf_si70xxtemp);
999: #else
1000: return 0;
1001: #endif
1002: case MODULE_CMD_FINI:
1003: #ifdef _MODULE
1.2 christos 1004: return config_fini_component(cfdriver_ioconf_si70xxtemp,
1.1 christos 1005: cfattach_ioconf_si70xxtemp, cfdata_ioconf_si70xxtemp);
1006: #else
1007: return 0;
1008: #endif
1009: default:
1010: return ENOTTY;
1011: }
1012: }
CVSweb <webmaster@jp.NetBSD.org>