aht20.c revision 1.1 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