1 1.1 brad /* $NetBSD: aht20.c,v 1.1 2022/11/17 19:20:06 brad 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.1 brad __KERNEL_RCSID(0, "$NetBSD: aht20.c,v 1.1 2022/11/17 19:20:06 brad Exp $"); 21 1.1 brad 22 1.1 brad /* 23 1.1 brad Driver for the Guangzhou Aosong AHT20 temperature and humidity sensor 24 1.1 brad */ 25 1.1 brad 26 1.1 brad #include <sys/param.h> 27 1.1 brad #include <sys/systm.h> 28 1.1 brad #include <sys/kernel.h> 29 1.1 brad #include <sys/device.h> 30 1.1 brad #include <sys/module.h> 31 1.1 brad #include <sys/sysctl.h> 32 1.1 brad #include <sys/mutex.h> 33 1.1 brad 34 1.1 brad #include <dev/sysmon/sysmonvar.h> 35 1.1 brad #include <dev/i2c/i2cvar.h> 36 1.1 brad #include <dev/i2c/aht20reg.h> 37 1.1 brad #include <dev/i2c/aht20var.h> 38 1.1 brad 39 1.1 brad 40 1.1 brad static uint8_t aht20_crc(uint8_t *, size_t); 41 1.1 brad static int aht20_poke(i2c_tag_t, i2c_addr_t, bool); 42 1.1 brad static int aht20_match(device_t, cfdata_t, void *); 43 1.1 brad static void aht20_attach(device_t, device_t, void *); 44 1.1 brad static int aht20_detach(device_t, int); 45 1.1 brad static void aht20_refresh(struct sysmon_envsys *, envsys_data_t *); 46 1.1 brad static int aht20_verify_sysctl(SYSCTLFN_ARGS); 47 1.1 brad 48 1.1 brad #define AHT20_DEBUG 49 1.1 brad #ifdef AHT20_DEBUG 50 1.1 brad #define DPRINTF(s, l, x) \ 51 1.1 brad do { \ 52 1.1 brad if (l <= s->sc_aht20debug) \ 53 1.1 brad printf x; \ 54 1.1 brad } while (/*CONSTCOND*/0) 55 1.1 brad #else 56 1.1 brad #define DPRINTF(s, l, x) 57 1.1 brad #endif 58 1.1 brad 59 1.1 brad CFATTACH_DECL_NEW(aht20temp, sizeof(struct aht20_sc), 60 1.1 brad aht20_match, aht20_attach, aht20_detach, NULL); 61 1.1 brad 62 1.1 brad static struct aht20_sensor aht20_sensors[] = { 63 1.1 brad { 64 1.1 brad .desc = "humidity", 65 1.1 brad .type = ENVSYS_SRELHUMIDITY, 66 1.1 brad }, 67 1.1 brad { 68 1.1 brad .desc = "temperature", 69 1.1 brad .type = ENVSYS_STEMP, 70 1.1 brad } 71 1.1 brad }; 72 1.1 brad 73 1.1 brad /* 74 1.1 brad * The delays are mentioned in the datasheet for the chip, except for 75 1.1 brad * the get status command. 76 1.1 brad */ 77 1.1 brad 78 1.1 brad static struct aht20_timing aht20_timings[] = { 79 1.1 brad { 80 1.1 brad .cmd = AHT20_INITIALIZE, 81 1.1 brad .typicaldelay = 10000, 82 1.1 brad }, 83 1.1 brad { 84 1.1 brad .cmd = AHT20_TRIGGER_MEASUREMENT, 85 1.1 brad .typicaldelay = 80000, 86 1.1 brad }, 87 1.1 brad { 88 1.1 brad .cmd = AHT20_GET_STATUS, 89 1.1 brad .typicaldelay = 5000, 90 1.1 brad }, 91 1.1 brad { 92 1.1 brad .cmd = AHT20_SOFT_RESET, 93 1.1 brad .typicaldelay = 20000, 94 1.1 brad } 95 1.1 brad }; 96 1.1 brad 97 1.1 brad int 98 1.1 brad aht20_verify_sysctl(SYSCTLFN_ARGS) 99 1.1 brad { 100 1.1 brad int error, t; 101 1.1 brad struct sysctlnode node; 102 1.1 brad 103 1.1 brad node = *rnode; 104 1.1 brad t = *(int *)rnode->sysctl_data; 105 1.1 brad node.sysctl_data = &t; 106 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node)); 107 1.1 brad if (error || newp == NULL) 108 1.1 brad return error; 109 1.1 brad 110 1.1 brad if (t < 0) 111 1.1 brad return EINVAL; 112 1.1 brad 113 1.1 brad *(int *)rnode->sysctl_data = t; 114 1.1 brad 115 1.1 brad return 0; 116 1.1 brad } 117 1.1 brad 118 1.1 brad static int 119 1.1 brad aht20_cmddelay(uint8_t cmd) 120 1.1 brad { 121 1.1 brad int r = -1; 122 1.1 brad 123 1.1 brad for(int i = 0;i < __arraycount(aht20_timings);i++) { 124 1.1 brad if (cmd == aht20_timings[i].cmd) { 125 1.1 brad r = aht20_timings[i].typicaldelay; 126 1.1 brad break; 127 1.1 brad } 128 1.1 brad } 129 1.1 brad 130 1.1 brad if (r == -1) { 131 1.1 brad panic("Bad command look up in cmd delay: cmd: %d\n",cmd); 132 1.1 brad } 133 1.1 brad 134 1.1 brad return r; 135 1.1 brad } 136 1.1 brad 137 1.1 brad static int 138 1.1 brad aht20_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t *cmd, 139 1.1 brad uint8_t clen, uint8_t *buf, size_t blen, int readattempts) 140 1.1 brad { 141 1.1 brad int error; 142 1.1 brad int cmddelay; 143 1.1 brad 144 1.1 brad error = iic_exec(tag,I2C_OP_WRITE_WITH_STOP,addr,cmd,clen,NULL,0,0); 145 1.1 brad 146 1.1 brad /* Every command returns something except for the soft reset and 147 1.1 brad initialize which returns nothing. 148 1.1 brad */ 149 1.1 brad 150 1.1 brad if (error == 0) { 151 1.1 brad cmddelay = aht20_cmddelay(cmd[0]); 152 1.1 brad delay(cmddelay); 153 1.1 brad 154 1.1 brad if (cmd[0] != AHT20_SOFT_RESET && 155 1.1 brad cmd[0] != AHT20_INITIALIZE) { 156 1.1 brad for (int aint = 0; aint < readattempts; aint++) { 157 1.1 brad error = iic_exec(tag,I2C_OP_READ_WITH_STOP,addr,NULL,0,buf,blen,0); 158 1.1 brad if (error == 0) 159 1.1 brad break; 160 1.1 brad delay(1000); 161 1.1 brad } 162 1.1 brad } 163 1.1 brad } 164 1.1 brad 165 1.1 brad return error; 166 1.1 brad } 167 1.1 brad 168 1.1 brad static int 169 1.1 brad aht20_cmdr(struct aht20_sc *sc, uint8_t *cmd, uint8_t clen, uint8_t *buf, size_t blen) 170 1.1 brad { 171 1.1 brad KASSERT(clen > 0); 172 1.1 brad 173 1.1 brad return aht20_cmd(sc->sc_tag, sc->sc_addr, cmd, clen, buf, blen, sc->sc_readattempts); 174 1.1 brad } 175 1.1 brad 176 1.1 brad static uint8_t 177 1.1 brad aht20_crc(uint8_t * data, size_t size) 178 1.1 brad { 179 1.1 brad uint8_t crc = 0xFF; 180 1.1 brad 181 1.1 brad for (size_t i = 0; i < size; i++) { 182 1.1 brad crc ^= data[i]; 183 1.1 brad for (size_t j = 8; j > 0; j--) { 184 1.1 brad if (crc & 0x80) 185 1.1 brad crc = (crc << 1) ^ 0x31; 186 1.1 brad else 187 1.1 brad crc <<= 1; 188 1.1 brad } 189 1.1 brad } 190 1.1 brad return crc; 191 1.1 brad } 192 1.1 brad 193 1.1 brad static int 194 1.1 brad aht20_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug) 195 1.1 brad { 196 1.1 brad uint8_t reg = AHT20_GET_STATUS; 197 1.1 brad uint8_t buf[6]; 198 1.1 brad int error; 199 1.1 brad 200 1.1 brad error = aht20_cmd(tag, addr, ®, 1, buf, 1, 10); 201 1.1 brad if (matchdebug) { 202 1.1 brad printf("poke X 1: %d\n", error); 203 1.1 brad } 204 1.1 brad return error; 205 1.1 brad } 206 1.1 brad 207 1.1 brad static int 208 1.1 brad aht20_sysctl_init(struct aht20_sc *sc) 209 1.1 brad { 210 1.1 brad int error; 211 1.1 brad const struct sysctlnode *cnode; 212 1.1 brad int sysctlroot_num; 213 1.1 brad 214 1.1 brad if ((error = sysctl_createv(&sc->sc_aht20log, 0, NULL, &cnode, 215 1.1 brad 0, CTLTYPE_NODE, device_xname(sc->sc_dev), 216 1.1 brad SYSCTL_DESCR("aht20 controls"), NULL, 0, NULL, 0, CTL_HW, 217 1.1 brad CTL_CREATE, CTL_EOL)) != 0) 218 1.1 brad return error; 219 1.1 brad 220 1.1 brad sysctlroot_num = cnode->sysctl_num; 221 1.1 brad 222 1.1 brad #ifdef AHT20_DEBUG 223 1.1 brad if ((error = sysctl_createv(&sc->sc_aht20log, 0, NULL, &cnode, 224 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "debug", 225 1.1 brad SYSCTL_DESCR("Debug level"), aht20_verify_sysctl, 0, 226 1.1 brad &sc->sc_aht20debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE, 227 1.1 brad CTL_EOL)) != 0) 228 1.1 brad return error; 229 1.1 brad 230 1.1 brad #endif 231 1.1 brad 232 1.1 brad if ((error = sysctl_createv(&sc->sc_aht20log, 0, NULL, &cnode, 233 1.1 brad CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts", 234 1.1 brad SYSCTL_DESCR("The number of times to attempt to read the values"), 235 1.1 brad aht20_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW, 236 1.1 brad sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0) 237 1.1 brad return error; 238 1.1 brad 239 1.1 brad if ((error = sysctl_createv(&sc->sc_aht20log, 0, NULL, &cnode, 240 1.1 brad CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc", 241 1.1 brad SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc, 242 1.1 brad 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0) 243 1.1 brad return error; 244 1.1 brad 245 1.1 brad return 0; 246 1.1 brad } 247 1.1 brad 248 1.1 brad static int 249 1.1 brad aht20_match(device_t parent, cfdata_t match, void *aux) 250 1.1 brad { 251 1.1 brad struct i2c_attach_args *ia = aux; 252 1.1 brad int error, match_result; 253 1.1 brad const bool matchdebug = false; 254 1.1 brad 255 1.1 brad if (iic_use_direct_match(ia, match, NULL, &match_result)) 256 1.1 brad return match_result; 257 1.1 brad 258 1.1 brad /* indirect config - check for configured address */ 259 1.1 brad if (ia->ia_addr != AHT20_TYPICAL_ADDR) 260 1.1 brad return 0; 261 1.1 brad 262 1.1 brad /* 263 1.1 brad * Check to see if something is really at this i2c address. This will 264 1.1 brad * keep phantom devices from appearing 265 1.1 brad */ 266 1.1 brad if (iic_acquire_bus(ia->ia_tag, 0) != 0) { 267 1.1 brad if (matchdebug) 268 1.1 brad printf("in match acquire bus failed\n"); 269 1.1 brad return 0; 270 1.1 brad } 271 1.1 brad 272 1.1 brad error = aht20_poke(ia->ia_tag, ia->ia_addr, matchdebug); 273 1.1 brad iic_release_bus(ia->ia_tag, 0); 274 1.1 brad 275 1.1 brad return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0; 276 1.1 brad } 277 1.1 brad 278 1.1 brad static void 279 1.1 brad aht20_attach(device_t parent, device_t self, void *aux) 280 1.1 brad { 281 1.1 brad struct aht20_sc *sc; 282 1.1 brad struct i2c_attach_args *ia; 283 1.1 brad uint8_t cmd[1]; 284 1.1 brad int error, i; 285 1.1 brad 286 1.1 brad ia = aux; 287 1.1 brad sc = device_private(self); 288 1.1 brad 289 1.1 brad sc->sc_dev = self; 290 1.1 brad sc->sc_tag = ia->ia_tag; 291 1.1 brad sc->sc_addr = ia->ia_addr; 292 1.1 brad sc->sc_aht20debug = 0; 293 1.1 brad sc->sc_readattempts = 10; 294 1.1 brad sc->sc_ignorecrc = false; 295 1.1 brad sc->sc_sme = NULL; 296 1.1 brad 297 1.1 brad aprint_normal("\n"); 298 1.1 brad 299 1.1 brad mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 300 1.1 brad sc->sc_numsensors = __arraycount(aht20_sensors); 301 1.1 brad 302 1.1 brad if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 303 1.1 brad aprint_error_dev(self, 304 1.1 brad "Unable to create sysmon structure\n"); 305 1.1 brad sc->sc_sme = NULL; 306 1.1 brad return; 307 1.1 brad } 308 1.1 brad if ((error = aht20_sysctl_init(sc)) != 0) { 309 1.1 brad aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error); 310 1.1 brad goto out; 311 1.1 brad } 312 1.1 brad 313 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0); 314 1.1 brad if (error) { 315 1.1 brad aprint_error_dev(self, "Could not acquire iic bus: %d\n", 316 1.1 brad error); 317 1.1 brad goto out; 318 1.1 brad } 319 1.1 brad 320 1.1 brad cmd[0] = AHT20_SOFT_RESET; 321 1.1 brad error = aht20_cmdr(sc, cmd, 1, NULL, 0); 322 1.1 brad if (error != 0) 323 1.1 brad aprint_error_dev(self, "Reset failed: %d\n", error); 324 1.1 brad 325 1.1 brad iic_release_bus(sc->sc_tag, 0); 326 1.1 brad 327 1.1 brad if (error != 0) { 328 1.1 brad aprint_error_dev(self, "Unable to setup device\n"); 329 1.1 brad goto out; 330 1.1 brad } 331 1.1 brad 332 1.1 brad for (i = 0; i < sc->sc_numsensors; i++) { 333 1.1 brad strlcpy(sc->sc_sensors[i].desc, aht20_sensors[i].desc, 334 1.1 brad sizeof(sc->sc_sensors[i].desc)); 335 1.1 brad 336 1.1 brad sc->sc_sensors[i].units = aht20_sensors[i].type; 337 1.1 brad sc->sc_sensors[i].state = ENVSYS_SINVALID; 338 1.1 brad 339 1.1 brad DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i, 340 1.1 brad sc->sc_sensors[i].desc)); 341 1.1 brad 342 1.1 brad error = sysmon_envsys_sensor_attach(sc->sc_sme, 343 1.1 brad &sc->sc_sensors[i]); 344 1.1 brad if (error) { 345 1.1 brad aprint_error_dev(self, 346 1.1 brad "Unable to attach sensor %d: %d\n", i, error); 347 1.1 brad goto out; 348 1.1 brad } 349 1.1 brad } 350 1.1 brad 351 1.1 brad sc->sc_sme->sme_name = device_xname(sc->sc_dev); 352 1.1 brad sc->sc_sme->sme_cookie = sc; 353 1.1 brad sc->sc_sme->sme_refresh = aht20_refresh; 354 1.1 brad 355 1.1 brad DPRINTF(sc, 2, ("aht20_attach: registering with envsys\n")); 356 1.1 brad 357 1.1 brad if (sysmon_envsys_register(sc->sc_sme)) { 358 1.1 brad aprint_error_dev(self, 359 1.1 brad "unable to register with sysmon\n"); 360 1.1 brad sysmon_envsys_destroy(sc->sc_sme); 361 1.1 brad sc->sc_sme = NULL; 362 1.1 brad return; 363 1.1 brad } 364 1.1 brad 365 1.1 brad aprint_normal_dev(self, "Guangzhou Aosong AHT20\n"); 366 1.1 brad 367 1.1 brad return; 368 1.1 brad out: 369 1.1 brad sysmon_envsys_destroy(sc->sc_sme); 370 1.1 brad sc->sc_sme = NULL; 371 1.1 brad } 372 1.1 brad 373 1.1 brad static void 374 1.1 brad aht20_refresh(struct sysmon_envsys * sme, envsys_data_t * edata) 375 1.1 brad { 376 1.1 brad struct aht20_sc *sc; 377 1.1 brad sc = sme->sme_cookie; 378 1.1 brad int error; 379 1.1 brad uint8_t cmd[3]; 380 1.1 brad uint8_t rawdata[7]; 381 1.1 brad edata->state = ENVSYS_SINVALID; 382 1.1 brad 383 1.1 brad mutex_enter(&sc->sc_mutex); 384 1.1 brad error = iic_acquire_bus(sc->sc_tag, 0); 385 1.1 brad if (error) { 386 1.1 brad DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n", 387 1.1 brad device_xname(sc->sc_dev), error)); 388 1.1 brad goto out; 389 1.1 brad } 390 1.1 brad 391 1.1 brad /* 392 1.1 brad The documented conversion calculations for the raw values are as follows: 393 1.1 brad 394 1.1 brad %RH = (Srh / 2^20) * 100% 395 1.1 brad 396 1.1 brad T in Celsius = ((St / 2^20) * 200) - 50 397 1.1 brad 398 1.1 brad It follows then: 399 1.1 brad 400 1.1 brad T in Kelvin = ((St / 2^20) * 200) + 223.15 401 1.1 brad 402 1.1 brad given the relationship between Celsius and Kelvin. 403 1.1 brad 404 1.1 brad What follows reorders the calculation a bit and scales it up to avoid 405 1.1 brad the use of any floating point. All that would really have to happen 406 1.1 brad is a scale up to 10^6 for the sysenv framework, which wants 407 1.1 brad temperature in micro-kelvin and percent relative humidity scaled up 408 1.1 brad 10^6, but since this conversion uses 64 bits due to intermediate 409 1.1 brad values that are bigger than 32 bits the conversion first scales up to 410 1.1 brad 10^9 and the scales back down by 10^3 at the end. This preserves some 411 1.1 brad precision in the conversion that would otherwise be lost. 412 1.1 brad */ 413 1.1 brad 414 1.1 brad cmd[0] = AHT20_TRIGGER_MEASUREMENT; 415 1.1 brad cmd[1] = AHT20_TRIGGER_PARAM1; 416 1.1 brad cmd[2] = AHT20_TRIGGER_PARAM2; 417 1.1 brad error = aht20_cmdr(sc, cmd, 3, rawdata, 7); 418 1.1 brad 419 1.1 brad if (error == 0) { 420 1.1 brad if (rawdata[0] & AHT20_STATUS_BUSY_MASK) { 421 1.1 brad aprint_error_dev(sc->sc_dev, 422 1.1 brad "Chip is busy. Status register: %02x\n", 423 1.1 brad rawdata[0]); 424 1.1 brad error = EINVAL; 425 1.1 brad } 426 1.1 brad 427 1.1 brad if (error == 0 && 428 1.1 brad rawdata[0] & AHT20_STATUS_CAL_MASK) { 429 1.1 brad 430 1.1 brad uint8_t testcrc; 431 1.1 brad 432 1.1 brad testcrc = aht20_crc(&rawdata[0],6); 433 1.1 brad 434 1.1 brad DPRINTF(sc, 2, ("%s: Raw data: STATUS: %02x - RH: %02x %02x - %02x - TEMP: %02x %02x - CRC: %02x -- %02x\n", 435 1.1 brad device_xname(sc->sc_dev), rawdata[0], rawdata[1], rawdata[2], 436 1.1 brad rawdata[3], rawdata[4], rawdata[5], rawdata[6], testcrc)); 437 1.1 brad 438 1.1 brad /* This chip splits the %rh and temp raw files ove the 3 byte returned. Since 439 1.1 brad there is no choice but to get both, split them both apart every time */ 440 1.1 brad 441 1.1 brad uint64_t rawhum; 442 1.1 brad uint64_t rawtemp; 443 1.1 brad 444 1.1 brad rawhum = (rawdata[1] << 12) | (rawdata[2] << 4) | ((rawdata[3] & 0xf0) >> 4); 445 1.1 brad rawtemp = ((rawdata[3] & 0x0f) << 16) | (rawdata[4] << 8) | rawdata[5]; 446 1.1 brad 447 1.1 brad DPRINTF(sc, 2, ("%s: Raw broken data: RH: %04jx (%jd) - TEMP: %04jx (%jd)\n", 448 1.1 brad device_xname(sc->sc_dev), rawhum, rawhum, rawtemp, rawtemp)); 449 1.1 brad 450 1.1 brad /* Fake out the CRC check if being asked to ignore CRC */ 451 1.1 brad if (sc->sc_ignorecrc) { 452 1.1 brad testcrc = rawdata[6]; 453 1.1 brad } 454 1.1 brad 455 1.1 brad if (rawdata[6] == testcrc) { 456 1.1 brad uint64_t q = 0; 457 1.1 brad 458 1.1 brad switch (edata->sensor) { 459 1.1 brad case AHT20_TEMP_SENSOR: 460 1.1 brad q = (((rawtemp * 1000000000) / 10485760) * 2) + 223150000; 461 1.1 brad 462 1.1 brad break; 463 1.1 brad case AHT20_HUMIDITY_SENSOR: 464 1.1 brad q = (rawhum * 1000000000) / 10485760; 465 1.1 brad 466 1.1 brad break; 467 1.1 brad default: 468 1.1 brad error = EINVAL; 469 1.1 brad break; 470 1.1 brad } 471 1.1 brad 472 1.1 brad DPRINTF(sc, 2, ("%s: Computed sensor: %#jx (%jd)\n", 473 1.1 brad device_xname(sc->sc_dev), (uintmax_t)q, (uintmax_t)q)); 474 1.1 brad 475 1.1 brad /* The results will fit in 32 bits, so nothing will be lost */ 476 1.1 brad edata->value_cur = (uint32_t) q; 477 1.1 brad edata->state = ENVSYS_SVALID; 478 1.1 brad } else { 479 1.1 brad error = EINVAL; 480 1.1 brad } 481 1.1 brad } else { 482 1.1 brad if (error == 0) { 483 1.1 brad aprint_error_dev(sc->sc_dev,"Calibration needs to be run on the chip.\n"); 484 1.1 brad 485 1.1 brad cmd[0] = AHT20_INITIALIZE; 486 1.1 brad cmd[1] = AHT20_INITIALIZE_PARAM1; 487 1.1 brad cmd[2] = AHT20_INITIALIZE_PARAM2; 488 1.1 brad error = aht20_cmdr(sc, cmd, 3, NULL, 0); 489 1.1 brad 490 1.1 brad if (error) { 491 1.1 brad DPRINTF(sc, 2, ("%s: Calibration failed to run: %d\n", 492 1.1 brad device_xname(sc->sc_dev), error)); 493 1.1 brad } 494 1.1 brad } 495 1.1 brad } 496 1.1 brad } 497 1.1 brad 498 1.1 brad if (error) { 499 1.1 brad DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n", 500 1.1 brad device_xname(sc->sc_dev), error)); 501 1.1 brad } 502 1.1 brad 503 1.1 brad iic_release_bus(sc->sc_tag, 0); 504 1.1 brad out: 505 1.1 brad mutex_exit(&sc->sc_mutex); 506 1.1 brad } 507 1.1 brad 508 1.1 brad static int 509 1.1 brad aht20_detach(device_t self, int flags) 510 1.1 brad { 511 1.1 brad struct aht20_sc *sc; 512 1.1 brad 513 1.1 brad sc = device_private(self); 514 1.1 brad 515 1.1 brad mutex_enter(&sc->sc_mutex); 516 1.1 brad 517 1.1 brad /* Remove the sensors */ 518 1.1 brad if (sc->sc_sme != NULL) { 519 1.1 brad sysmon_envsys_unregister(sc->sc_sme); 520 1.1 brad sc->sc_sme = NULL; 521 1.1 brad } 522 1.1 brad mutex_exit(&sc->sc_mutex); 523 1.1 brad 524 1.1 brad /* Remove the sysctl tree */ 525 1.1 brad sysctl_teardown(&sc->sc_aht20log); 526 1.1 brad 527 1.1 brad /* Remove the mutex */ 528 1.1 brad mutex_destroy(&sc->sc_mutex); 529 1.1 brad 530 1.1 brad return 0; 531 1.1 brad } 532 1.1 brad 533 1.1 brad MODULE(MODULE_CLASS_DRIVER, aht20temp, "iic,sysmon_envsys"); 534 1.1 brad 535 1.1 brad #ifdef _MODULE 536 1.1 brad #include "ioconf.c" 537 1.1 brad #endif 538 1.1 brad 539 1.1 brad static int 540 1.1 brad aht20temp_modcmd(modcmd_t cmd, void *opaque) 541 1.1 brad { 542 1.1 brad 543 1.1 brad switch (cmd) { 544 1.1 brad case MODULE_CMD_INIT: 545 1.1 brad #ifdef _MODULE 546 1.1 brad return config_init_component(cfdriver_ioconf_aht20temp, 547 1.1 brad cfattach_ioconf_aht20temp, cfdata_ioconf_aht20temp); 548 1.1 brad #else 549 1.1 brad return 0; 550 1.1 brad #endif 551 1.1 brad case MODULE_CMD_FINI: 552 1.1 brad #ifdef _MODULE 553 1.1 brad return config_fini_component(cfdriver_ioconf_aht20temp, 554 1.1 brad cfattach_ioconf_aht20temp, cfdata_ioconf_aht20temp); 555 1.1 brad #else 556 1.1 brad return 0; 557 1.1 brad #endif 558 1.1 brad default: 559 1.1 brad return ENOTTY; 560 1.1 brad } 561 1.1 brad } 562