1 /*        $NetBSD: bmx280.c,v 1.2 2023/04/16 17:16:45 brad Exp $      */
2 
3 /*
4  * Copyright (c) 2022 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>
20 __KERNEL_RCSID(0, "$NetBSD: bmx280.c,v 1.2 2023/04/16 17:16:45 brad 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
bmx280_osrs_text_to_mask(int 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
bmx280_irr_text_to_mask(int 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
bmx280_verify_sysctl(SYSCTLFN_ARGS)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
bmx280_verify_sysctl_osrs(SYSCTLFN_ARGS)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
bmx280_verify_sysctl_irr(SYSCTLFN_ARGS)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
bmx280_store_raw_blob_tp(struct bmx280_sc * sc,uint8_t * b)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
bmx280_store_raw_blob_h(struct bmx280_sc * sc,uint8_t * b)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
bmx280_sysctl_init(struct bmx280_sc * sc)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           sc->sc_func_attach = &bmx280_attach;
286 
287           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
288               0, CTLTYPE_NODE, device_xname(sc->sc_dev),
289               SYSCTL_DESCR("bmx280 controls"), NULL, 0, NULL, 0, CTL_HW,
290               CTL_CREATE, CTL_EOL)) != 0)
291                     return error;
292 
293           sysctlroot_num = cnode->sysctl_num;
294 
295 #ifdef BMX280_DEBUG
296           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
297               CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
298               SYSCTL_DESCR("Debug level"), bmx280_verify_sysctl, 0,
299               &sc->sc_bmx280debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
300               CTL_EOL)) != 0)
301                     return error;
302 
303           /* It would be nice to have a CTLTYPE_SHORT */
304 
305           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
306               CTLFLAG_READWRITE, CTLTYPE_BOOL, "dump_calibration",
307               SYSCTL_DESCR("Dumps the calibration values to the console"),
308               bmx280_verify_sysctl, 0,
309               &sc->sc_bmx280dump, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
310               CTL_EOL)) != 0)
311                     return error;
312 #endif
313           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
314               CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
315               SYSCTL_DESCR("Read attempts"), bmx280_verify_sysctl, 0,
316               &sc->sc_readattempts, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
317               CTL_EOL)) != 0)
318                     return error;
319 
320           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
321               CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_t",
322               SYSCTL_DESCR("Temperature oversample"),
323               bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_t,
324               0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
325                     return error;
326 
327           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
328               CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_p",
329               SYSCTL_DESCR("Pressure oversample"),
330               bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_p,
331               0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
332                     return error;
333 
334           if (sc->sc_has_humidity) {
335                     if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
336                         CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_h",
337                         SYSCTL_DESCR("Humidity oversample"),
338                         bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_h,
339                         0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
340                               return error;
341           }
342 
343           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
344               CTLFLAG_READWRITE, CTLTYPE_INT, "irr_samples",
345               SYSCTL_DESCR("IRR samples"),
346               bmx280_verify_sysctl_irr, 0, &sc->sc_irr_samples,
347               0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
348                     return error;
349 
350           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
351               0, CTLTYPE_NODE, "waitfactor",
352               SYSCTL_DESCR("bmx280 wait factors"), NULL, 0, NULL, 0, CTL_HW,
353               sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
354                     return error;
355           sysctlwait_num = cnode->sysctl_num;
356 
357           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
358               CTLFLAG_READWRITE, CTLTYPE_INT, "t",
359               SYSCTL_DESCR("Temperature wait multiplier"),
360               bmx280_verify_sysctl, 0, &sc->sc_waitfactor_t,
361               0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
362                     return error;
363 
364           if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
365               CTLFLAG_READWRITE, CTLTYPE_INT, "p",
366               SYSCTL_DESCR("Pressure wait multiplier"),
367               bmx280_verify_sysctl, 0, &sc->sc_waitfactor_p,
368               0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
369                     return error;
370 
371           if (sc->sc_has_humidity) {
372                     if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
373                         CTLFLAG_READWRITE, CTLTYPE_INT, "h",
374                         SYSCTL_DESCR("Humidity wait multiplier"),
375                         bmx280_verify_sysctl, 0, &sc->sc_waitfactor_h,
376                         0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
377                               return error;
378           }
379 
380           return 0;
381 }
382 void
bmx280_attach(struct bmx280_sc * sc)383 bmx280_attach(struct bmx280_sc *sc)
384 {
385           int error, i;
386           uint8_t reg, chip_id;
387           uint8_t buf[2];
388 
389           sc->sc_bmx280dump = false;
390           sc->sc_has_humidity = false;
391           sc->sc_readattempts = 25;
392           sc->sc_osrs_t = 1;
393           sc->sc_osrs_p = 4;
394           sc->sc_osrs_h = 1;
395           sc->sc_irr_samples = 1;
396           sc->sc_previous_irr = 0xff;
397           sc->sc_waitfactor_t = 6;
398           sc->sc_waitfactor_p = 2;
399           sc->sc_waitfactor_h = 2;
400           sc->sc_sme = NULL;
401 
402           aprint_normal("\n");
403 
404           mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
405           sc->sc_numsensors = __arraycount(bmx280_sensors);
406 
407           if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
408                     aprint_error_dev(sc->sc_dev,
409                         "Unable to create sysmon structure\n");
410                     sc->sc_sme = NULL;
411                     return;
412           }
413 
414           error = (*(sc->sc_func_acquire_bus))(sc);
415           if (error) {
416                     aprint_error_dev(sc->sc_dev, "Could not acquire the bus: %d\n",
417                         error);
418                     goto out;
419           }
420 
421           buf[0] = BMX280_REGISTER_RESET;
422           buf[1] = BMX280_TRIGGER_RESET;
423           error = (*(sc->sc_func_write_register))(sc, buf, 2);
424           if (error) {
425                     aprint_error_dev(sc->sc_dev, "Failed to reset chip: %d\n",
426                         error);
427           }
428 
429           delay(30000);
430 
431           reg = BMX280_REGISTER_ID;
432           error = (*(sc->sc_func_read_register))(sc, reg, &chip_id, 1);
433           if (error) {
434                     aprint_error_dev(sc->sc_dev, "Failed to read ID: %d\n",
435                         error);
436           }
437 
438           delay(1000);
439 
440           DPRINTF(sc, 2, ("%s: read ID value: %02x\n",
441               device_xname(sc->sc_dev), chip_id));
442 
443           if (chip_id == BMX280_ID_BME280) {
444                     sc->sc_has_humidity = true;
445           }
446 
447           uint8_t raw_blob_tp[24];
448           reg = BMX280_REGISTER_DIG_T1;
449           error = (*(sc->sc_func_read_register))(sc, reg, raw_blob_tp, 24);
450           if (error) {
451                     aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for tp: %d\n",
452                         error);
453           }
454 
455           if (sc->sc_bmx280debug > 0) {
456                     for(int _d = 0;_d < 24;_d++) {
457                               DPRINTF(sc, 0, ("%s: %d %02x\n",
458                                   device_xname(sc->sc_dev), _d, raw_blob_tp[_d]));
459                     }
460           }
461 
462           bmx280_store_raw_blob_tp(sc,raw_blob_tp);
463 
464           if (sc->sc_has_humidity) {
465                     uint8_t raw_blob_h[8];
466 
467                     reg = BMX280_REGISTER_DIG_H1;
468                     error = (*(sc->sc_func_read_register))(sc, reg, raw_blob_h, 1);
469                     if (error) {
470                               aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h1: %d\n",
471                                   error);
472                     }
473 
474                     reg = BMX280_REGISTER_DIG_H2;
475                     error = (*(sc->sc_func_read_register))(sc, reg, &raw_blob_h[1], 7);
476                     if (error) {
477                               aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h2 - h6: %d\n",
478                                   error);
479                     }
480 
481                     if (sc->sc_bmx280debug > 0) {
482                               for(int _d = 0;_d < 8;_d++) {
483                                         DPRINTF(sc, 0, ("%s: %d %02x\n",
484                                             device_xname(sc->sc_dev), _d, raw_blob_h[_d]));
485                               }
486                     }
487 
488                     bmx280_store_raw_blob_h(sc,raw_blob_h);
489           }
490 
491           (*(sc->sc_func_release_bus))(sc);
492 
493           if (error != 0) {
494                     aprint_error_dev(sc->sc_dev, "Unable to setup device\n");
495                     goto out;
496           }
497 
498           if ((error = bmx280_sysctl_init(sc)) != 0) {
499                     aprint_error_dev(sc->sc_dev, "Can't setup sysctl tree (%d)\n", error);
500                     goto out;
501           }
502 
503           for (i = 0; i < sc->sc_numsensors; i++) {
504                     if (sc->sc_has_humidity == false &&
505                         bmx280_sensors[i].type == ENVSYS_SRELHUMIDITY) {
506                               break;
507                     }
508 
509                     strlcpy(sc->sc_sensors[i].desc, bmx280_sensors[i].desc,
510                         sizeof(sc->sc_sensors[i].desc));
511 
512                     sc->sc_sensors[i].units = bmx280_sensors[i].type;
513                     sc->sc_sensors[i].state = ENVSYS_SINVALID;
514 
515                     DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
516                         sc->sc_sensors[i].desc));
517 
518                     error = sysmon_envsys_sensor_attach(sc->sc_sme,
519                         &sc->sc_sensors[i]);
520                     if (error) {
521                               aprint_error_dev(sc->sc_dev,
522                                   "Unable to attach sensor %d: %d\n", i, error);
523                               goto out;
524                     }
525           }
526 
527           sc->sc_sme->sme_name = device_xname(sc->sc_dev);
528           sc->sc_sme->sme_cookie = sc;
529           sc->sc_sme->sme_refresh = bmx280_refresh;
530 
531           DPRINTF(sc, 2, ("bmx280_attach: registering with envsys\n"));
532 
533           if (sysmon_envsys_register(sc->sc_sme)) {
534                     aprint_error_dev(sc->sc_dev,
535                               "unable to register with sysmon\n");
536                     sysmon_envsys_destroy(sc->sc_sme);
537                     sc->sc_sme = NULL;
538                     return;
539           }
540 
541           aprint_normal_dev(sc->sc_dev, "Bosch Sensortec %s, Chip ID: 0x%02x\n",
542               (chip_id == BMX280_ID_BMP280) ? "BMP280" : (chip_id == BMX280_ID_BME280) ? "BME280" : "Unknown chip",
543               chip_id);
544 
545           return;
546 out:
547           sysmon_envsys_destroy(sc->sc_sme);
548           sc->sc_sme = NULL;
549 }
550 
551 /* The conversion algorithms are taken from the BMP280 datasheet.  The
552  * same algorithms are used with the BME280.
553  *
554  * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
555  *
556  * Section 3.11.3, page 21
557  *
558  */
559 
560 static int32_t
bmx280_compensate_T_int32(struct bmx280_calibration_blob * b,int32_t adc_T,int32_t * t_fine)561 bmx280_compensate_T_int32(struct bmx280_calibration_blob *b,
562     int32_t adc_T,
563     int32_t *t_fine)
564 {
565           int32_t var1, var2, T;
566           var1 = ((((adc_T>>3) - ((int32_t)b->dig_T1<<1))) * ((int32_t)b->dig_T2)) >> 11;
567           var2 = (((((adc_T>>4) - ((int32_t)b->dig_T1)) * ((adc_T>>4) - ((int32_t)b->dig_T1))) >> 12) *
568               ((int32_t)b->dig_T3)) >> 14;
569           *t_fine = var1 + var2;
570           T = (*t_fine * 5 + 128) >> 8;
571           return T;
572 }
573 
574 /* Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
575  * Output value of 24674867 represents 24674867/256 = 96386.2 Pa = 963.862 hPa
576  */
577 static uint32_t
bmx280_compensate_P_int64(struct bmx280_calibration_blob * b,int32_t adc_P,int32_t t_fine)578 bmx280_compensate_P_int64(struct bmx280_calibration_blob *b,
579     int32_t adc_P,
580     int32_t t_fine)
581 {
582           int64_t var1, var2, p;
583           var1 = ((int64_t)t_fine) - 128000;
584           var2 = var1 * var1 * (int64_t)b->dig_P6;
585           var2 = var2 + ((var1*(int64_t)b->dig_P5)<<17);
586           var2 = var2 + (((int64_t)b->dig_P4)<<35);
587           var1 = ((var1 * var1 * (int64_t)b->dig_P3)>>8) + ((var1 * (int64_t)b->dig_P2)<<12);
588           var1 = (((((int64_t)1)<<47)+var1))*((int64_t)b->dig_P1)>>33;
589           if (var1 == 0) {
590                     return 0; /* avoid exception caused by division by zero */
591           }
592           p = 1048576-adc_P;
593           p = (((p<<31)-var2)*3125)/var1;
594           var1 = (((int64_t)b->dig_P9) * (p>>13) * (p>>13)) >> 25;
595           var2 = (((int64_t)b->dig_P8) * p) >> 19;
596           p = ((p + var1 + var2) >> 8) + (((int64_t)b->dig_P7)<<4);
597           return (uint32_t)p;
598 }
599 
600 /* Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
601  *
602  * Output value of 47445 represents 47445/1024 = 46.333 %RH
603  */
604 static uint32_t
bmx280_compensate_H_int32(struct bmx280_calibration_blob * b,int32_t adc_H,int32_t t_fine)605 bmx280_compensate_H_int32(struct bmx280_calibration_blob *b,
606     int32_t adc_H,
607     int32_t t_fine)
608 {
609           int32_t v_x1_u32r;
610           v_x1_u32r = (t_fine - ((int32_t)76800));
611           v_x1_u32r = (((((adc_H << 14) - (((int32_t)b->dig_H4) << 20) - (((int32_t)b->dig_H5) *
612               v_x1_u32r)) + ((int32_t)16384)) >> 15) * (((((((v_x1_u32r *
613               ((int32_t)b->dig_H6)) >> 10) * (((v_x1_u32r * ((int32_t)b->dig_H3)) >> 11) +
614               ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)b->dig_H2) +
615               8192) >> 14));
616           v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
617               ((int32_t)b->dig_H1)) >> 4));
618           v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
619           v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
620           return (uint32_t)(v_x1_u32r>>12);
621 }
622 
623 
624 static int
bmx280_set_control_and_trigger(struct bmx280_sc * sc,uint8_t osrs_t_mask,uint8_t osrs_p_mask,uint8_t osrs_h_mask,uint8_t filter_mask)625 bmx280_set_control_and_trigger(struct bmx280_sc *sc,
626     uint8_t osrs_t_mask,
627     uint8_t osrs_p_mask,
628     uint8_t osrs_h_mask,
629     uint8_t filter_mask)
630 {
631           uint8_t cr[6];
632           int error;
633           int s = 0;
634 
635           cr[0] = cr[1] = cr[2] = cr[3] = cr[4] = cr[5] = 0;
636 
637           if (filter_mask != sc->sc_previous_irr) {
638                     cr[s] = BMX280_REGISTER_CONFIG;
639                     s++;
640                     cr[s] = filter_mask << BMX280_CONFIG_FILTER_SHIFT;
641                     s++;
642                     sc->sc_previous_irr = filter_mask;
643           }
644           if (sc->sc_has_humidity) {
645                     cr[s] = BMX280_REGISTER_CTRL_HUM;
646                     s++;
647                     cr[s] = osrs_h_mask;
648                     s++;
649           }
650           cr[s] = BMX280_REGISTER_CTRL_MEAS;
651           s++;
652           cr[s] = osrs_t_mask << BMX280_CTRL_OSRS_T_SHIFT;
653           cr[s] = cr[s] | osrs_p_mask << BMX280_CTRL_OSRS_P_SHIFT;
654           cr[s] = cr[s] | BMX280_MODE_FORCED;
655           s++;
656           DPRINTF(sc, 2, ("%s: control register set up: num: %d ; %02x %02x ; %02x %02x ; %02x %02x\n",
657               device_xname(sc->sc_dev), s, cr[0], cr[1], cr[2], cr[3], cr[4], cr[5]));
658           error = (*(sc->sc_func_write_register))(sc, cr, s);
659           if (error) {
660                     DPRINTF(sc, 2, ("%s: write control registers: %d\n",
661                         device_xname(sc->sc_dev), error));
662                     error = EINVAL;
663           }
664 
665           /* The wait needed is not well documented, so this is somewhat of a guess.
666            * There is an attempt with this to only wait as long as needed.
667            */
668 
669           int p1, p2;
670 
671           p1 = (osrs_t_mask * sc->sc_waitfactor_t) + (osrs_p_mask * sc->sc_waitfactor_p);
672           if (sc->sc_has_humidity) {
673                     p1 = p1 + (osrs_h_mask * sc->sc_waitfactor_h);
674           }
675           p2 = mstohz(p1);
676           if (p2 == 0) {
677                     p2 = 1;
678           }
679           /* Be careful with this...  the print itself will cause extra delay */
680           DPRINTF(sc, 2, ("%s: p1: %d ; %d\n",
681               device_xname(sc->sc_dev), p1, p2));
682           kpause("b280mea",false,p2,NULL);
683 
684           return error;
685 }
686 
687 static int
bmx280_wait_for_data(struct bmx280_sc * sc)688 bmx280_wait_for_data(struct bmx280_sc *sc)
689 {
690           uint8_t reg;
691           uint8_t running = 99;
692           int c = sc->sc_readattempts;
693           int error = 0, ierror;
694 
695           reg = BMX280_REGISTER_STATUS;
696           do {
697                     delay(1000);
698                     ierror = (*(sc->sc_func_read_register))(sc, reg, &running, 1);
699                     if (ierror) {
700                               DPRINTF(sc, 2, ("%s: Refresh failed to read back status: %d\n",
701                                   device_xname(sc->sc_dev), ierror));
702                               error = EINVAL;
703                               break;
704                     }
705 
706                     DPRINTF(sc, 2, ("%s: Refresh status read back: %02x\n",
707                         device_xname(sc->sc_dev), running));
708 
709                     c--;
710           } while (c > 0 && (running & BMX280_STATUS_MEASURING_MASK));
711 
712           return error;
713 }
714 
715 static int
bmx280_read_data(struct bmx280_sc * sc,int32_t * temp,int32_t * press,int32_t * hum,bool justtemp)716 bmx280_read_data(struct bmx280_sc *sc,
717     int32_t *temp,
718     int32_t *press,
719     int32_t *hum,
720     bool justtemp)
721 {
722           int error = 0, ierror;
723           int rlen, rtstart, rpstart, rhstart;
724           int x_temp, x_press, x_hum;
725           uint8_t raw_press_temp_hum[8], reg;
726 
727           raw_press_temp_hum[0] = raw_press_temp_hum[1] =
728               raw_press_temp_hum[2] = raw_press_temp_hum[3] =
729               raw_press_temp_hum[4] = raw_press_temp_hum[5] =
730               raw_press_temp_hum[6] = raw_press_temp_hum[7] = 0;
731 
732           if (justtemp) {
733                     reg = BMX280_REGISTER_TEMP_MSB;
734                     rlen = 3;
735                     rtstart = 0;
736                     rpstart = 0;
737                     rhstart = 0;
738           } else {
739                     reg = BMX280_REGISTER_PRESS_MSB;
740                     if (sc->sc_has_humidity == false) {
741                               rlen = 6;
742                     } else {
743                               rlen = 8;
744                     }
745                     rtstart = 3;
746                     rpstart = 0;
747                     rhstart = 6;
748           }
749 
750           DPRINTF(sc, 2, ("%s: read data: reg: %02x ; len: %d ; tstart: %d ; pstart: %d\n",
751               device_xname(sc->sc_dev), reg, rlen, rtstart, rpstart));
752 
753           ierror = (*(sc->sc_func_read_register))(sc, reg, raw_press_temp_hum, rlen);
754           if (ierror) {
755                     DPRINTF(sc, 2, ("%s: failed to read pressure and temp registers: %d\n",
756                         device_xname(sc->sc_dev), ierror));
757                     error = EINVAL;
758                     goto out;
759           }
760 
761           DPRINTF(sc, 2, ("%s: raw pressure, temp and hum: %02x %02x %02x - %02x %02x %02x - %02x %02x\n",
762               device_xname(sc->sc_dev),
763               raw_press_temp_hum[0], raw_press_temp_hum[1], raw_press_temp_hum[2],
764               raw_press_temp_hum[3], raw_press_temp_hum[4], raw_press_temp_hum[5],
765               raw_press_temp_hum[6],raw_press_temp_hum[7]));
766 
767           x_temp = raw_press_temp_hum[rtstart] << 12;
768           x_temp = x_temp | (raw_press_temp_hum[rtstart + 1] << 4);
769           x_temp = x_temp | (raw_press_temp_hum[rtstart + 2] >> 4);
770 
771           DPRINTF(sc, 1, ("%s: intermediate temp: %d (%04x)\n",
772               device_xname(sc->sc_dev), x_temp, x_temp));
773 
774           *temp = x_temp;
775 
776           *hum = 0;
777           *press = 0;
778 
779           if (justtemp == false) {
780                     x_press = raw_press_temp_hum[rpstart] << 12;
781                     x_press = x_press | (raw_press_temp_hum[rpstart + 1] << 4);
782                     x_press = x_press | (raw_press_temp_hum[rpstart + 2] >> 4);
783 
784                     DPRINTF(sc, 1, ("%s: intermediate pressure: %d (%04x)\n",
785                         device_xname(sc->sc_dev), x_press, x_press));
786                     *press = x_press;
787           }
788           if (sc->sc_has_humidity) {
789                     x_hum = raw_press_temp_hum[rhstart] << 8;
790                     x_hum = x_hum | raw_press_temp_hum[rhstart + 1];
791 
792                     DPRINTF(sc, 1, ("%s: intermediate humidity: %d (%02x)\n",
793                         device_xname(sc->sc_dev), x_hum, x_hum));
794                     *hum = x_hum;
795           }
796 
797  out:
798           return error;
799 }
800 
801 static void
bmx280_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)802 bmx280_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
803 {
804           struct bmx280_sc *sc;
805           sc = sme->sme_cookie;
806           int error = 0;
807           int32_t t_fine;
808           int32_t m_temp, m_press, m_hum;
809           int32_t comp_temp;
810           uint32_t comp_press;
811           uint32_t comp_hum;
812           edata->state = ENVSYS_SINVALID;
813 
814           /* Ya... just do this on a refresh... */
815 
816           if (sc->sc_bmx280dump) {
817                     DPRINTF(sc, 1, ("%s: dig_T1: %d %04x\n",__func__,sc->sc_cal_blob.dig_T1,sc->sc_cal_blob.dig_T1));
818                     DPRINTF(sc, 1, ("%s: dig_T2: %d %04x\n",__func__,sc->sc_cal_blob.dig_T2,sc->sc_cal_blob.dig_T2));
819                     DPRINTF(sc, 1, ("%s: dig_T3: %d %04x\n",__func__,sc->sc_cal_blob.dig_T3,sc->sc_cal_blob.dig_T3));
820                     DPRINTF(sc, 1, ("%s: dig_P1: %d %04x\n",__func__,sc->sc_cal_blob.dig_P1,sc->sc_cal_blob.dig_P1));
821                     DPRINTF(sc, 1, ("%s: dig_P2: %d %04x\n",__func__,sc->sc_cal_blob.dig_P2,sc->sc_cal_blob.dig_P2));
822                     DPRINTF(sc, 1, ("%s: dig_P3: %d %04x\n",__func__,sc->sc_cal_blob.dig_P3,sc->sc_cal_blob.dig_P3));
823                     DPRINTF(sc, 1, ("%s: dig_P4: %d %04x\n",__func__,sc->sc_cal_blob.dig_P4,sc->sc_cal_blob.dig_P4));
824                     DPRINTF(sc, 1, ("%s: dig_P5: %d %04x\n",__func__,sc->sc_cal_blob.dig_P5,sc->sc_cal_blob.dig_P5));
825                     DPRINTF(sc, 1, ("%s: dig_P6: %d %04x\n",__func__,sc->sc_cal_blob.dig_P6,sc->sc_cal_blob.dig_P6));
826                     DPRINTF(sc, 1, ("%s: dig_P7: %d %04x\n",__func__,sc->sc_cal_blob.dig_P7,sc->sc_cal_blob.dig_P7));
827                     DPRINTF(sc, 1, ("%s: dig_P8: %d %04x\n",__func__,sc->sc_cal_blob.dig_P8,sc->sc_cal_blob.dig_P8));
828                     DPRINTF(sc, 1, ("%s: dig_P9: %d %04x\n",__func__,sc->sc_cal_blob.dig_P9,sc->sc_cal_blob.dig_P9));
829 
830                     if (sc->sc_has_humidity) {
831                               DPRINTF(sc, 1, ("%s: dig_H1: %d %02x\n",__func__,sc->sc_cal_blob.dig_H1,sc->sc_cal_blob.dig_H1));
832                               DPRINTF(sc, 1, ("%s: dig_H2: %d %04x\n",__func__,sc->sc_cal_blob.dig_H2,sc->sc_cal_blob.dig_H2));
833                               DPRINTF(sc, 1, ("%s: dig_H3: %d %02x\n",__func__,sc->sc_cal_blob.dig_H3,sc->sc_cal_blob.dig_H3));
834                               DPRINTF(sc, 1, ("%s: dig_H4: %d %04x\n",__func__,sc->sc_cal_blob.dig_H4,sc->sc_cal_blob.dig_H4));
835                               DPRINTF(sc, 1, ("%s: dig_H5: %d %04x\n",__func__,sc->sc_cal_blob.dig_H5,sc->sc_cal_blob.dig_H5));
836                               DPRINTF(sc, 1, ("%s: dig_H6: %d %02x\n",__func__,sc->sc_cal_blob.dig_H6,sc->sc_cal_blob.dig_H6));
837                     }
838 
839                     sc->sc_bmx280dump = false;
840           }
841 
842           mutex_enter(&sc->sc_mutex);
843           error = (*(sc->sc_func_acquire_bus))(sc);
844           if (error) {
845                     DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
846                         device_xname(sc->sc_dev), error));
847                     goto out;
848           }
849 
850           if (error == 0) {
851                     switch (edata->sensor) {
852                     case BMX280_TEMP_SENSOR:
853                               /* A temperature reading does not need pressure */
854 
855                               error = bmx280_set_control_and_trigger(sc,
856                                   bmx280_osrs_text_to_mask(sc->sc_osrs_t),
857                                   0,
858                                   0,
859                                   bmx280_irr_text_to_mask(sc->sc_irr_samples));
860 
861                               if (error == 0) {
862                                         error = bmx280_wait_for_data(sc);
863 
864                                         if (error == 0) {
865                                                   error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, true);
866 
867                                                   if (error == 0) {
868                                                             comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
869 
870                                                             DPRINTF(sc, 1, ("%s: Refresh compensated temp: %d - t_fine: %d\n",
871                                                                 device_xname(sc->sc_dev), comp_temp, t_fine));
872 
873                                                             /* comp_temp is in Celcius * 100.  This converts it to microkelvin */
874 
875                                                             uint32_t q;
876 
877                                                             q = (uint32_t)comp_temp;
878                                                             q = q + 27315;
879                                                             q = q * 10000;
880 
881                                                             DPRINTF(sc, 1, ("%s: Refresh Q: %d\n", __func__, q));
882 
883                                                             edata->value_cur = q;
884                                                             edata->state = ENVSYS_SVALID;
885                                                   }
886                                         }
887                               }
888                               break;
889                     case BMX280_PRESSURE_SENSOR:
890 
891                               /* Pressure needs the temp too */
892                               error = bmx280_set_control_and_trigger(sc,
893                                   bmx280_osrs_text_to_mask(sc->sc_osrs_t),
894                                   bmx280_osrs_text_to_mask(sc->sc_osrs_p),
895                                   0,
896                                   bmx280_irr_text_to_mask(sc->sc_irr_samples));
897 
898                               if (error == 0) {
899                                         error = bmx280_wait_for_data(sc);
900 
901                                         if (error == 0) {
902                                                   error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, false);
903 
904                                                   if (error == 0) {
905                                                             comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
906 
907                                                             DPRINTF(sc, 1, ("%s: Refresh compensated temp for pressure: %d - t_fine: %d\n",
908                                                                 device_xname(sc->sc_dev), comp_temp, t_fine));
909 
910                                                             comp_press = bmx280_compensate_P_int64(&sc->sc_cal_blob, m_press, t_fine);
911 
912                                                             DPRINTF(sc, 1, ("%s: Refresh compensated pressure: %d\n",
913                                                                 device_xname(sc->sc_dev), comp_press));
914 
915                                                             uint32_t q;
916 
917                                                             q = comp_press;
918                                                             q = q / 256;
919                                                             q = q * 100;
920 
921                                                             DPRINTF(sc, 1, ("%s: Refresh pressure Q: %d\n", __func__, q));
922 
923                                                             edata->value_cur = q;
924                                                             edata->state = ENVSYS_SVALID;
925                                                   }
926                                         }
927                               }
928                               break;
929 
930                     case BMX280_HUMIDITY_SENSOR:
931 
932                               /* Humidity wants temperature */
933 
934                               error = bmx280_set_control_and_trigger(sc,
935                                   bmx280_osrs_text_to_mask(sc->sc_osrs_t),
936                                   0,
937                                   bmx280_osrs_text_to_mask(sc->sc_osrs_h),
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 humidity: %d - t_fine: %d\n",
950                                                                 device_xname(sc->sc_dev), comp_temp, t_fine));
951 
952                                                             comp_hum = bmx280_compensate_H_int32(&sc->sc_cal_blob, m_hum, t_fine);
953 
954                                                             DPRINTF(sc, 2, ("%s: Refresh compensated humidity: %d\n",
955                                                                 device_xname(sc->sc_dev), comp_hum));
956 
957                                                             uint64_t q;
958 
959                                                             q = (uint64_t)comp_hum * 1000000;
960                                                             DPRINTF(sc, 1, ("%s: Refresh humidity Q 1: %jd\n", __func__, (uintmax_t)q));
961                                                             q = q / 1024;
962 
963                                                             DPRINTF(sc, 1, ("%s: Refresh humidity Q 2: %jd\n", __func__, (uintmax_t)q));
964 
965                                                             edata->value_cur = (uint32_t) q;
966                                                             edata->state = ENVSYS_SVALID;
967                                                   }
968                                         }
969                               }
970                               break;
971                     }
972           }
973 
974           if (error) {
975                     DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
976                         device_xname(sc->sc_dev), error));
977           }
978 
979           (*(sc->sc_func_release_bus))(sc);
980 out:
981           mutex_exit(&sc->sc_mutex);
982 }
983 
984 MODULE(MODULE_CLASS_DRIVER, bmx280thp, NULL);
985 
986 #ifdef _MODULE
987 CFDRIVER_DECL(bmx280thp, DV_DULL, NULL);
988 #include "ioconf.c"
989 #endif
990 
991 static int
bmx280thp_modcmd(modcmd_t cmd,void * opaque)992 bmx280thp_modcmd(modcmd_t cmd, void *opaque)
993 {
994 
995           switch (cmd) {
996           case MODULE_CMD_INIT:
997 #ifdef _MODULE
998                     return config_init_component(cfdriver_ioconf_bmx280thp,
999                         cfattach_ioconf_bmx280thp, cfdata_ioconf_bmx280thp);
1000 #else
1001                     return 0;
1002 #endif
1003           case MODULE_CMD_FINI:
1004 #ifdef _MODULE
1005                     return config_fini_component(cfdriver_ioconf_bmx280thp,
1006                           cfattach_ioconf_bmx280thp, cfdata_ioconf_bmx280thp);
1007 #else
1008                     return 0;
1009 #endif
1010           default:
1011                     return ENOTTY;
1012           }
1013 }
1014