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