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