bmx280.c revision 1.3 1 /* $NetBSD: bmx280.c,v 1.3 2025/09/13 15:55:45 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2022 Brad Spencer <brad (at) 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>
20 __KERNEL_RCSID(0, "$NetBSD: bmx280.c,v 1.3 2025/09/13 15:55:45 thorpej Exp $");
21
22 /*
23 * Common driver for the Bosch BMP280/BME280 temperature, humidity (sometimes) and
24 * (usually barometric) pressure sensor. Calls out to specific frontends to
25 * the move bits around.
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/device.h>
32 #include <sys/module.h>
33 #include <sys/sysctl.h>
34 #include <sys/mutex.h>
35 #include <sys/proc.h>
36
37 #include <dev/sysmon/sysmonvar.h>
38 #include <dev/spi/spivar.h>
39 #include <dev/i2c/i2cvar.h>
40 #include <dev/ic/bmx280reg.h>
41 #include <dev/ic/bmx280var.h>
42
43
44 static void bmx280_store_raw_blob_tp(struct bmx280_sc *, uint8_t *);
45 static void bmx280_store_raw_blob_h(struct bmx280_sc *, uint8_t *);
46 void bmx280_attach(struct bmx280_sc *);
47 static void bmx280_refresh(struct sysmon_envsys *, envsys_data_t *);
48 static int bmx280_verify_sysctl(SYSCTLFN_ARGS);
49 static int bmx280_verify_sysctl_osrs(SYSCTLFN_ARGS);
50 static int bmx280_verify_sysctl_irr(SYSCTLFN_ARGS);
51
52 #define BMX280_DEBUG
53 #ifdef BMX280_DEBUG
54 #define DPRINTF(s, l, x) \
55 do { \
56 if (l <= s->sc_bmx280debug) \
57 printf x; \
58 } while (/*CONSTCOND*/0)
59 #else
60 #define DPRINTF(s, l, x)
61 #endif
62
63 static struct bmx280_sensor bmx280_sensors[] = {
64 {
65 .desc = "temperature",
66 .type = ENVSYS_STEMP,
67 },
68 {
69 .desc = "pressure",
70 .type = ENVSYS_PRESSURE,
71 },
72 {
73 .desc = "humidity",
74 .type = ENVSYS_SRELHUMIDITY,
75 }
76 };
77
78 static struct bmx280_osrs_list bmx280_osrs[] = {
79 {
80 .text = 1,
81 .mask = BMX280_OSRS_TP_VALUE_X1,
82 },
83 {
84 .text = 2,
85 .mask = BMX280_OSRS_TP_VALUE_X2,
86 },
87 {
88 .text = 4,
89 .mask = BMX280_OSRS_TP_VALUE_X4,
90 },
91 {
92 .text = 8,
93 .mask = BMX280_OSRS_TP_VALUE_X8,
94 },
95 {
96 .text = 16,
97 .mask = BMX280_OSRS_TP_VALUE_X16,
98 }
99 };
100
101 static struct bmx280_irr_list bmx280_irr[] = {
102 {
103 .text = 1,
104 .mask = BMX280_FILTER_VALUE_OFF,
105 },
106 {
107 .text = 2,
108 .mask = BMX280_FILTER_VALUE_2,
109 },
110 {
111 .text = 5,
112 .mask = BMX280_FILTER_VALUE_5,
113 },
114 {
115 .text = 11,
116 .mask = BMX280_FILTER_VALUE_11,
117 },
118 {
119 .text = 22,
120 .mask = BMX280_FILTER_VALUE_22,
121 }
122 };
123
124 static uint8_t
125 bmx280_osrs_text_to_mask(int t)
126 {
127 int i;
128 uint8_t m = 0;
129
130 for (i = 0; i < __arraycount(bmx280_osrs); i++) {
131 if (t == bmx280_osrs[i].text) {
132 m = bmx280_osrs[i].mask;
133 break;
134 }
135 }
136
137 return m;
138 }
139
140 static uint8_t
141 bmx280_irr_text_to_mask(int t)
142 {
143 int i;
144 uint8_t m = 0;
145
146 for (i = 0; i < __arraycount(bmx280_irr); i++) {
147 if (t == bmx280_irr[i].text) {
148 m = bmx280_irr[i].mask;
149 break;
150 }
151 }
152
153 return m;
154 }
155
156 int
157 bmx280_verify_sysctl(SYSCTLFN_ARGS)
158 {
159 int error, t;
160 struct sysctlnode node;
161
162 node = *rnode;
163 t = *(int *)rnode->sysctl_data;
164 node.sysctl_data = &t;
165 error = sysctl_lookup(SYSCTLFN_CALL(&node));
166 if (error || newp == NULL)
167 return error;
168
169 if (t < 0)
170 return EINVAL;
171
172 *(int *)rnode->sysctl_data = t;
173
174 return 0;
175 }
176
177 int
178 bmx280_verify_sysctl_osrs(SYSCTLFN_ARGS)
179 {
180 struct sysctlnode node;
181 int error = 0, t;
182 size_t i;
183
184 node = *rnode;
185 t = *(int *)rnode->sysctl_data;
186 node.sysctl_data = &t;
187 error = sysctl_lookup(SYSCTLFN_CALL(&node));
188 if (error || newp == NULL)
189 return error;
190
191 for (i = 0; i < __arraycount(bmx280_osrs); i++) {
192 if (t == bmx280_osrs[i].text) {
193 break;
194 }
195 }
196
197 if (i == __arraycount(bmx280_osrs))
198 return EINVAL;
199
200 *(int *)rnode->sysctl_data = t;
201
202 return error;
203 }
204
205 int
206 bmx280_verify_sysctl_irr(SYSCTLFN_ARGS)
207 {
208 struct sysctlnode node;
209 int error = 0, t;
210 size_t i;
211
212 node = *rnode;
213 t = *(int *)rnode->sysctl_data;
214 node.sysctl_data = &t;
215 error = sysctl_lookup(SYSCTLFN_CALL(&node));
216 if (error || newp == NULL)
217 return error;
218
219 for (i = 0; i < __arraycount(bmx280_irr); i++) {
220 if (t == bmx280_irr[i].text) {
221 break;
222 }
223 }
224
225 if (i == __arraycount(bmx280_irr))
226 return EINVAL;
227
228 *(int *)rnode->sysctl_data = t;
229
230 return error;
231 }
232
233 /* The datasheet was pretty vague as to the byte order...
234 * in fact, down right deceptive...
235 */
236
237 static void
238 bmx280_store_raw_blob_tp(struct bmx280_sc *sc, uint8_t *b) {
239 sc->sc_cal_blob.dig_T1 = (uint16_t)b[1] << 8;
240 sc->sc_cal_blob.dig_T1 = sc->sc_cal_blob.dig_T1 | (uint16_t)b[0];
241 sc->sc_cal_blob.dig_T2 = (int16_t)b[3] << 8;
242 sc->sc_cal_blob.dig_T2 = sc->sc_cal_blob.dig_T2 | (int16_t)b[2];
243 sc->sc_cal_blob.dig_T3 = (int16_t)b[5] << 8;
244 sc->sc_cal_blob.dig_T3 = sc->sc_cal_blob.dig_T3 | (int16_t)b[4];
245
246 sc->sc_cal_blob.dig_P1 = (uint16_t)b[7] << 8;
247 sc->sc_cal_blob.dig_P1 = sc->sc_cal_blob.dig_P1 | (uint16_t)b[6];
248 sc->sc_cal_blob.dig_P2 = (int16_t)b[9] << 8;
249 sc->sc_cal_blob.dig_P2 = sc->sc_cal_blob.dig_P2 | (int16_t)b[8];
250 sc->sc_cal_blob.dig_P3 = (int16_t)b[11] << 8;
251 sc->sc_cal_blob.dig_P3 = sc->sc_cal_blob.dig_P3 | (int16_t)b[10];
252 sc->sc_cal_blob.dig_P4 = (int16_t)b[13] << 8;
253 sc->sc_cal_blob.dig_P4 = sc->sc_cal_blob.dig_P4 | (int16_t)b[12];
254 sc->sc_cal_blob.dig_P5 = (int16_t)b[15] << 8;
255 sc->sc_cal_blob.dig_P5 = sc->sc_cal_blob.dig_P5 | (int16_t)b[14];
256 sc->sc_cal_blob.dig_P6 = (int16_t)b[17] << 8;
257 sc->sc_cal_blob.dig_P6 = sc->sc_cal_blob.dig_P6 | (int16_t)b[16];
258 sc->sc_cal_blob.dig_P7 = (int16_t)b[19] << 8;
259 sc->sc_cal_blob.dig_P7 = sc->sc_cal_blob.dig_P7 | (int16_t)b[18];
260 sc->sc_cal_blob.dig_P8 = (int16_t)b[21] << 8;
261 sc->sc_cal_blob.dig_P8 = sc->sc_cal_blob.dig_P8 | (int16_t)b[20];
262 sc->sc_cal_blob.dig_P9 = (int16_t)b[23] << 8;
263 sc->sc_cal_blob.dig_P9 = sc->sc_cal_blob.dig_P9 | (int16_t)b[22];
264 }
265
266 static void
267 bmx280_store_raw_blob_h(struct bmx280_sc *sc, uint8_t *b) {
268 sc->sc_cal_blob.dig_H1 = (uint8_t)b[0];
269 sc->sc_cal_blob.dig_H2 = (int16_t)b[2] << 8;
270 sc->sc_cal_blob.dig_H2 = sc->sc_cal_blob.dig_H2 | (int16_t)b[1];
271 sc->sc_cal_blob.dig_H3 = (uint8_t)b[3];
272 sc->sc_cal_blob.dig_H4 = ((int16_t)((b[4] << 4) | (b[5] & 0x0F)));
273 sc->sc_cal_blob.dig_H5 = (int16_t)b[6] << 4;
274 sc->sc_cal_blob.dig_H5 = sc->sc_cal_blob.dig_H5 | (((int16_t)b[5] & 0x00f0) >> 4);
275 sc->sc_cal_blob.dig_H6 = (int8_t)b[7];
276 }
277
278 static int
279 bmx280_sysctl_init(struct bmx280_sc *sc)
280 {
281 int error;
282 const struct sysctlnode *cnode;
283 int sysctlroot_num, sysctlwait_num;
284
285 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
286 0, CTLTYPE_NODE, device_xname(sc->sc_dev),
287 SYSCTL_DESCR("bmx280 controls"), NULL, 0, NULL, 0, CTL_HW,
288 CTL_CREATE, CTL_EOL)) != 0)
289 return error;
290
291 sysctlroot_num = cnode->sysctl_num;
292
293 #ifdef BMX280_DEBUG
294 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
295 CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
296 SYSCTL_DESCR("Debug level"), bmx280_verify_sysctl, 0,
297 &sc->sc_bmx280debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
298 CTL_EOL)) != 0)
299 return error;
300
301 /* It would be nice to have a CTLTYPE_SHORT */
302
303 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
304 CTLFLAG_READWRITE, CTLTYPE_BOOL, "dump_calibration",
305 SYSCTL_DESCR("Dumps the calibration values to the console"),
306 bmx280_verify_sysctl, 0,
307 &sc->sc_bmx280dump, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
308 CTL_EOL)) != 0)
309 return error;
310 #endif
311 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
312 CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
313 SYSCTL_DESCR("Read attempts"), bmx280_verify_sysctl, 0,
314 &sc->sc_readattempts, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
315 CTL_EOL)) != 0)
316 return error;
317
318 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
319 CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_t",
320 SYSCTL_DESCR("Temperature oversample"),
321 bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_t,
322 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
323 return error;
324
325 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
326 CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_p",
327 SYSCTL_DESCR("Pressure oversample"),
328 bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_p,
329 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
330 return error;
331
332 if (sc->sc_has_humidity) {
333 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
334 CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_h",
335 SYSCTL_DESCR("Humidity oversample"),
336 bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_h,
337 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
338 return error;
339 }
340
341 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
342 CTLFLAG_READWRITE, CTLTYPE_INT, "irr_samples",
343 SYSCTL_DESCR("IRR samples"),
344 bmx280_verify_sysctl_irr, 0, &sc->sc_irr_samples,
345 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
346 return error;
347
348 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
349 0, CTLTYPE_NODE, "waitfactor",
350 SYSCTL_DESCR("bmx280 wait factors"), NULL, 0, NULL, 0, CTL_HW,
351 sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
352 return error;
353 sysctlwait_num = cnode->sysctl_num;
354
355 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
356 CTLFLAG_READWRITE, CTLTYPE_INT, "t",
357 SYSCTL_DESCR("Temperature wait multiplier"),
358 bmx280_verify_sysctl, 0, &sc->sc_waitfactor_t,
359 0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
360 return error;
361
362 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
363 CTLFLAG_READWRITE, CTLTYPE_INT, "p",
364 SYSCTL_DESCR("Pressure wait multiplier"),
365 bmx280_verify_sysctl, 0, &sc->sc_waitfactor_p,
366 0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
367 return error;
368
369 if (sc->sc_has_humidity) {
370 if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
371 CTLFLAG_READWRITE, CTLTYPE_INT, "h",
372 SYSCTL_DESCR("Humidity wait multiplier"),
373 bmx280_verify_sysctl, 0, &sc->sc_waitfactor_h,
374 0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
375 return error;
376 }
377
378 return 0;
379 }
380 void
381 bmx280_attach(struct bmx280_sc *sc)
382 {
383 int error, i;
384 uint8_t reg, chip_id;
385 uint8_t buf[2];
386
387 sc->sc_bmx280dump = false;
388 sc->sc_has_humidity = false;
389 sc->sc_readattempts = 25;
390 sc->sc_osrs_t = 1;
391 sc->sc_osrs_p = 4;
392 sc->sc_osrs_h = 1;
393 sc->sc_irr_samples = 1;
394 sc->sc_previous_irr = 0xff;
395 sc->sc_waitfactor_t = 6;
396 sc->sc_waitfactor_p = 2;
397 sc->sc_waitfactor_h = 2;
398 sc->sc_sme = NULL;
399
400 aprint_normal("\n");
401
402 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
403 sc->sc_numsensors = __arraycount(bmx280_sensors);
404
405 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
406 aprint_error_dev(sc->sc_dev,
407 "Unable to create sysmon structure\n");
408 sc->sc_sme = NULL;
409 return;
410 }
411
412 error = sc->sc_funcs->acquire_bus(sc);
413 if (error) {
414 aprint_error_dev(sc->sc_dev, "Could not acquire the bus: %d\n",
415 error);
416 goto out;
417 }
418
419 buf[0] = BMX280_REGISTER_RESET;
420 buf[1] = BMX280_TRIGGER_RESET;
421 error = sc->sc_funcs->write_reg(sc, buf, 2);
422 if (error) {
423 aprint_error_dev(sc->sc_dev, "Failed to reset chip: %d\n",
424 error);
425 }
426
427 delay(30000);
428
429 reg = BMX280_REGISTER_ID;
430 error = sc->sc_funcs->read_reg(sc, reg, &chip_id, 1);
431 if (error) {
432 aprint_error_dev(sc->sc_dev, "Failed to read ID: %d\n",
433 error);
434 }
435
436 delay(1000);
437
438 DPRINTF(sc, 2, ("%s: read ID value: %02x\n",
439 device_xname(sc->sc_dev), chip_id));
440
441 if (chip_id == BMX280_ID_BME280) {
442 sc->sc_has_humidity = true;
443 }
444
445 uint8_t raw_blob_tp[24];
446 reg = BMX280_REGISTER_DIG_T1;
447 error = sc->sc_funcs->read_reg(sc, reg, raw_blob_tp, 24);
448 if (error) {
449 aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for tp: %d\n",
450 error);
451 }
452
453 if (sc->sc_bmx280debug > 0) {
454 for(int _d = 0;_d < 24;_d++) {
455 DPRINTF(sc, 0, ("%s: %d %02x\n",
456 device_xname(sc->sc_dev), _d, raw_blob_tp[_d]));
457 }
458 }
459
460 bmx280_store_raw_blob_tp(sc,raw_blob_tp);
461
462 if (sc->sc_has_humidity) {
463 uint8_t raw_blob_h[8];
464
465 reg = BMX280_REGISTER_DIG_H1;
466 error = sc->sc_funcs->read_reg(sc, reg, raw_blob_h, 1);
467 if (error) {
468 aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h1: %d\n",
469 error);
470 }
471
472 reg = BMX280_REGISTER_DIG_H2;
473 error = sc->sc_funcs->read_reg(sc, reg, &raw_blob_h[1], 7);
474 if (error) {
475 aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h2 - h6: %d\n",
476 error);
477 }
478
479 if (sc->sc_bmx280debug > 0) {
480 for(int _d = 0;_d < 8;_d++) {
481 DPRINTF(sc, 0, ("%s: %d %02x\n",
482 device_xname(sc->sc_dev), _d, raw_blob_h[_d]));
483 }
484 }
485
486 bmx280_store_raw_blob_h(sc,raw_blob_h);
487 }
488
489 sc->sc_funcs->release_bus(sc);
490
491 if (error != 0) {
492 aprint_error_dev(sc->sc_dev, "Unable to setup device\n");
493 goto out;
494 }
495
496 if ((error = bmx280_sysctl_init(sc)) != 0) {
497 aprint_error_dev(sc->sc_dev, "Can't setup sysctl tree (%d)\n", error);
498 goto out;
499 }
500
501 for (i = 0; i < sc->sc_numsensors; i++) {
502 if (sc->sc_has_humidity == false &&
503 bmx280_sensors[i].type == ENVSYS_SRELHUMIDITY) {
504 break;
505 }
506
507 strlcpy(sc->sc_sensors[i].desc, bmx280_sensors[i].desc,
508 sizeof(sc->sc_sensors[i].desc));
509
510 sc->sc_sensors[i].units = bmx280_sensors[i].type;
511 sc->sc_sensors[i].state = ENVSYS_SINVALID;
512
513 DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
514 sc->sc_sensors[i].desc));
515
516 error = sysmon_envsys_sensor_attach(sc->sc_sme,
517 &sc->sc_sensors[i]);
518 if (error) {
519 aprint_error_dev(sc->sc_dev,
520 "Unable to attach sensor %d: %d\n", i, error);
521 goto out;
522 }
523 }
524
525 sc->sc_sme->sme_name = device_xname(sc->sc_dev);
526 sc->sc_sme->sme_cookie = sc;
527 sc->sc_sme->sme_refresh = bmx280_refresh;
528
529 DPRINTF(sc, 2, ("bmx280_attach: registering with envsys\n"));
530
531 if (sysmon_envsys_register(sc->sc_sme)) {
532 aprint_error_dev(sc->sc_dev,
533 "unable to register with sysmon\n");
534 sysmon_envsys_destroy(sc->sc_sme);
535 sc->sc_sme = NULL;
536 return;
537 }
538
539 aprint_normal_dev(sc->sc_dev, "Bosch Sensortec %s, Chip ID: 0x%02x\n",
540 (chip_id == BMX280_ID_BMP280) ? "BMP280" : (chip_id == BMX280_ID_BME280) ? "BME280" : "Unknown chip",
541 chip_id);
542
543 return;
544 out:
545 sysmon_envsys_destroy(sc->sc_sme);
546 sc->sc_sme = NULL;
547 }
548
549 /* The conversion algorithms are taken from the BMP280 datasheet. The
550 * same algorithms are used with the BME280.
551 *
552 * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
553 *
554 * Section 3.11.3, page 21
555 *
556 */
557
558 static int32_t
559 bmx280_compensate_T_int32(struct bmx280_calibration_blob *b,
560 int32_t adc_T,
561 int32_t *t_fine)
562 {
563 int32_t var1, var2, T;
564 var1 = ((((adc_T>>3) - ((int32_t)b->dig_T1<<1))) * ((int32_t)b->dig_T2)) >> 11;
565 var2 = (((((adc_T>>4) - ((int32_t)b->dig_T1)) * ((adc_T>>4) - ((int32_t)b->dig_T1))) >> 12) *
566 ((int32_t)b->dig_T3)) >> 14;
567 *t_fine = var1 + var2;
568 T = (*t_fine * 5 + 128) >> 8;
569 return T;
570 }
571
572 /* Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
573 * Output value of 24674867 represents 24674867/256 = 96386.2 Pa = 963.862 hPa
574 */
575 static uint32_t
576 bmx280_compensate_P_int64(struct bmx280_calibration_blob *b,
577 int32_t adc_P,
578 int32_t t_fine)
579 {
580 int64_t var1, var2, p;
581 var1 = ((int64_t)t_fine) - 128000;
582 var2 = var1 * var1 * (int64_t)b->dig_P6;
583 var2 = var2 + ((var1*(int64_t)b->dig_P5)<<17);
584 var2 = var2 + (((int64_t)b->dig_P4)<<35);
585 var1 = ((var1 * var1 * (int64_t)b->dig_P3)>>8) + ((var1 * (int64_t)b->dig_P2)<<12);
586 var1 = (((((int64_t)1)<<47)+var1))*((int64_t)b->dig_P1)>>33;
587 if (var1 == 0) {
588 return 0; /* avoid exception caused by division by zero */
589 }
590 p = 1048576-adc_P;
591 p = (((p<<31)-var2)*3125)/var1;
592 var1 = (((int64_t)b->dig_P9) * (p>>13) * (p>>13)) >> 25;
593 var2 = (((int64_t)b->dig_P8) * p) >> 19;
594 p = ((p + var1 + var2) >> 8) + (((int64_t)b->dig_P7)<<4);
595 return (uint32_t)p;
596 }
597
598 /* Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
599 *
600 * Output value of 47445 represents 47445/1024 = 46.333 %RH
601 */
602 static uint32_t
603 bmx280_compensate_H_int32(struct bmx280_calibration_blob *b,
604 int32_t adc_H,
605 int32_t t_fine)
606 {
607 int32_t v_x1_u32r;
608 v_x1_u32r = (t_fine - ((int32_t)76800));
609 v_x1_u32r = (((((adc_H << 14) - (((int32_t)b->dig_H4) << 20) - (((int32_t)b->dig_H5) *
610 v_x1_u32r)) + ((int32_t)16384)) >> 15) * (((((((v_x1_u32r *
611 ((int32_t)b->dig_H6)) >> 10) * (((v_x1_u32r * ((int32_t)b->dig_H3)) >> 11) +
612 ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)b->dig_H2) +
613 8192) >> 14));
614 v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
615 ((int32_t)b->dig_H1)) >> 4));
616 v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
617 v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
618 return (uint32_t)(v_x1_u32r>>12);
619 }
620
621
622 static int
623 bmx280_set_control_and_trigger(struct bmx280_sc *sc,
624 uint8_t osrs_t_mask,
625 uint8_t osrs_p_mask,
626 uint8_t osrs_h_mask,
627 uint8_t filter_mask)
628 {
629 uint8_t cr[6];
630 int error;
631 int s = 0;
632
633 cr[0] = cr[1] = cr[2] = cr[3] = cr[4] = cr[5] = 0;
634
635 if (filter_mask != sc->sc_previous_irr) {
636 cr[s] = BMX280_REGISTER_CONFIG;
637 s++;
638 cr[s] = filter_mask << BMX280_CONFIG_FILTER_SHIFT;
639 s++;
640 sc->sc_previous_irr = filter_mask;
641 }
642 if (sc->sc_has_humidity) {
643 cr[s] = BMX280_REGISTER_CTRL_HUM;
644 s++;
645 cr[s] = osrs_h_mask;
646 s++;
647 }
648 cr[s] = BMX280_REGISTER_CTRL_MEAS;
649 s++;
650 cr[s] = osrs_t_mask << BMX280_CTRL_OSRS_T_SHIFT;
651 cr[s] = cr[s] | osrs_p_mask << BMX280_CTRL_OSRS_P_SHIFT;
652 cr[s] = cr[s] | BMX280_MODE_FORCED;
653 s++;
654 DPRINTF(sc, 2, ("%s: control register set up: num: %d ; %02x %02x ; %02x %02x ; %02x %02x\n",
655 device_xname(sc->sc_dev), s, cr[0], cr[1], cr[2], cr[3], cr[4], cr[5]));
656 error = sc->sc_funcs->write_reg(sc, cr, s);
657 if (error) {
658 DPRINTF(sc, 2, ("%s: write control registers: %d\n",
659 device_xname(sc->sc_dev), error));
660 error = EINVAL;
661 }
662
663 /* The wait needed is not well documented, so this is somewhat of a guess.
664 * There is an attempt with this to only wait as long as needed.
665 */
666
667 int p1, p2;
668
669 p1 = (osrs_t_mask * sc->sc_waitfactor_t) + (osrs_p_mask * sc->sc_waitfactor_p);
670 if (sc->sc_has_humidity) {
671 p1 = p1 + (osrs_h_mask * sc->sc_waitfactor_h);
672 }
673 p2 = mstohz(p1);
674 if (p2 == 0) {
675 p2 = 1;
676 }
677 /* Be careful with this... the print itself will cause extra delay */
678 DPRINTF(sc, 2, ("%s: p1: %d ; %d\n",
679 device_xname(sc->sc_dev), p1, p2));
680 kpause("b280mea",false,p2,NULL);
681
682 return error;
683 }
684
685 static int
686 bmx280_wait_for_data(struct bmx280_sc *sc)
687 {
688 uint8_t reg;
689 uint8_t running = 99;
690 int c = sc->sc_readattempts;
691 int error = 0, ierror;
692
693 reg = BMX280_REGISTER_STATUS;
694 do {
695 delay(1000);
696 ierror = sc->sc_funcs->read_reg(sc, reg, &running, 1);
697 if (ierror) {
698 DPRINTF(sc, 2, ("%s: Refresh failed to read back status: %d\n",
699 device_xname(sc->sc_dev), ierror));
700 error = EINVAL;
701 break;
702 }
703
704 DPRINTF(sc, 2, ("%s: Refresh status read back: %02x\n",
705 device_xname(sc->sc_dev), running));
706
707 c--;
708 } while (c > 0 && (running & BMX280_STATUS_MEASURING_MASK));
709
710 return error;
711 }
712
713 static int
714 bmx280_read_data(struct bmx280_sc *sc,
715 int32_t *temp,
716 int32_t *press,
717 int32_t *hum,
718 bool justtemp)
719 {
720 int error = 0, ierror;
721 int rlen, rtstart, rpstart, rhstart;
722 int x_temp, x_press, x_hum;
723 uint8_t raw_press_temp_hum[8], reg;
724
725 raw_press_temp_hum[0] = raw_press_temp_hum[1] =
726 raw_press_temp_hum[2] = raw_press_temp_hum[3] =
727 raw_press_temp_hum[4] = raw_press_temp_hum[5] =
728 raw_press_temp_hum[6] = raw_press_temp_hum[7] = 0;
729
730 if (justtemp) {
731 reg = BMX280_REGISTER_TEMP_MSB;
732 rlen = 3;
733 rtstart = 0;
734 rpstart = 0;
735 rhstart = 0;
736 } else {
737 reg = BMX280_REGISTER_PRESS_MSB;
738 if (sc->sc_has_humidity == false) {
739 rlen = 6;
740 } else {
741 rlen = 8;
742 }
743 rtstart = 3;
744 rpstart = 0;
745 rhstart = 6;
746 }
747
748 DPRINTF(sc, 2, ("%s: read data: reg: %02x ; len: %d ; tstart: %d ; pstart: %d\n",
749 device_xname(sc->sc_dev), reg, rlen, rtstart, rpstart));
750
751 ierror = sc->sc_funcs->read_reg(sc, reg, raw_press_temp_hum, rlen);
752 if (ierror) {
753 DPRINTF(sc, 2, ("%s: failed to read pressure and temp registers: %d\n",
754 device_xname(sc->sc_dev), ierror));
755 error = EINVAL;
756 goto out;
757 }
758
759 DPRINTF(sc, 2, ("%s: raw pressure, temp and hum: %02x %02x %02x - %02x %02x %02x - %02x %02x\n",
760 device_xname(sc->sc_dev),
761 raw_press_temp_hum[0], raw_press_temp_hum[1], raw_press_temp_hum[2],
762 raw_press_temp_hum[3], raw_press_temp_hum[4], raw_press_temp_hum[5],
763 raw_press_temp_hum[6],raw_press_temp_hum[7]));
764
765 x_temp = raw_press_temp_hum[rtstart] << 12;
766 x_temp = x_temp | (raw_press_temp_hum[rtstart + 1] << 4);
767 x_temp = x_temp | (raw_press_temp_hum[rtstart + 2] >> 4);
768
769 DPRINTF(sc, 1, ("%s: intermediate temp: %d (%04x)\n",
770 device_xname(sc->sc_dev), x_temp, x_temp));
771
772 *temp = x_temp;
773
774 *hum = 0;
775 *press = 0;
776
777 if (justtemp == false) {
778 x_press = raw_press_temp_hum[rpstart] << 12;
779 x_press = x_press | (raw_press_temp_hum[rpstart + 1] << 4);
780 x_press = x_press | (raw_press_temp_hum[rpstart + 2] >> 4);
781
782 DPRINTF(sc, 1, ("%s: intermediate pressure: %d (%04x)\n",
783 device_xname(sc->sc_dev), x_press, x_press));
784 *press = x_press;
785 }
786 if (sc->sc_has_humidity) {
787 x_hum = raw_press_temp_hum[rhstart] << 8;
788 x_hum = x_hum | raw_press_temp_hum[rhstart + 1];
789
790 DPRINTF(sc, 1, ("%s: intermediate humidity: %d (%02x)\n",
791 device_xname(sc->sc_dev), x_hum, x_hum));
792 *hum = x_hum;
793 }
794
795 out:
796 return error;
797 }
798
799 static void
800 bmx280_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
801 {
802 struct bmx280_sc *sc;
803 sc = sme->sme_cookie;
804 int error = 0;
805 int32_t t_fine;
806 int32_t m_temp, m_press, m_hum;
807 int32_t comp_temp;
808 uint32_t comp_press;
809 uint32_t comp_hum;
810 edata->state = ENVSYS_SINVALID;
811
812 /* Ya... just do this on a refresh... */
813
814 if (sc->sc_bmx280dump) {
815 DPRINTF(sc, 1, ("%s: dig_T1: %d %04x\n",__func__,sc->sc_cal_blob.dig_T1,sc->sc_cal_blob.dig_T1));
816 DPRINTF(sc, 1, ("%s: dig_T2: %d %04x\n",__func__,sc->sc_cal_blob.dig_T2,sc->sc_cal_blob.dig_T2));
817 DPRINTF(sc, 1, ("%s: dig_T3: %d %04x\n",__func__,sc->sc_cal_blob.dig_T3,sc->sc_cal_blob.dig_T3));
818 DPRINTF(sc, 1, ("%s: dig_P1: %d %04x\n",__func__,sc->sc_cal_blob.dig_P1,sc->sc_cal_blob.dig_P1));
819 DPRINTF(sc, 1, ("%s: dig_P2: %d %04x\n",__func__,sc->sc_cal_blob.dig_P2,sc->sc_cal_blob.dig_P2));
820 DPRINTF(sc, 1, ("%s: dig_P3: %d %04x\n",__func__,sc->sc_cal_blob.dig_P3,sc->sc_cal_blob.dig_P3));
821 DPRINTF(sc, 1, ("%s: dig_P4: %d %04x\n",__func__,sc->sc_cal_blob.dig_P4,sc->sc_cal_blob.dig_P4));
822 DPRINTF(sc, 1, ("%s: dig_P5: %d %04x\n",__func__,sc->sc_cal_blob.dig_P5,sc->sc_cal_blob.dig_P5));
823 DPRINTF(sc, 1, ("%s: dig_P6: %d %04x\n",__func__,sc->sc_cal_blob.dig_P6,sc->sc_cal_blob.dig_P6));
824 DPRINTF(sc, 1, ("%s: dig_P7: %d %04x\n",__func__,sc->sc_cal_blob.dig_P7,sc->sc_cal_blob.dig_P7));
825 DPRINTF(sc, 1, ("%s: dig_P8: %d %04x\n",__func__,sc->sc_cal_blob.dig_P8,sc->sc_cal_blob.dig_P8));
826 DPRINTF(sc, 1, ("%s: dig_P9: %d %04x\n",__func__,sc->sc_cal_blob.dig_P9,sc->sc_cal_blob.dig_P9));
827
828 if (sc->sc_has_humidity) {
829 DPRINTF(sc, 1, ("%s: dig_H1: %d %02x\n",__func__,sc->sc_cal_blob.dig_H1,sc->sc_cal_blob.dig_H1));
830 DPRINTF(sc, 1, ("%s: dig_H2: %d %04x\n",__func__,sc->sc_cal_blob.dig_H2,sc->sc_cal_blob.dig_H2));
831 DPRINTF(sc, 1, ("%s: dig_H3: %d %02x\n",__func__,sc->sc_cal_blob.dig_H3,sc->sc_cal_blob.dig_H3));
832 DPRINTF(sc, 1, ("%s: dig_H4: %d %04x\n",__func__,sc->sc_cal_blob.dig_H4,sc->sc_cal_blob.dig_H4));
833 DPRINTF(sc, 1, ("%s: dig_H5: %d %04x\n",__func__,sc->sc_cal_blob.dig_H5,sc->sc_cal_blob.dig_H5));
834 DPRINTF(sc, 1, ("%s: dig_H6: %d %02x\n",__func__,sc->sc_cal_blob.dig_H6,sc->sc_cal_blob.dig_H6));
835 }
836
837 sc->sc_bmx280dump = false;
838 }
839
840 mutex_enter(&sc->sc_mutex);
841 error = sc->sc_funcs->acquire_bus(sc);
842 if (error) {
843 DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
844 device_xname(sc->sc_dev), error));
845 goto out;
846 }
847
848 if (error == 0) {
849 switch (edata->sensor) {
850 case BMX280_TEMP_SENSOR:
851 /* A temperature reading does not need pressure */
852
853 error = bmx280_set_control_and_trigger(sc,
854 bmx280_osrs_text_to_mask(sc->sc_osrs_t),
855 0,
856 0,
857 bmx280_irr_text_to_mask(sc->sc_irr_samples));
858
859 if (error == 0) {
860 error = bmx280_wait_for_data(sc);
861
862 if (error == 0) {
863 error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, true);
864
865 if (error == 0) {
866 comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
867
868 DPRINTF(sc, 1, ("%s: Refresh compensated temp: %d - t_fine: %d\n",
869 device_xname(sc->sc_dev), comp_temp, t_fine));
870
871 /* comp_temp is in Celcius * 100. This converts it to microkelvin */
872
873 uint32_t q;
874
875 q = (uint32_t)comp_temp;
876 q = q + 27315;
877 q = q * 10000;
878
879 DPRINTF(sc, 1, ("%s: Refresh Q: %d\n", __func__, q));
880
881 edata->value_cur = q;
882 edata->state = ENVSYS_SVALID;
883 }
884 }
885 }
886 break;
887 case BMX280_PRESSURE_SENSOR:
888
889 /* Pressure needs the temp too */
890 error = bmx280_set_control_and_trigger(sc,
891 bmx280_osrs_text_to_mask(sc->sc_osrs_t),
892 bmx280_osrs_text_to_mask(sc->sc_osrs_p),
893 0,
894 bmx280_irr_text_to_mask(sc->sc_irr_samples));
895
896 if (error == 0) {
897 error = bmx280_wait_for_data(sc);
898
899 if (error == 0) {
900 error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, false);
901
902 if (error == 0) {
903 comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
904
905 DPRINTF(sc, 1, ("%s: Refresh compensated temp for pressure: %d - t_fine: %d\n",
906 device_xname(sc->sc_dev), comp_temp, t_fine));
907
908 comp_press = bmx280_compensate_P_int64(&sc->sc_cal_blob, m_press, t_fine);
909
910 DPRINTF(sc, 1, ("%s: Refresh compensated pressure: %d\n",
911 device_xname(sc->sc_dev), comp_press));
912
913 uint32_t q;
914
915 q = comp_press;
916 q = q / 256;
917 q = q * 100;
918
919 DPRINTF(sc, 1, ("%s: Refresh pressure Q: %d\n", __func__, q));
920
921 edata->value_cur = q;
922 edata->state = ENVSYS_SVALID;
923 }
924 }
925 }
926 break;
927
928 case BMX280_HUMIDITY_SENSOR:
929
930 /* Humidity wants temperature */
931
932 error = bmx280_set_control_and_trigger(sc,
933 bmx280_osrs_text_to_mask(sc->sc_osrs_t),
934 0,
935 bmx280_osrs_text_to_mask(sc->sc_osrs_h),
936 bmx280_irr_text_to_mask(sc->sc_irr_samples));
937
938 if (error == 0) {
939 error = bmx280_wait_for_data(sc);
940
941 if (error == 0) {
942 error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, false);
943
944 if (error == 0) {
945 comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
946
947 DPRINTF(sc, 1, ("%s: Refresh compensated temp for humidity: %d - t_fine: %d\n",
948 device_xname(sc->sc_dev), comp_temp, t_fine));
949
950 comp_hum = bmx280_compensate_H_int32(&sc->sc_cal_blob, m_hum, t_fine);
951
952 DPRINTF(sc, 2, ("%s: Refresh compensated humidity: %d\n",
953 device_xname(sc->sc_dev), comp_hum));
954
955 uint64_t q;
956
957 q = (uint64_t)comp_hum * 1000000;
958 DPRINTF(sc, 1, ("%s: Refresh humidity Q 1: %jd\n", __func__, (uintmax_t)q));
959 q = q / 1024;
960
961 DPRINTF(sc, 1, ("%s: Refresh humidity Q 2: %jd\n", __func__, (uintmax_t)q));
962
963 edata->value_cur = (uint32_t) q;
964 edata->state = ENVSYS_SVALID;
965 }
966 }
967 }
968 break;
969 }
970 }
971
972 if (error) {
973 DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
974 device_xname(sc->sc_dev), error));
975 }
976
977 sc->sc_funcs->release_bus(sc);
978 out:
979 mutex_exit(&sc->sc_mutex);
980 }
981
982 MODULE(MODULE_CLASS_DRIVER, bmx280thp, NULL);
983
984 #ifdef _MODULE
985 CFDRIVER_DECL(bmx280thp, DV_DULL, NULL);
986 #include "ioconf.c"
987 #endif
988
989 static int
990 bmx280thp_modcmd(modcmd_t cmd, void *opaque)
991 {
992
993 switch (cmd) {
994 case MODULE_CMD_INIT:
995 #ifdef _MODULE
996 return config_init_component(cfdriver_ioconf_bmx280thp,
997 cfattach_ioconf_bmx280thp, cfdata_ioconf_bmx280thp);
998 #else
999 return 0;
1000 #endif
1001 case MODULE_CMD_FINI:
1002 #ifdef _MODULE
1003 return config_fini_component(cfdriver_ioconf_bmx280thp,
1004 cfattach_ioconf_bmx280thp, cfdata_ioconf_bmx280thp);
1005 #else
1006 return 0;
1007 #endif
1008 default:
1009 return ENOTTY;
1010 }
1011 }
1012