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
44static void	bmx280_store_raw_blob_tp(struct bmx280_sc *, uint8_t *);
45static void	bmx280_store_raw_blob_h(struct bmx280_sc *, uint8_t *);
46void 		bmx280_attach(struct bmx280_sc *);
47static void 	bmx280_refresh(struct sysmon_envsys *, envsys_data_t *);
48static int 	bmx280_verify_sysctl(SYSCTLFN_ARGS);
49static int 	bmx280_verify_sysctl_osrs(SYSCTLFN_ARGS);
50static 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
63static 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
78static 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
101static 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
124static uint8_t
125bmx280_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
140static uint8_t
141bmx280_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
156int
157bmx280_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
177int
178bmx280_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
205int
206bmx280_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
237static void
238bmx280_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
266static void
267bmx280_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
278static int
279bmx280_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}
382void
383bmx280_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;
546out:
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
560static int32_t
561bmx280_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 */
577static uint32_t
578bmx280_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 */
604static uint32_t
605bmx280_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
624static int
625bmx280_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
687static int
688bmx280_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
715static int
716bmx280_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
801static void
802bmx280_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);
980out:
981	mutex_exit(&sc->sc_mutex);
982}
983
984MODULE(MODULE_CLASS_DRIVER, bmx280thp, NULL);
985
986#ifdef _MODULE
987CFDRIVER_DECL(bmx280thp, DV_DULL, NULL);
988#include "ioconf.c"
989#endif
990
991static int
992bmx280thp_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