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