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