1 /*- 2 * Copyright (c) 2014 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Frank Kardel. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * IST-AG P14 calibrated Hygro-/Temperature sensor module 32 * Devices: HYT-271, HYT-221 and HYT-939 33 * 34 * see: 35 * http://www.ist-ag.com/eh/ist-ag/resource.nsf/imgref/Download_AHHYTM_E2.1.pdf/ 36 * $FILE/AHHYTM_E2.1.pdf 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: hytp14.c,v 1.6 2015/09/18 17:21:43 phx Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/device.h> 46 #include <sys/module.h> 47 #include <sys/sysctl.h> 48 49 #include <dev/sysmon/sysmonvar.h> 50 #include <dev/i2c/i2cvar.h> 51 #include <dev/i2c/hytp14reg.h> 52 #include <dev/i2c/hytp14var.h> 53 54 static int hytp14_match(device_t, cfdata_t, void *); 55 static void hytp14_attach(device_t, device_t, void *); 56 static int hytp14_detach(device_t, int); 57 static void hytp14_measurement_request(void *); 58 static int hytp14_refresh_sensor(struct hytp14_sc *sc); 59 static void hytp14_refresh(struct sysmon_envsys *, envsys_data_t *); 60 static void hytp14_refresh_humidity(struct hytp14_sc *, envsys_data_t *); 61 static void hytp14_refresh_temp(struct hytp14_sc *, envsys_data_t *); 62 static int sysctl_hytp14_interval(SYSCTLFN_ARGS); 63 64 /*#define HYT_DEBUG 3*/ 65 #ifdef HYT_DEBUG 66 volatile int hythygtemp_debug = HYT_DEBUG; 67 68 #define DPRINTF(_L_, _X_) do { \ 69 if ((_L_) <= hythygtemp_debug) { \ 70 printf _X_; \ 71 } \ 72 } while (0) 73 #else 74 #define DPRINTF(_L_, _X_) 75 #endif 76 77 CFATTACH_DECL_NEW(hythygtemp, sizeof(struct hytp14_sc), 78 hytp14_match, hytp14_attach, hytp14_detach, NULL); 79 80 static struct hytp14_sensor hytp14_sensors[] = { 81 { 82 .desc = "humidity", 83 .type = ENVSYS_SRELHUMIDITY, 84 .refresh = hytp14_refresh_humidity 85 }, 86 { 87 .desc = "temperature", 88 .type = ENVSYS_STEMP, 89 .refresh = hytp14_refresh_temp 90 } 91 }; 92 93 static int 94 hytp14_match(device_t parent, cfdata_t match, void *aux) 95 { 96 struct i2c_attach_args *ia; 97 98 ia = aux; 99 100 if (ia->ia_name) { 101 /* direct config - check name */ 102 if (strcmp(ia->ia_name, "hythygtemp") == 0) 103 return 1; 104 } else { 105 /* indirect config - check for configured address */ 106 if ((ia->ia_addr > 0) && (ia->ia_addr <= 0x7F)) 107 return 1; 108 } 109 return 0; 110 } 111 112 static void 113 hytp14_attach(device_t parent, device_t self, void *aux) 114 { 115 const struct sysctlnode *rnode, *node; 116 struct hytp14_sc *sc; 117 struct i2c_attach_args *ia; 118 int i; 119 120 ia = aux; 121 sc = device_private(self); 122 123 sc->sc_dev = self; 124 sc->sc_tag = ia->ia_tag; 125 sc->sc_addr = ia->ia_addr; 126 sc->sc_valid = ENVSYS_SINVALID; 127 sc->sc_numsensors = __arraycount(hytp14_sensors); 128 129 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 130 aprint_error_dev(sc->sc_dev, 131 "unable to create sysmon structure\n"); 132 return; 133 } 134 135 for (i = 0; i < sc->sc_numsensors; i++) { 136 strlcpy(sc->sc_sensors[i].desc, 137 hytp14_sensors[i].desc, 138 sizeof sc->sc_sensors[i].desc); 139 140 sc->sc_sensors[i].units = hytp14_sensors[i].type; 141 sc->sc_sensors[i].state = ENVSYS_SINVALID; 142 143 DPRINTF(2, ("hytp14_attach: registering sensor %d (%s)\n", i, 144 sc->sc_sensors[i].desc)); 145 146 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[i])) { 147 aprint_error_dev(sc->sc_dev, 148 "unable to attach sensor\n"); 149 sysmon_envsys_destroy(sc->sc_sme); 150 return; 151 } 152 } 153 154 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 155 sc->sc_sme->sme_cookie = sc; 156 sc->sc_sme->sme_refresh = hytp14_refresh; 157 158 DPRINTF(2, ("hytp14_attach: registering with envsys\n")); 159 160 if (sysmon_envsys_register(sc->sc_sme)) { 161 aprint_error_dev(sc->sc_dev, 162 "unable to register with sysmon\n"); 163 sysmon_envsys_destroy(sc->sc_sme); 164 return; 165 } 166 167 /* create a sysctl node for setting the measurement interval */ 168 rnode = node = NULL; 169 sysctl_createv(NULL, 0, NULL, &rnode, 170 CTLFLAG_READWRITE, 171 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 172 NULL, 0, NULL, 0, 173 CTL_HW, CTL_CREATE, CTL_EOL); 174 175 if (rnode != NULL) 176 sysctl_createv(NULL, 0, NULL, &node, 177 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 178 CTLTYPE_INT, "interval", 179 SYSCTL_DESCR("Sensor sampling interval in seconds"), 180 sysctl_hytp14_interval, 0, (void *)sc, 0, 181 CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL); 182 183 aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n"); 184 185 /* set up callout for the default measurement interval */ 186 sc->sc_mrinterval = HYTP14_MR_INTERVAL; 187 callout_init(&sc->sc_mrcallout, 0); 188 callout_setfunc(&sc->sc_mrcallout, hytp14_measurement_request, sc); 189 190 /* issue initial measurement request */ 191 hytp14_measurement_request(sc); 192 } 193 194 static int 195 hytp14_detach(device_t self, int flags) 196 { 197 struct hytp14_sc *sc; 198 199 sc = device_private(self); 200 201 if (sc->sc_sme != NULL) { 202 sysmon_envsys_unregister(sc->sc_sme); 203 sc->sc_sme = NULL; 204 } 205 206 /* stop our measurement requests */ 207 callout_stop(&sc->sc_mrcallout); 208 callout_destroy(&sc->sc_mrcallout); 209 210 return 0; 211 } 212 213 static void 214 hytp14_measurement_request(void *aux) 215 { 216 uint8_t buf[I2C_EXEC_MAX_BUFLEN]; 217 struct hytp14_sc *sc; 218 int error; 219 220 sc = aux; 221 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 222 223 error = iic_acquire_bus(sc->sc_tag, 0); 224 if (error == 0) { 225 226 /* send DF command - read last data from sensor */ 227 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 228 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 229 if (error != 0) { 230 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 231 device_xname(sc->sc_dev), __func__, 232 sc->sc_addr, error)); 233 sc->sc_valid = ENVSYS_SINVALID; 234 } else { 235 DPRINTF(3, ("%s(%s): DF success : " 236 "0x%02x%02x%02x%02x\n", 237 __func__, device_xname(sc->sc_dev), 238 sc->sc_data[0], sc->sc_data[1], 239 sc->sc_data[2], sc->sc_data[3])); 240 241 /* remember last data, when valid */ 242 if (!(sc->sc_data[0] & 243 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 244 memcpy(sc->sc_last, sc->sc_data, 245 sizeof(sc->sc_last)); 246 sc->sc_valid = ENVSYS_SVALID; 247 } 248 } 249 250 /* send MR command to request a new measurement */ 251 error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 252 sc->sc_addr, NULL, 0, buf, sizeof(buf), 0); 253 254 if (error == 0) { 255 DPRINTF(3, ("%s(%s): MR sent\n", 256 __func__, device_xname(sc->sc_dev))); 257 } else { 258 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 259 device_xname(sc->sc_dev), __func__, 260 sc->sc_addr, error)); 261 } 262 263 iic_release_bus(sc->sc_tag, 0); 264 DPRINTF(3, ("%s(%s): bus released\n", 265 __func__, device_xname(sc->sc_dev))); 266 } else { 267 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 268 device_xname(sc->sc_dev), __func__, error)); 269 } 270 271 /* schedule next measurement interval */ 272 callout_schedule(&sc->sc_mrcallout, sc->sc_mrinterval * hz); 273 } 274 275 static int 276 hytp14_refresh_sensor(struct hytp14_sc *sc) 277 { 278 int error; 279 280 DPRINTF(2, ("%s(%s)\n", __func__, device_xname(sc->sc_dev))); 281 282 error = iic_acquire_bus(sc->sc_tag, 0); 283 if (error == 0) { 284 285 /* send DF command - read last data from sensor */ 286 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 287 sc->sc_addr, NULL, 0, sc->sc_data, sizeof(sc->sc_data), 0); 288 if (error != 0) { 289 DPRINTF(2, ("%s: %s: failed read from 0x%02x - error %d\n", 290 device_xname(sc->sc_dev), __func__, 291 sc->sc_addr, error)); 292 sc->sc_valid = ENVSYS_SINVALID; 293 } else { 294 DPRINTF(3, ("%s(%s): DF success : " 295 "0x%02x%02x%02x%02x\n", 296 __func__, device_xname(sc->sc_dev), 297 sc->sc_data[0], sc->sc_data[1], 298 sc->sc_data[2], sc->sc_data[3])); 299 300 /* 301 * Use old data from sc_last[] when new data 302 * is not yet valid (i.e. DF command came too 303 * quickly after the last command). 304 */ 305 if (!(sc->sc_data[0] & 306 (HYTP14_RESP_CMDMODE | HYTP14_RESP_STALE))) { 307 memcpy(sc->sc_last, sc->sc_data, 308 sizeof(sc->sc_last)); 309 sc->sc_valid = ENVSYS_SVALID; 310 } else 311 memcpy(sc->sc_data, sc->sc_last, 312 sizeof(sc->sc_data)); 313 } 314 315 iic_release_bus(sc->sc_tag, 0); 316 DPRINTF(3, ("%s(%s): bus released\n", 317 __func__, device_xname(sc->sc_dev))); 318 } else { 319 DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", 320 device_xname(sc->sc_dev), __func__, error)); 321 } 322 323 return sc->sc_valid; 324 } 325 326 327 static void 328 hytp14_refresh_humidity(struct hytp14_sc *sc, envsys_data_t *edata) 329 { 330 uint16_t hyg; 331 int status; 332 333 status = hytp14_refresh_sensor(sc); 334 335 if (status == ENVSYS_SVALID) { 336 hyg = (sc->sc_data[0] << 8) | sc->sc_data[1]; 337 338 edata->value_cur = (1000000000 / HYTP14_HYG_SCALE) * (int32_t)HYTP14_HYG_RAWVAL(hyg); 339 edata->value_cur /= 10; 340 } 341 342 edata->state = status; 343 } 344 345 static void 346 hytp14_refresh_temp(struct hytp14_sc *sc, envsys_data_t *edata) 347 { 348 uint16_t temp; 349 int status; 350 351 status = hytp14_refresh_sensor(sc); 352 353 if (status == ENVSYS_SVALID) { 354 temp = HYTP14_TEMP_RAWVAL((sc->sc_data[2] << 8) | sc->sc_data[3]); 355 356 edata->value_cur = (HYTP14_TEMP_FACTOR * 1000000) / HYTP14_TEMP_SCALE; 357 edata->value_cur *= (int32_t)temp; 358 edata->value_cur += HYTP14_TEMP_OFFSET * 1000000 + 273150000; 359 } 360 361 edata->state = status; 362 } 363 364 static void 365 hytp14_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 366 { 367 struct hytp14_sc *sc; 368 369 sc = sme->sme_cookie; 370 hytp14_sensors[edata->sensor].refresh(sc, edata); 371 } 372 373 static int 374 sysctl_hytp14_interval(SYSCTLFN_ARGS) 375 { 376 struct sysctlnode node; 377 struct hytp14_sc *sc; 378 int32_t t; 379 int error; 380 381 node = *rnode; 382 sc = node.sysctl_data; 383 384 t = sc->sc_mrinterval; 385 node.sysctl_data = &t; 386 387 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 388 if (error || newp == NULL) 389 return error; 390 if (t <= 0) 391 return EINVAL; 392 393 sc->sc_mrinterval = t; 394 return 0; 395 } 396 397 MODULE(MODULE_CLASS_DRIVER, hythygtemp, "i2cexec,sysmon_envsys"); 398 399 #ifdef _MODULE 400 #include "ioconf.c" 401 #endif 402 403 static int 404 hythygtemp_modcmd(modcmd_t cmd, void *opaque) 405 { 406 int error; 407 408 error = 0; 409 410 switch (cmd) { 411 case MODULE_CMD_INIT: 412 #ifdef _MODULE 413 error = config_init_component(cfdriver_ioconf_hythygtemp, 414 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 415 #endif 416 return error; 417 418 case MODULE_CMD_FINI: 419 #ifdef _MODULE 420 error = config_fini_component(cfdriver_ioconf_hythygtemp, 421 cfattach_ioconf_hythygtemp, cfdata_ioconf_hythygtemp); 422 #endif 423 return error; 424 425 default: 426 return ENOTTY; 427 } 428 } 429