1 /* $NetBSD: am2315.c,v 1.2 2017/12/30 03:18:26 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Brad Spencer <brad@anduin.eldar.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/cdefs.h> 20 __KERNEL_RCSID(0, "$NetBSD: am2315.c,v 1.2 2017/12/30 03:18:26 christos Exp $"); 21 22 /* 23 * Driver for the Aosong AM2315 24 */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/kernel.h> 29 #include <sys/device.h> 30 #include <sys/module.h> 31 #include <sys/sysctl.h> 32 #include <sys/condvar.h> 33 #include <sys/mutex.h> 34 #include <sys/time.h> 35 36 #include <dev/sysmon/sysmonvar.h> 37 #include <dev/i2c/i2cvar.h> 38 #include <dev/i2c/am2315reg.h> 39 #include <dev/i2c/am2315var.h> 40 41 static uint16_t am2315_crc(uint8_t *, size_t); 42 static int am2315_poke(struct am2315_sc *); 43 static int am2315_poke_m(i2c_tag_t, i2c_addr_t, const char *, bool); 44 static int am2315_match(device_t, cfdata_t, void *); 45 static void am2315_attach(device_t, device_t, void *); 46 static int am2315_detach(device_t, int); 47 static void am2315_refresh(struct sysmon_envsys *, envsys_data_t *); 48 static int am2315_verify_sysctl(SYSCTLFN_ARGS); 49 50 #define AM2315_DEBUG 51 #ifdef AM2315_DEBUG 52 #define DPRINTF(s, l, x) \ 53 do { \ 54 if (l <= s->sc_am2315debug) \ 55 printf x; \ 56 } while (/*CONSTCOND*/0) 57 #else 58 #define DPRINTF(s, l, x) 59 #endif 60 61 CFATTACH_DECL_NEW(am2315temp, sizeof(struct am2315_sc), 62 am2315_match, am2315_attach, am2315_detach, NULL); 63 64 static struct am2315_sensor am2315_sensors[] = { 65 { 66 .desc = "humidity", 67 .type = ENVSYS_SRELHUMIDITY, 68 }, 69 { 70 .desc = "temperature", 71 .type = ENVSYS_STEMP, 72 } 73 }; 74 75 static uint16_t 76 am2315_crc(uint8_t *data, size_t len) 77 { 78 uint16_t crc = 0xffff; 79 80 for (size_t j = 0; j < len; j++) { 81 crc ^= data[j]; 82 for (size_t i = 0; i < 8; i++) { 83 if (crc & 0x01) { 84 crc >>= 1; 85 crc ^= 0xA001; 86 } else { 87 crc >>= 1; 88 } 89 } 90 } 91 92 return crc; 93 } 94 95 int 96 am2315_verify_sysctl(SYSCTLFN_ARGS) 97 { 98 int error, t; 99 struct sysctlnode node; 100 101 node = *rnode; 102 t = *(int *)rnode->sysctl_data; 103 node.sysctl_data = &t; 104 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 105 if (error || newp == NULL) 106 return error; 107 108 if (t < 0) 109 return EINVAL; 110 111 *(int *) rnode->sysctl_data = t; 112 113 return 0; 114 } 115 116 static int 117 am2315_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t dir, uint8_t cmd, 118 uint8_t clen, uint8_t *buf, size_t blen) 119 { 120 uint8_t command[] = { dir, cmd, clen }; 121 if (buf) 122 memset(buf, 0xff, blen); 123 uint8_t reg = dir == AM2315_READ_REGISTERS ? 124 I2C_OP_READ_WITH_STOP : I2C_OP_WRITE_WITH_STOP; 125 126 return iic_exec(tag, reg, addr, command, 127 __arraycount(command), buf, blen, 0); 128 } 129 130 static int 131 am2315_read_regs(struct am2315_sc *sc, uint8_t cmd, uint8_t clen, uint8_t *buf, 132 size_t blen) 133 { 134 return am2315_cmd(sc->sc_tag, sc->sc_addr, AM2315_READ_REGISTERS, 135 cmd, clen, buf, blen); 136 } 137 138 static int 139 am2315_poke(struct am2315_sc *sc) 140 { 141 return am2315_poke_m(sc->sc_tag, sc->sc_addr, device_xname(sc->sc_dev), 142 sc->sc_am2315debug >= 2); 143 } 144 145 static int 146 am2315_poke_m(i2c_tag_t tag, i2c_addr_t addr, const char *name, bool debug) 147 { 148 uint8_t buf[5]; 149 int error; 150 151 error = am2315_cmd(tag, addr, AM2315_WRITE_REGISTERS, 152 AM2315_REGISTER_HIGH_USER1, 1, NULL, 0); 153 if (debug) 154 printf("%s: poke 1: %d\n", name, error); 155 156 if (error) 157 delay(2800); 158 159 error = am2315_cmd(tag, addr, AM2315_READ_REGISTERS, 160 AM2315_REGISTER_STATUS, 1, buf, __arraycount(buf)); 161 if (debug) 162 printf("%s: poke 2: %d %02x %02x %02x %02x%02x\n", name, error, 163 buf[0], buf[1], buf[2], buf[3], buf[4]); 164 165 if (error) 166 delay(2800); 167 return error; 168 } 169 170 static int 171 am2315_match(device_t parent, cfdata_t match, void *aux) 172 { 173 struct i2c_attach_args *ia; 174 int rv; 175 const bool matchdebug = false; 176 177 ia = aux; 178 179 if (ia->ia_name) { 180 /* direct config - check name */ 181 if (strcmp(ia->ia_name, "am2315temp") != 0) 182 return 0; 183 } else { 184 /* indirect config - check for configured address */ 185 if (ia->ia_addr != AM2315_TYPICAL_ADDR) 186 return 0; 187 } 188 189 /* 190 * Check to see if something is really at this i2c address. This will 191 * keep phantom devices from appearing 192 */ 193 if (iic_acquire_bus(ia->ia_tag, 0) != 0) { 194 if (matchdebug) 195 printf("in match acquire bus failed\n"); 196 return 0; 197 } 198 199 if ((rv = am2315_poke_m(ia->ia_tag, ia->ia_addr, __func__, matchdebug)) 200 != 0) { 201 if (matchdebug) 202 printf("match rv poke %d\n", rv); 203 iic_release_bus(ia->ia_tag, 0); 204 return 0; 205 } 206 207 iic_release_bus(ia->ia_tag, 0); 208 return 1; 209 } 210 211 static void 212 am2315_attach(device_t parent, device_t self, void *aux) 213 { 214 struct am2315_sc *sc = device_private(self); 215 struct i2c_attach_args *ia = aux; 216 uint8_t buf[11]; 217 int error; 218 uint16_t crc, readcrc, model; 219 uint8_t chipver; 220 uint32_t id; 221 bool modelgood, chipvergood, idgood; 222 223 sc->sc_dev = self; 224 sc->sc_tag = ia->ia_tag; 225 sc->sc_addr = ia->ia_addr; 226 sc->sc_am2315debug = 0; 227 sc->sc_readcount = 2; 228 sc->sc_readticks = 100; 229 sc->sc_sme = NULL; 230 231 aprint_normal("\n"); 232 233 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 234 mutex_init(&sc->sc_waitmutex, MUTEX_DEFAULT, IPL_NONE); 235 cv_init(&sc->sc_condwait, "am2315wait"); 236 237 sc->sc_numsensors = __arraycount(am2315_sensors); 238 239 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 240 aprint_error_dev(self, "unable to create sysmon structure\n"); 241 return; 242 } 243 244 /* XXX: sysctl's not destroyed on failure */ 245 const struct sysctlnode *cnode; 246 int sysctlroot_num; 247 if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode, 0, 248 CTLTYPE_NODE, device_xname(self), 249 SYSCTL_DESCR("am2315 controls"), NULL, 0, NULL, 0, CTL_HW, 250 CTL_CREATE, CTL_EOL)) != 0) 251 goto badsysctl; 252 sysctlroot_num = cnode->sysctl_num; 253 254 #ifdef AM2315_DEBUG 255 if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode, 256 CTLFLAG_READWRITE, CTLTYPE_INT, "debug", 257 SYSCTL_DESCR("Debug level"), am2315_verify_sysctl, 0, 258 &sc->sc_am2315debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE, 259 CTL_EOL)) != 0) 260 goto badsysctl; 261 262 #endif 263 264 if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode, 265 CTLFLAG_READWRITE, CTLTYPE_INT, "readcount", 266 SYSCTL_DESCR("Number of times to read the sensor"), 267 am2315_verify_sysctl, 0, &sc->sc_readcount, 0, CTL_HW, 268 sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0) 269 goto badsysctl; 270 271 if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode, 272 CTLFLAG_READWRITE, CTLTYPE_INT, "readticks", 273 SYSCTL_DESCR("Number of ticks between reads"), 274 am2315_verify_sysctl, 0, &sc->sc_readticks, 0, CTL_HW, 275 sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0) 276 goto badsysctl; 277 278 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) { 279 aprint_error_dev(self, 280 "Could not acquire iic bus: %d\n", error); 281 return; 282 } 283 am2315_poke(sc); 284 285 #define DUMP(a) \ 286 DPRINTF(sc, 2, ("%s: read cmd+len+%s+crcl+crch values: %02x %02x " \ 287 "%02x%02x %02x%02x -- %02x%02x%02x%02x%02x -- %04x %04x\n", a, \ 288 device_xname(self), buf[0], buf[1], buf[2], buf[3], \ 289 buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], \ 290 buf[10], crc, readcrc)) 291 292 error = am2315_read_regs(sc, AM2315_REGISTER_HIGH_MODEL, 2, buf, 6); 293 if (error) 294 aprint_error_dev(sc->sc_dev, "read model: %d\n", error); 295 readcrc = buf[5] << 8 | buf[4]; 296 crc = am2315_crc(buf, 4); 297 DUMP("modh+modl"); 298 model = buf[2] << 8 | buf[3]; 299 modelgood = buf[0] == AM2315_READ_REGISTERS && buf[1] == 2 300 && crc == readcrc; 301 302 error = am2315_read_regs(sc, AM2315_REGISTER_VERSION, 1, buf, 5); 303 if (error) 304 aprint_error_dev(self, "read chipver: %d\n", error); 305 readcrc = buf[4] << 8 | buf[3]; 306 crc = am2315_crc(buf, 3); 307 DUMP("ver"); 308 chipver = buf[2]; 309 chipvergood = buf[0] == AM2315_READ_REGISTERS && buf[1] == 1 310 && crc == readcrc; 311 312 error = am2315_read_regs(sc, AM2315_REGISTER_ID_PT_24_31, 2, buf, 6); 313 if (error) 314 aprint_error_dev(self, "read id 1: %d\n", error); 315 readcrc = buf[5] << 8 | buf[4]; 316 crc = am2315_crc(buf, 4); 317 DUMP("id1+id2"); 318 id = buf[2] << 8 | buf[3]; 319 idgood = buf[0] == AM2315_READ_REGISTERS && buf[1] == 2 320 && crc == readcrc; 321 322 error = am2315_read_regs(sc, AM2315_REGISTER_ID_PT_8_15, 2, buf, 6); 323 if (error) 324 aprint_error_dev(self, "read id 2: %d\n", error); 325 readcrc = buf[5] << 8 | buf[4]; 326 crc = am2315_crc(buf, 4); 327 DUMP("id3+id4"); 328 id = id << 8 | buf[2]; 329 id = id << 8 | buf[3]; 330 idgood = buf[0] == AM2315_READ_REGISTERS && buf[1] == 2 331 && crc == readcrc && idgood; 332 333 iic_release_bus(sc->sc_tag, 0); 334 335 for (int i = 0; i < sc->sc_numsensors; i++) { 336 strlcpy(sc->sc_sensors[i].desc, am2315_sensors[i].desc, 337 sizeof(sc->sc_sensors[i].desc)); 338 339 sc->sc_sensors[i].units = am2315_sensors[i].type; 340 sc->sc_sensors[i].state = ENVSYS_SINVALID; 341 342 DPRINTF(sc, 2, ("am2315_attach: registering sensor %d (%s)\n", 343 i, sc->sc_sensors[i].desc)); 344 345 error = sysmon_envsys_sensor_attach(sc->sc_sme, 346 &sc->sc_sensors[i]); 347 if (error) { 348 aprint_error_dev(self, "unable to attach sensor %d\n", 349 error); 350 goto badregister; 351 } 352 } 353 354 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 355 sc->sc_sme->sme_cookie = sc; 356 sc->sc_sme->sme_refresh = am2315_refresh; 357 358 DPRINTF(sc, 2, ("am2315_attach: registering with envsys\n")); 359 360 error = sysmon_envsys_register(sc->sc_sme); 361 if (error) { 362 aprint_error_dev(self, "unable to register with sysmon %d\n", 363 error); 364 goto badregister; 365 } 366 aprint_normal_dev(self, "Aosong AM2315, Model: %04x%s Version: %02x%s" 367 " ID: %08x%s", 368 model, (modelgood ? "," : "(inaccurate),"), 369 chipver, (chipvergood ? "," : "(inaccurate),"), 370 id, (idgood ? "\n" : "(inaccurate)\n")); 371 return; 372 373 badsysctl: 374 aprint_error_dev(self, ": can't setup sysctl tree (%d)\n", error); 375 return; 376 badregister: 377 sysmon_envsys_destroy(sc->sc_sme); 378 sc->sc_sme = NULL; 379 } 380 381 static void 382 am2315_refresh(struct sysmon_envsys * sme, envsys_data_t * edata) 383 { 384 struct am2315_sc *sc; 385 uint8_t buf[11], thecommand; 386 uint16_t crc, readcrc; 387 int error, rv; 388 uint32_t val32; 389 bool istempneg = false; 390 391 sc = sme->sme_cookie; 392 edata->state = ENVSYS_SINVALID; 393 394 mutex_enter(&sc->sc_mutex); 395 error = iic_acquire_bus(sc->sc_tag, 0); 396 if (error) { 397 DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %d\n", 398 device_xname(sc->sc_dev), error)); 399 goto out; 400 } 401 402 switch (edata->sensor) { 403 case AM2315_HUMIDITY_SENSOR: 404 thecommand = AM2315_REGISTER_HIGH_RH; 405 break; 406 case AM2315_TEMP_SENSOR: 407 thecommand = AM2315_REGISTER_HIGH_TEMP; 408 break; 409 default: 410 DPRINTF(sc, 2, ("%s: bad sensor %d\n", 411 device_xname(sc->sc_dev), edata->sensor)); 412 goto out; 413 } 414 415 for (int count = 0; ;) { 416 am2315_poke(sc); 417 418 if ((error = am2315_read_regs(sc, thecommand, 2, buf, 6)) != 0) 419 DPRINTF(sc, 2, ("%s: Read sensor %d error: %d\n", 420 device_xname(sc->sc_dev),edata->sensor, error)); 421 422 readcrc = buf[5] << 8 | buf[4]; 423 crc = am2315_crc(buf, 4); 424 425 DPRINTF(sc, 2, ("%s: read cmd+len+dh+dl+crch+crcl values: %02x" 426 " %02x %02x%02x %02x%02x -- %04x %04x -- %d\n", 427 device_xname(sc->sc_dev), buf[0], buf[1], buf[2], 428 buf[3], buf[4], buf[5], crc, readcrc, count)); 429 if (++count == sc->sc_readcount) 430 break; 431 mutex_enter(&sc->sc_waitmutex); 432 rv = cv_timedwait(&sc->sc_condwait, &sc->sc_waitmutex, 433 sc->sc_readticks); 434 DPRINTF(sc, 2, ("%s: wait rv: %d\n", device_xname(sc->sc_dev), 435 rv)); 436 mutex_exit(&sc->sc_waitmutex); 437 } 438 439 iic_release_bus(sc->sc_tag, 0); 440 441 if (buf[0] != AM2315_READ_REGISTERS || buf[1] != 2 || 442 crc != readcrc) { 443 DPRINTF(sc, 2, ("%s: Invalid sensor data for %d\n", 444 device_xname(sc->sc_dev), edata->sensor)); 445 goto out; 446 } 447 448 switch (edata->sensor) { 449 case AM2315_HUMIDITY_SENSOR: 450 val32 = buf[2] << 8 | buf[3]; 451 val32 = val32 * 100000; 452 DPRINTF(sc, 2, ("%s: read translated values RH: %x\n", 453 device_xname(sc->sc_dev), val32)); 454 edata->value_cur = val32; 455 edata->state = ENVSYS_SVALID; 456 break; 457 case AM2315_TEMP_SENSOR: 458 istempneg = (buf[2] & AM2315_TEMP_NEGATIVE); 459 buf[2] = buf[2] & (~AM2315_TEMP_NEGATIVE); 460 val32 = buf[2] << 8 | buf[3]; 461 if (istempneg) { 462 val32 = 273150000 - (val32 * 100000); 463 } else { 464 val32 = (val32 * 100000) + 273150000; 465 } 466 DPRINTF(sc, 2, ("%s: read translated values TEMP: %x\n", 467 device_xname(sc->sc_dev), val32)); 468 edata->value_cur = val32; 469 edata->state = ENVSYS_SVALID; 470 break; 471 default: 472 panic("bad sensor %d\n", edata->sensor); 473 } 474 out: 475 mutex_exit(&sc->sc_mutex); 476 } 477 478 static int 479 am2315_detach(device_t self, int flags) 480 { 481 struct am2315_sc *sc = device_private(self); 482 483 mutex_enter(&sc->sc_mutex); 484 485 /* Remove the sensors */ 486 if (sc->sc_sme != NULL) { 487 sysmon_envsys_unregister(sc->sc_sme); 488 sc->sc_sme = NULL; 489 } 490 mutex_exit(&sc->sc_mutex); 491 492 /* Destroy the wait cond */ 493 cv_destroy(&sc->sc_condwait); 494 495 /* Remove the sysctl tree */ 496 sysctl_teardown(&sc->sc_am2315log); 497 498 /* Remove the mutex */ 499 mutex_destroy(&sc->sc_waitmutex); 500 mutex_destroy(&sc->sc_mutex); 501 502 return 0; 503 } 504 505 MODULE(MODULE_CLASS_DRIVER, am2315temp, "i2cexec,sysmon_envsys"); 506 507 #ifdef _MODULE 508 #include "ioconf.c" 509 #endif 510 511 static int 512 am2315temp_modcmd(modcmd_t cmd, void *opaque) 513 { 514 switch (cmd) { 515 case MODULE_CMD_INIT: 516 #ifdef _MODULE 517 return config_init_component(cfdriver_ioconf_am2315temp, 518 cfattach_ioconf_am2315temp, cfdata_ioconf_am2315temp); 519 #else 520 return 0; 521 #endif 522 case MODULE_CMD_FINI: 523 #ifdef _MODULE 524 return config_fini_component(cfdriver_ioconf_am2315temp, 525 cfattach_ioconf_am2315temp, cfdata_ioconf_am2315temp); 526 #else 527 return 0; 528 #endif 529 default: 530 return ENOTTY; 531 } 532 } 533